17
17
18
18
#include <zephyr/drivers/clock_control.h>
19
19
#include <zephyr/drivers/i3c.h>
20
-
20
+ #include <zephyr/spinlock.h>
21
21
#include <zephyr/drivers/pinctrl.h>
22
22
23
23
/*
@@ -128,6 +128,9 @@ struct mcux_i3c_data {
128
128
#endif
129
129
};
130
130
131
+ uint32_t merrwarn_reg ;
132
+ static struct k_spinlock lock ;
133
+
131
134
/**
132
135
* @brief Read a register and test for bit matches with timeout.
133
136
*
@@ -235,70 +238,23 @@ static void mcux_i3c_interrupt_enable(I3C_Type *base, uint32_t mask)
235
238
/**
236
239
* @brief Check if there are any errors.
237
240
*
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.
242
242
*/
243
- static bool mcux_i3c_has_error (I3C_Type * base )
243
+ static uint32_t mcux_i3c_has_error (void )
244
244
{
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 ;
262
246
263
- return false;
264
- }
247
+ k_spinlock_key_t key = k_spin_lock (& lock );
265
248
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 ;
278
253
}
279
254
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 );
300
256
301
- return false ;
257
+ return ret ;
302
258
}
303
259
304
260
/**
@@ -612,7 +568,7 @@ static int mcux_i3c_request_emit_start(I3C_Type *base, uint8_t addr, bool is_i2c
612
568
1000 );
613
569
if (ret == 0 ) {
614
570
/* Check for NACK */
615
- if (mcux_i3c_error_is_nack ( base ) ) {
571
+ if (mcux_i3c_has_error () & I3C_MERRWARN_NACK_MASK ) {
616
572
ret = - ENODEV ;
617
573
}
618
574
}
@@ -632,6 +588,8 @@ static int mcux_i3c_request_emit_start(I3C_Type *base, uint8_t addr, bool is_i2c
632
588
*/
633
589
static inline int mcux_i3c_do_request_emit_stop (I3C_Type * base , bool wait_stop )
634
590
{
591
+ uint32_t merrwarn ;
592
+
635
593
reg32_update (& base -> MCTRL ,
636
594
I3C_MCTRL_REQUEST_MASK | I3C_MCTRL_DIR_MASK | I3C_MCTRL_RDTERM_MASK ,
637
595
I3C_MCTRL_REQUEST_EMIT_STOP );
@@ -649,16 +607,15 @@ static inline int mcux_i3c_do_request_emit_stop(I3C_Type *base, bool wait_stop)
649
607
*/
650
608
while (reg32_test_match (& base -> MSTATUS , I3C_MSTATUS_STATE_MASK ,
651
609
I3C_MSTATUS_STATE_NORMACT )) {
652
- if (mcux_i3c_has_error (base )) {
610
+ merrwarn = mcux_i3c_has_error ();
611
+ if (merrwarn ) {
653
612
/*
654
613
* A timeout error has been observed on
655
614
* an EMIT_STOP request. Refman doesn't say
656
615
* how that could occur but clear it
657
616
* and return the error.
658
617
*/
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 ) {
662
619
return - ETIMEDOUT ;
663
620
}
664
621
return - EIO ;
@@ -693,7 +650,7 @@ static inline void mcux_i3c_request_emit_stop(struct mcux_i3c_data *dev_data,
693
650
* it so any error as a result of emitting the stop
694
651
* itself doesn't get incorrectly mixed together.
695
652
*/
696
- if (mcux_i3c_has_error (base )) {
653
+ if (mcux_i3c_has_error ()) {
697
654
mcux_i3c_errwarn_clear_all_nowait (base );
698
655
}
699
656
@@ -928,27 +885,21 @@ static int mcux_i3c_do_one_xfer_read(I3C_Type *base, struct mcux_i3c_data *data,
928
885
}
929
886
}
930
887
/*
931
- * If controller says timed out, we abort the transaction.
888
+ * If timed out, we abort the transaction.
932
889
*/
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 ;
939
892
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" );
951
901
}
902
+ break ;
952
903
}
953
904
954
905
}
@@ -1078,7 +1029,7 @@ static int mcux_i3c_do_one_xfer(I3C_Type *base, struct mcux_i3c_data *data,
1078
1029
}
1079
1030
}
1080
1031
1081
- if (mcux_i3c_has_error (base )) {
1032
+ if (mcux_i3c_has_error ()) {
1082
1033
ret = - EIO ;
1083
1034
}
1084
1035
@@ -1251,7 +1202,7 @@ static int mcux_i3c_do_daa(const struct device *dev)
1251
1202
do {
1252
1203
/* Loop to grab data from devices (Provisioned ID, BCR and DCR) */
1253
1204
do {
1254
- if (mcux_i3c_has_error (base )) {
1205
+ if (mcux_i3c_has_error ()) {
1255
1206
LOG_ERR ("DAA recv error" );
1256
1207
1257
1208
ret = - EIO ;
@@ -1576,7 +1527,7 @@ static void mcux_i3c_ibi_work(struct k_work *work)
1576
1527
break ;
1577
1528
}
1578
1529
1579
- if (mcux_i3c_has_error (base )) {
1530
+ if (mcux_i3c_has_error ()) {
1580
1531
/*
1581
1532
* If the controller detects any errors, simply
1582
1533
* emit a STOP to abort the IBI. The target will
@@ -1872,6 +1823,11 @@ static void mcux_i3c_isr(const struct device *dev)
1872
1823
} else {
1873
1824
/* Nothing to do right now */
1874
1825
}
1826
+
1827
+ if (interrupt_enable & I3C_MSTATUS_ERRWARN_MASK ) {
1828
+ merrwarn_reg = base -> MERRWARN ;
1829
+ base -> MERRWARN = base -> MERRWARN ;
1830
+ }
1875
1831
}
1876
1832
1877
1833
/**
@@ -2033,16 +1989,18 @@ static int mcux_i3c_init(const struct device *dev)
2033
1989
goto err_out ;
2034
1990
}
2035
1991
2036
- /* Disable all interrupts */
1992
+ /* Disable all interrupts except error interrupt */
2037
1993
base -> MINTCLR = I3C_MINTCLR_SLVSTART_MASK |
2038
1994
I3C_MINTCLR_MCTRLDONE_MASK |
2039
1995
I3C_MINTCLR_COMPLETE_MASK |
2040
1996
I3C_MINTCLR_RXPEND_MASK |
2041
1997
I3C_MINTCLR_TXNOTFULL_MASK |
2042
1998
I3C_MINTCLR_IBIWON_MASK |
2043
- I3C_MINTCLR_ERRWARN_MASK |
2044
1999
I3C_MINTCLR_NOWMASTER_MASK ;
2045
2000
2001
+ /* Enable error interrupt */
2002
+ base -> MINTSET = I3C_MSTATUS_ERRWARN_MASK ;
2003
+
2046
2004
/* Just in case the bus is not in idle. */
2047
2005
ret = mcux_i3c_recover_bus (dev );
2048
2006
if (ret != 0 ) {
0 commit comments