Skip to content

Commit

Permalink
uart: mediatek: support Rx in-band wakeup
Browse files Browse the repository at this point in the history
In order to support Rx in-band wakeup, we need to enable irq wake on an
edge sensitive interrupt of Rx pin before suspend and disable it when
resuming.

This interrupt is used only as wake source to resume the system when
suspended. Note that the sent character will be lost as the controller is
actually suspended.

We use this to support wakeup on bluetooth. Bluetooth will repeatedly send
0xFD to wakeup host. Once host detects Rx falling, an interrupt is
triggered, and the system leaves sleep state. Then, the bluetooth driver
will send 0xFC to bluetooth and bluetooth can start to send normal HCI
packets.

Signed-off-by: Claire Chang <tientzu@chromium.org>
Reviewed-by: Nicolas Boichat <drinkcat@chromium.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Claire Chang authored and Greg Kroah-Hartman committed Jun 10, 2019
1 parent 277375b commit 9315ad9
Showing 1 changed file with 24 additions and 0 deletions.
24 changes: 24 additions & 0 deletions drivers/tty/serial/8250/8250_mtk.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/serial_8250.h>
Expand Down Expand Up @@ -69,6 +70,7 @@ struct mtk8250_data {
#ifdef CONFIG_SERIAL_8250_DMA
enum dma_rx_status rx_status;
#endif
int rx_wakeup_irq;
};

/* flow control mode */
Expand Down Expand Up @@ -542,6 +544,8 @@ static int mtk8250_probe(struct platform_device *pdev)
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);

data->rx_wakeup_irq = platform_get_irq(pdev, 1);

return 0;
}

Expand All @@ -563,15 +567,35 @@ static int mtk8250_remove(struct platform_device *pdev)
static int __maybe_unused mtk8250_suspend(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
int irq = data->rx_wakeup_irq;
int err;

serial8250_suspend_port(data->line);

pinctrl_pm_select_sleep_state(dev);
if (irq >= 0) {
err = enable_irq_wake(irq);
if (err) {
dev_err(dev,
"failed to enable irq wake on IRQ %d: %d\n",
irq, err);
pinctrl_pm_select_default_state(dev);
serial8250_resume_port(data->line);
return err;
}
}

return 0;
}

static int __maybe_unused mtk8250_resume(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
int irq = data->rx_wakeup_irq;

if (irq >= 0)
disable_irq_wake(irq);
pinctrl_pm_select_default_state(dev);

serial8250_resume_port(data->line);

Expand Down

0 comments on commit 9315ad9

Please sign in to comment.