@@ -369,6 +369,10 @@ struct uart_ns16550_dev_data {
369369 void * cb_data ; /**< Callback function arg */
370370#endif
371371
372+ #ifdef CONFIG_UART_NS16550_WA_TX_FIFO_EMPTY_INTERRUPT
373+ uint8_t sw_tx_irq ; /**< software tx ready flag */
374+ #endif
375+
372376#if UART_NS16550_DLF_ENABLED
373377 uint8_t dlf ; /**< DLF value */
374378#endif
@@ -933,6 +937,10 @@ static void uart_ns16550_poll_out(const struct device *dev,
933937
934938 ns16550_outbyte (dev_cfg , THR (dev ), c );
935939
940+ #ifdef CONFIG_UART_NS16550_WA_TX_FIFO_EMPTY_INTERRUPT
941+ data -> sw_tx_irq = 0 ; /**< clean up */
942+ #endif
943+
936944 k_spin_unlock (& data -> lock , key );
937945}
938946
@@ -980,6 +988,12 @@ static int uart_ns16550_fifo_fill(const struct device *dev,
980988 ns16550_outbyte (dev_cfg , THR (dev ), tx_data [i ]);
981989 }
982990
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+
983997 k_spin_unlock (& data -> lock , key );
984998
985999 return i ;
@@ -1042,6 +1056,26 @@ static void uart_ns16550_irq_tx_enable(const struct device *dev)
10421056#endif
10431057 ns16550_outbyte (dev_cfg , IER (dev ), ns16550_inbyte (dev_cfg , IER (dev )) | IER_TBE );
10441058
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+
10451079 k_spin_unlock (& data -> lock , key );
10461080}
10471081
@@ -1056,6 +1090,10 @@ static void uart_ns16550_irq_tx_disable(const struct device *dev)
10561090 const struct uart_ns16550_dev_config * const dev_cfg = dev -> config ;
10571091 k_spinlock_key_t key = k_spin_lock (& data -> lock );
10581092
1093+ #ifdef CONFIG_UART_NS16550_WA_TX_FIFO_EMPTY_INTERRUPT
1094+ data -> sw_tx_irq = 0 ; /**< clean up */
1095+ #endif
1096+
10591097 ns16550_outbyte (dev_cfg , IER (dev ),
10601098 ns16550_inbyte (dev_cfg , IER (dev )) & (~IER_TBE ));
10611099
@@ -1096,6 +1134,17 @@ static int uart_ns16550_irq_tx_ready(const struct device *dev)
10961134
10971135 int ret = ((IIRC (dev ) & IIR_ID ) == IIR_THRE ) ? 1 : 0 ;
10981136
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+
10991148 k_spin_unlock (& data -> lock , key );
11001149
11011150 return ret ;
0 commit comments