public inbox for linux-bluetooth@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 0/2] Bluetooth: mediatek: add gpio pin to reset bt
@ 2025-06-27  5:59 Zhangchao Zhang
  2025-06-27  5:59 ` [PATCH v5 1/2] " Zhangchao Zhang
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Zhangchao Zhang @ 2025-06-27  5:59 UTC (permalink / raw)
  To: Marcel Holtmann, Matthias Brugger, Luiz Von Dentz,
	AngeloGioacchino Del Regno, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: Sean Wang, Jiande Lu, Deren Wu, Chris Lu, Hao Qin,
	linux-bluetooth, linux-kernel, linux-arm-kernel, linux-mediatek,
	devicetree, Zhangchao Zhang

The enhanced BT reset feature builds upon the previous software-based
BT reset by adding support for hardware pin resets.
To maintain compatibility with existing projects that
still use the software BT reset, both methods are supported.

When performing a BT reset, the system first checks whether the
Device Tree Source (DTS) is configured with the appropriate settings.
If the specified compatible and BT reset GPIO are defined in the DTS,
the system will pull the designated GPIO pin low for at least 200ms,
then pull it high to trigger the BT reset. If these settings are not
configured, the system will fall back to the original software
BT reset methods.

Compared with the previously submitted version, the following
information are some specific revision histories

V4-->V5 modifications:
-Modify the comments mentioned in v1.
-Modify dt_binding files and 
   make dt binding a separate patch.

V3-->V4 modifications:
Modify dt binding format information and
   the explanation text in the patch

V2-->V3 modifications:
-Changed the capitalization of co-developer names,
   using the correct capitalization of abbreviations and full
   name, and corrected obvious spelling errors.
-Add a revision history.
-Remove the "BT Driver" in the prefix.
-Add the bt-binding document, include inforamtion related to reset
   pin and compatibility matching.
-Add a comment before the schedule_delayed_work function call,
   although schedule_delayed_work is asynchronous, there is no risk.
   Even if it is not completed within 200ms, it will only postpone
   the subsequent probe and will not have any impact.
-Add a comment before the btmtk_reset_by_gpio function call,
   if the compatibility filed or pin cannot be found in the dts
   files, it can still reset bluetooth using software reset.

V2 modifications:
Modify gpio to GPIO, SW to software,
and fix other obvious spelling errors.

-- 
2.46.0


^ permalink raw reply	[flat|nested] 9+ messages in thread
* [PATCH v7 1/1] Bluetooth: mediatek: add gpio pin to reset bt
@ 2025-09-05  8:40 Zhangchao Zhang
  2025-09-05  8:59 ` bluez.test.bot
  0 siblings, 1 reply; 9+ messages in thread
From: Zhangchao Zhang @ 2025-09-05  8:40 UTC (permalink / raw)
  To: Marcel Holtmann, Matthias Brugger, Krzysztof Kozlowski,
	Luiz Von Dentz, AngeloGioacchino Del Regno
  Cc: Sean Wang, Jiande Lu, Deren Wu, Chris Lu, Hao Qin,
	linux-bluetooth, linux-kernel, linux-arm-kernel, linux-mediatek,
	Zhangchao Zhang

Makes the platform Bluetooth to be reset by hardware pin,
it provides two methods to do it for mediatek controller,
and it has been tested locally many times and can reset normally.

When an exception occurs, resetting Bluetooth by hardware pin
is more stable than resetting Bluetooth by software.
If the corresponding pin is not found in dts,
bluetooth can also be reset successfully.

Co-developed: Hao Qin <hao.qin@mediatek.com>
Co-developed: Chris Lu <chris.lu@mediatek.com>
Co-developed: Jiande Lu <jiande.lu@mediatek.com>
Signed-off-by: Zhangchao Zhang <ot_zhangchao.zhang@mediatek.com>
---
 drivers/bluetooth/btmtk.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index 4390fd571dbd..29d6a93f255d 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -6,6 +6,8 @@
 #include <linux/firmware.h>
 #include <linux/usb.h>
 #include <linux/iopoll.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of.h>
 #include <linux/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -359,11 +361,41 @@ int btmtk_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
 }
 EXPORT_SYMBOL_GPL(btmtk_set_bdaddr);
 
+static int btmtk_hw_gpio_reset(struct hci_dev *hdev, struct btmtk_data *reset_work)
+{
+	struct gpio_desc *reset_gpio;
+
+	/* Find device node*/
+	hdev->dev.of_node = of_find_compatible_node(NULL, NULL, "mediatek,mt7925-bluetooth");
+	reset_gpio = gpiod_get_optional(hdev->dev.of_node, "reset", GPIOD_OUT_HIGH);
+	if (IS_ERR(reset_gpio))
+		return PTR_ERR(reset_gpio);
+
+	if (!reset_gpio)
+		return -ENODEV;
+
+	if (test_and_set_bit(BTMTK_HW_RESET_ACTIVE, &reset_work->flags)) {
+		bt_dev_err(hdev, "last reset failed? Not resetting again");
+		gpiod_put(reset_gpio);
+		return -EBUSY;
+	}
+	gpiod_set_value_cansleep(reset_gpio, 0);
+	msleep(100);
+	gpiod_set_value_cansleep(reset_gpio, 1);
+	gpiod_put(reset_gpio);
+	return 0;
+}
+
 void btmtk_reset_sync(struct hci_dev *hdev)
 {
 	struct btmtk_data *reset_work = hci_get_priv(hdev);
 	int err;
 
+	/* Try hardware GPIO reset*/
+	err = btmtk_hw_gpio_reset(hdev, reset_work);
+	if (!err)
+		return;
+	/* Otherwise, do software reset */
 	hci_dev_lock(hdev);
 
 	err = hci_cmd_sync_queue(hdev, reset_work->reset_sync, NULL, NULL);
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread
* [PATCH v6 1/1] Bluetooth: mediatek: add gpio pin to reset bt
@ 2025-07-08  6:01 Zhangchao Zhang
  2025-07-08  6:42 ` bluez.test.bot
  0 siblings, 1 reply; 9+ messages in thread
From: Zhangchao Zhang @ 2025-07-08  6:01 UTC (permalink / raw)
  To: Marcel Holtmann, Matthias Brugger, Luiz Von Dentz,
	AngeloGioacchino Del Regno, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: Sean Wang, Jiande Lu, Deren Wu, Chris Lu, Hao Qin, Wallace Yu,
	linux-bluetooth, linux-kernel, linux-arm-kernel, linux-mediatek,
	devicetree, Zhangchao Zhang

Makes the platform Bluetooth to be reset by hardware pin,
it provides two methods to do it for mediatek controller,
and it has been tested locally many times and can reset normally.

When an exception occurs, resetting Bluetooth by hardware pin
is more stable than resetting Bluetooth by software.
If the corresponding pin is not found in dts,
bluetooth can also be reset successfully.

Co-developed: Hao Qin <hao.qin@mediatek.com>
Co-developed: Chris Lu <chris.lu@mediatek.com>
Co-developed: Jiande Lu <jiande.lu@mediatek.com>
Signed-off-by: Zhangchao Zhang <ot_zhangchao.zhang@mediatek.com>
---
 drivers/bluetooth/btmtk.c | 69 +++++++++++++++++++++++++++++++++++++++
 drivers/bluetooth/btmtk.h |  5 +++
 2 files changed, 74 insertions(+)

diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index 4390fd571dbd..cdb90143be61 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -6,6 +6,8 @@
 #include <linux/firmware.h>
 #include <linux/usb.h>
 #include <linux/iopoll.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 #include <linux/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -109,6 +111,65 @@ static void btmtk_coredump_notify(struct hci_dev *hdev, int state)
 	}
 }
 
+static void btmtk_reset_by_gpio_work(struct work_struct *work)
+{
+	struct btmtk_reset_gpio *reset_gpio_data =
+			container_of(work, struct btmtk_reset_gpio, reset_work.work);
+
+	gpio_direction_output(reset_gpio_data->gpio_number, 1);
+	kfree(reset_gpio_data);
+}
+
+static int btmtk_reset_by_gpio(struct hci_dev *hdev)
+{
+	struct btmtk_data *data = hci_get_priv(hdev);
+	struct btmtk_reset_gpio *reset_gpio_data;
+	struct device_node *node;
+	int reset_gpio_number;
+
+	node = of_find_compatible_node(NULL, NULL, "mediatek,mt7925-bluetooth");
+	if (node) {
+		reset_gpio_number = of_get_named_gpio(node, "reset-gpios", 0);
+		if (!gpio_is_valid(reset_gpio_number)) {
+			bt_dev_warn(hdev, "invalid reset GPIO, use software reset");
+			return -EINVAL;
+		}
+	} else {
+		bt_dev_warn(hdev, "no reset GPIO, use software reset");
+		return -ENODEV;
+	}
+
+	/* Toggle the hard reset line. The Mediatek device is going to
+	 * yank itself off the USB and then replug. The cleanup is handled
+	 * correctly on the way out (standard USB disconnect), and the new
+	 * device is detected cleanly and bound to the driver again like
+	 * it should be.
+	 */
+
+	if (test_and_set_bit(BTMTK_HW_RESET_ACTIVE, &data->flags)) {
+		bt_dev_err(hdev, "last reset failed? Not resetting again");
+		return 0;
+	}
+
+	reset_gpio_data = kzalloc(sizeof(*reset_gpio_data), GFP_KERNEL);
+	if (!reset_gpio_data)
+		return -ENOMEM;
+
+	INIT_DELAYED_WORK(&reset_gpio_data->reset_work, btmtk_reset_by_gpio_work);
+	reset_gpio_data->gpio_number = reset_gpio_number;
+
+	gpio_direction_output(reset_gpio_number, 0);
+
+	/* It requires 200ms for mtk bt chip to do reset,
+	 * although Schedule_delayed_work is asynchronous,
+	 * it is risk-free. If it is not completed in 200ms,
+	 * it will only postpone the next probe, which will
+	 * only make the probe run later. There is no other risk.
+	 */
+	schedule_delayed_work(&reset_gpio_data->reset_work, msecs_to_jiffies(200));
+	return 0;
+}
+
 void btmtk_fw_get_filename(char *buf, size_t size, u32 dev_id, u32 fw_ver,
 			   u32 fw_flavor)
 {
@@ -364,6 +425,14 @@ void btmtk_reset_sync(struct hci_dev *hdev)
 	struct btmtk_data *reset_work = hci_get_priv(hdev);
 	int err;
 
+	/* Toggle reset gpio if the platform provides one,
+	 * if the compatibility field or pin cannot be found
+	 * in the dts files, it can still reset bluetooth using
+	 * software reset.
+	 */
+	err = btmtk_reset_by_gpio(hdev);
+	if (!err)
+		return;
 	hci_dev_lock(hdev);
 
 	err = hci_cmd_sync_queue(hdev, reset_work->reset_sync, NULL, NULL);
diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h
index 5df7c3296624..8a265ce367d1 100644
--- a/drivers/bluetooth/btmtk.h
+++ b/drivers/bluetooth/btmtk.h
@@ -179,6 +179,11 @@ struct btmtk_data {
 	spinlock_t isorxlock;
 };
 
+struct btmtk_reset_gpio {
+	struct delayed_work reset_work;
+	int gpio_number;
+};
+
 typedef int (*wmt_cmd_sync_func_t)(struct hci_dev *,
 				   struct btmtk_hci_wmt_params *);
 
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread
* [PATCH v4 1/1] Bluetooth: mediatek: add gpio pin to reset bt
@ 2025-06-23 10:23 Zhangchao Zhang
  2025-06-23 11:06 ` bluez.test.bot
  0 siblings, 1 reply; 9+ messages in thread
From: Zhangchao Zhang @ 2025-06-23 10:23 UTC (permalink / raw)
  To: Marcel Holtmann, Matthias Brugger, Luiz Von Dentz,
	AngeloGioacchino Del Regno
  Cc: Sean Wang, Deren Wu, Chris Lu, Hao Qin, linux-bluetooth,
	linux-kernel, linux-arm-kernel, linux-mediatek, Zhangchao Zhang

Makes the platform Bluetooth to be reset by hardware pin,
it provides two methods to do it for mediatek controller,
and it has been tested locally many times and can reset normally.

When an exception occurs, resetting Bluetooth by hardware pin
is more stable than resetting Bluetooth by software.
If the corresponding pin is not found in dts,
bluetooth can also be reset successfully.

Co-developed: Hao Qin <hao.qin@mediatek.com>
Co-developed: Chris Lu <chris.lu@mediatek.com>
Co-developed: Jiande Lu <jiande.lu@mediatek.com>
Signed-off-by: Zhangchao Zhang <ot_zhangchao.zhang@mediatek.com>
---
 drivers/bluetooth/btmtk.c | 69 +++++++++++++++++++++++++++++++++++++++
 drivers/bluetooth/btmtk.h |  5 +++
 2 files changed, 74 insertions(+)

diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index 4390fd571dbd..3e5f3ca6f0d5 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -6,6 +6,8 @@
 #include <linux/firmware.h>
 #include <linux/usb.h>
 #include <linux/iopoll.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 #include <linux/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -109,6 +111,65 @@ static void btmtk_coredump_notify(struct hci_dev *hdev, int state)
 	}
 }
 
+static void btmtk_reset_by_gpio_work(struct work_struct *work)
+{
+	struct btmtk_reset_gpio *reset_gpio_data =
+			container_of(work, struct btmtk_reset_gpio, reset_work.work);
+
+	gpio_direction_output(reset_gpio_data->gpio_number, 1);
+	kfree(reset_gpio_data);
+}
+
+static int btmtk_reset_by_gpio(struct hci_dev *hdev)
+{
+	struct btmtk_data *data = hci_get_priv(hdev);
+	struct btmtk_reset_gpio *reset_gpio_data;
+	struct device_node *node;
+	int reset_gpio_number;
+
+	node = of_find_compatible_node(NULL, NULL, "mediatek,usb-bluetooth");
+	if (node) {
+		reset_gpio_number = of_get_named_gpio(node, "reset-gpios", 0);
+		if (!gpio_is_valid(reset_gpio_number)) {
+			bt_dev_warn(hdev, "invalid reset GPIO, use software reset");
+			return -EINVAL;
+		}
+	} else {
+		bt_dev_warn(hdev, "no reset GPIO, use software reset");
+		return -ENODEV;
+	}
+
+	/* Toggle the hard reset line. The Mediatek device is going to
+	 * yank itself off the USB and then replug. The cleanup is handled
+	 * correctly on the way out (standard USB disconnect), and the new
+	 * device is detected cleanly and bound to the driver again like
+	 * it should be.
+	 */
+
+	if (test_and_set_bit(BTMTK_HW_RESET_ACTIVE, &data->flags)) {
+		bt_dev_err(hdev, "last reset failed? Not resetting again");
+		return 0;
+	}
+
+	reset_gpio_data = kzalloc(sizeof(*reset_gpio_data), GFP_KERNEL);
+	if (!reset_gpio_data)
+		return -ENOMEM;
+
+	INIT_DELAYED_WORK(&reset_gpio_data->reset_work, btmtk_reset_by_gpio_work);
+	reset_gpio_data->gpio_number = reset_gpio_number;
+
+	gpio_direction_output(reset_gpio_number, 0);
+
+	/* It requires 200ms for mtk bt chip to do reset,
+	 * although Schedule_delayed_work is asynchronous,
+	 * it is risk-free. If it is not completed in 200ms,
+	 * it will only postpone the next probe, which will
+	 * only make the probe run later. There is no other risk.
+	 */
+	schedule_delayed_work(&reset_gpio_data->reset_work, msecs_to_jiffies(200));
+	return 0;
+}
+
 void btmtk_fw_get_filename(char *buf, size_t size, u32 dev_id, u32 fw_ver,
 			   u32 fw_flavor)
 {
@@ -364,6 +425,14 @@ void btmtk_reset_sync(struct hci_dev *hdev)
 	struct btmtk_data *reset_work = hci_get_priv(hdev);
 	int err;
 
+	/* Toggle reset gpio if the platform provieds one,
+	 * if the compatibility field or pin cannot be found
+	 * in the dts files, it can still reset bluetooth using
+	 * software reset.
+	 */
+	err = btmtk_reset_by_gpio(hdev);
+	if (!err)
+		return;
 	hci_dev_lock(hdev);
 
 	err = hci_cmd_sync_queue(hdev, reset_work->reset_sync, NULL, NULL);
diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h
index 5df7c3296624..8a265ce367d1 100644
--- a/drivers/bluetooth/btmtk.h
+++ b/drivers/bluetooth/btmtk.h
@@ -179,6 +179,11 @@ struct btmtk_data {
 	spinlock_t isorxlock;
 };
 
+struct btmtk_reset_gpio {
+	struct delayed_work reset_work;
+	int gpio_number;
+};
+
 typedef int (*wmt_cmd_sync_func_t)(struct hci_dev *,
 				   struct btmtk_hci_wmt_params *);
 
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2025-09-05  8:59 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-27  5:59 [PATCH v5 0/2] Bluetooth: mediatek: add gpio pin to reset bt Zhangchao Zhang
2025-06-27  5:59 ` [PATCH v5 1/2] " Zhangchao Zhang
2025-06-27  6:42   ` bluez.test.bot
2025-06-27  5:59 ` [PATCH v5 2/2] dt-bindings: net: mediatek,mt7925-bluetooth.yaml Zhangchao Zhang
2025-06-28 12:03   ` Krzysztof Kozlowski
2025-06-28 12:03 ` [PATCH v5 0/2] Bluetooth: mediatek: add gpio pin to reset bt Krzysztof Kozlowski
  -- strict thread matches above, loose matches on Subject: below --
2025-09-05  8:40 [PATCH v7 1/1] " Zhangchao Zhang
2025-09-05  8:59 ` bluez.test.bot
2025-07-08  6:01 [PATCH v6 1/1] " Zhangchao Zhang
2025-07-08  6:42 ` bluez.test.bot
2025-06-23 10:23 [PATCH v4 1/1] " Zhangchao Zhang
2025-06-23 11:06 ` bluez.test.bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox