* [PATCH v4 0/3] Enable Bluetooth functionality for WCN3990. @ 2018-05-04 15:35 Balakrishna Godavarthi 2018-05-04 15:35 ` [PATCH v4 1/3] dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990 Balakrishna Godavarthi ` (2 more replies) 0 siblings, 3 replies; 15+ messages in thread From: Balakrishna Godavarthi @ 2018-05-04 15:35 UTC (permalink / raw) To: marcel, johan.hedberg Cc: linux-bluetooth, rtatiya, hemantg, linux-arm-msm, Balakrishna Godavarthi These patches enable Bluetooth functionality for WCN3990 by - adding support for voting of voltage regulators for WCN3990 attached to MSM - Bluetooth firmware download support for WCN3990 - description of device tree bindings v4: * rebased all changes on top of bluetooth-next. * addressed review comments. * New patch created for firmware download. v3: * Rebased all changes on top of bluetooth-next. * dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990 - added dt-binding snippet for bluetooth chip wcn3990. * Bluetooth: Add support for wcn3990 soc. - updated BT_INFO with bt_dev_info, where ever necessary. v2: * Add support for wcn3990: These changes are aligned as per serdev frame work. We implemented these changes on top of https://patchwork.kernel.org/patch/10316093/ As this patch enable serdev for one of the Qualcomm BT chip. The changes in the patch include. - Adding support to voting up/down regulators for WCN3990. - Bluetooth firmware download for wcn3990. * Add device tree bindings for Atheros chips: These changes are on top of https://patchwork.kernel.org/patch/10316097/. - Description of device tree bindings. Balakrishna Godavarthi (3): dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990 Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990. Bluetooth: btqca: Add wcn3990 firmware download support. .../devicetree/bindings/net/qualcomm-bluetooth.txt | 31 +- drivers/bluetooth/btqca.c | 45 +- drivers/bluetooth/btqca.h | 19 + drivers/bluetooth/hci_qca.c | 555 ++++++++++++++++++--- 4 files changed, 575 insertions(+), 75 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v4 1/3] dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990 2018-05-04 15:35 [PATCH v4 0/3] Enable Bluetooth functionality for WCN3990 Balakrishna Godavarthi @ 2018-05-04 15:35 ` Balakrishna Godavarthi 2018-05-04 15:35 ` [PATCH v4 2/3] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth " Balakrishna Godavarthi 2018-05-04 15:35 ` [PATCH v4 3/3] Bluetooth: btqca: Add wcn3990 firmware download support Balakrishna Godavarthi 2 siblings, 0 replies; 15+ messages in thread From: Balakrishna Godavarthi @ 2018-05-04 15:35 UTC (permalink / raw) To: marcel, johan.hedberg Cc: linux-bluetooth, rtatiya, hemantg, linux-arm-msm, Balakrishna Godavarthi Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org> --- .../devicetree/bindings/net/qualcomm-bluetooth.txt | 31 ++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt b/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt index 0ea18a5..63cae49 100644 --- a/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt +++ b/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt @@ -10,12 +10,24 @@ device the slave device is attached to. Required properties: - compatible: should contain one of the following: * "qcom,qca6174-bt" + * "qcom,wcn3990-bt" Optional properties: - enable-gpios: gpio specifier used to enable chip - clocks: clock provided to the controller (SUSCLK_32KHZ) - -Example: + - vddpa-supply: Bluetooth VDD PA regulator handle + - vddio-supply: Bluetooth VDD IO regulator handle + - vddldo-supply: Bluetooth VDD LDO regulator handle. Kept under optional + parameters as some of the chipsets doesn't require ldo or + it may use from same vddio. + - vddxtal-supply: Bluetooth VDD XTAL regulator handle + - vddcore-supply: Bluetooth VDD CORE regulator handle + - vddpwd-supply: Chip power down gpio is required when bluetooth module + and other modules like wifi co-exist in a singe chip and + shares a common gpio to bring chip out of reset. + - oper-speed: operating speed of the chip. + +Examples: serial@7570000 { label = "BT-UART"; @@ -28,3 +40,18 @@ serial@7570000 { clocks = <&divclk4>; }; }; + +serial@898000 { + label = "BT-UART"; + status = "okay"; + + bluetooth: bt_wcn3990 { + compatible = "qcom,wcn3990-bt"; + vddio-supply = <&pm8998_s3>; + vddxtal-supply = <&pm8998_s5>; + vddcore-supply = <&pm8998_l7>; + vddpa-supply = <&pm8998_l17>; + vddldo-supply = <&pm8998_l25>; + oper-speed = <3200000>; + }; +}; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 2/3] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990. 2018-05-04 15:35 [PATCH v4 0/3] Enable Bluetooth functionality for WCN3990 Balakrishna Godavarthi 2018-05-04 15:35 ` [PATCH v4 1/3] dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990 Balakrishna Godavarthi @ 2018-05-04 15:35 ` Balakrishna Godavarthi 2018-05-05 1:17 ` Matthias Kaehlcke ` (3 more replies) 2018-05-04 15:35 ` [PATCH v4 3/3] Bluetooth: btqca: Add wcn3990 firmware download support Balakrishna Godavarthi 2 siblings, 4 replies; 15+ messages in thread From: Balakrishna Godavarthi @ 2018-05-04 15:35 UTC (permalink / raw) To: marcel, johan.hedberg Cc: linux-bluetooth, rtatiya, hemantg, linux-arm-msm, Balakrishna Godavarthi Add support to set voltage/current of various regulators to power up/down Bluetooth chip wcn3990. Add support to read baudrate from dts. Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org> --- drivers/bluetooth/hci_qca.c | 555 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 483 insertions(+), 72 deletions(-) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index f05382b..075fab7 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -5,7 +5,7 @@ * protocol extension to H4. * * Copyright (C) 2007 Texas Instruments, Inc. - * Copyright (c) 2010, 2012 The Linux Foundation. All rights reserved. + * Copyright (c) 2010, 2012, 2018 The Linux Foundation. All rights reserved. * * Acknowledgements: * This file is based on hci_ll.c, which was... @@ -35,6 +35,10 @@ #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/serdev.h> +#include <asm-generic/delay.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/of_device.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> @@ -119,12 +123,51 @@ struct qca_data { u64 votes_off; }; +enum btqca_soc_t { + BTQCA_INVALID = -1, + BTQCA_AR3002, + BTQCA_ROME, + BTQCA_CHEROKEE +}; + struct qca_serdev { struct hci_uart serdev_hu; struct gpio_desc *bt_en; struct clk *susclk; + enum btqca_soc_t btsoc_type; + u32 init_speed; + u32 oper_speed; +}; + +/* + * voltage regulator information required for configuring the + * QCA bluetooth chipset + */ +struct btqca_vreg { + const char *name; + unsigned int min_v; + unsigned int max_v; + unsigned int load_ua; +}; + +struct btqca_vreg_data { + enum btqca_soc_t soc_type; + struct btqca_vreg *vregs; + size_t num_vregs; }; +/* + * Platform data for the QCA bluetooth power driver. + */ +struct btqca_power { + struct device *dev; + const struct btqca_vreg_data *vreg_data; + struct regulator_bulk_data *vreg_bulk; + bool vreg_status; +}; + +static struct btqca_power *qca; + static void __serial_clock_on(struct tty_struct *tty) { /* TODO: Some chipset requires to enable UART clock on client @@ -463,7 +506,12 @@ static int qca_open(struct hci_uart *hu) serdev_device_open(hu->serdev); qcadev = serdev_device_get_drvdata(hu->serdev); - gpiod_set_value_cansleep(qcadev->bt_en, 1); + if (qcadev->btsoc_type == BTQCA_CHEROKEE) { + hu->init_speed = qcadev->init_speed; + hu->oper_speed = qcadev->oper_speed; + btqca_power_setup(true); + } else + gpiod_set_value_cansleep(qcadev->bt_en, 1); } BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u", @@ -552,7 +600,10 @@ static int qca_close(struct hci_uart *hu) serdev_device_close(hu->serdev); qcadev = serdev_device_get_drvdata(hu->serdev); - gpiod_set_value_cansleep(qcadev->bt_en, 0); + if (qcadev->btsoc_type == BTQCA_CHEROKEE) + qca_btsoc_cleanup(hu->hdev); + else + gpiod_set_value_cansleep(qcadev->bt_en, 0); } kfree_skb(qca->rx_skb); @@ -872,6 +923,8 @@ static uint8_t qca_get_baudrate_value(int speed) return QCA_BAUDRATE_2000000; case 3000000: return QCA_BAUDRATE_3000000; + case 3200000: + return QCA_BAUDRATE_3200000; case 3500000: return QCA_BAUDRATE_3500000; default: @@ -886,7 +939,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate) struct sk_buff *skb; u8 cmd[] = { 0x01, 0x48, 0xFC, 0x01, 0x00 }; - if (baudrate > QCA_BAUDRATE_3000000) + if (baudrate > QCA_BAUDRATE_3200000) return -EINVAL; cmd[4] = baudrate; @@ -923,68 +976,292 @@ static inline void host_set_baudrate(struct hci_uart *hu, unsigned int speed) hci_uart_set_baudrate(hu, speed); } +static int qca_send_poweron_cmd(struct hci_dev *hdev) +{ + struct hci_uart *hu = hci_get_drvdata(hdev); + struct qca_data *qca = hu->priv; + struct sk_buff *skb; + u8 cmd; + + BT_DBG("%s sending power on command to btsoc", hdev->name); + /* By sending 0xFC host is trying to power up the soc */ + cmd = CHEROKEE_POWERON_PULSE; + skb = bt_skb_alloc(sizeof(cmd), GFP_ATOMIC); + if (!skb) { + BT_ERR("Failed to allocate memory for skb packet"); + return -ENOMEM; + } + + skb_put_data(skb, &cmd, sizeof(cmd)); + hci_skb_pkt_type(skb) = HCI_COMMAND_PKT; + + skb_queue_tail(&qca->txq, skb); + hci_uart_tx_wakeup(hu); + + /* Wait for 100 us for soc to settle down */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(usecs_to_jiffies(100)); + set_current_state(TASK_INTERRUPTIBLE); + + return 0; +} + +static int qca_send_poweroff_cmd(struct hci_dev *hdev) +{ + struct hci_uart *hu = hci_get_drvdata(hdev); + struct qca_data *qca = hu->priv; + struct sk_buff *skb; + u8 cmd; + + BT_DBG("%s sending power off command to btsoc", hdev->name); + /* By sending 0xC0 host is trying to power off the soc */ + cmd = CHEROKEE_POWEROFF_PULSE; + skb = bt_skb_alloc(sizeof(cmd), GFP_ATOMIC); + if (!skb) { + BT_ERR("Failed to allocate memory for skb packet"); + return -ENOMEM; + } + + skb_put_data(skb, &cmd, sizeof(cmd)); + hci_skb_pkt_type(skb) = HCI_COMMAND_PKT; + + skb_queue_tail(&qca->txq, skb); + hci_uart_tx_wakeup(hu); + + /* Wait for 100 us for soc to settle down */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(usecs_to_jiffies(100)); + set_current_state(TASK_INTERRUPTIBLE); + + return 0; +} + +static int qca_serdev_open(struct hci_uart *hu) +{ + int ret = 0; + + if (hu->serdev) + serdev_device_open(hu->serdev); + else { + bt_dev_err(hu->hdev, "open operation not supported"); + ret = 1; + } + + return ret; +} + +int qca_btsoc_cleanup(struct hci_dev *hdev) +{ + struct hci_uart *hu = hci_get_drvdata(hdev); + + /* change host baud rate before sending power off command */ + host_set_baudrate(hu, 2400); + /* send 0xC0 command to btsoc before turning off regulators */ + qca_send_poweroff_cmd(hdev); + /* turn off btsoc */ + return btqca_power_setup(false); +} + +static int qca_serdev_close(struct hci_uart *hu) +{ + int ret = 0; + + if (hu->serdev) + serdev_device_close(hu->serdev); + else { + bt_dev_err(hu->hdev, "close operation not supported"); + ret = 1; + } + + return ret; +} static int qca_setup(struct hci_uart *hu) { struct hci_dev *hdev = hu->hdev; struct qca_data *qca = hu->priv; + struct qca_serdev *qcadev; unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200; int ret; + int soc_ver; + + qcadev = serdev_device_get_drvdata(hu->serdev); + + switch (qcadev->btsoc_type) { + case BTQCA_CHEROKEE: + bt_dev_info(hdev, "setting up wcn3990"); + /* Patch downloading has to be done without IBS mode */ + clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); + /* Setup initial baudrate */ + speed = 0; + if (hu->init_speed) + speed = hu->init_speed; + else if (hu->proto->init_speed) + speed = hu->proto->init_speed; + + if (speed) + host_set_baudrate(hu, speed); + else { + bt_dev_err(hdev, "initial speed %u", speed); + return -1; + } - bt_dev_info(hdev, "ROME setup"); + /* disable flow control, as chip is still not turned on */ + hci_uart_set_flow_control(hu, true); + /* send poweron command to btsoc */ + ret = qca_send_poweron_cmd(hdev); + if (ret) { + bt_dev_err(hdev, "Failed to send power on command"); + return ret; + } - /* Patch downloading has to be done without IBS mode */ - clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); + /* close serial port */ + ret = qca_serdev_close(hu); + if (ret) + return ret; + /* open serial port */ + ret = qca_serdev_open(hu); + if (ret) + return ret; - /* Setup initial baudrate */ - speed = 0; - if (hu->init_speed) - speed = hu->init_speed; - else if (hu->proto->init_speed) - speed = hu->proto->init_speed; + /* Setup initial baudrate */ + speed = 0; + if (hu->init_speed) + speed = hu->init_speed; + else if (hu->proto->init_speed) + speed = hu->proto->init_speed; + if (speed) + host_set_baudrate(hu, speed); + else { + BT_ERR("%s:initial speed %u", hdev->name, speed); + return -1; + } - if (speed) - host_set_baudrate(hu, speed); + /* Enable flow control */ + hci_uart_set_flow_control(hu, false); + /* wait until flow control settled */ + mdelay(100); + bt_dev_info(hdev, "wcn3990 Patch Version Request"); + ret = rome_patch_ver_req(hdev, &soc_ver); + if (ret < 0 || soc_ver == 0) { + BT_ERR("%s: Failed to get version 0x%x", hdev->name, + ret); + return ret; + } - /* Setup user speed if needed */ - speed = 0; - if (hu->oper_speed) - speed = hu->oper_speed; - else if (hu->proto->oper_speed) - speed = hu->proto->oper_speed; + bt_dev_info(hdev, "wcn3990 controller version 0x%08x", soc_ver); + + /* clear flow control */ + hci_uart_set_flow_control(hu, true); + /* set operating speed */ + speed = 0; + if (hu->oper_speed) + speed = hu->oper_speed; + else if (hu->proto->oper_speed) + speed = hu->proto->oper_speed; + if (speed) { + qca_baudrate = qca_get_baudrate_value(speed); + bt_dev_info(hdev, "Set UART speed to %d", speed); + ret = qca_set_baudrate(hdev, qca_baudrate); + if (ret) { + BT_ERR("%s:Failed to change the baud rate(%d)", + hdev->name, ret); + return ret; + } + if (speed) + host_set_baudrate(hu, speed); + else { + BT_ERR("%s:Error in setting operator speed:%u", + hdev->name, speed); + return -1; + } + } - if (speed) { - qca_baudrate = qca_get_baudrate_value(speed); + /* Set flow control */ + hci_uart_set_flow_control(hu, false); + /*Setup patch and NVM configurations */ + ret = qca_uart_setup_cherokee(hdev, qca_baudrate, &soc_ver); + if (!ret) { + set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); + qca_debugfs_init(hdev); + } else if (ret == -ENOENT) { + /* No patch/nvm-config found, run with original + * fw/config. + */ + ret = 0; + } else if (ret == -EAGAIN) { + /* + * Userspace firmware loader will return -EAGAIN in + * case no patch/nvm-config is found, so run with + * original fw/config. + */ + ret = 0; + } - bt_dev_info(hdev, "Set UART speed to %d", speed); - ret = qca_set_baudrate(hdev, qca_baudrate); - if (ret) { - bt_dev_err(hdev, "Failed to change the baud rate (%d)", - ret); + /* Setup wcn3990 bdaddr */ + hu->hdev->set_bdaddr = qca_set_bdaddr_rome; + + return ret; + + default: + bt_dev_info(hdev, "ROME setup"); + + /* Patch downloading has to be done without IBS mode */ + clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); + + /* Setup initial baudrate */ + speed = 0; + if (hu->init_speed) + speed = hu->init_speed; + else if (hu->proto->init_speed) + speed = hu->proto->init_speed; + + if (speed) + host_set_baudrate(hu, speed); + + /* Setup user speed if needed */ + speed = 0; + if (hu->oper_speed) + speed = hu->oper_speed; + else if (hu->proto->oper_speed) + speed = hu->proto->oper_speed; + + if (speed) { + qca_baudrate = qca_get_baudrate_value(speed); + + bt_dev_info(hdev, "Set UART speed to %d", speed); + ret = qca_set_baudrate(hdev, qca_baudrate); + if (ret) { + bt_dev_err(hdev, "Failed to change the baud rate (%d)", + ret); return ret; + } + host_set_baudrate(hu, speed); } - host_set_baudrate(hu, speed); - } - /* Setup patch / NVM configurations */ - ret = qca_uart_setup_rome(hdev, qca_baudrate); - if (!ret) { - set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); - qca_debugfs_init(hdev); - } else if (ret == -ENOENT) { - /* No patch/nvm-config found, run with original fw/config */ - ret = 0; - } else if (ret == -EAGAIN) { - /* - * Userspace firmware loader will return -EAGAIN in case no - * patch/nvm-config is found, so run with original fw/config. - */ - ret = 0; - } + /* Setup patch / NVM configurations */ + ret = qca_uart_setup_rome(hdev, qca_baudrate); + if (!ret) { + set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); + qca_debugfs_init(hdev); + } else if (ret == -ENOENT) { + /* No patch/nvm-config found, run with original + * fw/config + */ + ret = 0; + } else if (ret == -EAGAIN) { + /* + * Userspace firmware loader will return -EAGAIN in + * case no patch/nvm-config is found, so run with + * original fw/config. + */ + ret = 0; + } - /* Setup bdaddr */ - hu->hdev->set_bdaddr = qca_set_bdaddr_rome; + /* Setup bdaddr */ + hu->hdev->set_bdaddr = qca_set_bdaddr_rome; - return ret; + return ret; + } } static struct hci_uart_proto qca_proto = { @@ -1002,44 +1279,174 @@ static int qca_setup(struct hci_uart *hu) .dequeue = qca_dequeue, }; +static const struct btqca_vreg_data cherokee_data = { + .soc_type = BTQCA_CHEROKEE, + .vregs = (struct btqca_vreg []) { + { "vddio", 1352000, 1352000, 0 }, + { "vddxtal", 1904000, 2040000, 0 }, + { "vddcore", 1800000, 1800000, 1 }, + { "vddpa", 130400, 1304000, 1 }, + { "vddldo", 3000000, 3312000, 1 }, + }, + .num_vregs = 5, +}; + +void btqca_disable_regulators(int reg_nu, struct btqca_vreg *vregs) +{ + /* disable the regulator if requested by user + * or when fault in any regulator. + */ + for (reg_nu = reg_nu - 1; reg_nu >= 0 ; reg_nu--) { + regulator_disable(qca->vreg_bulk[reg_nu].consumer); + regulator_set_voltage(qca->vreg_bulk[reg_nu].consumer, 0, + vregs[reg_nu].max_v); + if (vregs[reg_nu].load_ua) + regulator_set_load(qca->vreg_bulk[reg_nu].consumer, 0); + } +} + +int btqca_power_setup(bool on) +{ + int ret = 0; + int i; + struct btqca_vreg *vregs; + + if (!qca || !qca->vreg_data || !qca->vreg_bulk) + return -EINVAL; + vregs = qca->vreg_data->vregs; + + BT_DBG("on: %d", on); + /* turn on if regualtors are off */ + if (on == true && qca->vreg_status == false) { + qca->vreg_status = true; + for (i = 0; ret == 0 && i < qca->vreg_data->num_vregs; i++) { + regulator_set_voltage(qca->vreg_bulk[i].consumer, + vregs[i].min_v, + vregs[i].max_v); + + if (vregs[i].load_ua) + regulator_set_load(qca->vreg_bulk[i].consumer, + vregs[i].load_ua); + + ret = regulator_enable(qca->vreg_bulk[i].consumer); + } + } else if (on == false && qca->vreg_status == true) { + qca->vreg_status = false; + /* turn of regualtor in reverse order */ + btqca_disable_regulators(qca->vreg_data->num_vregs, vregs); + } + + /* regulatos fails to enable */ + if (ret) { + qca->vreg_status = false; + BT_ERR("failed to enable regualtor:%s", vregs[i].name); + /* set regulator voltage and load to zero */ + regulator_set_voltage(qca->vreg_bulk[i].consumer, + 0, vregs[i].max_v); + if (vregs[i].load_ua) + regulator_set_load(qca->vreg_bulk[i].consumer, 0); + /* turn off regulators which are enabled */ + btqca_disable_regulators(i+1, vregs); + } + + return ret; +} + +static int init_regulators(struct btqca_power *qca, + const struct btqca_vreg *vregs, + size_t num_vregs) +{ + int i; + + qca->vreg_bulk = devm_kzalloc(qca->dev, num_vregs * + sizeof(struct regulator_bulk_data), + GFP_KERNEL); + if (!qca->vreg_bulk) + return -ENOMEM; + + for (i = 0; i < num_vregs; i++) + qca->vreg_bulk[i].supply = vregs[i].name; + + return devm_regulator_bulk_get(qca->dev, num_vregs, qca->vreg_bulk); +} + static int qca_serdev_probe(struct serdev_device *serdev) { struct qca_serdev *qcadev; - int err; + const struct btqca_vreg_data *data; + int err = 0; qcadev = devm_kzalloc(&serdev->dev, sizeof(*qcadev), GFP_KERNEL); if (!qcadev) return -ENOMEM; qcadev->serdev_hu.serdev = serdev; + data = of_device_get_match_data(&serdev->dev); + if (data && data->soc_type == BTQCA_CHEROKEE) + qcadev->btsoc_type = BTQCA_CHEROKEE; + else + qcadev->btsoc_type = BTQCA_ROME; + serdev_device_set_drvdata(serdev, qcadev); + if (qcadev->btsoc_type == BTQCA_CHEROKEE) { + qca = kzalloc(sizeof(struct btqca_power), GFP_KERNEL); + if (!qca) + return -ENOMEM; + + qca->dev = &serdev->dev; + qca->vreg_data = data; + err = init_regulators(qca, data->vregs, data->num_vregs); + if (err) { + BT_ERR("Failed to init regualtors:%d", err); + kfree(qca); + goto out; + } - qcadev->bt_en = devm_gpiod_get(&serdev->dev, "enable", - GPIOD_OUT_LOW); - if (IS_ERR(qcadev->bt_en)) { - dev_err(&serdev->dev, "failed to acquire enable gpio\n"); - return PTR_ERR(qcadev->bt_en); - } + /* set voltage regulator status as false */ + qca->vreg_status = false; + /* get operating speed */ + device_property_read_u32(&serdev->dev, "oper-speed", + &qcadev->oper_speed); + device_property_read_u32(&serdev->dev, "init-speed", + &qcadev->init_speed); + if (!qcadev->oper_speed) + BT_INFO("DTS entry for operating speed is disabled"); + err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto); + if (err) { + BT_ERR("wcn3990 serdev registration failed"); + kfree(qca); + goto out; + } - qcadev->susclk = devm_clk_get(&serdev->dev, NULL); - if (IS_ERR(qcadev->susclk)) { - dev_err(&serdev->dev, "failed to acquire clk\n"); - return PTR_ERR(qcadev->susclk); - } + } else { + qcadev->bt_en = devm_gpiod_get(&serdev->dev, "enable", + GPIOD_OUT_LOW); + if (IS_ERR(qcadev->bt_en)) { + dev_err(&serdev->dev, "failed to acquire enable gpio\n"); + return PTR_ERR(qcadev->bt_en); + } - err = clk_set_rate(qcadev->susclk, SUSCLK_RATE_32KHZ); - if (err) - return err; + qcadev->susclk = devm_clk_get(&serdev->dev, NULL); + if (IS_ERR(qcadev->susclk)) { + dev_err(&serdev->dev, "failed to acquire clk\n"); + return PTR_ERR(qcadev->susclk); + } - err = clk_prepare_enable(qcadev->susclk); - if (err) - return err; + err = clk_set_rate(qcadev->susclk, SUSCLK_RATE_32KHZ); + if (err) + return err; - err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto); - if (err) - clk_disable_unprepare(qcadev->susclk); + err = clk_prepare_enable(qcadev->susclk); + if (err) + return err; + + err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto); + if (err) + clk_disable_unprepare(qcadev->susclk); + } + +out: return err; - return err; } static void qca_serdev_remove(struct serdev_device *serdev) @@ -1047,12 +1454,16 @@ static void qca_serdev_remove(struct serdev_device *serdev) struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev); hci_uart_unregister_device(&qcadev->serdev_hu); - - clk_disable_unprepare(qcadev->susclk); + if (qcadev->btsoc_type == BTQCA_CHEROKEE) { + btqca_power_setup(false); + kfree(qca); + } else + clk_disable_unprepare(qcadev->susclk); } static const struct of_device_id qca_bluetooth_of_match[] = { { .compatible = "qcom,qca6174-bt" }, + { .compatible = "qcom,wcn3990-bt", .data = &cherokee_data}, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v4 2/3] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990. 2018-05-04 15:35 ` [PATCH v4 2/3] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth " Balakrishna Godavarthi @ 2018-05-05 1:17 ` Matthias Kaehlcke 2018-05-09 8:56 ` Balakrishna Godavarthi ` (2 more replies) 2018-05-05 19:21 ` kbuild test robot ` (2 subsequent siblings) 3 siblings, 3 replies; 15+ messages in thread From: Matthias Kaehlcke @ 2018-05-05 1:17 UTC (permalink / raw) To: Balakrishna Godavarthi Cc: marcel, johan.hedberg, linux-bluetooth, rtatiya, hemantg, linux-arm-msm Hi, On Fri, May 04, 2018 at 09:05:05PM +0530, Balakrishna Godavarthi wrote: > Add support to set voltage/current of various regulators > to power up/down Bluetooth chip wcn3990. > Add support to read baudrate from dts. > > Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org> > --- > drivers/bluetooth/hci_qca.c | 555 ++++++++++++++++++++++++++++++++++++++------ > 1 file changed, 483 insertions(+), 72 deletions(-) > > diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c > index f05382b..075fab7 100644 > --- a/drivers/bluetooth/hci_qca.c > +++ b/drivers/bluetooth/hci_qca.c > @@ -5,7 +5,7 @@ > * protocol extension to H4. > * > * Copyright (C) 2007 Texas Instruments, Inc. > - * Copyright (c) 2010, 2012 The Linux Foundation. All rights reserved. > + * Copyright (c) 2010, 2012, 2018 The Linux Foundation. All rights reserved. > * > * Acknowledgements: > * This file is based on hci_ll.c, which was... > @@ -35,6 +35,10 @@ > #include <linux/mod_devicetable.h> > #include <linux/module.h> > #include <linux/serdev.h> > +#include <asm-generic/delay.h> > +#include <linux/platform_device.h> > +#include <linux/regulator/consumer.h> > +#include <linux/of_device.h> AFAIK the convention is to order includes alphabetically. > +static struct btqca_power *qca; This limits the driver to a single instance. This is probably the most common use case, but in general it's preferable not to have this kind of limitations. > static void __serial_clock_on(struct tty_struct *tty) > { > /* TODO: Some chipset requires to enable UART clock on client > @@ -463,7 +506,12 @@ static int qca_open(struct hci_uart *hu) > serdev_device_open(hu->serdev); > > qcadev = serdev_device_get_drvdata(hu->serdev); > - gpiod_set_value_cansleep(qcadev->bt_en, 1); > + if (qcadev->btsoc_type == BTQCA_CHEROKEE) { > + hu->init_speed = qcadev->init_speed; > + hu->oper_speed = qcadev->oper_speed; > + btqca_power_setup(true); > + } else > + gpiod_set_value_cansleep(qcadev->bt_en, 1); Use curly braces for the else branch too. > +static int qca_send_poweron_cmd(struct hci_dev *hdev) > +{ > + struct hci_uart *hu = hci_get_drvdata(hdev); > + struct qca_data *qca = hu->priv; > + struct sk_buff *skb; > + u8 cmd; > + > + BT_DBG("%s sending power on command to btsoc", hdev->name); Use bt_dev_dbg(), same for other BT_XXX(). > + /* By sending 0xFC host is trying to power up the soc */ nit: SoC, same a few lines below. > + cmd = CHEROKEE_POWERON_PULSE; > + skb = bt_skb_alloc(sizeof(cmd), GFP_ATOMIC); Use GFP_KERNEL, the code sleeps a few lines below, hence it must definitely not be called in atomic context. > + if (!skb) { > + BT_ERR("Failed to allocate memory for skb packet"); > + return -ENOMEM; > + } > + > + skb_put_data(skb, &cmd, sizeof(cmd)); > + hci_skb_pkt_type(skb) = HCI_COMMAND_PKT; > + > + skb_queue_tail(&qca->txq, skb); > + hci_uart_tx_wakeup(hu); > + > + /* Wait for 100 us for soc to settle down */ > + set_current_state(TASK_UNINTERRUPTIBLE); > + schedule_timeout(usecs_to_jiffies(100)); > + set_current_state(TASK_INTERRUPTIBLE); > + > + return 0; > +} > + > +static int qca_send_poweroff_cmd(struct hci_dev *hdev) > +{ > + struct hci_uart *hu = hci_get_drvdata(hdev); > + struct qca_data *qca = hu->priv; > + struct sk_buff *skb; > + u8 cmd; > + > + BT_DBG("%s sending power off command to btsoc", hdev->name); > + /* By sending 0xC0 host is trying to power off the soc */ > + cmd = CHEROKEE_POWEROFF_PULSE; > + skb = bt_skb_alloc(sizeof(cmd), GFP_ATOMIC); > + if (!skb) { > + BT_ERR("Failed to allocate memory for skb packet"); > + return -ENOMEM; > + } > + > + skb_put_data(skb, &cmd, sizeof(cmd)); > + hci_skb_pkt_type(skb) = HCI_COMMAND_PKT; > + > + skb_queue_tail(&qca->txq, skb); > + hci_uart_tx_wakeup(hu); > + > + /* Wait for 100 us for soc to settle down */ > + set_current_state(TASK_UNINTERRUPTIBLE); > + schedule_timeout(usecs_to_jiffies(100)); > + set_current_state(TASK_INTERRUPTIBLE); > + > + return 0; > +} This function is almost a clone of qca_send_poweron_cmd(), move the common code to something like qca_send_cmd() and call it from qca_send_poweron/off_cmd(). > +static int qca_serdev_open(struct hci_uart *hu) > +{ > + int ret = 0; > + > + if (hu->serdev) > + serdev_device_open(hu->serdev); Check return value. Add curly braces to the if branch too. > +static int qca_serdev_close(struct hci_uart *hu) > +{ > + int ret = 0; > + > + if (hu->serdev) > + serdev_device_close(hu->serdev); Add curly braces to the if branch too. > static int qca_setup(struct hci_uart *hu) > { > struct hci_dev *hdev = hu->hdev; > struct qca_data *qca = hu->priv; > + struct qca_serdev *qcadev; > unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200; > int ret; > + int soc_ver; > + > + qcadev = serdev_device_get_drvdata(hu->serdev); > + > + switch (qcadev->btsoc_type) { > + case BTQCA_CHEROKEE: > + bt_dev_info(hdev, "setting up wcn3990"); > + /* Patch downloading has to be done without IBS mode */ > + clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); > + /* Setup initial baudrate */ > + speed = 0; > + if (hu->init_speed) > + speed = hu->init_speed; > + else if (hu->proto->init_speed) > + speed = hu->proto->init_speed; > + > + if (speed) > + host_set_baudrate(hu, speed); Add curly braces. > + else { > + bt_dev_err(hdev, "initial speed %u", speed); > + return -1; > + } > > - bt_dev_info(hdev, "ROME setup"); > + /* disable flow control, as chip is still not turned on */ > + hci_uart_set_flow_control(hu, true); The interface of this function is confusing. enable = true disables flow control ... Not the fault of this driver though :) > + /* send poweron command to btsoc */ > + ret = qca_send_poweron_cmd(hdev); > + if (ret) { > + bt_dev_err(hdev, "Failed to send power on command"); > + return ret; > + } > > - /* Patch downloading has to be done without IBS mode */ > - clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); > + /* close serial port */ > + ret = qca_serdev_close(hu); > + if (ret) > + return ret; > + /* open serial port */ > + ret = qca_serdev_open(hu); > + if (ret) > + return ret; > > - /* Setup initial baudrate */ > - speed = 0; > - if (hu->init_speed) > - speed = hu->init_speed; > - else if (hu->proto->init_speed) > - speed = hu->proto->init_speed; > + /* Setup initial baudrate */ > + speed = 0; > + if (hu->init_speed) > + speed = hu->init_speed; > + else if (hu->proto->init_speed) > + speed = hu->proto->init_speed; > + if (speed) > + host_set_baudrate(hu, speed); Add curly braces. > + else { > + BT_ERR("%s:initial speed %u", hdev->name, speed); > + return -1; > + } > > - if (speed) > - host_set_baudrate(hu, speed); > + /* Enable flow control */ > + hci_uart_set_flow_control(hu, false); > + /* wait until flow control settled */ > + mdelay(100); A busy wait of 100ms doesn't seem a good idea. Use msleep() instead. Is it really necessary to wait that long? > + bt_dev_info(hdev, "wcn3990 Patch Version Request"); > + ret = rome_patch_ver_req(hdev, &soc_ver); > + if (ret < 0 || soc_ver == 0) { > + BT_ERR("%s: Failed to get version 0x%x", hdev->name, > + ret); > + return ret; > + } > > - /* Setup user speed if needed */ > - speed = 0; > - if (hu->oper_speed) > - speed = hu->oper_speed; > - else if (hu->proto->oper_speed) > - speed = hu->proto->oper_speed; > + bt_dev_info(hdev, "wcn3990 controller version 0x%08x", soc_ver); > + > + /* clear flow control */ > + hci_uart_set_flow_control(hu, true); > + /* set operating speed */ > + speed = 0; > + if (hu->oper_speed) > + speed = hu->oper_speed; > + else if (hu->proto->oper_speed) > + speed = hu->proto->oper_speed; > + if (speed) { > + qca_baudrate = qca_get_baudrate_value(speed); > + bt_dev_info(hdev, "Set UART speed to %d", speed); > + ret = qca_set_baudrate(hdev, qca_baudrate); > + if (ret) { > + BT_ERR("%s:Failed to change the baud rate(%d)", > + hdev->name, ret); > + return ret; > + } > + if (speed) > + host_set_baudrate(hu, speed); Add curly braces. > + else { > + BT_ERR("%s:Error in setting operator speed:%u", > + hdev->name, speed); > + return -1; > + } > + } > > - if (speed) { > - qca_baudrate = qca_get_baudrate_value(speed); > + /* Set flow control */ > + hci_uart_set_flow_control(hu, false); > + /*Setup patch and NVM configurations */ Add blank before 'Setup' and remove one before 'NVM'. > + ret = qca_uart_setup_cherokee(hdev, qca_baudrate, &soc_ver); > + if (!ret) { > + set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); > + qca_debugfs_init(hdev); > + } else if (ret == -ENOENT) { > + /* No patch/nvm-config found, run with original > + * fw/config. > + */ > + ret = 0; > + } else if (ret == -EAGAIN) { > + /* > + * Userspace firmware loader will return -EAGAIN in > + * case no patch/nvm-config is found, so run with > + * original fw/config. > + */ > + ret = 0; > + } > > - bt_dev_info(hdev, "Set UART speed to %d", speed); > - ret = qca_set_baudrate(hdev, qca_baudrate); > - if (ret) { > - bt_dev_err(hdev, "Failed to change the baud rate (%d)", > - ret); > + /* Setup wcn3990 bdaddr */ > + hu->hdev->set_bdaddr = qca_set_bdaddr_rome; > + > + return ret; > + > + default: What follows looks similar to the Cherokee path. I didn't look at all the details, but it's probably possible to share some more code. > + bt_dev_info(hdev, "ROME setup"); > + > + /* Patch downloading has to be done without IBS mode */ > + clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); > + > + /* Setup initial baudrate */ > + speed = 0; > + if (hu->init_speed) > + speed = hu->init_speed; > + else if (hu->proto->init_speed) > + speed = hu->proto->init_speed; > + > + if (speed) > + host_set_baudrate(hu, speed); > + > + /* Setup user speed if needed */ > + speed = 0; > + if (hu->oper_speed) > + speed = hu->oper_speed; > + else if (hu->proto->oper_speed) > + speed = hu->proto->oper_speed; > + > + if (speed) { > + qca_baudrate = qca_get_baudrate_value(speed); > + > + bt_dev_info(hdev, "Set UART speed to %d", speed); > + ret = qca_set_baudrate(hdev, qca_baudrate); > + if (ret) { > + bt_dev_err(hdev, "Failed to change the baud rate (%d)", > + ret); > return ret; Fix indentation. > +static const struct btqca_vreg_data cherokee_data = { > + .soc_type = BTQCA_CHEROKEE, > + .vregs = (struct btqca_vreg []) { > + { "vddio", 1352000, 1352000, 0 }, > + { "vddxtal", 1904000, 2040000, 0 }, > + { "vddcore", 1800000, 1800000, 1 }, > + { "vddpa", 130400, 1304000, 1 }, 0 missing for min_v? > + { "vddldo", 3000000, 3312000, 1 }, > + }, > + .num_vregs = 5, > +}; > + > +void btqca_disable_regulators(int reg_nu, struct btqca_vreg *vregs) > +{ > + /* disable the regulator if requested by user > + * or when fault in any regulator. > + */ > + for (reg_nu = reg_nu - 1; reg_nu >= 0 ; reg_nu--) { Better use a local variable for iteration instead of the function parameter > +int btqca_power_setup(bool on) > +{ > + int ret = 0; > + int i; > + struct btqca_vreg *vregs; > + > + if (!qca || !qca->vreg_data || !qca->vreg_bulk) > + return -EINVAL; > + vregs = qca->vreg_data->vregs; > + > + BT_DBG("on: %d", on); > + /* turn on if regualtors are off */ > + if (on == true && qca->vreg_status == false) { if (on && !qca->vreg_status) You might also consider a more expressive name instead of vreg_status, something like vregs_on. > + qca->vreg_status = true; > + for (i = 0; ret == 0 && i < qca->vreg_data->num_vregs; i++) { Better check ret inline and break when an error is encountered > + regulator_set_voltage(qca->vreg_bulk[i].consumer, > + vregs[i].min_v, > + vregs[i].max_v); Check return value. > + > + if (vregs[i].load_ua) > + regulator_set_load(qca->vreg_bulk[i].consumer, > + vregs[i].load_ua); Check return value. > + ret = regulator_enable(qca->vreg_bulk[i].consumer); > + } Fix indentation. > + } else if (on == false && qca->vreg_status == true) { (!on && qca->vreg_status) > + qca->vreg_status = false; > + /* turn of regualtor in reverse order */ 'off, regulator' > + btqca_disable_regulators(qca->vreg_data->num_vregs, vregs); > + } > + > + /* regulatos fails to enable */ 'regulators failed' > + if (ret) { > + qca->vreg_status = false; > + BT_ERR("failed to enable regualtor:%s", vregs[i].name); 'regulator' > + /* set regulator voltage and load to zero */ > + regulator_set_voltage(qca->vreg_bulk[i].consumer, > + 0, vregs[i].max_v); check return value. > static int qca_serdev_probe(struct serdev_device *serdev) > { > struct qca_serdev *qcadev; > - int err; > + const struct btqca_vreg_data *data; > + int err = 0; > > qcadev = devm_kzalloc(&serdev->dev, sizeof(*qcadev), GFP_KERNEL); > if (!qcadev) > return -ENOMEM; > > qcadev->serdev_hu.serdev = serdev; > + data = of_device_get_match_data(&serdev->dev); > + if (data && data->soc_type == BTQCA_CHEROKEE) > + qcadev->btsoc_type = BTQCA_CHEROKEE; > + else > + qcadev->btsoc_type = BTQCA_ROME; > + > serdev_device_set_drvdata(serdev, qcadev); > + if (qcadev->btsoc_type == BTQCA_CHEROKEE) { > + qca = kzalloc(sizeof(struct btqca_power), GFP_KERNEL); Use devm_kzalloc() > + if (!qca) > + return -ENOMEM; > + > + qca->dev = &serdev->dev; > + qca->vreg_data = data; > + err = init_regulators(qca, data->vregs, data->num_vregs); > + if (err) { > + BT_ERR("Failed to init regualtors:%d", err); 'regulators' > + kfree(qca); > + goto out; > + } > > - qcadev->bt_en = devm_gpiod_get(&serdev->dev, "enable", > - GPIOD_OUT_LOW); > - if (IS_ERR(qcadev->bt_en)) { > - dev_err(&serdev->dev, "failed to acquire enable gpio\n"); > - return PTR_ERR(qcadev->bt_en); > - } > + /* set voltage regulator status as false */ > + qca->vreg_status = false; > + /* get operating speed */ > + device_property_read_u32(&serdev->dev, "oper-speed", > + &qcadev->oper_speed); > + device_property_read_u32(&serdev->dev, "init-speed", > + &qcadev->init_speed); > + if (!qcadev->oper_speed) > + BT_INFO("DTS entry for operating speed is > - disabled"); The message isn't very clear. The entry isn't disabled, it doesn't exist. > static void qca_serdev_remove(struct serdev_device *serdev) > @@ -1047,12 +1454,16 @@ static void qca_serdev_remove(struct serdev_device *serdev) > struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev); > > hci_uart_unregister_device(&qcadev->serdev_hu); > - > - clk_disable_unprepare(qcadev->susclk); > + if (qcadev->btsoc_type == BTQCA_CHEROKEE) { > + btqca_power_setup(false); > + kfree(qca); > + } else > + clk_disable_unprepare(qcadev->susclk); Add curly braces. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v4 2/3] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990. 2018-05-05 1:17 ` Matthias Kaehlcke @ 2018-05-09 8:56 ` Balakrishna Godavarthi 2018-05-09 9:27 ` Balakrishna Godavarthi 2018-05-09 10:07 ` Balakrishna Godavarthi 2 siblings, 0 replies; 15+ messages in thread From: Balakrishna Godavarthi @ 2018-05-09 8:56 UTC (permalink / raw) To: Matthias Kaehlcke Cc: marcel, johan.hedberg, linux-bluetooth, rtatiya, hemantg, linux-arm-msm Hi, On 2018-05-05 06:47, Matthias Kaehlcke wrote: > Hi, > > On Fri, May 04, 2018 at 09:05:05PM +0530, Balakrishna Godavarthi wrote: >> Add support to set voltage/current of various regulators >> to power up/down Bluetooth chip wcn3990. >> Add support to read baudrate from dts. >> >> Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org> >> --- >> drivers/bluetooth/hci_qca.c | 555 >> ++++++++++++++++++++++++++++++++++++++------ >> 1 file changed, 483 insertions(+), 72 deletions(-) >> >> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c >> index f05382b..075fab7 100644 >> --- a/drivers/bluetooth/hci_qca.c >> +++ b/drivers/bluetooth/hci_qca.c >> @@ -5,7 +5,7 @@ >> * protocol extension to H4. >> * >> * Copyright (C) 2007 Texas Instruments, Inc. >> - * Copyright (c) 2010, 2012 The Linux Foundation. All rights >> reserved. >> + * Copyright (c) 2010, 2012, 2018 The Linux Foundation. All rights >> reserved. >> * >> * Acknowledgements: >> * This file is based on hci_ll.c, which was... >> @@ -35,6 +35,10 @@ >> #include <linux/mod_devicetable.h> >> #include <linux/module.h> >> #include <linux/serdev.h> >> +#include <asm-generic/delay.h> >> +#include <linux/platform_device.h> >> +#include <linux/regulator/consumer.h> >> +#include <linux/of_device.h> > > AFAIK the convention is to order includes alphabetically. > >> +static struct btqca_power *qca; > > This limits the driver to a single instance. This is probably the most > common use case, but in general it's preferable not to have this kind > of limitations. > >> static void __serial_clock_on(struct tty_struct *tty) >> { >> /* TODO: Some chipset requires to enable UART clock on client >> @@ -463,7 +506,12 @@ static int qca_open(struct hci_uart *hu) >> serdev_device_open(hu->serdev); >> >> qcadev = serdev_device_get_drvdata(hu->serdev); >> - gpiod_set_value_cansleep(qcadev->bt_en, 1); >> + if (qcadev->btsoc_type == BTQCA_CHEROKEE) { >> + hu->init_speed = qcadev->init_speed; >> + hu->oper_speed = qcadev->oper_speed; >> + btqca_power_setup(true); >> + } else >> + gpiod_set_value_cansleep(qcadev->bt_en, 1); > > Use curly braces for the else branch too. > >> +static int qca_send_poweron_cmd(struct hci_dev *hdev) >> +{ >> + struct hci_uart *hu = hci_get_drvdata(hdev); >> + struct qca_data *qca = hu->priv; >> + struct sk_buff *skb; >> + u8 cmd; >> + >> + BT_DBG("%s sending power on command to btsoc", hdev->name); > > Use bt_dev_dbg(), same for other BT_XXX(). > >> + /* By sending 0xFC host is trying to power up the soc */ > > nit: SoC, same a few lines below. > >> + cmd = CHEROKEE_POWERON_PULSE; >> + skb = bt_skb_alloc(sizeof(cmd), GFP_ATOMIC); > > Use GFP_KERNEL, the code sleeps a few lines below, hence it must > definitely not be called in atomic context. > >> + if (!skb) { >> + BT_ERR("Failed to allocate memory for skb packet"); >> + return -ENOMEM; >> + } >> + >> + skb_put_data(skb, &cmd, sizeof(cmd)); >> + hci_skb_pkt_type(skb) = HCI_COMMAND_PKT; >> + >> + skb_queue_tail(&qca->txq, skb); >> + hci_uart_tx_wakeup(hu); >> + >> + /* Wait for 100 us for soc to settle down */ >> + set_current_state(TASK_UNINTERRUPTIBLE); >> + schedule_timeout(usecs_to_jiffies(100)); >> + set_current_state(TASK_INTERRUPTIBLE); >> + >> + return 0; >> +} >> + >> +static int qca_send_poweroff_cmd(struct hci_dev *hdev) >> +{ >> + struct hci_uart *hu = hci_get_drvdata(hdev); >> + struct qca_data *qca = hu->priv; >> + struct sk_buff *skb; >> + u8 cmd; >> + >> + BT_DBG("%s sending power off command to btsoc", hdev->name); >> + /* By sending 0xC0 host is trying to power off the soc */ >> + cmd = CHEROKEE_POWEROFF_PULSE; >> + skb = bt_skb_alloc(sizeof(cmd), GFP_ATOMIC); >> + if (!skb) { >> + BT_ERR("Failed to allocate memory for skb packet"); >> + return -ENOMEM; >> + } >> + >> + skb_put_data(skb, &cmd, sizeof(cmd)); >> + hci_skb_pkt_type(skb) = HCI_COMMAND_PKT; >> + >> + skb_queue_tail(&qca->txq, skb); >> + hci_uart_tx_wakeup(hu); >> + >> + /* Wait for 100 us for soc to settle down */ >> + set_current_state(TASK_UNINTERRUPTIBLE); >> + schedule_timeout(usecs_to_jiffies(100)); >> + set_current_state(TASK_INTERRUPTIBLE); >> + >> + return 0; >> +} > > This function is almost a clone of qca_send_poweron_cmd(), move the > common code to something like qca_send_cmd() and call it from > qca_send_poweron/off_cmd(). > >> +static int qca_serdev_open(struct hci_uart *hu) >> +{ >> + int ret = 0; >> + >> + if (hu->serdev) >> + serdev_device_open(hu->serdev); > > Check return value. > > Add curly braces to the if branch too. > >> +static int qca_serdev_close(struct hci_uart *hu) >> +{ >> + int ret = 0; >> + >> + if (hu->serdev) >> + serdev_device_close(hu->serdev); > > Add curly braces to the if branch too. > >> static int qca_setup(struct hci_uart *hu) >> { >> struct hci_dev *hdev = hu->hdev; >> struct qca_data *qca = hu->priv; >> + struct qca_serdev *qcadev; >> unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200; >> int ret; >> + int soc_ver; >> + >> + qcadev = serdev_device_get_drvdata(hu->serdev); >> + >> + switch (qcadev->btsoc_type) { >> + case BTQCA_CHEROKEE: >> + bt_dev_info(hdev, "setting up wcn3990"); >> + /* Patch downloading has to be done without IBS mode */ >> + clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); >> + /* Setup initial baudrate */ >> + speed = 0; >> + if (hu->init_speed) >> + speed = hu->init_speed; >> + else if (hu->proto->init_speed) >> + speed = hu->proto->init_speed; >> + >> + if (speed) >> + host_set_baudrate(hu, speed); > > Add curly braces. > >> + else { >> + bt_dev_err(hdev, "initial speed %u", speed); >> + return -1; >> + } >> >> - bt_dev_info(hdev, "ROME setup"); >> + /* disable flow control, as chip is still not turned on */ >> + hci_uart_set_flow_control(hu, true); > > The interface of this function is confusing. enable = true disables > flow control ... Not the fault of this driver though :) > >> + /* send poweron command to btsoc */ >> + ret = qca_send_poweron_cmd(hdev); >> + if (ret) { >> + bt_dev_err(hdev, "Failed to send power on command"); >> + return ret; >> + } >> >> - /* Patch downloading has to be done without IBS mode */ >> - clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); >> + /* close serial port */ >> + ret = qca_serdev_close(hu); >> + if (ret) >> + return ret; >> + /* open serial port */ >> + ret = qca_serdev_open(hu); >> + if (ret) >> + return ret; >> >> - /* Setup initial baudrate */ >> - speed = 0; >> - if (hu->init_speed) >> - speed = hu->init_speed; >> - else if (hu->proto->init_speed) >> - speed = hu->proto->init_speed; >> + /* Setup initial baudrate */ >> + speed = 0; >> + if (hu->init_speed) >> + speed = hu->init_speed; >> + else if (hu->proto->init_speed) >> + speed = hu->proto->init_speed; >> + if (speed) >> + host_set_baudrate(hu, speed); > > Add curly braces. > >> + else { >> + BT_ERR("%s:initial speed %u", hdev->name, speed); >> + return -1; >> + } >> >> - if (speed) >> - host_set_baudrate(hu, speed); >> + /* Enable flow control */ >> + hci_uart_set_flow_control(hu, false); >> + /* wait until flow control settled */ >> + mdelay(100); > > A busy wait of 100ms doesn't seem a good idea. Use msleep() > instead. Is it really necessary to wait that long? > >> + bt_dev_info(hdev, "wcn3990 Patch Version Request"); >> + ret = rome_patch_ver_req(hdev, &soc_ver); >> + if (ret < 0 || soc_ver == 0) { >> + BT_ERR("%s: Failed to get version 0x%x", hdev->name, >> + ret); >> + return ret; >> + } >> >> - /* Setup user speed if needed */ >> - speed = 0; >> - if (hu->oper_speed) >> - speed = hu->oper_speed; >> - else if (hu->proto->oper_speed) >> - speed = hu->proto->oper_speed; >> + bt_dev_info(hdev, "wcn3990 controller version 0x%08x", soc_ver); >> + >> + /* clear flow control */ >> + hci_uart_set_flow_control(hu, true); >> + /* set operating speed */ >> + speed = 0; >> + if (hu->oper_speed) >> + speed = hu->oper_speed; >> + else if (hu->proto->oper_speed) >> + speed = hu->proto->oper_speed; >> + if (speed) { >> + qca_baudrate = qca_get_baudrate_value(speed); >> + bt_dev_info(hdev, "Set UART speed to %d", speed); >> + ret = qca_set_baudrate(hdev, qca_baudrate); >> + if (ret) { >> + BT_ERR("%s:Failed to change the baud rate(%d)", >> + hdev->name, ret); >> + return ret; >> + } >> + if (speed) >> + host_set_baudrate(hu, speed); > > Add curly braces. > >> + else { >> + BT_ERR("%s:Error in setting operator speed:%u", >> + hdev->name, speed); >> + return -1; >> + } >> + } >> >> - if (speed) { >> - qca_baudrate = qca_get_baudrate_value(speed); >> + /* Set flow control */ >> + hci_uart_set_flow_control(hu, false); >> + /*Setup patch and NVM configurations */ > > Add blank before 'Setup' and remove one before 'NVM'. > >> + ret = qca_uart_setup_cherokee(hdev, qca_baudrate, &soc_ver); >> + if (!ret) { >> + set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); >> + qca_debugfs_init(hdev); >> + } else if (ret == -ENOENT) { >> + /* No patch/nvm-config found, run with original >> + * fw/config. >> + */ >> + ret = 0; >> + } else if (ret == -EAGAIN) { >> + /* >> + * Userspace firmware loader will return -EAGAIN in >> + * case no patch/nvm-config is found, so run with >> + * original fw/config. >> + */ >> + ret = 0; >> + } >> >> - bt_dev_info(hdev, "Set UART speed to %d", speed); >> - ret = qca_set_baudrate(hdev, qca_baudrate); >> - if (ret) { >> - bt_dev_err(hdev, "Failed to change the baud rate (%d)", >> - ret); >> + /* Setup wcn3990 bdaddr */ >> + hu->hdev->set_bdaddr = qca_set_bdaddr_rome; >> + >> + return ret; >> + >> + default: > > What follows looks similar to the Cherokee path. I didn't look at all > the details, but it's probably possible to share some more code. > >> + bt_dev_info(hdev, "ROME setup"); >> + >> + /* Patch downloading has to be done without IBS mode */ >> + clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); >> + >> + /* Setup initial baudrate */ >> + speed = 0; >> + if (hu->init_speed) >> + speed = hu->init_speed; >> + else if (hu->proto->init_speed) >> + speed = hu->proto->init_speed; >> + >> + if (speed) >> + host_set_baudrate(hu, speed); >> + >> + /* Setup user speed if needed */ >> + speed = 0; >> + if (hu->oper_speed) >> + speed = hu->oper_speed; >> + else if (hu->proto->oper_speed) >> + speed = hu->proto->oper_speed; >> + >> + if (speed) { >> + qca_baudrate = qca_get_baudrate_value(speed); >> + >> + bt_dev_info(hdev, "Set UART speed to %d", speed); >> + ret = qca_set_baudrate(hdev, qca_baudrate); >> + if (ret) { >> + bt_dev_err(hdev, "Failed to change the baud rate (%d)", >> + ret); >> return ret; > > Fix indentation. > >> +static const struct btqca_vreg_data cherokee_data = { >> + .soc_type = BTQCA_CHEROKEE, >> + .vregs = (struct btqca_vreg []) { >> + { "vddio", 1352000, 1352000, 0 }, >> + { "vddxtal", 1904000, 2040000, 0 }, >> + { "vddcore", 1800000, 1800000, 1 }, >> + { "vddpa", 130400, 1304000, 1 }, > > 0 missing for min_v? > >> + { "vddldo", 3000000, 3312000, 1 }, >> + }, >> + .num_vregs = 5, >> +}; >> + >> +void btqca_disable_regulators(int reg_nu, struct btqca_vreg *vregs) >> +{ >> + /* disable the regulator if requested by user >> + * or when fault in any regulator. >> + */ >> + for (reg_nu = reg_nu - 1; reg_nu >= 0 ; reg_nu--) { > > Better use a local variable for iteration instead of the function > parameter > >> +int btqca_power_setup(bool on) >> +{ >> + int ret = 0; >> + int i; >> + struct btqca_vreg *vregs; >> + >> + if (!qca || !qca->vreg_data || !qca->vreg_bulk) >> + return -EINVAL; >> + vregs = qca->vreg_data->vregs; >> + >> + BT_DBG("on: %d", on); >> + /* turn on if regualtors are off */ >> + if (on == true && qca->vreg_status == false) { > > if (on && !qca->vreg_status) > > You might also consider a more expressive name instead of vreg_status, > something like vregs_on. > >> + qca->vreg_status = true; >> + for (i = 0; ret == 0 && i < qca->vreg_data->num_vregs; i++) { > > Better check ret inline and break when an error is encountered > >> + regulator_set_voltage(qca->vreg_bulk[i].consumer, >> + vregs[i].min_v, >> + vregs[i].max_v); > > Check return value. > >> + >> + if (vregs[i].load_ua) >> + regulator_set_load(qca->vreg_bulk[i].consumer, >> + vregs[i].load_ua); > > Check return value. > >> + ret = regulator_enable(qca->vreg_bulk[i].consumer); >> + } > > Fix indentation. > >> + } else if (on == false && qca->vreg_status == true) { > > (!on && qca->vreg_status) > >> + qca->vreg_status = false; >> + /* turn of regualtor in reverse order */ > > 'off, regulator' > >> + btqca_disable_regulators(qca->vreg_data->num_vregs, vregs); >> + } >> + >> + /* regulatos fails to enable */ > > 'regulators failed' > >> + if (ret) { >> + qca->vreg_status = false; >> + BT_ERR("failed to enable regualtor:%s", vregs[i].name); > > 'regulator' > >> + /* set regulator voltage and load to zero */ >> + regulator_set_voltage(qca->vreg_bulk[i].consumer, >> + 0, vregs[i].max_v); > > check return value. > >> static int qca_serdev_probe(struct serdev_device *serdev) >> { >> struct qca_serdev *qcadev; >> - int err; >> + const struct btqca_vreg_data *data; >> + int err = 0; >> >> qcadev = devm_kzalloc(&serdev->dev, sizeof(*qcadev), GFP_KERNEL); >> if (!qcadev) >> return -ENOMEM; >> >> qcadev->serdev_hu.serdev = serdev; >> + data = of_device_get_match_data(&serdev->dev); >> + if (data && data->soc_type == BTQCA_CHEROKEE) >> + qcadev->btsoc_type = BTQCA_CHEROKEE; >> + else >> + qcadev->btsoc_type = BTQCA_ROME; >> + >> serdev_device_set_drvdata(serdev, qcadev); >> + if (qcadev->btsoc_type == BTQCA_CHEROKEE) { >> + qca = kzalloc(sizeof(struct btqca_power), GFP_KERNEL); > > Use devm_kzalloc() > >> + if (!qca) >> + return -ENOMEM; >> + >> + qca->dev = &serdev->dev; >> + qca->vreg_data = data; >> + err = init_regulators(qca, data->vregs, data->num_vregs); >> + if (err) { >> + BT_ERR("Failed to init regualtors:%d", err); > > 'regulators' > >> + kfree(qca); >> + goto out; >> + } >> >> - qcadev->bt_en = devm_gpiod_get(&serdev->dev, "enable", >> - GPIOD_OUT_LOW); >> - if (IS_ERR(qcadev->bt_en)) { >> - dev_err(&serdev->dev, "failed to acquire enable gpio\n"); >> - return PTR_ERR(qcadev->bt_en); >> - } >> + /* set voltage regulator status as false */ >> + qca->vreg_status = false; >> + /* get operating speed */ >> + device_property_read_u32(&serdev->dev, "oper-speed", >> + &qcadev->oper_speed); >> + device_property_read_u32(&serdev->dev, "init-speed", >> + &qcadev->init_speed); >> + if (!qcadev->oper_speed) >> + BT_INFO("DTS entry for operating speed is >> - disabled"); > > The message isn't very clear. The entry isn't disabled, it doesn't > exist. > >> static void qca_serdev_remove(struct serdev_device *serdev) >> @@ -1047,12 +1454,16 @@ static void qca_serdev_remove(struct >> serdev_device *serdev) >> struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev); >> >> hci_uart_unregister_device(&qcadev->serdev_hu); >> - >> - clk_disable_unprepare(qcadev->susclk); >> + if (qcadev->btsoc_type == BTQCA_CHEROKEE) { >> + btqca_power_setup(false); >> + kfree(qca); >> + } else >> + clk_disable_unprepare(qcadev->susclk); > > Add curly braces. will send a incremental patches as per your comments. -- Regards Balakrishna. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v4 2/3] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990. 2018-05-05 1:17 ` Matthias Kaehlcke 2018-05-09 8:56 ` Balakrishna Godavarthi @ 2018-05-09 9:27 ` Balakrishna Godavarthi 2018-05-09 10:07 ` Balakrishna Godavarthi 2 siblings, 0 replies; 15+ messages in thread From: Balakrishna Godavarthi @ 2018-05-09 9:27 UTC (permalink / raw) To: Matthias Kaehlcke Cc: marcel, johan.hedberg, linux-bluetooth, rtatiya, hemantg, linux-arm-msm hi, On 2018-05-05 06:47, Matthias Kaehlcke wrote: > Hi, > > On Fri, May 04, 2018 at 09:05:05PM +0530, Balakrishna Godavarthi wrote: >> Add support to set voltage/current of various regulators >> to power up/down Bluetooth chip wcn3990. >> Add support to read baudrate from dts. >> >> Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org> >> --- >> drivers/bluetooth/hci_qca.c | 555 >> ++++++++++++++++++++++++++++++++++++++------ >> 1 file changed, 483 insertions(+), 72 deletions(-) >> >> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c >> index f05382b..075fab7 100644 >> --- a/drivers/bluetooth/hci_qca.c >> +++ b/drivers/bluetooth/hci_qca.c >> @@ -5,7 +5,7 @@ >> * protocol extension to H4. >> * >> * Copyright (C) 2007 Texas Instruments, Inc. >> - * Copyright (c) 2010, 2012 The Linux Foundation. All rights >> reserved. >> + * Copyright (c) 2010, 2012, 2018 The Linux Foundation. All rights >> reserved. >> * >> * Acknowledgements: >> * This file is based on hci_ll.c, which was... >> @@ -35,6 +35,10 @@ >> #include <linux/mod_devicetable.h> >> #include <linux/module.h> >> #include <linux/serdev.h> >> +#include <asm-generic/delay.h> >> +#include <linux/platform_device.h> >> +#include <linux/regulator/consumer.h> >> +#include <linux/of_device.h> > > AFAIK the convention is to order includes alphabetically. [Bala]:will update. > >> +static struct btqca_power *qca; > > This limits the driver to a single instance. This is probably the most > common use case, but in general it's preferable not to have this kind > of limitations. > [Bala]:yes, as we need to limit driver fro single instance. >> static void __serial_clock_on(struct tty_struct *tty) >> { >> /* TODO: Some chipset requires to enable UART clock on client >> @@ -463,7 +506,12 @@ static int qca_open(struct hci_uart *hu) >> serdev_device_open(hu->serdev); >> >> qcadev = serdev_device_get_drvdata(hu->serdev); >> - gpiod_set_value_cansleep(qcadev->bt_en, 1); >> + if (qcadev->btsoc_type == BTQCA_CHEROKEE) { >> + hu->init_speed = qcadev->init_speed; >> + hu->oper_speed = qcadev->oper_speed; >> + btqca_power_setup(true); >> + } else >> + gpiod_set_value_cansleep(qcadev->bt_en, 1); > > Use curly braces for the else branch too. [Bala]:will update. > >> +static int qca_send_poweron_cmd(struct hci_dev *hdev) >> +{ >> + struct hci_uart *hu = hci_get_drvdata(hdev); >> + struct qca_data *qca = hu->priv; >> + struct sk_buff *skb; >> + u8 cmd; >> + >> + BT_DBG("%s sending power on command to btsoc", hdev->name); > > Use bt_dev_dbg(), same for other BT_XXX(). > >> + /* By sending 0xFC host is trying to power up the soc */ > > nit: SoC, same a few lines below. > >> + cmd = CHEROKEE_POWERON_PULSE; >> + skb = bt_skb_alloc(sizeof(cmd), GFP_ATOMIC); > > Use GFP_KERNEL, the code sleeps a few lines below, hence it must > definitely not be called in atomic context. > >> + if (!skb) { >> + BT_ERR("Failed to allocate memory for skb packet"); >> + return -ENOMEM; >> + } >> + >> + skb_put_data(skb, &cmd, sizeof(cmd)); >> + hci_skb_pkt_type(skb) = HCI_COMMAND_PKT; >> + >> + skb_queue_tail(&qca->txq, skb); >> + hci_uart_tx_wakeup(hu); >> + >> + /* Wait for 100 us for soc to settle down */ >> + set_current_state(TASK_UNINTERRUPTIBLE); >> + schedule_timeout(usecs_to_jiffies(100)); >> + set_current_state(TASK_INTERRUPTIBLE); >> + >> + return 0; >> +} >> + >> +static int qca_send_poweroff_cmd(struct hci_dev *hdev) >> +{ >> + struct hci_uart *hu = hci_get_drvdata(hdev); >> + struct qca_data *qca = hu->priv; >> + struct sk_buff *skb; >> + u8 cmd; >> + >> + BT_DBG("%s sending power off command to btsoc", hdev->name); >> + /* By sending 0xC0 host is trying to power off the soc */ >> + cmd = CHEROKEE_POWEROFF_PULSE; >> + skb = bt_skb_alloc(sizeof(cmd), GFP_ATOMIC); >> + if (!skb) { >> + BT_ERR("Failed to allocate memory for skb packet"); >> + return -ENOMEM; >> + } >> + >> + skb_put_data(skb, &cmd, sizeof(cmd)); >> + hci_skb_pkt_type(skb) = HCI_COMMAND_PKT; >> + >> + skb_queue_tail(&qca->txq, skb); >> + hci_uart_tx_wakeup(hu); >> + >> + /* Wait for 100 us for soc to settle down */ >> + set_current_state(TASK_UNINTERRUPTIBLE); >> + schedule_timeout(usecs_to_jiffies(100)); >> + set_current_state(TASK_INTERRUPTIBLE); >> + >> + return 0; >> +} > > This function is almost a clone of qca_send_poweron_cmd(), move the > common code to something like qca_send_cmd() and call it from > qca_send_poweron/off_cmd(). [Bala]: will make as one function. > >> +static int qca_serdev_open(struct hci_uart *hu) >> +{ >> + int ret = 0; >> + >> + if (hu->serdev) >> + serdev_device_open(hu->serdev); > > Check return value. > > Add curly braces to the if branch too. > >> +static int qca_serdev_close(struct hci_uart *hu) >> +{ >> + int ret = 0; >> + >> + if (hu->serdev) >> + serdev_device_close(hu->serdev); > > Add curly braces to the if branch too. [Bala]- Will update > >> static int qca_setup(struct hci_uart *hu) >> { >> struct hci_dev *hdev = hu->hdev; >> struct qca_data *qca = hu->priv; >> + struct qca_serdev *qcadev; >> unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200; >> int ret; >> + int soc_ver; >> + >> + qcadev = serdev_device_get_drvdata(hu->serdev); >> + >> + switch (qcadev->btsoc_type) { >> + case BTQCA_CHEROKEE: >> + bt_dev_info(hdev, "setting up wcn3990"); >> + /* Patch downloading has to be done without IBS mode */ >> + clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); >> + /* Setup initial baudrate */ >> + speed = 0; >> + if (hu->init_speed) >> + speed = hu->init_speed; >> + else if (hu->proto->init_speed) >> + speed = hu->proto->init_speed; >> + >> + if (speed) >> + host_set_baudrate(hu, speed); > > Add curly braces. [Bala]- will update. > >> + else { >> + bt_dev_err(hdev, "initial speed %u", speed); >> + return -1; >> + } >> >> - bt_dev_info(hdev, "ROME setup"); >> + /* disable flow control, as chip is still not turned on */ >> + hci_uart_set_flow_control(hu, true); > > The interface of this function is confusing. enable = true disables > flow control ... Not the fault of this driver though :) [Bala]- yes i feel it is reverse. but i don't want disturb the function as some one may be using the same function before calling these function, i have written a comment. > >> + /* send poweron command to btsoc */ >> + ret = qca_send_poweron_cmd(hdev); >> + if (ret) { >> + bt_dev_err(hdev, "Failed to send power on command"); >> + return ret; >> + } >> >> - /* Patch downloading has to be done without IBS mode */ >> - clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); >> + /* close serial port */ >> + ret = qca_serdev_close(hu); >> + if (ret) >> + return ret; >> + /* open serial port */ >> + ret = qca_serdev_open(hu); >> + if (ret) >> + return ret; >> >> - /* Setup initial baudrate */ >> - speed = 0; >> - if (hu->init_speed) >> - speed = hu->init_speed; >> - else if (hu->proto->init_speed) >> - speed = hu->proto->init_speed; >> + /* Setup initial baudrate */ >> + speed = 0; >> + if (hu->init_speed) >> + speed = hu->init_speed; >> + else if (hu->proto->init_speed) >> + speed = hu->proto->init_speed; >> + if (speed) >> + host_set_baudrate(hu, speed); > > Add curly braces. > >> + else { >> + BT_ERR("%s:initial speed %u", hdev->name, speed); >> + return -1; >> + } >> >> - if (speed) >> - host_set_baudrate(hu, speed); >> + /* Enable flow control */ >> + hci_uart_set_flow_control(hu, false); >> + /* wait until flow control settled */ >> + mdelay(100); > > A busy wait of 100ms doesn't seem a good idea. Use msleep() > instead. Is it really necessary to wait that long? [Bala]- after long analysis we conclude to wait for 100ms to make SoC to bootup.\ > >> + bt_dev_info(hdev, "wcn3990 Patch Version Request"); >> + ret = rome_patch_ver_req(hdev, &soc_ver); >> + if (ret < 0 || soc_ver == 0) { >> + BT_ERR("%s: Failed to get version 0x%x", hdev->name, >> + ret); >> + return ret; >> + } >> >> - /* Setup user speed if needed */ >> - speed = 0; >> - if (hu->oper_speed) >> - speed = hu->oper_speed; >> - else if (hu->proto->oper_speed) >> - speed = hu->proto->oper_speed; >> + bt_dev_info(hdev, "wcn3990 controller version 0x%08x", soc_ver); >> + >> + /* clear flow control */ >> + hci_uart_set_flow_control(hu, true); >> + /* set operating speed */ >> + speed = 0; >> + if (hu->oper_speed) >> + speed = hu->oper_speed; >> + else if (hu->proto->oper_speed) >> + speed = hu->proto->oper_speed; >> + if (speed) { >> + qca_baudrate = qca_get_baudrate_value(speed); >> + bt_dev_info(hdev, "Set UART speed to %d", speed); >> + ret = qca_set_baudrate(hdev, qca_baudrate); >> + if (ret) { >> + BT_ERR("%s:Failed to change the baud rate(%d)", >> + hdev->name, ret); >> + return ret; >> + } >> + if (speed) >> + host_set_baudrate(hu, speed); > > Add curly braces. > >> + else { >> + BT_ERR("%s:Error in setting operator speed:%u", >> + hdev->name, speed); >> + return -1; >> + } >> + } >> >> - if (speed) { >> - qca_baudrate = qca_get_baudrate_value(speed); >> + /* Set flow control */ >> + hci_uart_set_flow_control(hu, false); >> + /*Setup patch and NVM configurations */ > > Add blank before 'Setup' and remove one before 'NVM'. > >> + ret = qca_uart_setup_cherokee(hdev, qca_baudrate, &soc_ver); >> + if (!ret) { >> + set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); >> + qca_debugfs_init(hdev); >> + } else if (ret == -ENOENT) { >> + /* No patch/nvm-config found, run with original >> + * fw/config. >> + */ >> + ret = 0; >> + } else if (ret == -EAGAIN) { >> + /* >> + * Userspace firmware loader will return -EAGAIN in >> + * case no patch/nvm-config is found, so run with >> + * original fw/config. >> + */ >> + ret = 0; >> + } >> >> - bt_dev_info(hdev, "Set UART speed to %d", speed); >> - ret = qca_set_baudrate(hdev, qca_baudrate); >> - if (ret) { >> - bt_dev_err(hdev, "Failed to change the baud rate (%d)", >> - ret); >> + /* Setup wcn3990 bdaddr */ >> + hu->hdev->set_bdaddr = qca_set_bdaddr_rome; >> + >> + return ret; >> + >> + default: > > What follows looks similar to the Cherokee path. I didn't look at all > the details, but it's probably possible to share some more code. [Bala]- Cherokee has a different way for setup. ROME will not have flow control enabled. > >> + bt_dev_info(hdev, "ROME setup"); >> + >> + /* Patch downloading has to be done without IBS mode */ >> + clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); >> + >> + /* Setup initial baudrate */ >> + speed = 0; >> + if (hu->init_speed) >> + speed = hu->init_speed; >> + else if (hu->proto->init_speed) >> + speed = hu->proto->init_speed; >> + >> + if (speed) >> + host_set_baudrate(hu, speed); >> + >> + /* Setup user speed if needed */ >> + speed = 0; >> + if (hu->oper_speed) >> + speed = hu->oper_speed; >> + else if (hu->proto->oper_speed) >> + speed = hu->proto->oper_speed; >> + >> + if (speed) { >> + qca_baudrate = qca_get_baudrate_value(speed); >> + >> + bt_dev_info(hdev, "Set UART speed to %d", speed); >> + ret = qca_set_baudrate(hdev, qca_baudrate); >> + if (ret) { >> + bt_dev_err(hdev, "Failed to change the baud rate (%d)", >> + ret); >> return ret; > > Fix indentation. > >> +static const struct btqca_vreg_data cherokee_data = { >> + .soc_type = BTQCA_CHEROKEE, >> + .vregs = (struct btqca_vreg []) { >> + { "vddio", 1352000, 1352000, 0 }, >> + { "vddxtal", 1904000, 2040000, 0 }, >> + { "vddcore", 1800000, 1800000, 1 }, >> + { "vddpa", 130400, 1304000, 1 }, > > 0 missing for min_v? > >> + { "vddldo", 3000000, 3312000, 1 }, >> + }, >> + .num_vregs = 5, >> +}; >> + >> +void btqca_disable_regulators(int reg_nu, struct btqca_vreg *vregs) >> +{ >> + /* disable the regulator if requested by user >> + * or when fault in any regulator. >> + */ >> + for (reg_nu = reg_nu - 1; reg_nu >= 0 ; reg_nu--) { > > Better use a local variable for iteration instead of the function > parameter > >> +int btqca_power_setup(bool on) >> +{ >> + int ret = 0; >> + int i; >> + struct btqca_vreg *vregs; >> + >> + if (!qca || !qca->vreg_data || !qca->vreg_bulk) >> + return -EINVAL; >> + vregs = qca->vreg_data->vregs; >> + >> + BT_DBG("on: %d", on); >> + /* turn on if regualtors are off */ >> + if (on == true && qca->vreg_status == false) { > > if (on && !qca->vreg_status) > > You might also consider a more expressive name instead of vreg_status, > something like vregs_on. > >> + qca->vreg_status = true; >> + for (i = 0; ret == 0 && i < qca->vreg_data->num_vregs; i++) { > > Better check ret inline and break when an error is encountered > >> + regulator_set_voltage(qca->vreg_bulk[i].consumer, >> + vregs[i].min_v, >> + vregs[i].max_v); > > Check return value. > >> + >> + if (vregs[i].load_ua) >> + regulator_set_load(qca->vreg_bulk[i].consumer, >> + vregs[i].load_ua); > > Check return value. > >> + ret = regulator_enable(qca->vreg_bulk[i].consumer); >> + } > > Fix indentation. > >> + } else if (on == false && qca->vreg_status == true) { > > (!on && qca->vreg_status) > >> + qca->vreg_status = false; >> + /* turn of regualtor in reverse order */ > > 'off, regulator' > >> + btqca_disable_regulators(qca->vreg_data->num_vregs, vregs); >> + } >> + >> + /* regulatos fails to enable */ > > 'regulators failed' > >> + if (ret) { >> + qca->vreg_status = false; >> + BT_ERR("failed to enable regualtor:%s", vregs[i].name); > > 'regulator' > >> + /* set regulator voltage and load to zero */ >> + regulator_set_voltage(qca->vreg_bulk[i].consumer, >> + 0, vregs[i].max_v); > > check return value. > >> static int qca_serdev_probe(struct serdev_device *serdev) >> { >> struct qca_serdev *qcadev; >> - int err; >> + const struct btqca_vreg_data *data; >> + int err = 0; >> >> qcadev = devm_kzalloc(&serdev->dev, sizeof(*qcadev), GFP_KERNEL); >> if (!qcadev) >> return -ENOMEM; >> >> qcadev->serdev_hu.serdev = serdev; >> + data = of_device_get_match_data(&serdev->dev); >> + if (data && data->soc_type == BTQCA_CHEROKEE) >> + qcadev->btsoc_type = BTQCA_CHEROKEE; >> + else >> + qcadev->btsoc_type = BTQCA_ROME; >> + >> serdev_device_set_drvdata(serdev, qcadev); >> + if (qcadev->btsoc_type == BTQCA_CHEROKEE) { >> + qca = kzalloc(sizeof(struct btqca_power), GFP_KERNEL); > > Use devm_kzalloc() > >> + if (!qca) >> + return -ENOMEM; >> + >> + qca->dev = &serdev->dev; >> + qca->vreg_data = data; >> + err = init_regulators(qca, data->vregs, data->num_vregs); >> + if (err) { >> + BT_ERR("Failed to init regualtors:%d", err); > > 'regulators' > >> + kfree(qca); >> + goto out; >> + } >> >> - qcadev->bt_en = devm_gpiod_get(&serdev->dev, "enable", >> - GPIOD_OUT_LOW); >> - if (IS_ERR(qcadev->bt_en)) { >> - dev_err(&serdev->dev, "failed to acquire enable gpio\n"); >> - return PTR_ERR(qcadev->bt_en); >> - } >> + /* set voltage regulator status as false */ >> + qca->vreg_status = false; >> + /* get operating speed */ >> + device_property_read_u32(&serdev->dev, "oper-speed", >> + &qcadev->oper_speed); >> + device_property_read_u32(&serdev->dev, "init-speed", >> + &qcadev->init_speed); >> + if (!qcadev->oper_speed) >> + BT_INFO("DTS entry for operating speed is >> - disabled"); > > The message isn't very clear. The entry isn't disabled, it doesn't > exist. > >> static void qca_serdev_remove(struct serdev_device *serdev) >> @@ -1047,12 +1454,16 @@ static void qca_serdev_remove(struct >> serdev_device *serdev) >> struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev); >> >> hci_uart_unregister_device(&qcadev->serdev_hu); >> - >> - clk_disable_unprepare(qcadev->susclk); >> + if (qcadev->btsoc_type == BTQCA_CHEROKEE) { >> + btqca_power_setup(false); >> + kfree(qca); >> + } else >> + clk_disable_unprepare(qcadev->susclk); > > Add curly braces. -- Regards Balakrishna. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v4 2/3] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990. 2018-05-05 1:17 ` Matthias Kaehlcke 2018-05-09 8:56 ` Balakrishna Godavarthi 2018-05-09 9:27 ` Balakrishna Godavarthi @ 2018-05-09 10:07 ` Balakrishna Godavarthi 2018-05-09 17:24 ` Matthias Kaehlcke 2 siblings, 1 reply; 15+ messages in thread From: Balakrishna Godavarthi @ 2018-05-09 10:07 UTC (permalink / raw) To: Matthias Kaehlcke Cc: marcel, johan.hedberg, linux-bluetooth, rtatiya, hemantg, linux-arm-msm Hi, Please find my comments inline. On 2018-05-05 06:47, Matthias Kaehlcke wrote: > Hi, > > On Fri, May 04, 2018 at 09:05:05PM +0530, Balakrishna Godavarthi wrote: >> Add support to set voltage/current of various regulators >> to power up/down Bluetooth chip wcn3990. >> Add support to read baudrate from dts. >> >> Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org> >> --- >> drivers/bluetooth/hci_qca.c | 555 >> ++++++++++++++++++++++++++++++++++++++------ >> 1 file changed, 483 insertions(+), 72 deletions(-) >> >> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c >> index f05382b..075fab7 100644 >> --- a/drivers/bluetooth/hci_qca.c >> +++ b/drivers/bluetooth/hci_qca.c >> @@ -5,7 +5,7 @@ >> * protocol extension to H4. >> * >> * Copyright (C) 2007 Texas Instruments, Inc. >> - * Copyright (c) 2010, 2012 The Linux Foundation. All rights >> reserved. >> + * Copyright (c) 2010, 2012, 2018 The Linux Foundation. All rights >> reserved. >> * >> * Acknowledgements: >> * This file is based on hci_ll.c, which was... >> @@ -35,6 +35,10 @@ >> #include <linux/mod_devicetable.h> >> #include <linux/module.h> >> #include <linux/serdev.h> >> +#include <asm-generic/delay.h> >> +#include <linux/platform_device.h> >> +#include <linux/regulator/consumer.h> >> +#include <linux/of_device.h> > > AFAIK the convention is to order includes alphabetically. [Bala]: will update. > >> +static struct btqca_power *qca; > > This limits the driver to a single instance. This is probably the most > common use case, but in general it's preferable not to have this kind > of limitations. [Bala]: yes, we need for one instance when the driver got probed. > >> static void __serial_clock_on(struct tty_struct *tty) >> { >> /* TODO: Some chipset requires to enable UART clock on client >> @@ -463,7 +506,12 @@ static int qca_open(struct hci_uart *hu) >> serdev_device_open(hu->serdev); >> >> qcadev = serdev_device_get_drvdata(hu->serdev); >> - gpiod_set_value_cansleep(qcadev->bt_en, 1); >> + if (qcadev->btsoc_type == BTQCA_CHEROKEE) { >> + hu->init_speed = qcadev->init_speed; >> + hu->oper_speed = qcadev->oper_speed; >> + btqca_power_setup(true); >> + } else >> + gpiod_set_value_cansleep(qcadev->bt_en, 1); > > Use curly braces for the else branch too. [Bala]: will update. > >> +static int qca_send_poweron_cmd(struct hci_dev *hdev) >> +{ >> + struct hci_uart *hu = hci_get_drvdata(hdev); >> + struct qca_data *qca = hu->priv; >> + struct sk_buff *skb; >> + u8 cmd; >> + >> + BT_DBG("%s sending power on command to btsoc", hdev->name); > > Use bt_dev_dbg(), same for other BT_XXX(). > >> + /* By sending 0xFC host is trying to power up the soc */ > > nit: SoC, same a few lines below. > >> + cmd = CHEROKEE_POWERON_PULSE; >> + skb = bt_skb_alloc(sizeof(cmd), GFP_ATOMIC); > > Use GFP_KERNEL, the code sleeps a few lines below, hence it must > definitely not be called in atomic context. [Bala]: will update. > >> + if (!skb) { >> + BT_ERR("Failed to allocate memory for skb packet"); >> + return -ENOMEM; >> + } >> + >> + skb_put_data(skb, &cmd, sizeof(cmd)); >> + hci_skb_pkt_type(skb) = HCI_COMMAND_PKT; >> + >> + skb_queue_tail(&qca->txq, skb); >> + hci_uart_tx_wakeup(hu); >> + >> + /* Wait for 100 us for soc to settle down */ >> + set_current_state(TASK_UNINTERRUPTIBLE); >> + schedule_timeout(usecs_to_jiffies(100)); >> + set_current_state(TASK_INTERRUPTIBLE); >> + >> + return 0; >> +} >> + >> +static int qca_send_poweroff_cmd(struct hci_dev *hdev) >> +{ >> + struct hci_uart *hu = hci_get_drvdata(hdev); >> + struct qca_data *qca = hu->priv; >> + struct sk_buff *skb; >> + u8 cmd; >> + >> + BT_DBG("%s sending power off command to btsoc", hdev->name); >> + /* By sending 0xC0 host is trying to power off the soc */ >> + cmd = CHEROKEE_POWEROFF_PULSE; >> + skb = bt_skb_alloc(sizeof(cmd), GFP_ATOMIC); >> + if (!skb) { >> + BT_ERR("Failed to allocate memory for skb packet"); >> + return -ENOMEM; >> + } >> + >> + skb_put_data(skb, &cmd, sizeof(cmd)); >> + hci_skb_pkt_type(skb) = HCI_COMMAND_PKT; >> + >> + skb_queue_tail(&qca->txq, skb); >> + hci_uart_tx_wakeup(hu); >> + >> + /* Wait for 100 us for soc to settle down */ >> + set_current_state(TASK_UNINTERRUPTIBLE); >> + schedule_timeout(usecs_to_jiffies(100)); >> + set_current_state(TASK_INTERRUPTIBLE); >> + >> + return 0; >> +} > > This function is almost a clone of qca_send_poweron_cmd(), move the > common code to something like qca_send_cmd() and call it from > qca_send_poweron/off_cmd(). [Bala]: will create on function for both ON and OFF. > >> +static int qca_serdev_open(struct hci_uart *hu) >> +{ >> + int ret = 0; >> + >> + if (hu->serdev) >> + serdev_device_open(hu->serdev); > > Check return value. [Bala]: as we are not checking in qca_open, the return in this function is to know the serdev function availability. > > Add curly braces to the if branch too. [Bala]: will update. > >> +static int qca_serdev_close(struct hci_uart *hu) >> +{ >> + int ret = 0; >> + >> + if (hu->serdev) >> + serdev_device_close(hu->serdev); > > Add curly braces to the if branch too. [Bala]: will update. > >> static int qca_setup(struct hci_uart *hu) >> { >> struct hci_dev *hdev = hu->hdev; >> struct qca_data *qca = hu->priv; >> + struct qca_serdev *qcadev; >> unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200; >> int ret; >> + int soc_ver; >> + >> + qcadev = serdev_device_get_drvdata(hu->serdev); >> + >> + switch (qcadev->btsoc_type) { >> + case BTQCA_CHEROKEE: >> + bt_dev_info(hdev, "setting up wcn3990"); >> + /* Patch downloading has to be done without IBS mode */ >> + clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); >> + /* Setup initial baudrate */ >> + speed = 0; >> + if (hu->init_speed) >> + speed = hu->init_speed; >> + else if (hu->proto->init_speed) >> + speed = hu->proto->init_speed; >> + >> + if (speed) >> + host_set_baudrate(hu, speed); > > Add curly braces. [Bala]: will update. > >> + else { >> + bt_dev_err(hdev, "initial speed %u", speed); >> + return -1; >> + } >> >> - bt_dev_info(hdev, "ROME setup"); >> + /* disable flow control, as chip is still not turned on */ >> + hci_uart_set_flow_control(hu, true); > > The interface of this function is confusing. enable = true disables > flow control ... Not the fault of this driver though :) [Bala]: yes it is bit confusing. i taught to update.. but not sure of impact. so instead of updating, using the same function and written a comment above. > >> + /* send poweron command to btsoc */ >> + ret = qca_send_poweron_cmd(hdev); >> + if (ret) { >> + bt_dev_err(hdev, "Failed to send power on command"); >> + return ret; >> + } >> >> - /* Patch downloading has to be done without IBS mode */ >> - clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); >> + /* close serial port */ >> + ret = qca_serdev_close(hu); >> + if (ret) >> + return ret; >> + /* open serial port */ >> + ret = qca_serdev_open(hu); >> + if (ret) >> + return ret; >> >> - /* Setup initial baudrate */ >> - speed = 0; >> - if (hu->init_speed) >> - speed = hu->init_speed; >> - else if (hu->proto->init_speed) >> - speed = hu->proto->init_speed; >> + /* Setup initial baudrate */ >> + speed = 0; >> + if (hu->init_speed) >> + speed = hu->init_speed; >> + else if (hu->proto->init_speed) >> + speed = hu->proto->init_speed; >> + if (speed) >> + host_set_baudrate(hu, speed); > > Add curly braces. [Bala]: will update. > >> + else { >> + BT_ERR("%s:initial speed %u", hdev->name, speed); >> + return -1; >> + } >> >> - if (speed) >> - host_set_baudrate(hu, speed); >> + /* Enable flow control */ >> + hci_uart_set_flow_control(hu, false); >> + /* wait until flow control settled */ >> + mdelay(100); > > A busy wait of 100ms doesn't seem a good idea. Use msleep() > instead. Is it really necessary to wait that long? [Bala]: yes this delay is required for BT Soc to bootup and settle down. > >> + bt_dev_info(hdev, "wcn3990 Patch Version Request"); >> + ret = rome_patch_ver_req(hdev, &soc_ver); >> + if (ret < 0 || soc_ver == 0) { >> + BT_ERR("%s: Failed to get version 0x%x", hdev->name, >> + ret); >> + return ret; >> + } >> >> - /* Setup user speed if needed */ >> - speed = 0; >> - if (hu->oper_speed) >> - speed = hu->oper_speed; >> - else if (hu->proto->oper_speed) >> - speed = hu->proto->oper_speed; >> + bt_dev_info(hdev, "wcn3990 controller version 0x%08x", soc_ver); >> + >> + /* clear flow control */ >> + hci_uart_set_flow_control(hu, true); >> + /* set operating speed */ >> + speed = 0; >> + if (hu->oper_speed) >> + speed = hu->oper_speed; >> + else if (hu->proto->oper_speed) >> + speed = hu->proto->oper_speed; >> + if (speed) { >> + qca_baudrate = qca_get_baudrate_value(speed); >> + bt_dev_info(hdev, "Set UART speed to %d", speed); >> + ret = qca_set_baudrate(hdev, qca_baudrate); >> + if (ret) { >> + BT_ERR("%s:Failed to change the baud rate(%d)", >> + hdev->name, ret); >> + return ret; >> + } >> + if (speed) >> + host_set_baudrate(hu, speed); > > Add curly braces. [Bala]: will update. > >> + else { >> + BT_ERR("%s:Error in setting operator speed:%u", >> + hdev->name, speed); >> + return -1; >> + } >> + } >> >> - if (speed) { >> - qca_baudrate = qca_get_baudrate_value(speed); >> + /* Set flow control */ >> + hci_uart_set_flow_control(hu, false); >> + /*Setup patch and NVM configurations */ > > Add blank before 'Setup' and remove one before 'NVM'. [Bala]: will update. > >> + ret = qca_uart_setup_cherokee(hdev, qca_baudrate, &soc_ver); >> + if (!ret) { >> + set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); >> + qca_debugfs_init(hdev); >> + } else if (ret == -ENOENT) { >> + /* No patch/nvm-config found, run with original >> + * fw/config. >> + */ >> + ret = 0; >> + } else if (ret == -EAGAIN) { >> + /* >> + * Userspace firmware loader will return -EAGAIN in >> + * case no patch/nvm-config is found, so run with >> + * original fw/config. >> + */ >> + ret = 0; >> + } >> >> - bt_dev_info(hdev, "Set UART speed to %d", speed); >> - ret = qca_set_baudrate(hdev, qca_baudrate); >> - if (ret) { >> - bt_dev_err(hdev, "Failed to change the baud rate (%d)", >> - ret); >> + /* Setup wcn3990 bdaddr */ >> + hu->hdev->set_bdaddr = qca_set_bdaddr_rome; >> + >> + return ret; >> + >> + default: > > What follows looks similar to the Cherokee path. I didn't look at all > the details, but it's probably possible to share some more code. [Bala]: yes these are two different chip. we also have difference in setup. the follwing are major differences Cherokee uses flow control. where ROME flow control is disabled. ON sequence also varies. > >> + bt_dev_info(hdev, "ROME setup"); >> + >> + /* Patch downloading has to be done without IBS mode */ >> + clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); >> + >> + /* Setup initial baudrate */ >> + speed = 0; >> + if (hu->init_speed) >> + speed = hu->init_speed; >> + else if (hu->proto->init_speed) >> + speed = hu->proto->init_speed; >> + >> + if (speed) >> + host_set_baudrate(hu, speed); >> + >> + /* Setup user speed if needed */ >> + speed = 0; >> + if (hu->oper_speed) >> + speed = hu->oper_speed; >> + else if (hu->proto->oper_speed) >> + speed = hu->proto->oper_speed; >> + >> + if (speed) { >> + qca_baudrate = qca_get_baudrate_value(speed); >> + >> + bt_dev_info(hdev, "Set UART speed to %d", speed); >> + ret = qca_set_baudrate(hdev, qca_baudrate); >> + if (ret) { >> + bt_dev_err(hdev, "Failed to change the baud rate (%d)", >> + ret); >> return ret; > > Fix indentation. [Bala]: will update. > >> +static const struct btqca_vreg_data cherokee_data = { >> + .soc_type = BTQCA_CHEROKEE, >> + .vregs = (struct btqca_vreg []) { >> + { "vddio", 1352000, 1352000, 0 }, >> + { "vddxtal", 1904000, 2040000, 0 }, >> + { "vddcore", 1800000, 1800000, 1 }, >> + { "vddpa", 130400, 1304000, 1 }, > > 0 missing for min_v? [Bala]: min_v is the minimum voltage required for BT chip. > >> + { "vddldo", 3000000, 3312000, 1 }, >> + }, >> + .num_vregs = 5, >> +}; >> + >> +void btqca_disable_regulators(int reg_nu, struct btqca_vreg *vregs) >> +{ >> + /* disable the regulator if requested by user >> + * or when fault in any regulator. >> + */ >> + for (reg_nu = reg_nu - 1; reg_nu >= 0 ; reg_nu--) { > > Better use a local variable for iteration instead of the function > parameter [Bala]: will update. > >> +int btqca_power_setup(bool on) >> +{ >> + int ret = 0; >> + int i; >> + struct btqca_vreg *vregs; >> + >> + if (!qca || !qca->vreg_data || !qca->vreg_bulk) >> + return -EINVAL; >> + vregs = qca->vreg_data->vregs; >> + >> + BT_DBG("on: %d", on); >> + /* turn on if regualtors are off */ >> + if (on == true && qca->vreg_status == false) { > > if (on && !qca->vreg_status) > > You might also consider a more expressive name instead of vreg_status, > something like vregs_on. [Bala]: will update. > >> + qca->vreg_status = true; >> + for (i = 0; ret == 0 && i < qca->vreg_data->num_vregs; i++) { > > Better check ret inline and break when an error is encountered [Bala]: will update. > >> + regulator_set_voltage(qca->vreg_bulk[i].consumer, >> + vregs[i].min_v, >> + vregs[i].max_v); > > Check return value. [Bala]: i am checking the status for regulator enable do we really require to check the status. as this same regulators are used by different sub systems. we will get an error during regulator enable when voltages are not settled down. > >> + >> + if (vregs[i].load_ua) >> + regulator_set_load(qca->vreg_bulk[i].consumer, >> + vregs[i].load_ua); > > Check return value. > >> + ret = regulator_enable(qca->vreg_bulk[i].consumer); >> + } > > Fix indentation. [Bala]: will update. > >> + } else if (on == false && qca->vreg_status == true) { > > (!on && qca->vreg_status) > >> + qca->vreg_status = false; >> + /* turn of regualtor in reverse order */ > > 'off, regulator' [Bala]: will update. > >> + btqca_disable_regulators(qca->vreg_data->num_vregs, vregs); >> + } >> + >> + /* regulatos fails to enable */ > > 'regulators failed' [Bala]: will update. > >> + if (ret) { >> + qca->vreg_status = false; >> + BT_ERR("failed to enable regualtor:%s", vregs[i].name); > > 'regulator' > >> + /* set regulator voltage and load to zero */ >> + regulator_set_voltage(qca->vreg_bulk[i].consumer, >> + 0, vregs[i].max_v); > > check return value. > >> static int qca_serdev_probe(struct serdev_device *serdev) >> { >> struct qca_serdev *qcadev; >> - int err; >> + const struct btqca_vreg_data *data; >> + int err = 0; >> >> qcadev = devm_kzalloc(&serdev->dev, sizeof(*qcadev), GFP_KERNEL); >> if (!qcadev) >> return -ENOMEM; >> >> qcadev->serdev_hu.serdev = serdev; >> + data = of_device_get_match_data(&serdev->dev); >> + if (data && data->soc_type == BTQCA_CHEROKEE) >> + qcadev->btsoc_type = BTQCA_CHEROKEE; >> + else >> + qcadev->btsoc_type = BTQCA_ROME; >> + >> serdev_device_set_drvdata(serdev, qcadev); >> + if (qcadev->btsoc_type == BTQCA_CHEROKEE) { >> + qca = kzalloc(sizeof(struct btqca_power), GFP_KERNEL); > > Use devm_kzalloc() [Bala]: will update. > >> + if (!qca) >> + return -ENOMEM; >> + >> + qca->dev = &serdev->dev; >> + qca->vreg_data = data; >> + err = init_regulators(qca, data->vregs, data->num_vregs); >> + if (err) { >> + BT_ERR("Failed to init regualtors:%d", err); > > 'regulators' [Bala]: will update. > >> + kfree(qca); >> + goto out; >> + } >> >> - qcadev->bt_en = devm_gpiod_get(&serdev->dev, "enable", >> - GPIOD_OUT_LOW); >> - if (IS_ERR(qcadev->bt_en)) { >> - dev_err(&serdev->dev, "failed to acquire enable gpio\n"); >> - return PTR_ERR(qcadev->bt_en); >> - } >> + /* set voltage regulator status as false */ >> + qca->vreg_status = false; >> + /* get operating speed */ >> + device_property_read_u32(&serdev->dev, "oper-speed", >> + &qcadev->oper_speed); >> + device_property_read_u32(&serdev->dev, "init-speed", >> + &qcadev->init_speed); >> + if (!qcadev->oper_speed) >> + BT_INFO("DTS entry for operating speed is >> - disabled"); > > The message isn't very clear. The entry isn't disabled, it doesn't > exist. [Bala]: will update. > >> static void qca_serdev_remove(struct serdev_device *serdev) >> @@ -1047,12 +1454,16 @@ static void qca_serdev_remove(struct >> serdev_device *serdev) >> struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev); >> >> hci_uart_unregister_device(&qcadev->serdev_hu); >> - >> - clk_disable_unprepare(qcadev->susclk); >> + if (qcadev->btsoc_type == BTQCA_CHEROKEE) { >> + btqca_power_setup(false); >> + kfree(qca); >> + } else >> + clk_disable_unprepare(qcadev->susclk); > > Add curly braces. [Bala]: will update. Thanks for code review. will send a updated patch with the changes. -- Regards Balakrishna. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v4 2/3] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990. 2018-05-09 10:07 ` Balakrishna Godavarthi @ 2018-05-09 17:24 ` Matthias Kaehlcke 2018-05-10 16:01 ` Balakrishna Godavarthi 0 siblings, 1 reply; 15+ messages in thread From: Matthias Kaehlcke @ 2018-05-09 17:24 UTC (permalink / raw) To: Balakrishna Godavarthi Cc: marcel, johan.hedberg, linux-bluetooth, rtatiya, hemantg, linux-arm-msm Hi Balakrishna, On Wed, May 09, 2018 at 03:37:34PM +0530, Balakrishna Godavarthi wrote: > Hi, > Please find my comments inline. > > On 2018-05-05 06:47, Matthias Kaehlcke wrote: > > Hi, > > > > On Fri, May 04, 2018 at 09:05:05PM +0530, Balakrishna Godavarthi wrote: > > > Add support to set voltage/current of various regulators > > > to power up/down Bluetooth chip wcn3990. > > > Add support to read baudrate from dts. > > > > > > Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org> > > > --- > > > drivers/bluetooth/hci_qca.c | 555 > > > ++++++++++++++++++++++++++++++++++++++------ > > > 1 file changed, 483 insertions(+), 72 deletions(-) > > > > > > diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c > > > index f05382b..075fab7 100644 > > > --- a/drivers/bluetooth/hci_qca.c > > > +++ b/drivers/bluetooth/hci_qca.c > > > ... > > > - bt_dev_info(hdev, "ROME setup"); > > > + /* disable flow control, as chip is still not turned on */ > > > + hci_uart_set_flow_control(hu, true); > > > > The interface of this function is confusing. enable = true disables > > flow control ... Not the fault of this driver though :) > [Bala]: yes it is bit confusing. i taught to update.. but not sure of > impact. > so instead of updating, using the same function and written a > comment above. Sure, not much you can do about it. Just mentioned it since I was about to comment that things are done inversely, but tean checked hci_uart_set_flow_control() and saw that it has this odd interface. Folks more familiar with the Bluetooth subsystem are probably already used to it ;-) > > > - if (speed) > > > - host_set_baudrate(hu, speed); > > > + /* Enable flow control */ > > > + hci_uart_set_flow_control(hu, false); > > > + /* wait until flow control settled */ > > > + mdelay(100); > > > > A busy wait of 100ms doesn't seem a good idea. Use msleep() > > instead. Is it really necessary to wait that long? > [Bala]: yes this delay is required for BT Soc to bootup and settle down. :( > > What follows looks similar to the Cherokee path. I didn't look at all > > the details, but it's probably possible to share some more code. > [Bala]: yes these are two different chip. > we also have difference in setup. the follwing are major differences > Cherokee uses flow control. where ROME flow control is disabled. > ON sequence also varies. Ok, I'll give it another pass in the next revision to see if I have suggestions to make it at least a bit less redundant. > > > +static const struct btqca_vreg_data cherokee_data = { > > > + .soc_type = BTQCA_CHEROKEE, > > > + .vregs = (struct btqca_vreg []) { > > > + { "vddio", 1352000, 1352000, 0 }, > > > + { "vddxtal", 1904000, 2040000, 0 }, > > > + { "vddcore", 1800000, 1800000, 1 }, > > > + { "vddpa", 130400, 1304000, 1 }, > > > > 0 missing for min_v? > > [Bala]: min_v is the minimum voltage required for BT chip. I referred to the value '130400', which happens to be exactly 1/10 of the max_v '1304000', so I suspect the voltages are the same and a zero is missing. > > > + regulator_set_voltage(qca->vreg_bulk[i].consumer, > > > + vregs[i].min_v, > > > + vregs[i].max_v); > > > > Check return value. > [Bala]: i am checking the status for regulator enable > do we really require to check the status. as this same regulators > are used by different sub systems. > we will get an error during regulator enable when voltages are not > settled down. regulator_set_voltage() could fail due to requesting a voltage range not supported by the regulator. In this case regulator_enable() could still succeed, but not supply the requested voltage. Thanks Matthias ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v4 2/3] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990. 2018-05-09 17:24 ` Matthias Kaehlcke @ 2018-05-10 16:01 ` Balakrishna Godavarthi 0 siblings, 0 replies; 15+ messages in thread From: Balakrishna Godavarthi @ 2018-05-10 16:01 UTC (permalink / raw) To: Matthias Kaehlcke Cc: marcel, johan.hedberg, linux-bluetooth, rtatiya, hemantg, linux-arm-msm Hi Matthias, On 2018-05-09 22:54, Matthias Kaehlcke wrote: > Hi Balakrishna, > > On Wed, May 09, 2018 at 03:37:34PM +0530, Balakrishna Godavarthi wrote: >> Hi, >> Please find my comments inline. >> >> On 2018-05-05 06:47, Matthias Kaehlcke wrote: >> > Hi, >> > >> > On Fri, May 04, 2018 at 09:05:05PM +0530, Balakrishna Godavarthi wrote: >> > > Add support to set voltage/current of various regulators >> > > to power up/down Bluetooth chip wcn3990. >> > > Add support to read baudrate from dts. >> > > >> > > Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org> >> > > --- >> > > drivers/bluetooth/hci_qca.c | 555 >> > > ++++++++++++++++++++++++++++++++++++++------ >> > > 1 file changed, 483 insertions(+), 72 deletions(-) >> > > >> > > diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c >> > > index f05382b..075fab7 100644 >> > > --- a/drivers/bluetooth/hci_qca.c >> > > +++ b/drivers/bluetooth/hci_qca.c >> > > ... >> > > - bt_dev_info(hdev, "ROME setup"); >> > > + /* disable flow control, as chip is still not turned on */ >> > > + hci_uart_set_flow_control(hu, true); >> > >> > The interface of this function is confusing. enable = true disables >> > flow control ... Not the fault of this driver though :) >> [Bala]: yes it is bit confusing. i taught to update.. but not sure of >> impact. >> so instead of updating, using the same function and written a >> comment above. > > Sure, not much you can do about it. Just mentioned it since I was > about to comment that things are done inversely, but tean checked > hci_uart_set_flow_control() and saw that it has this odd > interface. Folks more familiar with the Bluetooth subsystem are > probably already used to it ;-) > >> > > - if (speed) >> > > - host_set_baudrate(hu, speed); >> > > + /* Enable flow control */ >> > > + hci_uart_set_flow_control(hu, false); >> > > + /* wait until flow control settled */ >> > > + mdelay(100); >> > >> > A busy wait of 100ms doesn't seem a good idea. Use msleep() >> > instead. Is it really necessary to wait that long? >> [Bala]: yes this delay is required for BT Soc to bootup and settle >> down. > > :( > >> > What follows looks similar to the Cherokee path. I didn't look at all >> > the details, but it's probably possible to share some more code. >> [Bala]: yes these are two different chip. >> we also have difference in setup. the follwing are major >> differences >> Cherokee uses flow control. where ROME flow control is >> disabled. >> ON sequence also varies. > > Ok, I'll give it another pass in the next revision to see if I have > suggestions to make it at least a bit less redundant. > >> > > +static const struct btqca_vreg_data cherokee_data = { >> > > + .soc_type = BTQCA_CHEROKEE, >> > > + .vregs = (struct btqca_vreg []) { >> > > + { "vddio", 1352000, 1352000, 0 }, >> > > + { "vddxtal", 1904000, 2040000, 0 }, >> > > + { "vddcore", 1800000, 1800000, 1 }, >> > > + { "vddpa", 130400, 1304000, 1 }, >> > >> > 0 missing for min_v? >> >> [Bala]: min_v is the minimum voltage required for BT chip. > > I referred to the value '130400', which happens to be exactly 1/10 of > the max_v '1304000', so I suspect the voltages are the same and a zero > is missing. > [Bala]: Good catch, the same regulator is used for WLAN too. that could be reason i could not able to catch this issue during testing will update and retest it again. >> > > + regulator_set_voltage(qca->vreg_bulk[i].consumer, >> > > + vregs[i].min_v, >> > > + vregs[i].max_v); >> > >> > Check return value. >> [Bala]: i am checking the status for regulator enable >> do we really require to check the status. as this same >> regulators >> are used by different sub systems. >> we will get an error during regulator enable when voltages are >> not >> settled down. > > regulator_set_voltage() could fail due to requesting a voltage range > not supported by the regulator. In this case regulator_enable() could > still succeed, but not supply the requested voltage. > [Bala]: will catch the return status. > Thanks > > Matthias I will send the patch after testing these changes. -- Regards Balakrishna. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v4 2/3] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990. 2018-05-04 15:35 ` [PATCH v4 2/3] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth " Balakrishna Godavarthi 2018-05-05 1:17 ` Matthias Kaehlcke @ 2018-05-05 19:21 ` kbuild test robot 2018-05-05 19:45 ` kbuild test robot 2018-05-05 20:11 ` [RFC PATCH] Bluetooth: hci_qca: btqca_disable_regulators() can be static kbuild test robot 3 siblings, 0 replies; 15+ messages in thread From: kbuild test robot @ 2018-05-05 19:21 UTC (permalink / raw) To: Balakrishna Godavarthi Cc: kbuild-all, marcel, johan.hedberg, linux-bluetooth, rtatiya, hemantg, linux-arm-msm, Balakrishna Godavarthi [-- Attachment #1: Type: text/plain, Size: 10191 bytes --] Hi Balakrishna, Thank you for the patch! Yet something to improve: [auto build test ERROR on bluetooth-next/master] [also build test ERROR on next-20180504] [cannot apply to bluetooth/master v4.17-rc3] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/Balakrishna-Godavarthi/dt-bindings-net-bluetooth-Add-device-tree-bindings-for-QTI-chip-wcn3990/20180506-004430 base: https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master config: x86_64-randconfig-x014-201818 (attached as .config) compiler: gcc-7 (Debian 7.3.0-16) 7.3.0 reproduce: # save the attached .config to linux build tree make ARCH=x86_64 Note: the linux-review/Balakrishna-Godavarthi/dt-bindings-net-bluetooth-Add-device-tree-bindings-for-QTI-chip-wcn3990/20180506-004430 HEAD 8ea35b4e8656709a14f0170188ef9004ac96b4ac builds fine. It only hurts bisectibility. All error/warnings (new ones prefixed by >>): drivers//bluetooth/hci_qca.c: In function 'qca_open': >> drivers//bluetooth/hci_qca.c:512:4: error: implicit declaration of function 'btqca_power_setup'; did you mean 'ether_setup'? [-Werror=implicit-function-declaration] btqca_power_setup(true); ^~~~~~~~~~~~~~~~~ ether_setup drivers//bluetooth/hci_qca.c: In function 'qca_close': >> drivers//bluetooth/hci_qca.c:604:4: error: implicit declaration of function 'qca_btsoc_cleanup'; did you mean 'hci_sock_cleanup'? [-Werror=implicit-function-declaration] qca_btsoc_cleanup(hu->hdev); ^~~~~~~~~~~~~~~~~ hci_sock_cleanup drivers//bluetooth/hci_qca.c: In function 'qca_send_poweron_cmd': >> drivers//bluetooth/hci_qca.c:988:8: error: 'CHEROKEE_POWERON_PULSE' undeclared (first use in this function) cmd = CHEROKEE_POWERON_PULSE; ^~~~~~~~~~~~~~~~~~~~~~ drivers//bluetooth/hci_qca.c:988:8: note: each undeclared identifier is reported only once for each function it appears in drivers//bluetooth/hci_qca.c: In function 'qca_send_poweroff_cmd': >> drivers//bluetooth/hci_qca.c:1018:8: error: 'CHEROKEE_POWEROFF_PULSE' undeclared (first use in this function) cmd = CHEROKEE_POWEROFF_PULSE; ^~~~~~~~~~~~~~~~~~~~~~~ drivers//bluetooth/hci_qca.c: In function 'qca_setup': >> drivers//bluetooth/hci_qca.c:1144:9: error: implicit declaration of function 'rome_patch_ver_req'; did you mean 'blk_path_error'? [-Werror=implicit-function-declaration] ret = rome_patch_ver_req(hdev, &soc_ver); ^~~~~~~~~~~~~~~~~~ blk_path_error >> drivers//bluetooth/hci_qca.c:1182:9: error: implicit declaration of function 'qca_uart_setup_cherokee'; did you mean 'qca_uart_setup_rome'? [-Werror=implicit-function-declaration] ret = qca_uart_setup_cherokee(hdev, qca_baudrate, &soc_ver); ^~~~~~~~~~~~~~~~~~~~~~~ qca_uart_setup_rome drivers//bluetooth/hci_qca.c: At top level: >> drivers//bluetooth/hci_qca.c:1308:5: error: conflicting types for 'btqca_power_setup' int btqca_power_setup(bool on) ^~~~~~~~~~~~~~~~~ drivers//bluetooth/hci_qca.c:1309:1: note: an argument type that has a default promotion can't match an empty parameter name list declaration { ^ drivers//bluetooth/hci_qca.c:512:4: note: previous implicit declaration of 'btqca_power_setup' was here btqca_power_setup(true); ^~~~~~~~~~~~~~~~~ drivers//bluetooth/hci_qca.c: In function 'btqca_power_setup': >> drivers//bluetooth/hci_qca.c:1346:3: warning: this 'if' clause does not guard... [-Wmisleading-indentation] if (vregs[i].load_ua) ^~ drivers//bluetooth/hci_qca.c:1349:4: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if' btqca_disable_regulators(i+1, vregs); ^~~~~~~~~~~~~~~~~~~~~~~~ cc1: some warnings being treated as errors vim +512 drivers//bluetooth/hci_qca.c 442 443 /* Initialize protocol */ 444 static int qca_open(struct hci_uart *hu) 445 { 446 struct qca_serdev *qcadev; 447 struct qca_data *qca; 448 449 BT_DBG("hu %p qca_open", hu); 450 451 qca = kzalloc(sizeof(struct qca_data), GFP_ATOMIC); 452 if (!qca) 453 return -ENOMEM; 454 455 skb_queue_head_init(&qca->txq); 456 skb_queue_head_init(&qca->tx_wait_q); 457 spin_lock_init(&qca->hci_ibs_lock); 458 qca->workqueue = alloc_ordered_workqueue("qca_wq", 0); 459 if (!qca->workqueue) { 460 BT_ERR("QCA Workqueue not initialized properly"); 461 kfree(qca); 462 return -ENOMEM; 463 } 464 465 INIT_WORK(&qca->ws_awake_rx, qca_wq_awake_rx); 466 INIT_WORK(&qca->ws_awake_device, qca_wq_awake_device); 467 INIT_WORK(&qca->ws_rx_vote_off, qca_wq_serial_rx_clock_vote_off); 468 INIT_WORK(&qca->ws_tx_vote_off, qca_wq_serial_tx_clock_vote_off); 469 470 qca->hu = hu; 471 472 /* Assume we start with both sides asleep -- extra wakes OK */ 473 qca->tx_ibs_state = HCI_IBS_TX_ASLEEP; 474 qca->rx_ibs_state = HCI_IBS_RX_ASLEEP; 475 476 /* clocks actually on, but we start votes off */ 477 qca->tx_vote = false; 478 qca->rx_vote = false; 479 qca->flags = 0; 480 481 qca->ibs_sent_wacks = 0; 482 qca->ibs_sent_slps = 0; 483 qca->ibs_sent_wakes = 0; 484 qca->ibs_recv_wacks = 0; 485 qca->ibs_recv_slps = 0; 486 qca->ibs_recv_wakes = 0; 487 qca->vote_last_jif = jiffies; 488 qca->vote_on_ms = 0; 489 qca->vote_off_ms = 0; 490 qca->votes_on = 0; 491 qca->votes_off = 0; 492 qca->tx_votes_on = 0; 493 qca->tx_votes_off = 0; 494 qca->rx_votes_on = 0; 495 qca->rx_votes_off = 0; 496 497 hu->priv = qca; 498 499 timer_setup(&qca->wake_retrans_timer, hci_ibs_wake_retrans_timeout, 0); 500 qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS; 501 502 timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0); 503 qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS; 504 505 if (hu->serdev) { 506 serdev_device_open(hu->serdev); 507 508 qcadev = serdev_device_get_drvdata(hu->serdev); 509 if (qcadev->btsoc_type == BTQCA_CHEROKEE) { 510 hu->init_speed = qcadev->init_speed; 511 hu->oper_speed = qcadev->oper_speed; > 512 btqca_power_setup(true); 513 } else 514 gpiod_set_value_cansleep(qcadev->bt_en, 1); 515 } 516 517 BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u", 518 qca->tx_idle_delay, qca->wake_retrans); 519 520 return 0; 521 } 522 523 static void qca_debugfs_init(struct hci_dev *hdev) 524 { 525 struct hci_uart *hu = hci_get_drvdata(hdev); 526 struct qca_data *qca = hu->priv; 527 struct dentry *ibs_dir; 528 umode_t mode; 529 530 if (!hdev->debugfs) 531 return; 532 533 ibs_dir = debugfs_create_dir("ibs", hdev->debugfs); 534 535 /* read only */ 536 mode = S_IRUGO; 537 debugfs_create_u8("tx_ibs_state", mode, ibs_dir, &qca->tx_ibs_state); 538 debugfs_create_u8("rx_ibs_state", mode, ibs_dir, &qca->rx_ibs_state); 539 debugfs_create_u64("ibs_sent_sleeps", mode, ibs_dir, 540 &qca->ibs_sent_slps); 541 debugfs_create_u64("ibs_sent_wakes", mode, ibs_dir, 542 &qca->ibs_sent_wakes); 543 debugfs_create_u64("ibs_sent_wake_acks", mode, ibs_dir, 544 &qca->ibs_sent_wacks); 545 debugfs_create_u64("ibs_recv_sleeps", mode, ibs_dir, 546 &qca->ibs_recv_slps); 547 debugfs_create_u64("ibs_recv_wakes", mode, ibs_dir, 548 &qca->ibs_recv_wakes); 549 debugfs_create_u64("ibs_recv_wake_acks", mode, ibs_dir, 550 &qca->ibs_recv_wacks); 551 debugfs_create_bool("tx_vote", mode, ibs_dir, &qca->tx_vote); 552 debugfs_create_u64("tx_votes_on", mode, ibs_dir, &qca->tx_votes_on); 553 debugfs_create_u64("tx_votes_off", mode, ibs_dir, &qca->tx_votes_off); 554 debugfs_create_bool("rx_vote", mode, ibs_dir, &qca->rx_vote); 555 debugfs_create_u64("rx_votes_on", mode, ibs_dir, &qca->rx_votes_on); 556 debugfs_create_u64("rx_votes_off", mode, ibs_dir, &qca->rx_votes_off); 557 debugfs_create_u64("votes_on", mode, ibs_dir, &qca->votes_on); 558 debugfs_create_u64("votes_off", mode, ibs_dir, &qca->votes_off); 559 debugfs_create_u32("vote_on_ms", mode, ibs_dir, &qca->vote_on_ms); 560 debugfs_create_u32("vote_off_ms", mode, ibs_dir, &qca->vote_off_ms); 561 562 /* read/write */ 563 mode = S_IRUGO | S_IWUSR; 564 debugfs_create_u32("wake_retrans", mode, ibs_dir, &qca->wake_retrans); 565 debugfs_create_u32("tx_idle_delay", mode, ibs_dir, 566 &qca->tx_idle_delay); 567 } 568 569 /* Flush protocol data */ 570 static int qca_flush(struct hci_uart *hu) 571 { 572 struct qca_data *qca = hu->priv; 573 574 BT_DBG("hu %p qca flush", hu); 575 576 skb_queue_purge(&qca->tx_wait_q); 577 skb_queue_purge(&qca->txq); 578 579 return 0; 580 } 581 582 /* Close protocol */ 583 static int qca_close(struct hci_uart *hu) 584 { 585 struct qca_serdev *qcadev; 586 struct qca_data *qca = hu->priv; 587 588 BT_DBG("hu %p qca close", hu); 589 590 serial_clock_vote(HCI_IBS_VOTE_STATS_UPDATE, hu); 591 592 skb_queue_purge(&qca->tx_wait_q); 593 skb_queue_purge(&qca->txq); 594 del_timer(&qca->tx_idle_timer); 595 del_timer(&qca->wake_retrans_timer); 596 destroy_workqueue(qca->workqueue); 597 qca->hu = NULL; 598 599 if (hu->serdev) { 600 serdev_device_close(hu->serdev); 601 602 qcadev = serdev_device_get_drvdata(hu->serdev); 603 if (qcadev->btsoc_type == BTQCA_CHEROKEE) > 604 qca_btsoc_cleanup(hu->hdev); 605 else 606 gpiod_set_value_cansleep(qcadev->bt_en, 0); 607 } 608 609 kfree_skb(qca->rx_skb); 610 611 hu->priv = NULL; 612 613 kfree(qca); 614 615 return 0; 616 } 617 --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation [-- Attachment #2: .config.gz --] [-- Type: application/gzip, Size: 26941 bytes --] ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v4 2/3] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990. 2018-05-04 15:35 ` [PATCH v4 2/3] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth " Balakrishna Godavarthi 2018-05-05 1:17 ` Matthias Kaehlcke 2018-05-05 19:21 ` kbuild test robot @ 2018-05-05 19:45 ` kbuild test robot 2018-05-05 20:11 ` [RFC PATCH] Bluetooth: hci_qca: btqca_disable_regulators() can be static kbuild test robot 3 siblings, 0 replies; 15+ messages in thread From: kbuild test robot @ 2018-05-05 19:45 UTC (permalink / raw) To: Balakrishna Godavarthi Cc: kbuild-all, marcel, johan.hedberg, linux-bluetooth, rtatiya, hemantg, linux-arm-msm, Balakrishna Godavarthi [-- Attachment #1: Type: text/plain, Size: 5950 bytes --] Hi Balakrishna, Thank you for the patch! Perhaps something to improve: [auto build test WARNING on bluetooth-next/master] [also build test WARNING on next-20180504] [cannot apply to bluetooth/master v4.17-rc3] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/Balakrishna-Godavarthi/dt-bindings-net-bluetooth-Add-device-tree-bindings-for-QTI-chip-wcn3990/20180506-004430 base: https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master config: x86_64-randconfig-x017-201818 (attached as .config) compiler: gcc-7 (Debian 7.3.0-16) 7.3.0 reproduce: # save the attached .config to linux build tree make ARCH=x86_64 All warnings (new ones prefixed by >>): drivers//bluetooth/hci_qca.c: In function 'qca_open': drivers//bluetooth/hci_qca.c:512:4: error: implicit declaration of function 'btqca_power_setup'; did you mean 'ether_setup'? [-Werror=implicit-function-declaration] btqca_power_setup(true); ^~~~~~~~~~~~~~~~~ ether_setup drivers//bluetooth/hci_qca.c: In function 'qca_close': drivers//bluetooth/hci_qca.c:604:4: error: implicit declaration of function 'qca_btsoc_cleanup'; did you mean 'hci_sock_cleanup'? [-Werror=implicit-function-declaration] qca_btsoc_cleanup(hu->hdev); ^~~~~~~~~~~~~~~~~ hci_sock_cleanup drivers//bluetooth/hci_qca.c: In function 'qca_send_poweron_cmd': drivers//bluetooth/hci_qca.c:988:8: error: 'CHEROKEE_POWERON_PULSE' undeclared (first use in this function) cmd = CHEROKEE_POWERON_PULSE; ^~~~~~~~~~~~~~~~~~~~~~ drivers//bluetooth/hci_qca.c:988:8: note: each undeclared identifier is reported only once for each function it appears in drivers//bluetooth/hci_qca.c: In function 'qca_send_poweroff_cmd': drivers//bluetooth/hci_qca.c:1018:8: error: 'CHEROKEE_POWEROFF_PULSE' undeclared (first use in this function) cmd = CHEROKEE_POWEROFF_PULSE; ^~~~~~~~~~~~~~~~~~~~~~~ drivers//bluetooth/hci_qca.c: In function 'qca_setup': drivers//bluetooth/hci_qca.c:1144:9: error: implicit declaration of function 'rome_patch_ver_req'; did you mean 'blk_path_error'? [-Werror=implicit-function-declaration] ret = rome_patch_ver_req(hdev, &soc_ver); ^~~~~~~~~~~~~~~~~~ blk_path_error drivers//bluetooth/hci_qca.c:1182:9: error: implicit declaration of function 'qca_uart_setup_cherokee'; did you mean 'qca_uart_setup_rome'? [-Werror=implicit-function-declaration] ret = qca_uart_setup_cherokee(hdev, qca_baudrate, &soc_ver); ^~~~~~~~~~~~~~~~~~~~~~~ qca_uart_setup_rome drivers//bluetooth/hci_qca.c: At top level: drivers//bluetooth/hci_qca.c:1308:5: error: conflicting types for 'btqca_power_setup' int btqca_power_setup(bool on) ^~~~~~~~~~~~~~~~~ drivers//bluetooth/hci_qca.c:1309:1: note: an argument type that has a default promotion can't match an empty parameter name list declaration { ^ drivers//bluetooth/hci_qca.c:512:4: note: previous implicit declaration of 'btqca_power_setup' was here btqca_power_setup(true); ^~~~~~~~~~~~~~~~~ In file included from include/linux/kernel.h:10:0, from drivers//bluetooth/hci_qca.c:31: drivers//bluetooth/hci_qca.c: In function 'btqca_power_setup': include/linux/compiler.h:58:2: warning: this 'if' clause does not guard... [-Wmisleading-indentation] if (__builtin_constant_p(!!(cond)) ? !!(cond) : \ ^ include/linux/compiler.h:56:23: note: in expansion of macro '__trace_if' #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) ) ^~~~~~~~~~ >> drivers//bluetooth/hci_qca.c:1346:3: note: in expansion of macro 'if' if (vregs[i].load_ua) ^~ drivers//bluetooth/hci_qca.c:1349:4: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if' btqca_disable_regulators(i+1, vregs); ^~~~~~~~~~~~~~~~~~~~~~~~ cc1: some warnings being treated as errors vim +/if +1346 drivers//bluetooth/hci_qca.c 1307 1308 int btqca_power_setup(bool on) 1309 { 1310 int ret = 0; 1311 int i; 1312 struct btqca_vreg *vregs; 1313 1314 if (!qca || !qca->vreg_data || !qca->vreg_bulk) 1315 return -EINVAL; 1316 vregs = qca->vreg_data->vregs; 1317 1318 BT_DBG("on: %d", on); 1319 /* turn on if regualtors are off */ 1320 if (on == true && qca->vreg_status == false) { 1321 qca->vreg_status = true; 1322 for (i = 0; ret == 0 && i < qca->vreg_data->num_vregs; i++) { 1323 regulator_set_voltage(qca->vreg_bulk[i].consumer, 1324 vregs[i].min_v, 1325 vregs[i].max_v); 1326 1327 if (vregs[i].load_ua) 1328 regulator_set_load(qca->vreg_bulk[i].consumer, 1329 vregs[i].load_ua); 1330 1331 ret = regulator_enable(qca->vreg_bulk[i].consumer); 1332 } 1333 } else if (on == false && qca->vreg_status == true) { 1334 qca->vreg_status = false; 1335 /* turn of regualtor in reverse order */ 1336 btqca_disable_regulators(qca->vreg_data->num_vregs, vregs); 1337 } 1338 1339 /* regulatos fails to enable */ 1340 if (ret) { 1341 qca->vreg_status = false; 1342 BT_ERR("failed to enable regualtor:%s", vregs[i].name); 1343 /* set regulator voltage and load to zero */ 1344 regulator_set_voltage(qca->vreg_bulk[i].consumer, 1345 0, vregs[i].max_v); > 1346 if (vregs[i].load_ua) 1347 regulator_set_load(qca->vreg_bulk[i].consumer, 0); 1348 /* turn off regulators which are enabled */ 1349 btqca_disable_regulators(i+1, vregs); 1350 } 1351 1352 return ret; 1353 } 1354 --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation [-- Attachment #2: .config.gz --] [-- Type: application/gzip, Size: 33451 bytes --] ^ permalink raw reply [flat|nested] 15+ messages in thread
* [RFC PATCH] Bluetooth: hci_qca: btqca_disable_regulators() can be static 2018-05-04 15:35 ` [PATCH v4 2/3] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth " Balakrishna Godavarthi ` (2 preceding siblings ...) 2018-05-05 19:45 ` kbuild test robot @ 2018-05-05 20:11 ` kbuild test robot 3 siblings, 0 replies; 15+ messages in thread From: kbuild test robot @ 2018-05-05 20:11 UTC (permalink / raw) To: Balakrishna Godavarthi Cc: kbuild-all, marcel, johan.hedberg, linux-bluetooth, rtatiya, hemantg, linux-arm-msm, Balakrishna Godavarthi Fixes: 1bab29c5dbe1 ("Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990.") Signed-off-by: Fengguang Wu <fengguang.wu@intel.com> --- hci_qca.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 075fab7..ff9fbe0 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -1291,7 +1291,7 @@ static const struct btqca_vreg_data cherokee_data = { .num_vregs = 5, }; -void btqca_disable_regulators(int reg_nu, struct btqca_vreg *vregs) +static void btqca_disable_regulators(int reg_nu, struct btqca_vreg *vregs) { /* disable the regulator if requested by user * or when fault in any regulator. ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 3/3] Bluetooth: btqca: Add wcn3990 firmware download support. 2018-05-04 15:35 [PATCH v4 0/3] Enable Bluetooth functionality for WCN3990 Balakrishna Godavarthi 2018-05-04 15:35 ` [PATCH v4 1/3] dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990 Balakrishna Godavarthi 2018-05-04 15:35 ` [PATCH v4 2/3] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth " Balakrishna Godavarthi @ 2018-05-04 15:35 ` Balakrishna Godavarthi 2018-05-05 19:11 ` kbuild test robot 2018-05-05 19:14 ` kbuild test robot 2 siblings, 2 replies; 15+ messages in thread From: Balakrishna Godavarthi @ 2018-05-04 15:35 UTC (permalink / raw) To: marcel, johan.hedberg Cc: linux-bluetooth, rtatiya, hemantg, linux-arm-msm, Balakrishna Godavarthi This patch enables the RAM and NV patch download for wcn3990. Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org> --- drivers/bluetooth/btqca.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- drivers/bluetooth/btqca.h | 19 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index 8219816..12b4dd3 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -27,7 +27,7 @@ #define VERSION "0.1" -static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version) +int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version) { struct sk_buff *skb; struct edl_event_hdr *edl; @@ -380,6 +380,49 @@ int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate) } EXPORT_SYMBOL_GPL(qca_uart_setup_rome); +int qca_uart_setup_cherokee(struct hci_dev *hdev, uint8_t baudrate, + u32 *soc_ver) +{ + struct rome_config config; + int err; + + /* we are using the existing funciton of ROME, + * instead of duplicating the function for wcn3990. + */ + config.user_baud_rate = baudrate; + /* Download rampatch file */ + config.type = TLV_TYPE_PATCH; + snprintf(config.fwname, sizeof(config.fwname), "qca/rampatch_%08x.tlv", + *soc_ver); + err = rome_download_firmware(hdev, &config); + if (err < 0) { + BT_ERR("%s: Failed to download patch (%d)", hdev->name, err); + return err; + } + + /* Download NVM configuration */ + config.type = TLV_TYPE_NVM; + snprintf(config.fwname, sizeof(config.fwname), "qca/nvm_%08x.bin", + *soc_ver); + err = rome_download_firmware(hdev, &config); + if (err < 0) { + BT_ERR("%s: Failed to download NVM (%d)", hdev->name, err); + return err; + } + + /* Perform HCI reset */ + err = rome_reset(hdev); + if (err < 0) { + BT_ERR("%s: Failed to run HCI_RESET (%d)", hdev->name, err); + return err; + } + + bt_dev_info(hdev, "wcn3990 setup on UART is completed"); + + return 0; +} +EXPORT_SYMBOL_GPL(qca_uart_setup_cherokee); + MODULE_AUTHOR("Ben Young Tae Kim <ytkim@qca.qualcomm.com>"); MODULE_DESCRIPTION("Bluetooth support for Qualcomm Atheros family ver " VERSION); MODULE_VERSION(VERSION); diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h index 13d77fd..2b41987 100644 --- a/drivers/bluetooth/btqca.h +++ b/drivers/bluetooth/btqca.h @@ -37,6 +37,9 @@ #define EDL_TAG_ID_HCI (17) #define EDL_TAG_ID_DEEP_SLEEP (27) +#define CHEROKEE_POWERON_PULSE (0xFC) +#define CHEROKEE_POWEROFF_PULSE (0xC0) + enum qca_bardrate { QCA_BAUDRATE_115200 = 0, QCA_BAUDRATE_57600, @@ -124,10 +127,16 @@ struct tlv_type_hdr { __u8 data[0]; } __packed; +int qca_btsoc_cleanup(struct hci_dev *hdev); +int btqca_power_setup(bool on); + #if IS_ENABLED(CONFIG_BT_QCA) int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr); int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate); +int qca_uart_setup_cherokee(struct hci_dev *hdev, uint8_t baudrate, + u32 *soc_ver); +int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version); #else @@ -141,4 +150,14 @@ static inline int qca_uart_setup_rome(struct hci_dev *hdev, int speed) return -EOPNOTSUPP; } +static int qca_uart_setup_cherokee(struct hci_dev *hdev, uint8_t baudrate, + u32 *soc_ver) +{ + return -EOPNOTSUPP; +} + +static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version) +{ + return -EOPNOTSUPP; +} #endif -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v4 3/3] Bluetooth: btqca: Add wcn3990 firmware download support. 2018-05-04 15:35 ` [PATCH v4 3/3] Bluetooth: btqca: Add wcn3990 firmware download support Balakrishna Godavarthi @ 2018-05-05 19:11 ` kbuild test robot 2018-05-05 19:14 ` kbuild test robot 1 sibling, 0 replies; 15+ messages in thread From: kbuild test robot @ 2018-05-05 19:11 UTC (permalink / raw) To: Balakrishna Godavarthi Cc: kbuild-all, marcel, johan.hedberg, linux-bluetooth, rtatiya, hemantg, linux-arm-msm, Balakrishna Godavarthi [-- Attachment #1: Type: text/plain, Size: 1796 bytes --] Hi Balakrishna, Thank you for the patch! Yet something to improve: [auto build test ERROR on bluetooth-next/master] [also build test ERROR on next-20180504] [cannot apply to bluetooth/master v4.17-rc3] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/Balakrishna-Godavarthi/dt-bindings-net-bluetooth-Add-device-tree-bindings-for-QTI-chip-wcn3990/20180506-004430 base: https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master config: sparc64-allyesconfig (attached as .config) compiler: sparc64-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0 reproduce: wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree make.cross ARCH=sparc64 All errors (new ones prefixed by >>): `.exit.data' referenced in section `.exit.text' of drivers/tty/n_hdlc.o: defined in discarded section `.exit.data' of drivers/tty/n_hdlc.o `.exit.data' referenced in section `.exit.text' of drivers/tty/n_hdlc.o: defined in discarded section `.exit.data' of drivers/tty/n_hdlc.o `.exit.data' referenced in section `.exit.text' of drivers/tty/n_hdlc.o: defined in discarded section `.exit.data' of drivers/tty/n_hdlc.o `.exit.data' referenced in section `.exit.text' of drivers/tty/n_hdlc.o: defined in discarded section `.exit.data' of drivers/tty/n_hdlc.o drivers/bluetooth/hci_qca.o: In function `qca_setup': >> hci_qca.c:(.text+0x1004): undefined reference to `__bad_udelay' --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation [-- Attachment #2: .config.gz --] [-- Type: application/gzip, Size: 53282 bytes --] ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v4 3/3] Bluetooth: btqca: Add wcn3990 firmware download support. 2018-05-04 15:35 ` [PATCH v4 3/3] Bluetooth: btqca: Add wcn3990 firmware download support Balakrishna Godavarthi 2018-05-05 19:11 ` kbuild test robot @ 2018-05-05 19:14 ` kbuild test robot 1 sibling, 0 replies; 15+ messages in thread From: kbuild test robot @ 2018-05-05 19:14 UTC (permalink / raw) To: Balakrishna Godavarthi Cc: kbuild-all, marcel, johan.hedberg, linux-bluetooth, rtatiya, hemantg, linux-arm-msm, Balakrishna Godavarthi [-- Attachment #1: Type: text/plain, Size: 1032 bytes --] Hi Balakrishna, Thank you for the patch! Yet something to improve: [auto build test ERROR on bluetooth-next/master] [also build test ERROR on next-20180504] [cannot apply to bluetooth/master v4.17-rc3] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/Balakrishna-Godavarthi/dt-bindings-net-bluetooth-Add-device-tree-bindings-for-QTI-chip-wcn3990/20180506-004430 base: https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master config: x86_64-randconfig-s0-05060048 (attached as .config) compiler: gcc-6 (Debian 6.4.0-9) 6.4.0 20171026 reproduce: # save the attached .config to linux build tree make ARCH=x86_64 All errors (new ones prefixed by >>): >> ERROR: "rome_patch_ver_req" [drivers/bluetooth/hci_uart.ko] undefined! --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation [-- Attachment #2: .config.gz --] [-- Type: application/gzip, Size: 26555 bytes --] ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2018-05-10 16:01 UTC | newest] Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2018-05-04 15:35 [PATCH v4 0/3] Enable Bluetooth functionality for WCN3990 Balakrishna Godavarthi 2018-05-04 15:35 ` [PATCH v4 1/3] dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990 Balakrishna Godavarthi 2018-05-04 15:35 ` [PATCH v4 2/3] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth " Balakrishna Godavarthi 2018-05-05 1:17 ` Matthias Kaehlcke 2018-05-09 8:56 ` Balakrishna Godavarthi 2018-05-09 9:27 ` Balakrishna Godavarthi 2018-05-09 10:07 ` Balakrishna Godavarthi 2018-05-09 17:24 ` Matthias Kaehlcke 2018-05-10 16:01 ` Balakrishna Godavarthi 2018-05-05 19:21 ` kbuild test robot 2018-05-05 19:45 ` kbuild test robot 2018-05-05 20:11 ` [RFC PATCH] Bluetooth: hci_qca: btqca_disable_regulators() can be static kbuild test robot 2018-05-04 15:35 ` [PATCH v4 3/3] Bluetooth: btqca: Add wcn3990 firmware download support Balakrishna Godavarthi 2018-05-05 19:11 ` kbuild test robot 2018-05-05 19:14 ` kbuild test robot
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.