Skip to content

Commit c50b566

Browse files
NeerajSanjayKaleVudentz
authored andcommitted
Bluetooth: btnxpuart: Implement host-wakeup feature
This implements host wakeup feature by reading the device tree property wakeup-source and 'wakeup' interrupt, and nxp,wakeout-pin, and configuring it as a FALLING EDGE triggered interrupt. When host is suspended, a trigger from the WAKE_OUT pin of the controller wakes it up. To enable this feature, both device tree properties are needed to be defined. Signed-off-by: Neeraj Sanjay Kale <neeraj.sanjaykale@nxp.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
1 parent a12a5f5 commit c50b566

File tree

1 file changed

+52
-6
lines changed

1 file changed

+52
-6
lines changed

drivers/bluetooth/btnxpuart.c

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/crc32.h>
1818
#include <linux/string_helpers.h>
1919
#include <linux/gpio/consumer.h>
20+
#include <linux/of_irq.h>
2021

2122
#include <net/bluetooth/bluetooth.h>
2223
#include <net/bluetooth/hci_core.h>
@@ -143,7 +144,9 @@ struct ps_data {
143144
bool driver_sent_cmd;
144145
u16 h2c_ps_interval;
145146
u16 c2h_ps_interval;
147+
bool wakeup_source;
146148
struct gpio_desc *h2c_ps_gpio;
149+
s32 irq_handler;
147150
struct hci_dev *hdev;
148151
struct work_struct work;
149152
struct timer_list ps_timer;
@@ -476,12 +479,21 @@ static void ps_timeout_func(struct timer_list *t)
476479
}
477480
}
478481

482+
static irqreturn_t ps_host_wakeup_irq_handler(int irq, void *priv)
483+
{
484+
struct btnxpuart_dev *nxpdev = (struct btnxpuart_dev *)priv;
485+
486+
bt_dev_dbg(nxpdev->hdev, "Host wakeup interrupt");
487+
return IRQ_HANDLED;
488+
}
479489
static int ps_setup(struct hci_dev *hdev)
480490
{
481491
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
482492
struct serdev_device *serdev = nxpdev->serdev;
483493
struct ps_data *psdata = &nxpdev->psdata;
494+
int ret;
484495

496+
/* Out-Of-Band Device Wakeup */
485497
psdata->h2c_ps_gpio = devm_gpiod_get_optional(&serdev->dev, "device-wakeup",
486498
GPIOD_OUT_LOW);
487499
if (IS_ERR(psdata->h2c_ps_gpio)) {
@@ -493,11 +505,37 @@ static int ps_setup(struct hci_dev *hdev)
493505
if (device_property_read_u8(&serdev->dev, "nxp,wakein-pin", &psdata->h2c_wakeup_gpio)) {
494506
psdata->h2c_wakeup_gpio = 0xff; /* 0xff: use default pin/gpio */
495507
} else if (!psdata->h2c_ps_gpio) {
496-
bt_dev_warn(hdev, "nxp,wakein-pin property without device-wakeup GPIO");
508+
bt_dev_warn(hdev, "nxp,wakein-pin property without device-wakeup-gpios");
497509
psdata->h2c_wakeup_gpio = 0xff;
498510
}
499511

500-
device_property_read_u8(&serdev->dev, "nxp,wakeout-pin", &psdata->c2h_wakeup_gpio);
512+
/* Out-Of-Band Host Wakeup */
513+
if (of_property_read_bool(serdev->dev.of_node, "wakeup-source")) {
514+
psdata->irq_handler = of_irq_get_byname(serdev->dev.of_node, "wakeup");
515+
bt_dev_info(nxpdev->hdev, "irq_handler: %d", psdata->irq_handler);
516+
if (psdata->irq_handler > 0)
517+
psdata->wakeup_source = true;
518+
}
519+
520+
if (device_property_read_u8(&serdev->dev, "nxp,wakeout-pin", &psdata->c2h_wakeup_gpio)) {
521+
psdata->c2h_wakeup_gpio = 0xff;
522+
if (psdata->wakeup_source) {
523+
bt_dev_warn(hdev, "host wakeup interrupt without nxp,wakeout-pin");
524+
psdata->wakeup_source = false;
525+
}
526+
} else if (!psdata->wakeup_source) {
527+
bt_dev_warn(hdev, "nxp,wakeout-pin property without host wakeup interrupt");
528+
psdata->c2h_wakeup_gpio = 0xff;
529+
}
530+
531+
if (psdata->wakeup_source) {
532+
ret = devm_request_irq(&serdev->dev, psdata->irq_handler,
533+
ps_host_wakeup_irq_handler,
534+
IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
535+
dev_name(&serdev->dev), nxpdev);
536+
disable_irq(psdata->irq_handler);
537+
device_init_wakeup(&serdev->dev, true);
538+
}
501539

502540
psdata->hdev = hdev;
503541
INIT_WORK(&psdata->work, ps_work_func);
@@ -637,12 +675,10 @@ static void ps_init(struct hci_dev *hdev)
637675

638676
psdata->ps_state = PS_STATE_AWAKE;
639677

640-
if (psdata->c2h_wakeup_gpio) {
678+
if (psdata->c2h_wakeup_gpio != 0xff)
641679
psdata->c2h_wakeupmode = BT_HOST_WAKEUP_METHOD_GPIO;
642-
} else {
680+
else
643681
psdata->c2h_wakeupmode = BT_HOST_WAKEUP_METHOD_NONE;
644-
psdata->c2h_wakeup_gpio = 0xff;
645-
}
646682

647683
psdata->cur_h2c_wakeupmode = WAKEUP_METHOD_INVALID;
648684
if (psdata->h2c_ps_gpio)
@@ -1821,6 +1857,11 @@ static int nxp_serdev_suspend(struct device *dev)
18211857
struct ps_data *psdata = &nxpdev->psdata;
18221858

18231859
ps_control(psdata->hdev, PS_STATE_SLEEP);
1860+
1861+
if (psdata->wakeup_source) {
1862+
enable_irq_wake(psdata->irq_handler);
1863+
enable_irq(psdata->irq_handler);
1864+
}
18241865
return 0;
18251866
}
18261867

@@ -1829,6 +1870,11 @@ static int nxp_serdev_resume(struct device *dev)
18291870
struct btnxpuart_dev *nxpdev = dev_get_drvdata(dev);
18301871
struct ps_data *psdata = &nxpdev->psdata;
18311872

1873+
if (psdata->wakeup_source) {
1874+
disable_irq(psdata->irq_handler);
1875+
disable_irq_wake(psdata->irq_handler);
1876+
}
1877+
18321878
ps_control(psdata->hdev, PS_STATE_AWAKE);
18331879
return 0;
18341880
}

0 commit comments

Comments
 (0)