On Mon, May 27, 2019 at 4:32 PM Claire Chang <tientzu@xxxxxxxxxxxx> wrote: > > 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@xxxxxxxxxxxx> Reviewed-by: Nicolas Boichat <drinkcat@xxxxxxxxxxxx> > --- > drivers/tty/serial/8250/8250_mtk.c | 24 ++++++++++++++++++++++++ > 1 file changed, 24 insertions(+) > > diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c > index 417c7c810df9..5b94b853387d 100644 > --- a/drivers/tty/serial/8250/8250_mtk.c > +++ b/drivers/tty/serial/8250/8250_mtk.c > @@ -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> > @@ -70,6 +71,7 @@ struct mtk8250_data { > #ifdef CONFIG_SERIAL_8250_DMA > enum dma_rx_status rx_status; > #endif > + int rx_wakeup_irq; > }; > > /* flow control mode */ > @@ -551,6 +553,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; > } > > @@ -572,15 +576,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); > > -- > 2.22.0.rc1.257.g3120a18244-goog >