tty: serial: sh-sci: Add support for tx end interrupt handling
authorBiju Das <biju.das.jz@bp.renesas.com>
Wed, 12 Apr 2023 14:50:52 +0000 (15:50 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 20 Apr 2023 11:47:33 +0000 (13:47 +0200)
As per the RZ/G2L users hardware manual (Rev.1.20 Sep, 2022), section
23.3.7 Serial Data Transmission (Asynchronous Mode), it is mentioned
that, set the SCR.TIE bit to 0 and SCR.TEIE bit to 1, after the last
data to be transmitted are written to the TDR.

This will generate tx end interrupt and in the handler set SCR.TE and
SCR.TEIE to 0.

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Link: https://lore.kernel.org/r/20230412145053.114847-5-biju.das.jz@bp.renesas.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/sh-sci.c
drivers/tty/serial/sh-sci.h

index 32f5c1f7d697a6a03eb41cedfa1c2804f343e2a8..5c9ae69c0555d09e711225f6d3f5bbdd4be47b74 100644 (file)
@@ -860,9 +860,16 @@ static void sci_transmit_chars(struct uart_port *port)
 
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
                uart_write_wakeup(port);
-       if (uart_circ_empty(xmit))
-               sci_stop_tx(port);
+       if (uart_circ_empty(xmit)) {
+               if (port->type == PORT_SCI) {
+                       ctrl = serial_port_in(port, SCSCR);
+                       ctrl &= ~SCSCR_TIE;
+                       ctrl |= SCSCR_TEIE;
+                       serial_port_out(port, SCSCR, ctrl);
+               }
 
+               sci_stop_tx(port);
+       }
 }
 
 static void sci_receive_chars(struct uart_port *port)
@@ -1766,6 +1773,24 @@ static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
        return IRQ_HANDLED;
 }
 
+static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr)
+{
+       struct uart_port *port = ptr;
+       unsigned long flags;
+       unsigned short ctrl;
+
+       if (port->type != PORT_SCI)
+               return sci_tx_interrupt(irq, ptr);
+
+       spin_lock_irqsave(&port->lock, flags);
+       ctrl = serial_port_in(port, SCSCR);
+       ctrl &= ~(SCSCR_TE | SCSCR_TEIE);
+       serial_port_out(port, SCSCR, ctrl);
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       return IRQ_HANDLED;
+}
+
 static irqreturn_t sci_br_interrupt(int irq, void *ptr)
 {
        struct uart_port *port = ptr;
@@ -1902,7 +1927,7 @@ static const struct sci_irq_desc {
 
        [SCIx_TEI_IRQ] = {
                .desc = "tx end",
-               .handler = sci_tx_interrupt,
+               .handler = sci_tx_end_interrupt,
        },
 
        /*
index c0ae78632dda77e0ea8d4b50677ae6993634f666..0b65563c4e9e3728c47c63f752e6ff464df82aed 100644 (file)
@@ -59,6 +59,9 @@ enum {
 #define SCSMR_SRC_19   0x0600  /* Sampling rate 1/19 */
 #define SCSMR_SRC_27   0x0700  /* Sampling rate 1/27 */
 
+/* Serial Control Register, SCI only bits */
+#define SCSCR_TEIE     BIT(2)  /* Transmit End Interrupt Enable */
+
 /* Serial Control Register, SCIFA/SCIFB only bits */
 #define SCSCR_TDRQE    BIT(15) /* Tx Data Transfer Request Enable */
 #define SCSCR_RDRQE    BIT(14) /* Rx Data Transfer Request Enable */