Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

uart: mediatek: support Rx in-band wakeup

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>

authored by

Claire Chang and committed by
Greg Kroah-Hartman
9315ad99 277375b8

+24
+24
drivers/tty/serial/8250/8250_mtk.c
··· 10 10 #include <linux/module.h> 11 11 #include <linux/of_irq.h> 12 12 #include <linux/of_platform.h> 13 + #include <linux/pinctrl/consumer.h> 13 14 #include <linux/platform_device.h> 14 15 #include <linux/pm_runtime.h> 15 16 #include <linux/serial_8250.h> ··· 70 69 #ifdef CONFIG_SERIAL_8250_DMA 71 70 enum dma_rx_status rx_status; 72 71 #endif 72 + int rx_wakeup_irq; 73 73 }; 74 74 75 75 /* flow control mode */ ··· 544 542 pm_runtime_set_active(&pdev->dev); 545 543 pm_runtime_enable(&pdev->dev); 546 544 545 + data->rx_wakeup_irq = platform_get_irq(pdev, 1); 546 + 547 547 return 0; 548 548 } 549 549 ··· 567 563 static int __maybe_unused mtk8250_suspend(struct device *dev) 568 564 { 569 565 struct mtk8250_data *data = dev_get_drvdata(dev); 566 + int irq = data->rx_wakeup_irq; 567 + int err; 570 568 571 569 serial8250_suspend_port(data->line); 570 + 571 + pinctrl_pm_select_sleep_state(dev); 572 + if (irq >= 0) { 573 + err = enable_irq_wake(irq); 574 + if (err) { 575 + dev_err(dev, 576 + "failed to enable irq wake on IRQ %d: %d\n", 577 + irq, err); 578 + pinctrl_pm_select_default_state(dev); 579 + serial8250_resume_port(data->line); 580 + return err; 581 + } 582 + } 572 583 573 584 return 0; 574 585 } ··· 591 572 static int __maybe_unused mtk8250_resume(struct device *dev) 592 573 { 593 574 struct mtk8250_data *data = dev_get_drvdata(dev); 575 + int irq = data->rx_wakeup_irq; 576 + 577 + if (irq >= 0) 578 + disable_irq_wake(irq); 579 + pinctrl_pm_select_default_state(dev); 594 580 595 581 serial8250_resume_port(data->line); 596 582