]> git.baikalelectronics.ru Git - kernel.git/commitdiff
tty: serial: qcom_geni_serial: Wakeup IRQ cleanup
authorAkash Asthana <akashast@codeaurora.org>
Mon, 6 Jan 2020 14:45:04 +0000 (20:15 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 6 Jan 2020 19:22:33 +0000 (20:22 +0100)
This patch is the continuation of below mentioned commits which adds wakeup
feature over the UART RX line.
1)commit 57713b5fc2b5 ("tty: serial: qcom_geni_serial: IRQ cleanup")[v2]
2)commit 2cdb5b922daf ("tty: serial: qcom_geni_serial: Wakeup over UART
  RX")[v2]

The following cleanup is done based on upstream comment received on
subsequent versions of the above-mentioned commits to simplifying the code.
 - Use devm_kasprintf API in place of scnprintf.
 - Use dev_pm_set_dedicated_wake_irq API that will take care of
   requesting and attaching wakeup irqs for devices. Also, it sets wakeirq
   status to WAKE_IRQ_DEDICATED_ALLOCATED as a result enabling/disabling of
   wake irq will be managed by suspend/resume framework. We can remove the
   code for enabling and disabling of wake irq from the this driver.
 - Use platform_get_irq_optional API to get optional wakeup IRQ for
   device.
 - Move ISR registration later in probe after uart port gets register with
   serial core.

Patch link:
 - https://patchwork.kernel.org/patch/11189717/ (v3)
 - https://patchwork.kernel.org/patch/11227435/ (v4)
 - https://patchwork.kernel.org/patch/11241669/ (v5)
 - https://patchwork.kernel.org/patch/11258045/ (v6)

Signed-off-by: Akash Asthana <akashast@codeaurora.org>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
Reviewed-by: Stephen Boyd <swboyd@chromium.org>
Link: https://lore.kernel.org/r/1578321905-25843-2-git-send-email-akashast@codeaurora.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/qcom_geni_serial.c

index c41c766d6c7ccd3cecd4be3857ab259c1c7d2973..1e164839662cec52959df3d4ea6ba39522221dcc 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/pm_wakeirq.h>
 #include <linux/qcom-geni-se.h>
 #include <linux/serial.h>
 struct qcom_geni_serial_port {
        struct uart_port uport;
        struct geni_se se;
-       char name[20];
+       const char *name;
        u32 tx_fifo_depth;
        u32 tx_fifo_width;
        u32 rx_fifo_depth;
@@ -753,15 +754,6 @@ out_write_wakeup:
                uart_write_wakeup(uport);
 }
 
-static irqreturn_t qcom_geni_serial_wakeup_isr(int isr, void *dev)
-{
-       struct uart_port *uport = dev;
-
-       pm_wakeup_event(uport->dev, 2000);
-
-       return IRQ_HANDLED;
-}
-
 static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
 {
        u32 m_irq_en;
@@ -1298,51 +1290,59 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
        port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
        port->tx_fifo_width = DEF_FIFO_WIDTH_BITS;
 
-       scnprintf(port->name, sizeof(port->name), "qcom_geni_serial_%s%d",
-               (uart_console(uport) ? "console" : "uart"), uport->line);
+       port->name = devm_kasprintf(uport->dev, GFP_KERNEL,
+                       "qcom_geni_serial_%s%d",
+                       uart_console(uport) ? "console" : "uart", uport->line);
+       if (!port->name)
+               return -ENOMEM;
+
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
                return irq;
        uport->irq = irq;
        uport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_QCOM_GENI_CONSOLE);
 
+       if (!console)
+               port->wakeup_irq = platform_get_irq_optional(pdev, 1);
+
+       uport->private_data = drv;
+       platform_set_drvdata(pdev, port);
+       port->handle_rx = console ? handle_rx_console : handle_rx_uart;
+       if (!console)
+               device_create_file(uport->dev, &dev_attr_loopback);
+
+       ret = uart_add_one_port(drv, uport);
+       if (ret)
+               return ret;
+
        irq_set_status_flags(uport->irq, IRQ_NOAUTOEN);
        ret = devm_request_irq(uport->dev, uport->irq, qcom_geni_serial_isr,
                        IRQF_TRIGGER_HIGH, port->name, uport);
        if (ret) {
                dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret);
+               uart_remove_one_port(drv, uport);
                return ret;
        }
 
-       if (!console) {
-               port->wakeup_irq = platform_get_irq(pdev, 1);
-               if (port->wakeup_irq < 0) {
-                       dev_err(&pdev->dev, "Failed to get wakeup IRQ %d\n",
-                                       port->wakeup_irq);
-               } else {
-                       irq_set_status_flags(port->wakeup_irq, IRQ_NOAUTOEN);
-                       ret = devm_request_irq(uport->dev, port->wakeup_irq,
-                               qcom_geni_serial_wakeup_isr,
-                               IRQF_TRIGGER_FALLING, "uart_wakeup", uport);
-                       if (ret) {
-                               dev_err(uport->dev, "Failed to register wakeup IRQ ret %d\n",
-                                               ret);
-                               return ret;
-                       }
-
-                       device_init_wakeup(&pdev->dev, true);
-                       ret = dev_pm_set_wake_irq(&pdev->dev, port->wakeup_irq);
-                       if (unlikely(ret))
-                               dev_err(uport->dev, "%s:Failed to set IRQ wake:%d\n",
-                                               __func__, ret);
+       /*
+        * Set pm_runtime status as ACTIVE so that wakeup_irq gets
+        * enabled/disabled from dev_pm_arm_wake_irq during system
+        * suspend/resume respectively.
+        */
+       pm_runtime_set_active(&pdev->dev);
+
+       if (port->wakeup_irq > 0) {
+               device_init_wakeup(&pdev->dev, true);
+               ret = dev_pm_set_dedicated_wake_irq(&pdev->dev,
+                                               port->wakeup_irq);
+               if (ret) {
+                       device_init_wakeup(&pdev->dev, false);
+                       uart_remove_one_port(drv, uport);
+                       return ret;
                }
        }
-       uport->private_data = drv;
-       platform_set_drvdata(pdev, port);
-       port->handle_rx = console ? handle_rx_console : handle_rx_uart;
-       if (!console)
-               device_create_file(uport->dev, &dev_attr_loopback);
-       return uart_add_one_port(drv, uport);
+
+       return 0;
 }
 
 static int qcom_geni_serial_remove(struct platform_device *pdev)
@@ -1350,7 +1350,10 @@ static int qcom_geni_serial_remove(struct platform_device *pdev)
        struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
        struct uart_driver *drv = port->uport.private_data;
 
+       dev_pm_clear_wake_irq(&pdev->dev);
+       device_init_wakeup(&pdev->dev, false);
        uart_remove_one_port(drv, &port->uport);
+
        return 0;
 }
 
@@ -1359,12 +1362,7 @@ static int __maybe_unused qcom_geni_serial_sys_suspend(struct device *dev)
        struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
        struct uart_port *uport = &port->uport;
 
-       uart_suspend_port(uport->private_data, uport);
-
-       if (port->wakeup_irq > 0)
-               enable_irq(port->wakeup_irq);
-
-       return 0;
+       return uart_suspend_port(uport->private_data, uport);
 }
 
 static int __maybe_unused qcom_geni_serial_sys_resume(struct device *dev)
@@ -1372,9 +1370,6 @@ static int __maybe_unused qcom_geni_serial_sys_resume(struct device *dev)
        struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
        struct uart_port *uport = &port->uport;
 
-       if (port->wakeup_irq > 0)
-               disable_irq(port->wakeup_irq);
-
        return uart_resume_port(uport->private_data, uport);
 }