1
1
/*
2
2
* Copyright (c) 2016 Freescale Semiconductor, Inc.
3
- * Copyright (c) 2019 NXP
3
+ * Copyright (c) 2019, 2025 NXP
4
4
* Copyright (c) 2022 Intel Corporation
5
5
*
6
6
* SPDX-License-Identifier: Apache-2.0
@@ -65,6 +65,10 @@ LOG_MODULE_REGISTER(i3c_mcux, CONFIG_I3C_MCUX_LOG_LEVEL);
65
65
66
66
#define I3C_MAX_STOP_RETRIES 5
67
67
68
+ #define I3C_TRANSFER_TIMEOUT_MSEC \
69
+ COND_CODE_0(CONFIG_I3C_NXP_TRANSFER_TIMEOUT, (K_FOREVER), \
70
+ (K_MSEC(CONFIG_I3C_NXP_TRANSFER_TIMEOUT)))
71
+
68
72
struct mcux_i3c_config {
69
73
/** Common I3C Driver Config */
70
74
struct i3c_driver_config common ;
@@ -95,6 +99,9 @@ struct mcux_i3c_data {
95
99
/** Mutex to serialize access */
96
100
struct k_mutex lock ;
97
101
102
+ /** Semaphore to synchronize data transfers */
103
+ struct k_sem device_sync_sem ;
104
+
98
105
/** Condvar for waiting for bus to be in IDLE state */
99
106
struct k_condvar condvar ;
100
107
@@ -886,58 +893,71 @@ static int mcux_i3c_recover_bus(const struct device *dev)
886
893
* or time out.
887
894
*
888
895
* @param base Pointer to controller registers.
896
+ * @param data Pointer to controller device instance data.
889
897
* @param buf Buffer to store data.
890
898
* @param buf_sz Buffer size in bytes.
891
899
*
892
900
* @return Number of bytes read, or negative if error.
893
901
*/
894
- static int mcux_i3c_do_one_xfer_read (I3C_Type * base , uint8_t * buf , uint8_t buf_sz , bool ibi )
902
+ static int mcux_i3c_do_one_xfer_read (I3C_Type * base , struct mcux_i3c_data * data ,
903
+ uint8_t * buf , uint8_t buf_sz , bool ibi )
895
904
{
896
905
int ret = 0 ;
897
906
int offset = 0 ;
898
907
899
908
while (offset < buf_sz ) {
900
909
/*
901
910
* Transfer data from FIFO into buffer. Read
902
- * in a tight loop to reduce chance of losing
903
- * FIFO data when the i3c speed is high.
911
+ * in a loop until data is unavailable in the FIFO.
904
912
*/
905
913
while (offset < buf_sz ) {
906
914
if (mcux_i3c_fifo_rx_count_get (base ) == 0 ) {
915
+ /* Enable Receive pending interrupt */
916
+ base -> MINTSET = I3C_MSTATUS_RXPEND_MASK ;
917
+
918
+ /* Wait for data to arrive or an error */
919
+ if (k_sem_take (& data -> device_sync_sem , I3C_TRANSFER_TIMEOUT_MSEC )) {
920
+ ret = - ETIMEDOUT ;
921
+ }
922
+ /* We break out of the loop to see if the interrupt
923
+ * was due to an error.
924
+ */
907
925
break ;
926
+ } else {
927
+ buf [offset ++ ] = (uint8_t )base -> MRDATAB ;
908
928
}
909
- buf [offset ++ ] = (uint8_t )base -> MRDATAB ;
910
929
}
911
-
912
930
/*
913
931
* If controller says timed out, we abort the transaction.
914
932
*/
915
- if (mcux_i3c_has_error (base )) {
933
+ if (mcux_i3c_has_error (base ) || ret ) {
916
934
if (mcux_i3c_error_is_timeout (base )) {
917
935
ret = - ETIMEDOUT ;
918
936
}
919
- /* clear error */
937
+ /* clear error */
920
938
base -> MERRWARN = base -> MERRWARN ;
921
939
922
- /* for ibi, ignore timeout err if any bytes were
923
- * read, since the code doesn't know how many
924
- * bytes will be sent by device. for regular
925
- * application read request, return err always.
926
- */
927
- if ((ret == - ETIMEDOUT ) && ibi && offset ) {
928
- break ;
929
- } else {
930
- if (ret == - ETIMEDOUT ) {
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 {
931
948
LOG_ERR ("Timeout error" );
932
949
}
933
- goto one_xfer_read_out ;
950
+ break ;
934
951
}
935
952
}
953
+
936
954
}
937
955
938
- ret = offset ;
956
+ /* If no errors, then return the number of bytes read */
957
+ if (ret > 0 ) {
958
+ ret = offset ;
959
+ }
939
960
940
- one_xfer_read_out :
941
961
return ret ;
942
962
}
943
963
@@ -948,22 +968,30 @@ static int mcux_i3c_do_one_xfer_read(I3C_Type *base, uint8_t *buf, uint8_t buf_s
948
968
* waiting for FIFO spaces.
949
969
*
950
970
* @param base Pointer to controller registers.
971
+ * @param data Pointer to controller device instance data.
951
972
* @param buf Buffer containing data to be sent.
952
973
* @param buf_sz Number of bytes in @p buf to send.
953
974
* @param no_ending True if not to signal end of write message.
954
975
*
955
976
* @return Number of bytes written, or negative if error.
956
977
*/
957
- static int mcux_i3c_do_one_xfer_write (I3C_Type * base , uint8_t * buf , uint8_t buf_sz , bool no_ending )
978
+ static int mcux_i3c_do_one_xfer_write (I3C_Type * base , struct mcux_i3c_data * data ,
979
+ uint8_t * buf , uint8_t buf_sz , bool no_ending )
958
980
{
959
981
int offset = 0 ;
960
982
int remaining = buf_sz ;
961
983
int ret = 0 ;
962
984
963
985
while (remaining > 0 ) {
964
- ret = reg32_poll_timeout (& base -> MDATACTRL , I3C_MDATACTRL_TXFULL_MASK , 0 , 1000 );
965
- if (ret == - ETIMEDOUT ) {
966
- goto one_xfer_write_out ;
986
+ if (base -> MDATACTRL & I3C_MDATACTRL_TXFULL_MASK ) {
987
+ /* Enable TX buffer ready interrupt */
988
+ base -> MINTSET = I3C_MSTATUS_TXNOTFULL_MASK ;
989
+
990
+ /* Wait for the transfer to complete */
991
+ ret = k_sem_take (& data -> device_sync_sem , I3C_TRANSFER_TIMEOUT_MSEC );
992
+ if (ret ) {
993
+ break ;
994
+ }
967
995
}
968
996
969
997
if ((remaining > 1 ) || no_ending ) {
@@ -976,9 +1004,11 @@ static int mcux_i3c_do_one_xfer_write(I3C_Type *base, uint8_t *buf, uint8_t buf_
976
1004
remaining -= 1 ;
977
1005
}
978
1006
979
- ret = offset ;
1007
+ if (!ret ) {
1008
+ /* Return the number of bytes received */
1009
+ ret = offset ;
1010
+ }
980
1011
981
- one_xfer_write_out :
982
1012
return ret ;
983
1013
}
984
1014
@@ -1024,9 +1054,9 @@ static int mcux_i3c_do_one_xfer(I3C_Type *base, struct mcux_i3c_data *data,
1024
1054
}
1025
1055
1026
1056
if (is_read ) {
1027
- ret = mcux_i3c_do_one_xfer_read (base , buf , buf_sz , false);
1057
+ ret = mcux_i3c_do_one_xfer_read (base , data , buf , buf_sz , false);
1028
1058
} else {
1029
- ret = mcux_i3c_do_one_xfer_write (base , buf , buf_sz , no_ending );
1059
+ ret = mcux_i3c_do_one_xfer_write (base , data , buf , buf_sz , no_ending );
1030
1060
}
1031
1061
1032
1062
if (ret < 0 ) {
@@ -1367,7 +1397,7 @@ static int mcux_i3c_do_ccc(const struct device *dev,
1367
1397
/* Write the CCC code */
1368
1398
mcux_i3c_status_clear_all (base );
1369
1399
mcux_i3c_errwarn_clear_all_nowait (base );
1370
- ret = mcux_i3c_do_one_xfer_write (base , & payload -> ccc .id , 1 ,
1400
+ ret = mcux_i3c_do_one_xfer_write (base , data , & payload -> ccc .id , 1 ,
1371
1401
payload -> ccc .data_len > 0 );
1372
1402
if (ret < 0 ) {
1373
1403
LOG_ERR ("CCC[0x%02x] %s command error (%d)" ,
@@ -1382,7 +1412,7 @@ static int mcux_i3c_do_ccc(const struct device *dev,
1382
1412
if (payload -> ccc .data_len > 0 ) {
1383
1413
mcux_i3c_status_clear_all (base );
1384
1414
mcux_i3c_errwarn_clear_all_nowait (base );
1385
- ret = mcux_i3c_do_one_xfer_write (base , payload -> ccc .data ,
1415
+ ret = mcux_i3c_do_one_xfer_write (base , data , payload -> ccc .data ,
1386
1416
payload -> ccc .data_len , false);
1387
1417
if (ret < 0 ) {
1388
1418
LOG_ERR ("CCC[0x%02x] %s command payload error (%d)" ,
@@ -1518,7 +1548,7 @@ static void mcux_i3c_ibi_work(struct k_work *work)
1518
1548
case I3C_MSTATUS_IBITYPE_IBI :
1519
1549
target = i3c_dev_list_i3c_addr_find (dev , (uint8_t )ibiaddr );
1520
1550
if (target != NULL ) {
1521
- ret = mcux_i3c_do_one_xfer_read (base , & payload [0 ],
1551
+ ret = mcux_i3c_do_one_xfer_read (base , data , & payload [0 ],
1522
1552
sizeof (payload ), true);
1523
1553
if (ret >= 0 ) {
1524
1554
payload_sz = (size_t )ret ;
@@ -1801,10 +1831,12 @@ int mcux_i3c_ibi_disable(const struct device *dev,
1801
1831
*/
1802
1832
static void mcux_i3c_isr (const struct device * dev )
1803
1833
{
1804
- #ifdef CONFIG_I3C_USE_IBI
1805
1834
const struct mcux_i3c_config * config = dev -> config ;
1806
1835
I3C_Type * base = config -> base ;
1836
+ struct mcux_i3c_data * dev_data = dev -> data ;
1837
+ uint32_t interrupt_enable = base -> MINTSET ;
1807
1838
1839
+ #ifdef CONFIG_I3C_USE_IBI
1808
1840
/* Target initiated IBIs */
1809
1841
if (mcux_i3c_status_is_set (base , I3C_MSTATUS_SLVSTART_MASK )) {
1810
1842
int err ;
@@ -1827,9 +1859,19 @@ static void mcux_i3c_isr(const struct device *dev)
1827
1859
base -> MINTSET = I3C_MINTCLR_SLVSTART_MASK ;
1828
1860
}
1829
1861
}
1830
- #else
1831
- ARG_UNUSED (dev );
1832
1862
#endif
1863
+
1864
+ if (interrupt_enable & I3C_MSTATUS_RXPEND_MASK ) {
1865
+ /* Disable RX buffer ready interrupt */
1866
+ base -> MINTCLR = I3C_MSTATUS_RXPEND_MASK ;
1867
+ k_sem_give (& dev_data -> device_sync_sem );
1868
+ } else if (interrupt_enable & I3C_MSTATUS_TXNOTFULL_MASK ) {
1869
+ /* Disable TX buffer ready interrupt */
1870
+ base -> MINTCLR = I3C_MSTATUS_TXNOTFULL_MASK ;
1871
+ k_sem_give (& dev_data -> device_sync_sem );
1872
+ } else {
1873
+ /* Nothing to do right now */
1874
+ }
1833
1875
}
1834
1876
1835
1877
/**
@@ -1966,6 +2008,7 @@ static int mcux_i3c_init(const struct device *dev)
1966
2008
1967
2009
k_mutex_init (& data -> lock );
1968
2010
k_condvar_init (& data -> condvar );
2011
+ k_sem_init (& data -> device_sync_sem , 0 , K_SEM_MAX_LIMIT );
1969
2012
1970
2013
I3C_MasterGetDefaultConfig (& ctrl_config_hal );
1971
2014
0 commit comments