Skip to content

Commit ba35846

Browse files
mmahadevan108fabiobaltieri
authored andcommitted
drivers: i3c_mcux: Update error handling
Enable the Error interrupt to capture errors and process them accordingly. Signed-off-by: Mahesh Mahadevan <[email protected]>
1 parent 7d15053 commit ba35846

File tree

1 file changed

+45
-87
lines changed

1 file changed

+45
-87
lines changed

drivers/i3c/i3c_mcux.c

Lines changed: 45 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
#include <zephyr/drivers/clock_control.h>
1919
#include <zephyr/drivers/i3c.h>
20-
20+
#include <zephyr/spinlock.h>
2121
#include <zephyr/drivers/pinctrl.h>
2222

2323
/*
@@ -128,6 +128,9 @@ struct mcux_i3c_data {
128128
#endif
129129
};
130130

131+
uint32_t merrwarn_reg;
132+
static struct k_spinlock lock;
133+
131134
/**
132135
* @brief Read a register and test for bit matches with timeout.
133136
*
@@ -235,70 +238,23 @@ static void mcux_i3c_interrupt_enable(I3C_Type *base, uint32_t mask)
235238
/**
236239
* @brief Check if there are any errors.
237240
*
238-
* This checks if MSTATUS has ERRWARN bit set.
239-
*
240-
* @retval True if there are any errors.
241-
* @retval False if no errors.
241+
* @retval errors reported or 0 if no errors.
242242
*/
243-
static bool mcux_i3c_has_error(I3C_Type *base)
243+
static uint32_t mcux_i3c_has_error(void)
244244
{
245-
uint32_t mstatus, merrwarn;
246-
247-
mstatus = base->MSTATUS;
248-
if ((mstatus & I3C_MSTATUS_ERRWARN_MASK) == I3C_MSTATUS_ERRWARN_MASK) {
249-
merrwarn = base->MERRWARN;
250-
251-
/*
252-
* Note that this uses LOG_DBG() for displaying
253-
* register values for debugging. In production builds,
254-
* printing any error messages should be handled in
255-
* callers of this function.
256-
*/
257-
LOG_DBG("ERROR: MSTATUS 0x%08x MERRWARN 0x%08x",
258-
mstatus, merrwarn);
259-
260-
return true;
261-
}
245+
uint32_t ret = 0;
262246

263-
return false;
264-
}
247+
k_spinlock_key_t key = k_spin_lock(&lock);
265248

266-
/**
267-
* @brief Check if there are any errors, and if one of them is time out error.
268-
*
269-
* @retval True if controller times out on operation.
270-
* @retval False if no time out error.
271-
*/
272-
static inline bool mcux_i3c_error_is_timeout(I3C_Type *base)
273-
{
274-
if (mcux_i3c_has_error(base)) {
275-
if (reg32_test(&base->MERRWARN, I3C_MERRWARN_TIMEOUT_MASK)) {
276-
return true;
277-
}
249+
if (merrwarn_reg) {
250+
/* Read and clear */
251+
ret = merrwarn_reg;
252+
merrwarn_reg = 0;
278253
}
279254

280-
return false;
281-
}
282-
283-
/**
284-
* @brief Check if there are any errors, and if one of them is NACK.
285-
*
286-
* NACK is generated when:
287-
* 1. Target does not ACK the last used address.
288-
* 2. All targets do not ACK on 0x7E.
289-
*
290-
* @retval True if NACK is received.
291-
* @retval False if no NACK error.
292-
*/
293-
static inline bool mcux_i3c_error_is_nack(I3C_Type *base)
294-
{
295-
if (mcux_i3c_has_error(base)) {
296-
if (reg32_test(&base->MERRWARN, I3C_MERRWARN_NACK_MASK)) {
297-
return true;
298-
}
299-
}
255+
k_spin_unlock(&lock, key);
300256

301-
return false;
257+
return ret;
302258
}
303259

304260
/**
@@ -612,7 +568,7 @@ static int mcux_i3c_request_emit_start(I3C_Type *base, uint8_t addr, bool is_i2c
612568
1000);
613569
if (ret == 0) {
614570
/* Check for NACK */
615-
if (mcux_i3c_error_is_nack(base)) {
571+
if (mcux_i3c_has_error() & I3C_MERRWARN_NACK_MASK) {
616572
ret = -ENODEV;
617573
}
618574
}
@@ -632,6 +588,8 @@ static int mcux_i3c_request_emit_start(I3C_Type *base, uint8_t addr, bool is_i2c
632588
*/
633589
static inline int mcux_i3c_do_request_emit_stop(I3C_Type *base, bool wait_stop)
634590
{
591+
uint32_t merrwarn;
592+
635593
reg32_update(&base->MCTRL,
636594
I3C_MCTRL_REQUEST_MASK | I3C_MCTRL_DIR_MASK | I3C_MCTRL_RDTERM_MASK,
637595
I3C_MCTRL_REQUEST_EMIT_STOP);
@@ -649,16 +607,15 @@ static inline int mcux_i3c_do_request_emit_stop(I3C_Type *base, bool wait_stop)
649607
*/
650608
while (reg32_test_match(&base->MSTATUS, I3C_MSTATUS_STATE_MASK,
651609
I3C_MSTATUS_STATE_NORMACT)) {
652-
if (mcux_i3c_has_error(base)) {
610+
merrwarn = mcux_i3c_has_error();
611+
if (merrwarn) {
653612
/*
654613
* A timeout error has been observed on
655614
* an EMIT_STOP request. Refman doesn't say
656615
* how that could occur but clear it
657616
* and return the error.
658617
*/
659-
if (reg32_test(&base->MERRWARN,
660-
I3C_MERRWARN_TIMEOUT_MASK)) {
661-
mcux_i3c_errwarn_clear_all_nowait(base);
618+
if (merrwarn & I3C_MERRWARN_TIMEOUT_MASK) {
662619
return -ETIMEDOUT;
663620
}
664621
return -EIO;
@@ -693,7 +650,7 @@ static inline void mcux_i3c_request_emit_stop(struct mcux_i3c_data *dev_data,
693650
* it so any error as a result of emitting the stop
694651
* itself doesn't get incorrectly mixed together.
695652
*/
696-
if (mcux_i3c_has_error(base)) {
653+
if (mcux_i3c_has_error()) {
697654
mcux_i3c_errwarn_clear_all_nowait(base);
698655
}
699656

@@ -928,27 +885,21 @@ static int mcux_i3c_do_one_xfer_read(I3C_Type *base, struct mcux_i3c_data *data,
928885
}
929886
}
930887
/*
931-
* If controller says timed out, we abort the transaction.
888+
* If timed out, we abort the transaction.
932889
*/
933-
if (mcux_i3c_has_error(base) || ret) {
934-
if (mcux_i3c_error_is_timeout(base)) {
935-
ret = -ETIMEDOUT;
936-
}
937-
/* clear error */
938-
base->MERRWARN = base->MERRWARN;
890+
if ((mcux_i3c_has_error() & I3C_MERRWARN_TIMEOUT_MASK) || ret) {
891+
ret = -ETIMEDOUT;
939892

940-
if (ret == -ETIMEDOUT) {
941-
/* for ibi, ignore timeout err if any bytes were
942-
* read, since the code doesn't know how many
943-
* bytes will be sent by device.
944-
*/
945-
if (ibi && offset) {
946-
ret = offset;
947-
} else {
948-
LOG_ERR("Timeout error");
949-
}
950-
break;
893+
/* for ibi, ignore timeout err if any bytes were
894+
* read, since the code doesn't know how many
895+
* bytes will be sent by device.
896+
*/
897+
if (ibi && offset) {
898+
ret = offset;
899+
} else {
900+
LOG_ERR("Timeout error");
951901
}
902+
break;
952903
}
953904

954905
}
@@ -1078,7 +1029,7 @@ static int mcux_i3c_do_one_xfer(I3C_Type *base, struct mcux_i3c_data *data,
10781029
}
10791030
}
10801031

1081-
if (mcux_i3c_has_error(base)) {
1032+
if (mcux_i3c_has_error()) {
10821033
ret = -EIO;
10831034
}
10841035

@@ -1251,7 +1202,7 @@ static int mcux_i3c_do_daa(const struct device *dev)
12511202
do {
12521203
/* Loop to grab data from devices (Provisioned ID, BCR and DCR) */
12531204
do {
1254-
if (mcux_i3c_has_error(base)) {
1205+
if (mcux_i3c_has_error()) {
12551206
LOG_ERR("DAA recv error");
12561207

12571208
ret = -EIO;
@@ -1576,7 +1527,7 @@ static void mcux_i3c_ibi_work(struct k_work *work)
15761527
break;
15771528
}
15781529

1579-
if (mcux_i3c_has_error(base)) {
1530+
if (mcux_i3c_has_error()) {
15801531
/*
15811532
* If the controller detects any errors, simply
15821533
* emit a STOP to abort the IBI. The target will
@@ -1872,6 +1823,11 @@ static void mcux_i3c_isr(const struct device *dev)
18721823
} else {
18731824
/* Nothing to do right now */
18741825
}
1826+
1827+
if (interrupt_enable & I3C_MSTATUS_ERRWARN_MASK) {
1828+
merrwarn_reg = base->MERRWARN;
1829+
base->MERRWARN = base->MERRWARN;
1830+
}
18751831
}
18761832

18771833
/**
@@ -2033,16 +1989,18 @@ static int mcux_i3c_init(const struct device *dev)
20331989
goto err_out;
20341990
}
20351991

2036-
/* Disable all interrupts */
1992+
/* Disable all interrupts except error interrupt */
20371993
base->MINTCLR = I3C_MINTCLR_SLVSTART_MASK |
20381994
I3C_MINTCLR_MCTRLDONE_MASK |
20391995
I3C_MINTCLR_COMPLETE_MASK |
20401996
I3C_MINTCLR_RXPEND_MASK |
20411997
I3C_MINTCLR_TXNOTFULL_MASK |
20421998
I3C_MINTCLR_IBIWON_MASK |
2043-
I3C_MINTCLR_ERRWARN_MASK |
20441999
I3C_MINTCLR_NOWMASTER_MASK;
20452000

2001+
/* Enable error interrupt */
2002+
base->MINTSET = I3C_MSTATUS_ERRWARN_MASK;
2003+
20462004
/* Just in case the bus is not in idle. */
20472005
ret = mcux_i3c_recover_bus(dev);
20482006
if (ret != 0) {

0 commit comments

Comments
 (0)