diff mbox series

[v4,2/2] Bluetooth: btnxpuart: Add GPIO support to power save feature

Message ID 20241007131316.626690-3-neeraj.sanjaykale@nxp.com
State Accepted
Commit 039468a219126b10e988bf67f73d8a6687cba7dc
Headers show
Series Bluetooth: btnxpuart: Add GPIO mechanism to | expand

Commit Message

Neeraj Sanjay Kale Oct. 7, 2024, 1:13 p.m. UTC
This adds support for driving the chip into sleep or wakeup with a GPIO.

If the device tree property device-wakeup-gpios is defined, the driver
utilizes this GPIO for controlling the chip's power save state, else it
uses the default UART-break method.

Signed-off-by: Neeraj Sanjay Kale <neeraj.sanjaykale@nxp.com>
---
v3: Remove GPIO toggling in ps_init(). (Shenwei Wang)
v4: Use devm_gpiod_get_optional() instead of devm_gpiod_get()
---
 drivers/bluetooth/btnxpuart.c | 57 +++++++++++++++++++++++++++++++----
 1 file changed, 51 insertions(+), 6 deletions(-)

Comments

kernel test robot Oct. 8, 2024, 7:09 a.m. UTC | #1
Hi Neeraj,

kernel test robot noticed the following build errors:

[auto build test ERROR on bluetooth/master]
[also build test ERROR on bluetooth-next/master robh/for-next linus/master v6.12-rc2 next-20241004]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Neeraj-Sanjay-Kale/dt-bindings-net-bluetooth-nxp-Add-support-for-power-save-feature-using-GPIO/20241007-211315
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git master
patch link:    https://lore.kernel.org/r/20241007131316.626690-3-neeraj.sanjaykale%40nxp.com
patch subject: [PATCH v4 2/2] Bluetooth: btnxpuart: Add GPIO support to power save feature
config: x86_64-buildonly-randconfig-003-20241008 (https://download.01.org/0day-ci/archive/20241008/202410081424.BaGORAHw-lkp@intel.com/config)
compiler: clang version 18.1.8 (https://github.com/llvm/llvm-project 3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241008/202410081424.BaGORAHw-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202410081424.BaGORAHw-lkp@intel.com/

All errors (new ones prefixed by >>):

>> drivers/bluetooth/btnxpuart.c:445:7: error: expected ')'
     445 |                            PTR_ERR(psdata->h2c_ps_gpio));
         |                            ^
   drivers/bluetooth/btnxpuart.c:444:3: note: to match this '('
     444 |                 bt_dev_err(hdev, "Error fetching device-wakeup-gpios: %ld"
         |                 ^
   include/net/bluetooth/bluetooth.h:278:2: note: expanded from macro 'bt_dev_err'
     278 |         BT_ERR("%s: " fmt, bt_dev_name(hdev), ##__VA_ARGS__)
         |         ^
   include/net/bluetooth/bluetooth.h:263:32: note: expanded from macro 'BT_ERR'
     263 | #define BT_ERR(fmt, ...)        bt_err(fmt "\n", ##__VA_ARGS__)
         |                                       ^
   1 error generated.


vim +445 drivers/bluetooth/btnxpuart.c

   434	
   435	static int ps_setup(struct hci_dev *hdev)
   436	{
   437		struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
   438		struct serdev_device *serdev = nxpdev->serdev;
   439		struct ps_data *psdata = &nxpdev->psdata;
   440	
   441		psdata->h2c_ps_gpio = devm_gpiod_get_optional(&serdev->dev, "device-wakeup",
   442							      GPIOD_OUT_LOW);
   443		if (IS_ERR(psdata->h2c_ps_gpio)) {
   444			bt_dev_err(hdev, "Error fetching device-wakeup-gpios: %ld"
 > 445				   PTR_ERR(psdata->h2c_ps_gpio));
   446			return PTR_ERR(psdata->h2c_ps_gpio);
   447		}
   448	
   449		if (!psdata->h2c_ps_gpio)
   450			psdata->h2c_wakeup_gpio = 0xff;
   451	
   452		psdata->hdev = hdev;
   453		INIT_WORK(&psdata->work, ps_work_func);
   454		mutex_init(&psdata->ps_lock);
   455		timer_setup(&psdata->ps_timer, ps_timeout_func, 0);
   456	
   457		return 0;
   458	}
   459
kernel test robot Oct. 8, 2024, 8:11 a.m. UTC | #2
Hi Neeraj,

kernel test robot noticed the following build errors:

[auto build test ERROR on bluetooth/master]
[also build test ERROR on bluetooth-next/master robh/for-next linus/master v6.12-rc2 next-20241004]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Neeraj-Sanjay-Kale/dt-bindings-net-bluetooth-nxp-Add-support-for-power-save-feature-using-GPIO/20241007-211315
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git master
patch link:    https://lore.kernel.org/r/20241007131316.626690-3-neeraj.sanjaykale%40nxp.com
patch subject: [PATCH v4 2/2] Bluetooth: btnxpuart: Add GPIO support to power save feature
config: m68k-allmodconfig (https://download.01.org/0day-ci/archive/20241008/202410081516.Mt35mvJk-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 14.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241008/202410081516.Mt35mvJk-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202410081516.Mt35mvJk-lkp@intel.com/

All error/warnings (new ones prefixed by >>):

   In file included from drivers/bluetooth/btnxpuart.c:21:
   drivers/bluetooth/btnxpuart.c: In function 'ps_setup':
>> drivers/bluetooth/btnxpuart.c:445:28: error: expected ')' before 'PTR_ERR'
     445 |                            PTR_ERR(psdata->h2c_ps_gpio));
         |                            ^~~~~~~
   include/net/bluetooth/bluetooth.h:263:40: note: in definition of macro 'BT_ERR'
     263 | #define BT_ERR(fmt, ...)        bt_err(fmt "\n", ##__VA_ARGS__)
         |                                        ^~~
   drivers/bluetooth/btnxpuart.c:444:17: note: in expansion of macro 'bt_dev_err'
     444 |                 bt_dev_err(hdev, "Error fetching device-wakeup-gpios: %ld"
         |                 ^~~~~~~~~~
   include/net/bluetooth/bluetooth.h:263:39: note: to match this '('
     263 | #define BT_ERR(fmt, ...)        bt_err(fmt "\n", ##__VA_ARGS__)
         |                                       ^
   include/net/bluetooth/bluetooth.h:278:9: note: in expansion of macro 'BT_ERR'
     278 |         BT_ERR("%s: " fmt, bt_dev_name(hdev), ##__VA_ARGS__)
         |         ^~~~~~
   drivers/bluetooth/btnxpuart.c:444:17: note: in expansion of macro 'bt_dev_err'
     444 |                 bt_dev_err(hdev, "Error fetching device-wakeup-gpios: %ld"
         |                 ^~~~~~~~~~
>> include/net/bluetooth/bluetooth.h:278:16: warning: format '%s' expects a matching 'char *' argument [-Wformat=]
     278 |         BT_ERR("%s: " fmt, bt_dev_name(hdev), ##__VA_ARGS__)
         |                ^~~~~~
   include/net/bluetooth/bluetooth.h:263:40: note: in definition of macro 'BT_ERR'
     263 | #define BT_ERR(fmt, ...)        bt_err(fmt "\n", ##__VA_ARGS__)
         |                                        ^~~
   drivers/bluetooth/btnxpuart.c:444:17: note: in expansion of macro 'bt_dev_err'
     444 |                 bt_dev_err(hdev, "Error fetching device-wakeup-gpios: %ld"
         |                 ^~~~~~~~~~
   include/net/bluetooth/bluetooth.h:278:18: note: format string is defined here
     278 |         BT_ERR("%s: " fmt, bt_dev_name(hdev), ##__VA_ARGS__)
         |                 ~^
         |                  |
         |                  char *
>> include/net/bluetooth/bluetooth.h:278:16: warning: format '%ld' expects a matching 'long int' argument [-Wformat=]
     278 |         BT_ERR("%s: " fmt, bt_dev_name(hdev), ##__VA_ARGS__)
         |                ^~~~~~
   include/net/bluetooth/bluetooth.h:263:40: note: in definition of macro 'BT_ERR'
     263 | #define BT_ERR(fmt, ...)        bt_err(fmt "\n", ##__VA_ARGS__)
         |                                        ^~~
   drivers/bluetooth/btnxpuart.c:444:17: note: in expansion of macro 'bt_dev_err'
     444 |                 bt_dev_err(hdev, "Error fetching device-wakeup-gpios: %ld"
         |                 ^~~~~~~~~~

Kconfig warnings: (for reference only)
   WARNING: unmet direct dependencies detected for GET_FREE_REGION
   Depends on [n]: SPARSEMEM [=n]
   Selected by [m]:
   - RESOURCE_KUNIT_TEST [=m] && RUNTIME_TESTING_MENU [=y] && KUNIT [=m]


vim +445 drivers/bluetooth/btnxpuart.c

   434	
   435	static int ps_setup(struct hci_dev *hdev)
   436	{
   437		struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
   438		struct serdev_device *serdev = nxpdev->serdev;
   439		struct ps_data *psdata = &nxpdev->psdata;
   440	
   441		psdata->h2c_ps_gpio = devm_gpiod_get_optional(&serdev->dev, "device-wakeup",
   442							      GPIOD_OUT_LOW);
   443		if (IS_ERR(psdata->h2c_ps_gpio)) {
   444			bt_dev_err(hdev, "Error fetching device-wakeup-gpios: %ld"
 > 445				   PTR_ERR(psdata->h2c_ps_gpio));
   446			return PTR_ERR(psdata->h2c_ps_gpio);
   447		}
   448	
   449		if (!psdata->h2c_ps_gpio)
   450			psdata->h2c_wakeup_gpio = 0xff;
   451	
   452		psdata->hdev = hdev;
   453		INIT_WORK(&psdata->work, ps_work_func);
   454		mutex_init(&psdata->ps_lock);
   455		timer_setup(&psdata->ps_timer, ps_timeout_func, 0);
   456	
   457		return 0;
   458	}
   459
diff mbox series

Patch

diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c
index 2b8a07c745c9..83665f0b96c5 100644
--- a/drivers/bluetooth/btnxpuart.c
+++ b/drivers/bluetooth/btnxpuart.c
@@ -16,6 +16,7 @@ 
 #include <linux/crc8.h>
 #include <linux/crc32.h>
 #include <linux/string_helpers.h>
+#include <linux/gpio/consumer.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -82,6 +83,7 @@ 
 #define WAKEUP_METHOD_BREAK     1
 #define WAKEUP_METHOD_EXT_BREAK 2
 #define WAKEUP_METHOD_RTS       3
+#define WAKEUP_METHOD_GPIO      4
 #define WAKEUP_METHOD_INVALID   0xff
 
 /* power save mode status */
@@ -135,6 +137,7 @@  struct ps_data {
 	bool  driver_sent_cmd;
 	u16   h2c_ps_interval;
 	u16   c2h_ps_interval;
+	struct gpio_desc *h2c_ps_gpio;
 	struct hci_dev *hdev;
 	struct work_struct work;
 	struct timer_list ps_timer;
@@ -365,7 +368,7 @@  static void ps_control(struct hci_dev *hdev, u8 ps_state)
 {
 	struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
 	struct ps_data *psdata = &nxpdev->psdata;
-	int status;
+	int status = 0;
 
 	if (psdata->ps_state == ps_state ||
 	    !test_bit(BTNXPUART_SERDEV_OPEN, &nxpdev->tx_state))
@@ -373,6 +376,14 @@  static void ps_control(struct hci_dev *hdev, u8 ps_state)
 
 	mutex_lock(&psdata->ps_lock);
 	switch (psdata->cur_h2c_wakeupmode) {
+	case WAKEUP_METHOD_GPIO:
+		if (ps_state == PS_STATE_AWAKE)
+			gpiod_set_value_cansleep(psdata->h2c_ps_gpio, 0);
+		else
+			gpiod_set_value_cansleep(psdata->h2c_ps_gpio, 1);
+		bt_dev_dbg(hdev, "Set h2c_ps_gpio: %s",
+			   str_high_low(ps_state == PS_STATE_SLEEP));
+		break;
 	case WAKEUP_METHOD_DTR:
 		if (ps_state == PS_STATE_AWAKE)
 			status = serdev_device_set_tiocm(nxpdev->serdev, TIOCM_DTR, 0);
@@ -422,15 +433,29 @@  static void ps_timeout_func(struct timer_list *t)
 	}
 }
 
-static void ps_setup(struct hci_dev *hdev)
+static int ps_setup(struct hci_dev *hdev)
 {
 	struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
+	struct serdev_device *serdev = nxpdev->serdev;
 	struct ps_data *psdata = &nxpdev->psdata;
 
+	psdata->h2c_ps_gpio = devm_gpiod_get_optional(&serdev->dev, "device-wakeup",
+						      GPIOD_OUT_LOW);
+	if (IS_ERR(psdata->h2c_ps_gpio)) {
+		bt_dev_err(hdev, "Error fetching device-wakeup-gpios: %ld"
+			   PTR_ERR(psdata->h2c_ps_gpio));
+		return PTR_ERR(psdata->h2c_ps_gpio);
+	}
+
+	if (!psdata->h2c_ps_gpio)
+		psdata->h2c_wakeup_gpio = 0xff;
+
 	psdata->hdev = hdev;
 	INIT_WORK(&psdata->work, ps_work_func);
 	mutex_init(&psdata->ps_lock);
 	timer_setup(&psdata->ps_timer, ps_timeout_func, 0);
+
+	return 0;
 }
 
 static bool ps_wakeup(struct btnxpuart_dev *nxpdev)
@@ -516,6 +541,9 @@  static int send_wakeup_method_cmd(struct hci_dev *hdev, void *data)
 	pcmd.c2h_wakeupmode = psdata->c2h_wakeupmode;
 	pcmd.c2h_wakeup_gpio = psdata->c2h_wakeup_gpio;
 	switch (psdata->h2c_wakeupmode) {
+	case WAKEUP_METHOD_GPIO:
+		pcmd.h2c_wakeupmode = BT_CTRL_WAKEUP_METHOD_GPIO;
+		break;
 	case WAKEUP_METHOD_DTR:
 		pcmd.h2c_wakeupmode = BT_CTRL_WAKEUP_METHOD_DSR;
 		break;
@@ -550,6 +578,7 @@  static void ps_init(struct hci_dev *hdev)
 {
 	struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
 	struct ps_data *psdata = &nxpdev->psdata;
+	u8 default_h2c_wakeup_mode = DEFAULT_H2C_WAKEUP_MODE;
 
 	serdev_device_set_tiocm(nxpdev->serdev, 0, TIOCM_RTS);
 	usleep_range(5000, 10000);
@@ -561,8 +590,17 @@  static void ps_init(struct hci_dev *hdev)
 	psdata->c2h_wakeup_gpio = 0xff;
 
 	psdata->cur_h2c_wakeupmode = WAKEUP_METHOD_INVALID;
+	if (psdata->h2c_ps_gpio)
+		default_h2c_wakeup_mode = WAKEUP_METHOD_GPIO;
+
 	psdata->h2c_ps_interval = PS_DEFAULT_TIMEOUT_PERIOD_MS;
-	switch (DEFAULT_H2C_WAKEUP_MODE) {
+
+	switch (default_h2c_wakeup_mode) {
+	case WAKEUP_METHOD_GPIO:
+		psdata->h2c_wakeupmode = WAKEUP_METHOD_GPIO;
+		gpiod_set_value_cansleep(psdata->h2c_ps_gpio, 0);
+		usleep_range(5000, 10000);
+		break;
 	case WAKEUP_METHOD_DTR:
 		psdata->h2c_wakeupmode = WAKEUP_METHOD_DTR;
 		serdev_device_set_tiocm(nxpdev->serdev, 0, TIOCM_DTR);
@@ -1279,6 +1317,9 @@  static int nxp_enqueue(struct hci_dev *hdev, struct sk_buff *skb)
 				psdata->c2h_wakeup_gpio = wakeup_parm.c2h_wakeup_gpio;
 				psdata->h2c_wakeup_gpio = wakeup_parm.h2c_wakeup_gpio;
 				switch (wakeup_parm.h2c_wakeupmode) {
+				case BT_CTRL_WAKEUP_METHOD_GPIO:
+					psdata->h2c_wakeupmode = WAKEUP_METHOD_GPIO;
+					break;
 				case BT_CTRL_WAKEUP_METHOD_DSR:
 					psdata->h2c_wakeupmode = WAKEUP_METHOD_DTR;
 					break;
@@ -1509,13 +1550,17 @@  static int nxp_serdev_probe(struct serdev_device *serdev)
 
 	if (hci_register_dev(hdev) < 0) {
 		dev_err(&serdev->dev, "Can't register HCI device\n");
-		hci_free_dev(hdev);
-		return -ENODEV;
+		goto probe_fail;
 	}
 
-	ps_setup(hdev);
+	if (ps_setup(hdev))
+		goto probe_fail;
 
 	return 0;
+
+probe_fail:
+	hci_free_dev(hdev);
+	return -ENODEV;
 }
 
 static void nxp_serdev_remove(struct serdev_device *serdev)