diff mbox series

[3/3] Bluetooth: btusb: Expose reset gpio to debugfs

Message ID 20210119124258.3.I7c6ae9b637f9a77f6e6f2e4256c6a0232476be43@changeid (mailing list archive)
State New, archived
Headers show
Series Bluetooth: btusb: Expose hw reset to debugfs | expand

Commit Message

Abhishek Pandit-Subedi Jan. 19, 2021, 8:43 p.m. UTC
If btusb has a reset gpio, expose it to userspace so we can toggle the
reset gpio directly. This is useful for testing and error recovery.

Signed-off-by: Abhishek Pandit-Subedi <abhishekpandit@chromium.org>
Reviewed-by: Miao-chen Chou <mcchou@chromium.org>
---

 drivers/bluetooth/btusb.c | 46 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

Comments

Marcel Holtmann Jan. 25, 2021, 5:51 p.m. UTC | #1
Hi Abhishek,

> If btusb has a reset gpio, expose it to userspace so we can toggle the
> reset gpio directly. This is useful for testing and error recovery.
> 
> Signed-off-by: Abhishek Pandit-Subedi <abhishekpandit@chromium.org>
> Reviewed-by: Miao-chen Chou <mcchou@chromium.org>
> ---
> 
> drivers/bluetooth/btusb.c | 46 +++++++++++++++++++++++++++++++++++++++
> 1 file changed, 46 insertions(+)
> 
> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> index 880e9cd4ee713..702be1871ed88 100644
> --- a/drivers/bluetooth/btusb.c
> +++ b/drivers/bluetooth/btusb.c
> @@ -6,6 +6,7 @@
>  *  Copyright (C) 2005-2008  Marcel Holtmann <marcel@holtmann.org>
>  */
> 
> +#include <linux/debugfs.h>
> #include <linux/dmi.h>
> #include <linux/module.h>
> #include <linux/usb.h>
> @@ -574,6 +575,46 @@ static void btusb_toggle_gpio(struct gpio_desc *desc, unsigned int duration)
> 	gpiod_set_value_cansleep(desc, 0);
> }
> 
> +#ifdef CONFIG_DEBUG_FS
> +static ssize_t btusb_debugfs_has_reset_gpio(struct file *file,
> +					    char __user *user_buf,
> +					    size_t count, loff_t *ppos)
> +{
> +	struct hci_dev *hdev = file->private_data;
> +	struct btusb_data *data = hci_get_drvdata(hdev);
> +	char buf[3];
> +
> +	buf[0] = data->reset_gpio ? 'Y' : 'N';
> +	buf[1] = '\n';
> +	buf[2] = '\0';
> +
> +	return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
> +}
> +
> +static ssize_t btusb_debugfs_reset_gpio(struct file *file,
> +					const char __user *user_buf,
> +					size_t count, loff_t *ppos)
> +{
> +	struct hci_dev *hdev = file->private_data;
> +	struct btusb_data *data = hci_get_drvdata(hdev);
> +
> +	if (!data->reset_gpio)
> +		return -EOPNOTSUPP;
> +
> +	bt_dev_warn(hdev, "Debugfs triggering HW reset via gpio");
> +	btusb_toggle_gpio(data->reset_gpio, data->reset_duration_ms);
> +
> +	return count;
> +}
> +
> +static const struct file_operations reset_gpio_fops = {
> +	.open		= simple_open,
> +	.read		= btusb_debugfs_has_reset_gpio,
> +	.write		= btusb_debugfs_reset_gpio,
> +	.llseek		= default_llseek,
> +};
> +#endif

while I am not convinced that this is the right way, I am fine doing it temporarily. However, please lets create the debugfs file only when a reset GPIO is available and skip the read callback. Only the write one should be supported since there is no point to read the status. The pure existence of the debugfs should indicate support for a HW reset.

Regards

Marcel
diff mbox series

Patch

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 880e9cd4ee713..702be1871ed88 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -6,6 +6,7 @@ 
  *  Copyright (C) 2005-2008  Marcel Holtmann <marcel@holtmann.org>
  */
 
+#include <linux/debugfs.h>
 #include <linux/dmi.h>
 #include <linux/module.h>
 #include <linux/usb.h>
@@ -574,6 +575,46 @@  static void btusb_toggle_gpio(struct gpio_desc *desc, unsigned int duration)
 	gpiod_set_value_cansleep(desc, 0);
 }
 
+#ifdef CONFIG_DEBUG_FS
+static ssize_t btusb_debugfs_has_reset_gpio(struct file *file,
+					    char __user *user_buf,
+					    size_t count, loff_t *ppos)
+{
+	struct hci_dev *hdev = file->private_data;
+	struct btusb_data *data = hci_get_drvdata(hdev);
+	char buf[3];
+
+	buf[0] = data->reset_gpio ? 'Y' : 'N';
+	buf[1] = '\n';
+	buf[2] = '\0';
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t btusb_debugfs_reset_gpio(struct file *file,
+					const char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct hci_dev *hdev = file->private_data;
+	struct btusb_data *data = hci_get_drvdata(hdev);
+
+	if (!data->reset_gpio)
+		return -EOPNOTSUPP;
+
+	bt_dev_warn(hdev, "Debugfs triggering HW reset via gpio");
+	btusb_toggle_gpio(data->reset_gpio, data->reset_duration_ms);
+
+	return count;
+}
+
+static const struct file_operations reset_gpio_fops = {
+	.open		= simple_open,
+	.read		= btusb_debugfs_has_reset_gpio,
+	.write		= btusb_debugfs_reset_gpio,
+	.llseek		= default_llseek,
+};
+#endif
+
 static void btusb_gpio_cmd_timeout(struct hci_dev *hdev)
 {
 	struct btusb_data *data = hci_get_drvdata(hdev);
@@ -4625,6 +4666,11 @@  static int btusb_probe(struct usb_interface *intf,
 	if (err < 0)
 		goto out_free_dev;
 
+#ifdef CONFIG_DEBUG_FS
+	debugfs_create_file("toggle_hw_reset", 0644, hdev->debugfs, hdev,
+			    &reset_gpio_fops);
+#endif
+
 	usb_set_intfdata(intf, data);
 
 	return 0;