@@ -370,6 +370,10 @@ struct uart_ns16550_dev_data {
370370 void * cb_data ; /**< Callback function arg */
371371#endif
372372
373+ #ifdef CONFIG_UART_NS16550_WA_TX_FIFO_EMPTY_INTERRUPT
374+ uint8_t sw_tx_irq ; /**< software tx ready flag */
375+ #endif
376+
373377#if UART_NS16550_DLF_ENABLED
374378 uint8_t dlf ; /**< DLF value */
375379#endif
@@ -966,6 +970,10 @@ static void uart_ns16550_poll_out(const struct device *dev,
966970
967971 ns16550_outbyte (dev_cfg , THR (dev ), c );
968972
973+ #ifdef CONFIG_UART_NS16550_WA_TX_FIFO_EMPTY_INTERRUPT
974+ data -> sw_tx_irq = 0 ; /**< clean up */
975+ #endif
976+
969977 k_spin_unlock (& data -> lock , key );
970978}
971979
@@ -1013,6 +1021,12 @@ static int uart_ns16550_fifo_fill(const struct device *dev,
10131021 ns16550_outbyte (dev_cfg , THR (dev ), tx_data [i ]);
10141022 }
10151023
1024+ #ifdef CONFIG_UART_NS16550_WA_TX_FIFO_EMPTY_INTERRUPT
1025+ if (i != 0 ) {
1026+ data -> sw_tx_irq = 0 ; /**< clean up */
1027+ }
1028+ #endif
1029+
10161030 k_spin_unlock (& data -> lock , key );
10171031
10181032 return i ;
@@ -1075,6 +1089,26 @@ static void uart_ns16550_irq_tx_enable(const struct device *dev)
10751089#endif
10761090 ns16550_outbyte (dev_cfg , IER (dev ), ns16550_inbyte (dev_cfg , IER (dev )) | IER_TBE );
10771091
1092+ #ifdef CONFIG_UART_NS16550_WA_TX_FIFO_EMPTY_INTERRUPT
1093+ if (ns16550_inbyte (dev_cfg , LSR (dev )) & LSR_THRE ) {
1094+ k_spin_unlock (& data -> lock , key );
1095+ /*
1096+ * The TX FIFO ready interrupt will be triggered if only if
1097+ * when the pre-state is not empty. Thus, if the pre-state is
1098+ * already empty, try to call the callback routine directly
1099+ * to resolve it.
1100+ */
1101+ int irq_lock_key = arch_irq_lock ();
1102+
1103+ if (data -> cb && (ns16550_inbyte (dev_cfg , LSR (dev )) & LSR_THRE )) {
1104+ data -> sw_tx_irq = 1 ; /**< set tx ready */
1105+ data -> cb (dev , data -> cb_data );
1106+ }
1107+ arch_irq_unlock (irq_lock_key );
1108+ return ;
1109+ }
1110+ #endif
1111+
10781112 k_spin_unlock (& data -> lock , key );
10791113}
10801114
@@ -1089,6 +1123,10 @@ static void uart_ns16550_irq_tx_disable(const struct device *dev)
10891123 const struct uart_ns16550_dev_config * const dev_cfg = dev -> config ;
10901124 k_spinlock_key_t key = k_spin_lock (& data -> lock );
10911125
1126+ #ifdef CONFIG_UART_NS16550_WA_TX_FIFO_EMPTY_INTERRUPT
1127+ data -> sw_tx_irq = 0 ; /**< clean up */
1128+ #endif
1129+
10921130 ns16550_outbyte (dev_cfg , IER (dev ),
10931131 ns16550_inbyte (dev_cfg , IER (dev )) & (~IER_TBE ));
10941132
@@ -1129,6 +1167,17 @@ static int uart_ns16550_irq_tx_ready(const struct device *dev)
11291167
11301168 int ret = ((IIRC (dev ) & IIR_ID ) == IIR_THRE ) ? 1 : 0 ;
11311169
1170+ #ifdef CONFIG_UART_NS16550_WA_TX_FIFO_EMPTY_INTERRUPT
1171+ if (ret == 0 && data -> sw_tx_irq ) {
1172+ /**< replace resoult when there is a software solution */
1173+ const struct uart_ns16550_dev_config * const dev_cfg = dev -> config ;
1174+
1175+ if (ns16550_inbyte (dev_cfg , IER (dev )) & IER_TBE ) {
1176+ ret = 1 ;
1177+ }
1178+ }
1179+ #endif
1180+
11321181 k_spin_unlock (& data -> lock , key );
11331182
11341183 return ret ;
0 commit comments