@@ -369,6 +369,10 @@ struct uart_ns16550_dev_data {
369
369
void * cb_data ; /**< Callback function arg */
370
370
#endif
371
371
372
+ #ifdef CONFIG_UART_NS16550_WA_TX_FIFO_EMPTY_INTERRUPT
373
+ uint8_t sw_tx_irq ; /**< software tx ready flag */
374
+ #endif
375
+
372
376
#if UART_NS16550_DLF_ENABLED
373
377
uint8_t dlf ; /**< DLF value */
374
378
#endif
@@ -933,6 +937,10 @@ static void uart_ns16550_poll_out(const struct device *dev,
933
937
934
938
ns16550_outbyte (dev_cfg , THR (dev ), c );
935
939
940
+ #ifdef CONFIG_UART_NS16550_WA_TX_FIFO_EMPTY_INTERRUPT
941
+ data -> sw_tx_irq = 0 ; /**< clean up */
942
+ #endif
943
+
936
944
k_spin_unlock (& data -> lock , key );
937
945
}
938
946
@@ -980,6 +988,12 @@ static int uart_ns16550_fifo_fill(const struct device *dev,
980
988
ns16550_outbyte (dev_cfg , THR (dev ), tx_data [i ]);
981
989
}
982
990
991
+ #ifdef CONFIG_UART_NS16550_WA_TX_FIFO_EMPTY_INTERRUPT
992
+ if (i != 0 ) {
993
+ data -> sw_tx_irq = 0 ; /**< clean up */
994
+ }
995
+ #endif
996
+
983
997
k_spin_unlock (& data -> lock , key );
984
998
985
999
return i ;
@@ -1042,6 +1056,26 @@ static void uart_ns16550_irq_tx_enable(const struct device *dev)
1042
1056
#endif
1043
1057
ns16550_outbyte (dev_cfg , IER (dev ), ns16550_inbyte (dev_cfg , IER (dev )) | IER_TBE );
1044
1058
1059
+ #ifdef CONFIG_UART_NS16550_WA_TX_FIFO_EMPTY_INTERRUPT
1060
+ if (ns16550_inbyte (dev_cfg , LSR (dev )) & LSR_THRE ) {
1061
+ k_spin_unlock (& data -> lock , key );
1062
+ /*
1063
+ * The TX FIFO ready interrupt will be triggered if only if
1064
+ * when the pre-state is not empty. Thus, if the pre-state is
1065
+ * already empty, try to call the callback routine directly
1066
+ * to resolve it.
1067
+ */
1068
+ int irq_lock_key = arch_irq_lock ();
1069
+
1070
+ if (data -> cb && (ns16550_inbyte (dev_cfg , LSR (dev )) & LSR_THRE )) {
1071
+ data -> sw_tx_irq = 1 ; /**< set tx ready */
1072
+ data -> cb (dev , data -> cb_data );
1073
+ }
1074
+ arch_irq_unlock (irq_lock_key );
1075
+ return ;
1076
+ }
1077
+ #endif
1078
+
1045
1079
k_spin_unlock (& data -> lock , key );
1046
1080
}
1047
1081
@@ -1056,6 +1090,10 @@ static void uart_ns16550_irq_tx_disable(const struct device *dev)
1056
1090
const struct uart_ns16550_dev_config * const dev_cfg = dev -> config ;
1057
1091
k_spinlock_key_t key = k_spin_lock (& data -> lock );
1058
1092
1093
+ #ifdef CONFIG_UART_NS16550_WA_TX_FIFO_EMPTY_INTERRUPT
1094
+ data -> sw_tx_irq = 0 ; /**< clean up */
1095
+ #endif
1096
+
1059
1097
ns16550_outbyte (dev_cfg , IER (dev ),
1060
1098
ns16550_inbyte (dev_cfg , IER (dev )) & (~IER_TBE ));
1061
1099
@@ -1096,6 +1134,17 @@ static int uart_ns16550_irq_tx_ready(const struct device *dev)
1096
1134
1097
1135
int ret = ((IIRC (dev ) & IIR_ID ) == IIR_THRE ) ? 1 : 0 ;
1098
1136
1137
+ #ifdef CONFIG_UART_NS16550_WA_TX_FIFO_EMPTY_INTERRUPT
1138
+ if (ret == 0 && data -> sw_tx_irq ) {
1139
+ /**< replace resoult when there is a software solution */
1140
+ const struct uart_ns16550_dev_config * const dev_cfg = dev -> config ;
1141
+
1142
+ if (ns16550_inbyte (dev_cfg , IER (dev )) & IER_TBE ) {
1143
+ ret = 1 ;
1144
+ }
1145
+ }
1146
+ #endif
1147
+
1099
1148
k_spin_unlock (& data -> lock , key );
1100
1149
1101
1150
return ret ;
0 commit comments