Skip to content

Commit 42b121e

Browse files
mjchen0mmahadevan108
authored andcommitted
drivers: i3c: mcux: fix issues when only i2c devices are on the bus
Fixes for bug: #57560 * don't do CCC if no i3c devices in device tree * don't wait for MCTRLDONE status when issuing stop * don't do data part of transfer if buf_sz is 0 * don't limit transfers to only i2c devices in the device tree so "i2c scan" shell cmd works as expected Signed-off-by: Mike J. Chen <mjchen@google.com>
1 parent 7c0784d commit 42b121e

File tree

1 file changed

+83
-120
lines changed

1 file changed

+83
-120
lines changed

drivers/i3c/i3c_mcux.c

Lines changed: 83 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -685,7 +685,10 @@ static inline void mcux_i3c_request_emit_stop(I3C_Type *base, bool wait_stop)
685685
I3C_MCTRL_REQUEST_MASK | I3C_MCTRL_DIR_MASK | I3C_MCTRL_RDTERM_MASK,
686686
I3C_MCTRL_REQUEST_EMIT_STOP);
687687

688-
mcux_i3c_status_wait_clear(base, I3C_MSTATUS_MCTRLDONE_MASK);
688+
/*
689+
* EMIT_STOP request doesn't result in MCTRLDONE being cleared
690+
* so don't wait for it.
691+
*/
689692

690693
if (wait_stop) {
691694
/*
@@ -816,27 +819,6 @@ struct i3c_device_desc *mcux_i3c_device_find(const struct device *dev,
816819
return i3c_dev_list_find(&config->common.dev_list, id);
817820
}
818821

819-
/**
820-
* Find a registered I2C target device.
821-
*
822-
* Controller only API.
823-
*
824-
* This returns the I2C device descriptor of the I2C device
825-
* matching the device address @p addr.
826-
*
827-
* @param dev Pointer to controller device driver instance.
828-
* @param id I2C target device address.
829-
*
830-
* @return @see i3c_i2c_device_find.
831-
*/
832-
static struct i3c_i2c_device_desc *
833-
mcux_i3c_i2c_device_find(const struct device *dev, uint16_t addr)
834-
{
835-
struct mcux_i3c_data *data = dev->data;
836-
837-
return i3c_dev_list_i2c_addr_find(&data->common.attached_dev, addr);
838-
}
839-
840822
/**
841823
* @brief Perform bus recovery.
842824
*
@@ -1035,7 +1017,7 @@ static int mcux_i3c_do_one_xfer(I3C_Type *base, struct mcux_i3c_data *data,
10351017
}
10361018
}
10371019

1038-
if (buf == NULL) {
1020+
if ((buf == NULL) || (buf_sz == 0)) {
10391021
goto out_one_xfer;
10401022
}
10411023

@@ -1050,6 +1032,8 @@ static int mcux_i3c_do_one_xfer(I3C_Type *base, struct mcux_i3c_data *data,
10501032
ret = mcux_i3c_status_wait_clear_timeout(base, I3C_MSTATUS_COMPLETE_MASK,
10511033
0, 10, 1000);
10521034
if (ret != 0) {
1035+
LOG_DBG("%s: timed out addr 0x%02x, buf_sz %u",
1036+
__func__, addr, buf_sz);
10531037
emit_stop = true;
10541038

10551039
goto out_one_xfer;
@@ -1165,97 +1149,6 @@ static int mcux_i3c_transfer(const struct device *dev,
11651149
return ret;
11661150
}
11671151

1168-
/**
1169-
* @brief Transfer messages in I2C mode.
1170-
*
1171-
* @see i3c_i2c_transfer
1172-
*
1173-
* @param dev Pointer to device driver instance.
1174-
* @param target Pointer to target device descriptor.
1175-
* @param msgs Pointer to I2C messages.
1176-
* @param num_msgs Number of messages to transfers.
1177-
*
1178-
* @return @see i3c_i2c_transfer
1179-
*/
1180-
static int mcux_i3c_i2c_transfer(const struct device *dev,
1181-
struct i3c_i2c_device_desc *i2c_dev,
1182-
struct i2c_msg *msgs,
1183-
uint8_t num_msgs)
1184-
{
1185-
const struct mcux_i3c_config *config = dev->config;
1186-
struct mcux_i3c_data *dev_data = dev->data;
1187-
I3C_Type *base = config->base;
1188-
uint32_t intmask;
1189-
int ret;
1190-
1191-
k_sem_take(&dev_data->lock, K_FOREVER);
1192-
1193-
intmask = mcux_i3c_interrupt_disable(base);
1194-
1195-
ret = mcux_i3c_state_wait_timeout(base, I3C_MSTATUS_STATE_IDLE, 0, 100, 100000);
1196-
if (ret == -ETIMEDOUT) {
1197-
goto out_xfer_i2c_unlock;
1198-
}
1199-
1200-
mcux_i3c_xfer_reset(base);
1201-
1202-
/* Iterate over all the messages */
1203-
for (int i = 0; i < num_msgs; i++) {
1204-
bool is_read = (msgs[i].flags & I2C_MSG_RW_MASK) == I2C_MSG_READ;
1205-
bool no_ending = false;
1206-
1207-
/*
1208-
* Emit start if this is the first message or that
1209-
* the RESTART flag is set in message.
1210-
*/
1211-
bool emit_start = (i == 0) ||
1212-
((msgs[i].flags & I2C_MSG_RESTART) == I2C_MSG_RESTART);
1213-
1214-
bool emit_stop = (msgs[i].flags & I2C_MSG_STOP) == I2C_MSG_STOP;
1215-
1216-
/*
1217-
* The controller requires special treatment of last byte of
1218-
* a write message. Since the API permits having a bunch of
1219-
* write messages without RESTART in between, this is just some
1220-
* logic to determine whether to treat the last byte of this
1221-
* message to be the last byte of a series of write mssages.
1222-
* If not, tell the write function not to treat it that way.
1223-
*/
1224-
if (!is_read && !emit_stop && ((i + 1) != num_msgs)) {
1225-
bool next_is_write =
1226-
(msgs[i + 1].flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE;
1227-
bool next_is_restart =
1228-
((msgs[i + 1].flags & I2C_MSG_RESTART) == I2C_MSG_RESTART);
1229-
1230-
if (next_is_write && !next_is_restart) {
1231-
no_ending = true;
1232-
}
1233-
}
1234-
1235-
ret = mcux_i3c_do_one_xfer(base, dev_data, i2c_dev->addr, true,
1236-
msgs[i].buf, msgs[i].len,
1237-
is_read, emit_start, emit_stop, no_ending);
1238-
if (ret < 0) {
1239-
goto out_xfer_i2c_stop_unlock;
1240-
}
1241-
}
1242-
1243-
ret = 0;
1244-
1245-
out_xfer_i2c_stop_unlock:
1246-
mcux_i3c_request_emit_stop(base, true);
1247-
1248-
out_xfer_i2c_unlock:
1249-
mcux_i3c_errwarn_clear_all_nowait(base);
1250-
mcux_i3c_status_clear_all(base);
1251-
1252-
mcux_i3c_interrupt_enable(base, intmask);
1253-
1254-
k_sem_give(&dev_data->lock);
1255-
1256-
return ret;
1257-
}
1258-
12591152
/**
12601153
* @brief Perform Dynamic Address Assignment.
12611154
*
@@ -1417,6 +1310,15 @@ static int mcux_i3c_do_ccc(const struct device *dev,
14171310
return -EINVAL;
14181311
}
14191312

1313+
if (config->common.dev_list.num_i3c == 0) {
1314+
/*
1315+
* No i3c devices in dev tree. Just return so
1316+
* we don't get errors doing cmds when there
1317+
* are no devices listening/responding.
1318+
*/
1319+
return 0;
1320+
}
1321+
14201322
k_sem_take(&data->lock, K_FOREVER);
14211323

14221324
intmask = mcux_i3c_interrupt_disable(base);
@@ -2078,16 +1980,77 @@ static int mcux_i3c_i2c_api_transfer(const struct device *dev,
20781980
uint8_t num_msgs,
20791981
uint16_t addr)
20801982
{
2081-
struct i3c_i2c_device_desc *i2c_dev =
2082-
mcux_i3c_i2c_device_find(dev, addr);
1983+
const struct mcux_i3c_config *config = dev->config;
1984+
struct mcux_i3c_data *dev_data = dev->data;
1985+
I3C_Type *base = config->base;
1986+
uint32_t intmask;
20831987
int ret;
20841988

2085-
if (i2c_dev == NULL) {
2086-
ret = -ENODEV;
2087-
} else {
2088-
ret = mcux_i3c_i2c_transfer(dev, i2c_dev, msgs, num_msgs);
1989+
k_sem_take(&dev_data->lock, K_FOREVER);
1990+
1991+
intmask = mcux_i3c_interrupt_disable(base);
1992+
1993+
ret = mcux_i3c_state_wait_timeout(base, I3C_MSTATUS_STATE_IDLE, 0, 100, 100000);
1994+
if (ret == -ETIMEDOUT) {
1995+
goto out_xfer_i2c_unlock;
1996+
}
1997+
1998+
mcux_i3c_xfer_reset(base);
1999+
2000+
/* Iterate over all the messages */
2001+
for (int i = 0; i < num_msgs; i++) {
2002+
bool is_read = (msgs[i].flags & I2C_MSG_RW_MASK) == I2C_MSG_READ;
2003+
bool no_ending = false;
2004+
2005+
/*
2006+
* Emit start if this is the first message or that
2007+
* the RESTART flag is set in message.
2008+
*/
2009+
bool emit_start = (i == 0) ||
2010+
((msgs[i].flags & I2C_MSG_RESTART) == I2C_MSG_RESTART);
2011+
2012+
bool emit_stop = (msgs[i].flags & I2C_MSG_STOP) == I2C_MSG_STOP;
2013+
2014+
/*
2015+
* The controller requires special treatment of last byte of
2016+
* a write message. Since the API permits having a bunch of
2017+
* write messages without RESTART in between, this is just some
2018+
* logic to determine whether to treat the last byte of this
2019+
* message to be the last byte of a series of write mssages.
2020+
* If not, tell the write function not to treat it that way.
2021+
*/
2022+
if (!is_read && !emit_stop && ((i + 1) != num_msgs)) {
2023+
bool next_is_write =
2024+
(msgs[i + 1].flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE;
2025+
bool next_is_restart =
2026+
((msgs[i + 1].flags & I2C_MSG_RESTART) == I2C_MSG_RESTART);
2027+
2028+
if (next_is_write && !next_is_restart) {
2029+
no_ending = true;
2030+
}
2031+
}
2032+
2033+
ret = mcux_i3c_do_one_xfer(base, dev_data, addr, true,
2034+
msgs[i].buf, msgs[i].len,
2035+
is_read, emit_start, emit_stop, no_ending);
2036+
if (ret < 0) {
2037+
goto out_xfer_i2c_stop_unlock;
2038+
}
20892039
}
20902040

2041+
ret = 0;
2042+
2043+
out_xfer_i2c_stop_unlock:
2044+
mcux_i3c_request_emit_stop(base, true);
2045+
2046+
out_xfer_i2c_unlock:
2047+
mcux_i3c_errwarn_clear_all_nowait(base);
2048+
mcux_i3c_status_clear_all(base);
2049+
2050+
mcux_i3c_interrupt_enable(base, intmask);
2051+
2052+
k_sem_give(&dev_data->lock);
2053+
20912054
return ret;
20922055
}
20932056

0 commit comments

Comments
 (0)