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 */
633589static 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