serial: imx: Fix the reporting of interrupts
authorFabio Estevam <fabio.estevam@freescale.com>
Mon, 27 Oct 2014 16:49:37 +0000 (14:49 -0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 6 Nov 2014 04:03:20 +0000 (20:03 -0800)
On a imx system with ttymxc0, ttymxc1 and ttymxc4 registered we see the
following output from 'cat /proc/interrupts':

$ cat /proc/interrupts
           CPU0
...
 58:         39       GIC  58  2020000.serial
 67:        115       GIC  67  21f8000.i2c

The only uart irq that appears is ttymxc0, which is the console.

As ttymxc1 and ttymxc4 will only have their irq registered at imx_startup(),
they are not shown right after probe.

Transmitting to ttymxc1 and ttymxc4 will cause their irqs to be registered, but
the output shows:

$ echo "111111" > /dev/ttymxc1
$ echo "444444" > /dev/ttymxc4
$ cat /proc/interrupts
           CPU0
...
 58:        150       GIC  58  2020000.serial
 59:          1       GIC  59
 62:          1       GIC  62
 67:        115       GIC  67  21f8000.i2c

,which misses printing the associated device address.

In order to fix this, register all the irqs inside the probe function via
devm_request_irq(), which will correctly report the serial interrupts associated
with their correspondent serial device and also helps simplyfing the code by
avoiding the calls to free_irq().

$ echo "111111" > /dev/ttymxc1
$ echo "444444" > /dev/ttymxc4
$ cat /proc/interrupts

   CPU0
....
 58:        202       GIC  58  2020000.serial
 59:          1       GIC  59  21e8000.serial
 62:          1       GIC  62  21f4000.serial
 67:        115       GIC  67  21f8000.i2c

Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/imx.c

index 8f62a3cec23ef89d27217779f3cf9e378241f4b1..e4a2846f34a6e221e6f382ba9eea8ba4ff2927ca 100644 (file)
@@ -1109,37 +1109,6 @@ static int imx_startup(struct uart_port *port)
        while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0))
                udelay(1);
 
-       /*
-        * Allocate the IRQ(s) i.MX1 has three interrupts whereas later
-        * chips only have one interrupt.
-        */
-       if (sport->txirq > 0) {
-               retval = request_irq(sport->rxirq, imx_rxint, 0,
-                                    dev_name(port->dev), sport);
-               if (retval)
-                       goto error_out1;
-
-               retval = request_irq(sport->txirq, imx_txint, 0,
-                                    dev_name(port->dev), sport);
-               if (retval)
-                       goto error_out2;
-
-               /* do not use RTS IRQ on IrDA */
-               if (!USE_IRDA(sport)) {
-                       retval = request_irq(sport->rtsirq, imx_rtsint, 0,
-                                            dev_name(port->dev), sport);
-                       if (retval)
-                               goto error_out3;
-               }
-       } else {
-               retval = request_irq(sport->port.irq, imx_int, 0,
-                                    dev_name(port->dev), sport);
-               if (retval) {
-                       free_irq(sport->port.irq, sport);
-                       goto error_out1;
-               }
-       }
-
        spin_lock_irqsave(&sport->port.lock, flags);
        /*
         * Finally, clear and enable interrupts
@@ -1202,12 +1171,6 @@ static int imx_startup(struct uart_port *port)
 
        return 0;
 
-error_out3:
-       if (sport->txirq)
-               free_irq(sport->txirq, sport);
-error_out2:
-       if (sport->rxirq)
-               free_irq(sport->rxirq, sport);
 error_out1:
        return retval;
 }
@@ -1254,17 +1217,6 @@ static void imx_shutdown(struct uart_port *port)
         */
        del_timer_sync(&sport->timer);
 
-       /*
-        * Free the interrupts
-        */
-       if (sport->txirq > 0) {
-               if (!USE_IRDA(sport))
-                       free_irq(sport->rtsirq, sport);
-               free_irq(sport->txirq, sport);
-               free_irq(sport->rxirq, sport);
-       } else
-               free_irq(sport->port.irq, sport);
-
        /*
         * Disable all interrupts, port and break condition.
         */
@@ -1929,6 +1881,36 @@ static int serial_imx_probe(struct platform_device *pdev)
 
        sport->port.uartclk = clk_get_rate(sport->clk_per);
 
+       /*
+        * Allocate the IRQ(s) i.MX1 has three interrupts whereas later
+        * chips only have one interrupt.
+        */
+       if (sport->txirq > 0) {
+               ret = devm_request_irq(&pdev->dev, sport->rxirq, imx_rxint, 0,
+                                      dev_name(&pdev->dev), sport);
+               if (ret)
+                       return ret;
+
+               ret = devm_request_irq(&pdev->dev, sport->txirq, imx_txint, 0,
+                                      dev_name(&pdev->dev), sport);
+               if (ret)
+                       return ret;
+
+               /* do not use RTS IRQ on IrDA */
+               if (!USE_IRDA(sport)) {
+                       ret = devm_request_irq(&pdev->dev, sport->rtsirq,
+                                              imx_rtsint, 0,
+                                              dev_name(&pdev->dev), sport);
+                       if (ret)
+                               return ret;
+               }
+       } else {
+               ret = devm_request_irq(&pdev->dev, sport->port.irq, imx_int, 0,
+                                      dev_name(&pdev->dev), sport);
+               if (ret)
+                       return ret;
+       }
+
        imx_ports[sport->port.line] = sport;
 
        platform_set_drvdata(pdev, sport);