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

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Neeraj Sanjay Kale and committed by
Luiz Augusto von Dentz
c50b5666 a12a5f5f

+52 -6
+52 -6
drivers/bluetooth/btnxpuart.c
··· 17 17 #include <linux/crc32.h> 18 18 #include <linux/string_helpers.h> 19 19 #include <linux/gpio/consumer.h> 20 + #include <linux/of_irq.h> 20 21 21 22 #include <net/bluetooth/bluetooth.h> 22 23 #include <net/bluetooth/hci_core.h> ··· 144 143 bool driver_sent_cmd; 145 144 u16 h2c_ps_interval; 146 145 u16 c2h_ps_interval; 146 + bool wakeup_source; 147 147 struct gpio_desc *h2c_ps_gpio; 148 + s32 irq_handler; 148 149 struct hci_dev *hdev; 149 150 struct work_struct work; 150 151 struct timer_list ps_timer; ··· 479 476 } 480 477 } 481 478 479 + static irqreturn_t ps_host_wakeup_irq_handler(int irq, void *priv) 480 + { 481 + struct btnxpuart_dev *nxpdev = (struct btnxpuart_dev *)priv; 482 + 483 + bt_dev_dbg(nxpdev->hdev, "Host wakeup interrupt"); 484 + return IRQ_HANDLED; 485 + } 482 486 static int ps_setup(struct hci_dev *hdev) 483 487 { 484 488 struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 485 489 struct serdev_device *serdev = nxpdev->serdev; 486 490 struct ps_data *psdata = &nxpdev->psdata; 491 + int ret; 487 492 493 + /* Out-Of-Band Device Wakeup */ 488 494 psdata->h2c_ps_gpio = devm_gpiod_get_optional(&serdev->dev, "device-wakeup", 489 495 GPIOD_OUT_LOW); 490 496 if (IS_ERR(psdata->h2c_ps_gpio)) { ··· 505 493 if (device_property_read_u8(&serdev->dev, "nxp,wakein-pin", &psdata->h2c_wakeup_gpio)) { 506 494 psdata->h2c_wakeup_gpio = 0xff; /* 0xff: use default pin/gpio */ 507 495 } else if (!psdata->h2c_ps_gpio) { 508 - bt_dev_warn(hdev, "nxp,wakein-pin property without device-wakeup GPIO"); 496 + bt_dev_warn(hdev, "nxp,wakein-pin property without device-wakeup-gpios"); 509 497 psdata->h2c_wakeup_gpio = 0xff; 510 498 } 511 499 512 - device_property_read_u8(&serdev->dev, "nxp,wakeout-pin", &psdata->c2h_wakeup_gpio); 500 + /* Out-Of-Band Host Wakeup */ 501 + if (of_property_read_bool(serdev->dev.of_node, "wakeup-source")) { 502 + psdata->irq_handler = of_irq_get_byname(serdev->dev.of_node, "wakeup"); 503 + bt_dev_info(nxpdev->hdev, "irq_handler: %d", psdata->irq_handler); 504 + if (psdata->irq_handler > 0) 505 + psdata->wakeup_source = true; 506 + } 507 + 508 + if (device_property_read_u8(&serdev->dev, "nxp,wakeout-pin", &psdata->c2h_wakeup_gpio)) { 509 + psdata->c2h_wakeup_gpio = 0xff; 510 + if (psdata->wakeup_source) { 511 + bt_dev_warn(hdev, "host wakeup interrupt without nxp,wakeout-pin"); 512 + psdata->wakeup_source = false; 513 + } 514 + } else if (!psdata->wakeup_source) { 515 + bt_dev_warn(hdev, "nxp,wakeout-pin property without host wakeup interrupt"); 516 + psdata->c2h_wakeup_gpio = 0xff; 517 + } 518 + 519 + if (psdata->wakeup_source) { 520 + ret = devm_request_irq(&serdev->dev, psdata->irq_handler, 521 + ps_host_wakeup_irq_handler, 522 + IRQF_ONESHOT | IRQF_TRIGGER_FALLING, 523 + dev_name(&serdev->dev), nxpdev); 524 + disable_irq(psdata->irq_handler); 525 + device_init_wakeup(&serdev->dev, true); 526 + } 513 527 514 528 psdata->hdev = hdev; 515 529 INIT_WORK(&psdata->work, ps_work_func); ··· 675 637 676 638 psdata->ps_state = PS_STATE_AWAKE; 677 639 678 - if (psdata->c2h_wakeup_gpio) { 640 + if (psdata->c2h_wakeup_gpio != 0xff) 679 641 psdata->c2h_wakeupmode = BT_HOST_WAKEUP_METHOD_GPIO; 680 - } else { 642 + else 681 643 psdata->c2h_wakeupmode = BT_HOST_WAKEUP_METHOD_NONE; 682 - psdata->c2h_wakeup_gpio = 0xff; 683 - } 684 644 685 645 psdata->cur_h2c_wakeupmode = WAKEUP_METHOD_INVALID; 686 646 if (psdata->h2c_ps_gpio) ··· 1857 1821 struct ps_data *psdata = &nxpdev->psdata; 1858 1822 1859 1823 ps_control(psdata->hdev, PS_STATE_SLEEP); 1824 + 1825 + if (psdata->wakeup_source) { 1826 + enable_irq_wake(psdata->irq_handler); 1827 + enable_irq(psdata->irq_handler); 1828 + } 1860 1829 return 0; 1861 1830 } 1862 1831 ··· 1869 1828 { 1870 1829 struct btnxpuart_dev *nxpdev = dev_get_drvdata(dev); 1871 1830 struct ps_data *psdata = &nxpdev->psdata; 1831 + 1832 + if (psdata->wakeup_source) { 1833 + disable_irq(psdata->irq_handler); 1834 + disable_irq_wake(psdata->irq_handler); 1835 + } 1872 1836 1873 1837 ps_control(psdata->hdev, PS_STATE_AWAKE); 1874 1838 return 0;