All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/2] Enable Bluetooth functionality for WCN3990
@ 2018-04-24 14:11 Balakrishna Godavarthi
  2018-04-24 14:11 ` [PATCH v3 1/2] dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990 Balakrishna Godavarthi
  2018-04-24 14:11 ` [PATCH v3 2/2] Bluetooth: Add support for wcn3990 soc Balakrishna Godavarthi
  0 siblings, 2 replies; 8+ messages in thread
From: Balakrishna Godavarthi @ 2018-04-24 14:11 UTC (permalink / raw)
  To: marcel, johan.hedberg
  Cc: linux-bluetooth, rtatiya, linux-arm-msm, hemantg, Balakrishna Godavarthi

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 (2):
  dt-bindings: net: bluetooth: Add device tree bindings for QTI chip
    wcn3990
  Bluetooth: Add support for wcn3990 soc.

 .../devicetree/bindings/net/qualcomm-bluetooth.txt |  39 +-
 drivers/bluetooth/btqca.c                          | 393 ++++++++++++----
 drivers/bluetooth/btqca.h                          |  49 +-
 drivers/bluetooth/hci_qca.c                        | 496 ++++++++++++++++++---
 include/net/bluetooth/hci_core.h                   |   3 +-
 net/bluetooth/hci_core.c                           |   2 +-
 net/bluetooth/hci_request.c                        |  23 +
 net/bluetooth/hci_request.h                        |   2 +
 8 files changed, 839 insertions(+), 168 deletions(-)

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* [PATCH v3 1/2] dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990
  2018-04-24 14:11 [PATCH v3 0/2] Enable Bluetooth functionality for WCN3990 Balakrishna Godavarthi
@ 2018-04-24 14:11 ` Balakrishna Godavarthi
  2018-04-24 15:17   ` Marcel Holtmann
  2018-04-24 14:11 ` [PATCH v3 2/2] Bluetooth: Add support for wcn3990 soc Balakrishna Godavarthi
  1 sibling, 1 reply; 8+ messages in thread
From: Balakrishna Godavarthi @ 2018-04-24 14:11 UTC (permalink / raw)
  To: marcel, johan.hedberg
  Cc: linux-bluetooth, rtatiya, linux-arm-msm, hemantg, Balakrishna Godavarthi

Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
---
 .../devicetree/bindings/net/qualcomm-bluetooth.txt | 39 ++++++++++++++++++----
 1 file changed, 32 insertions(+), 7 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt b/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt
index 0ea18a5..c81ac04 100644
--- a/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt
+++ b/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt
@@ -1,21 +1,32 @@
-Qualcomm Bluetooth Chips
----------------------
+Qualcomm Technologies Inc Bluetooth Chips
+-----------------------------------------
 
 This documents the binding structure and common properties for serial
-attached Qualcomm devices.
+attached Qualcomm Technologies Inc devices.
 
-Serial attached Qualcomm devices shall be a child node of the host UART
-device the slave device is attached to.
+Serial attached Qualcomm Technologies Inc devices shall be a child node
+of the host UART 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.
+
+Examples:
 
 serial@7570000 {
 	label = "BT-UART";
@@ -28,3 +39,17 @@ serial@7570000 {
 		clocks = <&divclk4>;
 	};
 };
+
+serial@898000 {
+	label = "BT-UART";
+	status = "okay";
+
+	bluetooth: bt_wcn3990 {
+		compatible = "qca,wcn3990-bt";
+		vddio-supply = <&pm8998_s3>;
+		vddxtal-supply = <&pm8998_s5>;
+		vddcore-supply = <&pm8998_l7>;
+		vddpa-supply = <&pm8998_l17>;
+		vddldo-supply = <&pm8998_l25>;
+	};
+};
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* [PATCH v3 2/2] Bluetooth: Add support for wcn3990 soc.
  2018-04-24 14:11 [PATCH v3 0/2] Enable Bluetooth functionality for WCN3990 Balakrishna Godavarthi
  2018-04-24 14:11 ` [PATCH v3 1/2] dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990 Balakrishna Godavarthi
@ 2018-04-24 14:11 ` Balakrishna Godavarthi
  2018-04-24 15:28   ` Marcel Holtmann
                     ` (2 more replies)
  1 sibling, 3 replies; 8+ messages in thread
From: Balakrishna Godavarthi @ 2018-04-24 14:11 UTC (permalink / raw)
  To: marcel, johan.hedberg
  Cc: linux-bluetooth, rtatiya, linux-arm-msm, hemantg, Balakrishna Godavarthi

 - Add support to set voltage/current of various regualtors
   to power up/down BT QCA chip wcn3990.
 - Add firmware download support for BT QCA chip wcn3990.

Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
---
 drivers/bluetooth/btqca.c        | 393 ++++++++++++++++++++++++-------
 drivers/bluetooth/btqca.h        |  49 +++-
 drivers/bluetooth/hci_qca.c      | 496 +++++++++++++++++++++++++++++++++------
 include/net/bluetooth/hci_core.h |   3 +-
 net/bluetooth/hci_core.c         |   2 +-
 net/bluetooth/hci_request.c      |  23 ++
 net/bluetooth/hci_request.h      |   2 +
 7 files changed, 807 insertions(+), 161 deletions(-)

diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index 2793d41..13c0d9e 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -1,7 +1,7 @@
 /*
  *  Bluetooth supports for Qualcomm Atheros chips
  *
- *  Copyright (c) 2015 The Linux Foundation. All rights reserved.
+ *  Copyright (c) 2015, 2018 The Linux Foundation. All rights reserved.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2
@@ -19,82 +19,18 @@
  */
 #include <linux/module.h>
 #include <linux/firmware.h>
-
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
-
 #include "btqca.h"
 
 #define VERSION "0.1"
 
-static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version)
-{
-	struct sk_buff *skb;
-	struct edl_event_hdr *edl;
-	struct rome_version *ver;
-	char cmd;
-	int err = 0;
-
-	BT_DBG("%s: ROME Patch Version Request", hdev->name);
-
-	cmd = EDL_PATCH_VER_REQ_CMD;
-	skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN,
-				&cmd, HCI_VENDOR_PKT, HCI_INIT_TIMEOUT);
-	if (IS_ERR(skb)) {
-		err = PTR_ERR(skb);
-		BT_ERR("%s: Failed to read version of ROME (%d)", hdev->name,
-		       err);
-		return err;
-	}
-
-	if (skb->len != sizeof(*edl) + sizeof(*ver)) {
-		BT_ERR("%s: Version size mismatch len %d", hdev->name,
-		       skb->len);
-		err = -EILSEQ;
-		goto out;
-	}
-
-	edl = (struct edl_event_hdr *)(skb->data);
-	if (!edl) {
-		BT_ERR("%s: TLV with no header", hdev->name);
-		err = -EILSEQ;
-		goto out;
-	}
-
-	if (edl->cresp != EDL_CMD_REQ_RES_EVT ||
-	    edl->rtype != EDL_APP_VER_RES_EVT) {
-		BT_ERR("%s: Wrong packet received %d %d", hdev->name,
-		       edl->cresp, edl->rtype);
-		err = -EIO;
-		goto out;
-	}
-
-	ver = (struct rome_version *)(edl->data);
-
-	BT_DBG("%s: Product:0x%08x", hdev->name, le32_to_cpu(ver->product_id));
-	BT_DBG("%s: Patch  :0x%08x", hdev->name, le16_to_cpu(ver->patch_ver));
-	BT_DBG("%s: ROM    :0x%08x", hdev->name, le16_to_cpu(ver->rome_ver));
-	BT_DBG("%s: SOC    :0x%08x", hdev->name, le32_to_cpu(ver->soc_id));
-
-	/* ROME chipset version can be decided by patch and SoC
-	 * version, combination with upper 2 bytes from SoC
-	 * and lower 2 bytes from patch will be used.
-	 */
-	*rome_version = (le32_to_cpu(ver->soc_id) << 16) |
-			(le16_to_cpu(ver->rome_ver) & 0x0000ffff);
-
-out:
-	kfree_skb(skb);
-
-	return err;
-}
-
-static int rome_reset(struct hci_dev *hdev)
+static int qca_btsoc_reset(struct hci_dev *hdev)
 {
 	struct sk_buff *skb;
 	int err;
 
-	BT_DBG("%s: ROME HCI_RESET", hdev->name);
+	BT_DBG("%s: ROME/wcn3990 HCI_RESET", hdev->name);
 
 	skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
 	if (IS_ERR(skb)) {
@@ -108,7 +44,7 @@ static int rome_reset(struct hci_dev *hdev)
 	return 0;
 }
 
-static void rome_tlv_check_data(struct rome_config *config,
+static void rome_tlv_check_data(struct qca_config *config,
 				const struct firmware *fw)
 {
 	const u8 *data;
@@ -194,8 +130,121 @@ static void rome_tlv_check_data(struct rome_config *config,
 	}
 }
 
-static int rome_tlv_send_segment(struct hci_dev *hdev, int idx, int seg_size,
-				 const u8 *data)
+static void cherokee_tlv_check_data(struct qca_config *config,
+			const struct firmware *fw, bool *dwnd_flag)
+{
+	const u8 *data;
+	u32 type_len;
+	u16 tag_id, tag_len;
+	int idx, length;
+	struct tlv_type_hdr *tlv;
+	struct cherokee_tlv_type_patch *tlv_patch;
+	struct tlv_type_nvm *tlv_nvm;
+
+	tlv = (struct tlv_type_hdr *)fw->data;
+
+	type_len = le32_to_cpu(tlv->type_len);
+	length = (type_len >> 8) & 0x00ffffff;
+
+	BT_DBG("TLV Type\t\t : 0x%x", type_len & 0x000000ff);
+	BT_DBG("Length\t\t : %d bytes", length);
+
+	switch (config->type) {
+	case TLV_TYPE_PATCH:
+		tlv_patch = (struct tlv_type_patch *)tlv->data;
+		BT_DBG("Total Length\t\t : %d bytes",
+			le32_to_cpu(tlv_patch->total_size));
+		BT_DBG("Patch Data Length\t : %d bytes",
+			le32_to_cpu(tlv_patch->data_length));
+		BT_DBG("Signing Format Version : 0x%x",
+			tlv_patch->format_version);
+		BT_DBG("Signature Algorithm\t : 0x%x",
+			tlv_patch->signature);
+		BT_DBG("Download flag\t : 0x%x",
+			tlv_patch->dwnd_cfg);
+		BT_DBG("Reserved\t\t : 0x%x",
+			le16_to_cpu(tlv_patch->reserved1));
+		BT_DBG("Product ID\t\t : 0x%04x",
+			le16_to_cpu(tlv_patch->product_id));
+		BT_DBG("Rom Build Version\t : 0x%04x",
+			le16_to_cpu(tlv_patch->rom_build));
+		BT_DBG("Patch Version\t\t : 0x%04x",
+			le16_to_cpu(tlv_patch->patch_version));
+		BT_DBG("Reserved\t\t : 0x%x",
+			le16_to_cpu(tlv_patch->reserved2));
+		BT_DBG("Patch Entry Address\t : 0x%x",
+			le32_to_cpu(tlv_patch->entry));
+		/* If the download flag is 0x03, don't wait
+		 * for response from soc,i.e. 1 to n-1
+		 * segment download.
+		 */
+		if (tlv_patch->dwnd_cfg == 0x03)
+			*dwnd_flag = false;
+		else
+			*dwnd_flag = true;
+		break;
+
+	case TLV_TYPE_NVM:
+		idx = 0;
+		data = tlv->data;
+		while (idx < length) {
+			tlv_nvm = (struct tlv_type_nvm *)(data + idx);
+			tag_id = le16_to_cpu(tlv_nvm->tag_id);
+			tag_len = le16_to_cpu(tlv_nvm->tag_len);
+
+			/* Update NVM tags as needed */
+			switch (tag_id) {
+			case EDL_TAG_ID_HCI:
+				/* HCI transport layer parameters
+				 * enabling software inband sleep
+				 * onto controller side.
+				 */
+				tlv_nvm->data[0] |= 0x80;
+
+				/* UART Baud Rate */
+				tlv_nvm->data[2] = config->user_baud_rate;
+				break;
+			case EDL_TAG_ID_DEEP_SLEEP:
+				/* Sleep enable mask
+				 * enabling deep sleep feature on controller.
+				 */
+				tlv_nvm->data[0] |= 0x01;
+				break;
+			}
+
+			idx += (sizeof(u16) + sizeof(u16) + 8 + tag_len);
+		}
+		break;
+	default:
+		BT_ERR("Unknown TLV type %d", config->type);
+		break;
+	}
+}
+
+static int cherokee_tlv_send_segment(struct hci_dev *hdev, int idx,
+					int seg_size, const u8 *data)
+{
+	u8 cmd[MAX_SIZE_PER_TLV_SEGMENT + 2];
+	int err = 0;
+
+	BT_DBG("%s: Download segment #%d size %d", hdev->name, idx, seg_size);
+
+	cmd[0] = EDL_PATCH_TLV_REQ_CMD;
+	cmd[1] = seg_size;
+	memcpy(cmd + 2, data, seg_size);
+
+	err = __hci_cmd_no_event(hdev, EDL_PATCH_CMD_OPCODE, seg_size + 2,
+					cmd);
+	if (err < 0) {
+		BT_ERR("%s: Failed to send TLV segment (%d)", hdev->name, err);
+		return err;
+	}
+
+	return err;
+}
+
+static int qca_btsoc_tlv_send_segment(struct hci_dev *hdev, int idx,
+					int seg_size, const u8 *data)
 {
 	struct sk_buff *skb;
 	struct edl_event_hdr *edl;
@@ -264,16 +313,56 @@ static int rome_tlv_download_request(struct hci_dev *hdev,
 	data = fw->data;
 	for (i = 0; i < total_segment; i++) {
 		buffer = data + i * MAX_SIZE_PER_TLV_SEGMENT;
-		ret = rome_tlv_send_segment(hdev, i, MAX_SIZE_PER_TLV_SEGMENT,
-					    buffer);
+		ret = qca_btsoc_tlv_send_segment(hdev, i,
+					MAX_SIZE_PER_TLV_SEGMENT, buffer);
 		if (ret < 0)
 			return -EIO;
 	}
 
 	if (remain_size) {
 		buffer = data + total_segment * MAX_SIZE_PER_TLV_SEGMENT;
-		ret = rome_tlv_send_segment(hdev, total_segment, remain_size,
-					    buffer);
+		ret = qca_btsoc_tlv_send_segment(hdev, total_segment,
+							remain_size, buffer);
+		if (ret < 0)
+			return -EIO;
+	}
+
+	return 0;
+}
+static int cherokee_tlv_download_request(struct hci_dev *hdev,
+			const struct firmware *fw)
+{
+	const u8 *buffer, *data;
+	int total_segment, remain_size;
+	int ret, i;
+
+	if (!fw || !fw->data)
+		return -EINVAL;
+
+	total_segment = fw->size / MAX_SIZE_PER_TLV_SEGMENT;
+	remain_size = fw->size % MAX_SIZE_PER_TLV_SEGMENT;
+
+	BT_DBG("%s: Total segment num %d remain size %d total size %zu",
+			hdev->name, total_segment, remain_size, fw->size);
+
+	data = fw->data;
+	for (i = 0; i < total_segment; i++) {
+		buffer = data + i * MAX_SIZE_PER_TLV_SEGMENT;
+		/* Read response from soc for last segment sent */
+		if (!remain_size && ((i+1) == total_segment))
+			ret = qca_btsoc_tlv_send_segment(hdev, i,
+					MAX_SIZE_PER_TLV_SEGMENT, buffer);
+		else
+			ret = cherokee_tlv_send_segment(hdev, i,
+					MAX_SIZE_PER_TLV_SEGMENT, buffer);
+		if (ret < 0)
+			return -EIO;
+	}
+
+	if (remain_size) {
+		buffer = data + total_segment * MAX_SIZE_PER_TLV_SEGMENT;
+		ret = qca_btsoc_tlv_send_segment(hdev, total_segment,
+							remain_size, buffer);
 		if (ret < 0)
 			return -EIO;
 	}
@@ -282,7 +371,7 @@ static int rome_tlv_download_request(struct hci_dev *hdev,
 }
 
 static int rome_download_firmware(struct hci_dev *hdev,
-				  struct rome_config *config)
+				  struct qca_config *config)
 {
 	const struct firmware *fw;
 	int ret;
@@ -309,7 +398,46 @@ static int rome_download_firmware(struct hci_dev *hdev,
 	return ret;
 }
 
-int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
+static int cherokee_download_firmware(struct hci_dev *hdev,
+					struct qca_config *config)
+{
+	const struct firmware *fw;
+	bool dwnd_flag = true;
+	int ret;
+
+	bt_dev_info(hdev, "wcn3990  Downloading", config->fwname);
+
+	ret = request_firmware(&fw, config->fwname, &hdev->dev);
+	if (ret) {
+		BT_ERR("%s: Failed to request file: %s (%d)", hdev->name,
+			config->fwname, ret);
+		return ret;
+	}
+
+	cherokee_tlv_check_data(config, fw, &dwnd_flag);
+	/* check whether the download flag is set.if bit is enabled
+	 * terminate the ram patch download. As we are not supporting,
+	 * receiving of response from soc for every segment sent.
+	 * We look for response from soc for last segment.
+	 */
+	if (dwnd_flag == true && config->type == TLV_TYPE_PATCH) {
+		BT_ERR("%s: btsoc download flag enabled", hdev->name);
+		return -EOPNOTSUPP;
+	}
+
+	ret = cherokee_tlv_download_request(hdev, fw);
+	if (ret) {
+		BT_ERR("%s: Failed to download file: %s (%d)", hdev->name,
+		config->fwname, ret);
+	}
+
+	release_firmware(fw);
+
+	return ret;
+}
+
+
+int qca_btsoc_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
 {
 	struct sk_buff *skb;
 	u8 cmd[9];
@@ -332,12 +460,12 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome);
+EXPORT_SYMBOL_GPL(qca_btsoc_set_bdaddr);
 
 int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate)
 {
 	u32 rome_ver = 0;
-	struct rome_config config;
+	struct qca_config config;
 	int err;
 
 	BT_DBG("%s: ROME setup on UART", hdev->name);
@@ -345,7 +473,7 @@ int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate)
 	config.user_baud_rate = baudrate;
 
 	/* Get ROME version information */
-	err = rome_patch_ver_req(hdev, &rome_ver);
+	err = qca_btsoc_patch_ver_req(hdev, &rome_ver);
 	if (err < 0 || rome_ver == 0) {
 		BT_ERR("%s: Failed to get version 0x%x", hdev->name, err);
 		return err;
@@ -374,7 +502,7 @@ int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate)
 	}
 
 	/* Perform HCI reset */
-	err = rome_reset(hdev);
+	err = qca_btsoc_reset(hdev);
 	if (err < 0) {
 		BT_ERR("%s: Failed to run HCI_RESET (%d)", hdev->name, err);
 		return err;
@@ -386,6 +514,111 @@ int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate)
 }
 EXPORT_SYMBOL_GPL(qca_uart_setup_rome);
 
+int qca_btsoc_patch_ver_req(struct hci_dev *hdev, u32 *soc_version)
+{
+	struct sk_buff *skb;
+	struct edl_event_hdr *edl;
+	struct qca_btsoc_version *ver;
+	char cmd;
+	int err = 0;
+
+	BT_DBG("%s: BTSOC Patch Version Request", hdev->name);
+
+	cmd = EDL_PATCH_VER_REQ_CMD;
+	skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN,
+				&cmd, HCI_VENDOR_PKT, HCI_INIT_TIMEOUT);
+	if (IS_ERR(skb)) {
+		err = PTR_ERR(skb);
+		BT_ERR("%s: Failed to read version of ROME (%d)", hdev->name,
+		       err);
+		return err;
+	}
+
+	if (skb->len != sizeof(*edl) + sizeof(*ver)) {
+		BT_ERR("%s: Version size mismatch len %d", hdev->name,
+		       skb->len);
+		err = -EILSEQ;
+		goto out;
+	}
+
+	edl = (struct edl_event_hdr *)(skb->data);
+	if (!edl) {
+		BT_ERR("%s: TLV with no header", hdev->name);
+		err = -EILSEQ;
+		goto out;
+	}
+
+	if (edl->cresp != EDL_CMD_REQ_RES_EVT ||
+	    edl->rtype != EDL_APP_VER_RES_EVT) {
+		BT_ERR("%s: Wrong packet received %d %d", hdev->name,
+		       edl->cresp, edl->rtype);
+		err = -EIO;
+		goto out;
+	}
+
+	ver = (struct qca_btsoc_version *)(edl->data);
+
+	BT_DBG("%s: Product:0x%08x", hdev->name, le32_to_cpu(ver->product_id));
+	BT_DBG("%s: Patch  :0x%08x", hdev->name, le16_to_cpu(ver->patch_ver));
+	BT_DBG("%s: ROM    :0x%08x", hdev->name, le16_to_cpu(ver->btsoc_ver));
+	BT_DBG("%s: SOC    :0x%08x", hdev->name, le32_to_cpu(ver->soc_id));
+
+	/* BTSOC chipset version can be decided by patch and SoC
+	 * version, combination with upper 2 bytes from SoC
+	 * and lower 2 bytes from patch will be used.
+	 */
+	*soc_version = (le32_to_cpu(ver->soc_id) << 16) |
+				(le16_to_cpu(ver->btsoc_ver) & 0x0000ffff);
+
+out:
+	kfree_skb(skb);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(qca_btsoc_patch_ver_req);
+
+int qca_uart_setup_cherokee(struct hci_dev *hdev, uint8_t baudrate,
+					u32 *cherokee_ver)
+{
+	struct qca_config config;
+	int err;
+
+	BT_DBG("%s: wcn3990 setup on UART", hdev->name);
+	config.user_baud_rate = baudrate;
+
+	/* Download rampatch file */
+	config.type = TLV_TYPE_PATCH;
+	snprintf(config.fwname, sizeof(config.fwname), "qca/rampatch_%08x.tlv",
+		*cherokee_ver);
+	err = cherokee_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",
+		*cherokee_ver);
+	err = cherokee_download_firmware(hdev, &config);
+	if (err < 0) {
+		BT_ERR("%s: Failed to download NVM (%d)", hdev->name, err);
+		return err;
+	}
+
+	/* Perform HCI reset */
+	err = qca_btsoc_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 65e994b..7608423 100644
--- a/drivers/bluetooth/btqca.h
+++ b/drivers/bluetooth/btqca.h
@@ -1,7 +1,7 @@
 /*
  *  Bluetooth supports for Qualcomm Atheros ROME chips
  *
- *  Copyright (c) 2015 The Linux Foundation. All rights reserved.
+ *  Copyright (c) 2015, 2018 The Linux Foundation. All rights reserved.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2
@@ -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,
@@ -66,7 +69,7 @@ enum rome_tlv_type {
 	TLV_TYPE_NVM
 };
 
-struct rome_config {
+struct qca_config {
 	u8 type;
 	char fwname[64];
 	uint8_t user_baud_rate;
@@ -78,13 +81,14 @@ struct edl_event_hdr {
 	__u8 data[0];
 } __packed;
 
-struct rome_version {
+struct qca_btsoc_version {
 	__le32 product_id;
 	__le16 patch_ver;
-	__le16 rome_ver;
+	__le16 btsoc_ver;
 	__le32 soc_id;
 } __packed;
 
+
 struct tlv_seg_resp {
 	__u8 result;
 } __packed;
@@ -102,6 +106,21 @@ struct tlv_type_patch {
 	__le32 entry;
 } __packed;
 
+struct cherokee_tlv_type_patch {
+	__le32 total_size;
+	__le32 data_length;
+	__u8   format_version;
+	__u8   signature;
+	__u8   dwnd_cfg;
+	__le16 reserved1;
+	__le16 product_id;
+	__le16 rom_build;
+	__le16 patch_version;
+	__le16 reserved2;
+	__le32 entry;
+} __packed;
+
+
 struct tlv_type_nvm {
 	__le16 tag_id;
 	__le16 tag_len;
@@ -115,14 +134,21 @@ 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_btsoc_set_bdaddr(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 *cherokee_ver);
+int qca_btsoc_patch_ver_req(struct hci_dev *hdev, u32 *soc_version);
 
 #else
 
-static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
+static inline int qca_btsoc_set_bdaddr(struct hci_dev *hdev,
+						const bdaddr_t *bdaddr)
 {
 	return -EOPNOTSUPP;
 }
@@ -132,4 +158,15 @@ static inline int qca_uart_setup_rome(struct hci_dev *hdev, int speed)
 	return -EOPNOTSUPP;
 }
 
+static inline int qca_uart_setup_cherokee(struct hci_dev *hdev,
+					uint8_t baudrate, u32 *cherokee_ver)
+{
+	return -EOPNOTSUPP;
+}
+
+static int qca_btsoc_patch_ver_req(struct hci_dev *hdev, u32 *cherokee_version)
+{
+	return -EOPNOTSUPP;
+}
+
 #endif
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index f05382b..bc08559 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,9 +35,13 @@
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/serdev.h>
-
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
+#include <asm-generic/delay.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_device.h>
 
 #include "hci_uart.h"
 #include "btqca.h"
@@ -119,12 +123,49 @@ 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;
+};
+
+/*
+ * 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;
+	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
@@ -461,9 +502,11 @@ static int qca_open(struct hci_uart *hu)
 
 	if (hu->serdev) {
 		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)
+			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 +595,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 +918,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 +934,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 +971,266 @@ 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, "%s: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;
+	unsigned 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");
+		/* clear flow control- for sync cmd*/
+		hci_uart_set_flow_control(hu, true);
+		/* send poweron command to btsoc */
+		ret = qca_send_poweron_cmd(hdev);
+		if (ret) {
+			BT_ERR("%s:sending sync command failed", hdev->name);
+			return ret;
+		}
 
-	/* Patch downloading has to be done without IBS mode */
-	clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
+		/* close port */
+		ret = qca_serdev_close(hu);
+		if (ret)
+			return ret;
+		/* reopen 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;
+		if (speed)
+			host_set_baudrate(hu, speed);
+		else {
+			bt_dev_err(hdev, "initial speed %u", speed);
+			return -1;
+		}
 
-	/* Setup initial baudrate */
-	speed = 0;
-	if (hu->init_speed)
-		speed = hu->init_speed;
-	else if (hu->proto->init_speed)
-		speed = hu->proto->init_speed;
+		/* Enable flow control */
+		hci_uart_set_flow_control(hu, false);
+		/*  wait until flow control settled */
+		mdelay(100);
 
-	if (speed)
-		host_set_baudrate(hu, speed);
+		ret = qca_btsoc_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)
+		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 = 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);
+		}
 
-	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);
+		}
 
-		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;
+		/* Setup wcn3990 bdaddr */
+		hu->hdev->set_bdaddr = qca_btsoc_set_bdaddr;
+
+		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)
+			hci_uart_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_btsoc_set_bdaddr;
 
-	return ret;
+		return ret;
+	}
 }
 
 static struct hci_uart_proto qca_proto = {
@@ -1002,42 +1248,142 @@ 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 },
+		{ "vddpwd",  3312000, 3600000,  0 },
+	},
+	.num_vregs = 6,
+};
+
+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; 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);
+
+			regulator_enable(qca->vreg_bulk[i].consumer);
+		}
+	} else if (on == false && qca->vreg_status == true) {
+		qca->vreg_status = false;
+		for (i = 0; i < qca->vreg_data->num_vregs; i++) {
+			regulator_disable(qca->vreg_bulk[i].consumer);
+			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);
+		}
+	}
+
+	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;
+	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);
+		}
 
-	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;
+		err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
+		if (err) {
+			BT_ERR("wcn3990 serdev registration failed");
+			kfree(qca);
+		}
+	} 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);
+		}
 
-	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);
-	}
+		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_set_rate(qcadev->susclk, SUSCLK_RATE_32KHZ);
-	if (err)
-		return err;
+		err = clk_set_rate(qcadev->susclk, SUSCLK_RATE_32KHZ);
+		if (err)
+			return err;
 
-	err = clk_prepare_enable(qcadev->susclk);
-	if (err)
-		return err;
+		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);
+		err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
+		if (err)
+			clk_disable_unprepare(qcadev->susclk);
+	}
 
 	return err;
 }
@@ -1047,12 +1393,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);
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index b619a19..a12e967 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1393,7 +1393,8 @@ struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
 			       const void *param, u32 timeout);
 struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
 				  const void *param, u8 event, u32 timeout);
-
+int __hci_cmd_no_event(struct hci_dev *hdev, u16 opcode, u32 plen,
+			const void *param);
 int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen,
 		 const void *param);
 void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 40d260f..48dc570 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3364,7 +3364,7 @@ int hci_unregister_cb(struct hci_cb *cb)
 }
 EXPORT_SYMBOL(hci_unregister_cb);
 
-static void hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
+void hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	int err;
 
diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index e44d347..775c3b4 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -119,6 +119,29 @@ void hci_req_sync_cancel(struct hci_dev *hdev, int err)
 	}
 }
 
+/*  Queue a frame to an asynchronous transfer to btdevice,
+ *  with out any event from btdevice.
+ */
+int __hci_cmd_no_event(struct hci_dev *hdev, u16 opcode, u32 plen,
+		       const void *param)
+{
+	struct sk_buff *skb;
+
+	BT_DBG("%s opcode 0x%4.4x plen %d", hdev->name, opcode, plen);
+
+	skb = hci_prepare_cmd(hdev, opcode, plen, param);
+	if (!skb) {
+		BT_ERR("%s no memory for command (opcode 0x%4.4x)",
+		       hdev->name, opcode);
+		return -ENOMEM;
+	}
+
+	hci_send_frame(hdev, skb);
+
+	return 0;
+}
+EXPORT_SYMBOL(__hci_cmd_no_event);
+
 struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
 				  const void *param, u8 event, u32 timeout)
 {
diff --git a/net/bluetooth/hci_request.h b/net/bluetooth/hci_request.h
index 702beb1..58d2cbf 100644
--- a/net/bluetooth/hci_request.h
+++ b/net/bluetooth/hci_request.h
@@ -129,3 +129,5 @@ static inline u16 eir_append_le16(u8 *eir, u16 eir_len, u8 type, u16 data)
 
 	return eir_len;
 }
+
+void hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb);
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH v3 1/2] dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990
  2018-04-24 14:11 ` [PATCH v3 1/2] dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990 Balakrishna Godavarthi
@ 2018-04-24 15:17   ` Marcel Holtmann
  0 siblings, 0 replies; 8+ messages in thread
From: Marcel Holtmann @ 2018-04-24 15:17 UTC (permalink / raw)
  To: Balakrishna Godavarthi
  Cc: Johan Hedberg, linux-bluetooth, rtatiya, linux-arm-msm, hemantg

Hi Balakrishna,,

> Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
> ---
> .../devicetree/bindings/net/qualcomm-bluetooth.txt | 39 ++++++++++++++++++----
> 1 file changed, 32 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt b/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt
> index 0ea18a5..c81ac04 100644
> --- a/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt
> +++ b/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt
> @@ -1,21 +1,32 @@
> -Qualcomm Bluetooth Chips
> ----------------------
> +Qualcomm Technologies Inc Bluetooth Chips
> +-----------------------------------------
> 
> This documents the binding structure and common properties for serial
> -attached Qualcomm devices.
> +attached Qualcomm Technologies Inc devices.
> 
> -Serial attached Qualcomm devices shall be a child node of the host UART
> -device the slave device is attached to.
> +Serial attached Qualcomm Technologies Inc devices shall be a child node
> +of the host UART device the slave device is attached to.

please skip these naming changes. Next week the company is named Qualcomm Something and I have no fun in entertaining changes around that. We also call it Intel and Broadcom and not their full legal entity names.

> 
> 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.
> +
> +Examples:
> 
> serial@7570000 {
> 	label = "BT-UART";
> @@ -28,3 +39,17 @@ serial@7570000 {
> 		clocks = <&divclk4>;
> 	};
> };
> +
> +serial@898000 {
> +	label = "BT-UART";
> +	status = "okay";
> +
> +	bluetooth: bt_wcn3990 {
> +		compatible = "qca,wcn3990-bt";
> +		vddio-supply = <&pm8998_s3>;
> +		vddxtal-supply = <&pm8998_s5>;
> +		vddcore-supply = <&pm8998_l7>;
> +		vddpa-supply = <&pm8998_l17>;
> +		vddldo-supply = <&pm8998_l25>;
> +	};
> +};

Regards

Marcel


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

* Re: [PATCH v3 2/2] Bluetooth: Add support for wcn3990 soc.
  2018-04-24 14:11 ` [PATCH v3 2/2] Bluetooth: Add support for wcn3990 soc Balakrishna Godavarthi
@ 2018-04-24 15:28   ` Marcel Holtmann
  2018-04-25  9:14     ` bgodavar
  2018-04-26  7:38   ` kbuild test robot
  2018-04-26  8:12   ` kbuild test robot
  2 siblings, 1 reply; 8+ messages in thread
From: Marcel Holtmann @ 2018-04-24 15:28 UTC (permalink / raw)
  To: Balakrishna Godavarthi
  Cc: Johan Hedberg, linux-bluetooth, rtatiya, linux-arm-msm, hemantg

Hi Balakrishna,

> - Add support to set voltage/current of various regualtors
>   to power up/down BT QCA chip wcn3990.
> - Add firmware download support for BT QCA chip wcn3990.
> 
> Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
> ---
> drivers/bluetooth/btqca.c        | 393 ++++++++++++++++++++++++-------
> drivers/bluetooth/btqca.h        |  49 +++-
> drivers/bluetooth/hci_qca.c      | 496 +++++++++++++++++++++++++++++++++------
> include/net/bluetooth/hci_core.h |   3 +-
> net/bluetooth/hci_core.c         |   2 +-
> net/bluetooth/hci_request.c      |  23 ++
> net/bluetooth/hci_request.h      |   2 +
> 7 files changed, 807 insertions(+), 161 deletions(-)
> 
> diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
> index 2793d41..13c0d9e 100644
> --- a/drivers/bluetooth/btqca.c
> +++ b/drivers/bluetooth/btqca.c
> @@ -1,7 +1,7 @@
> /*
>  *  Bluetooth supports for Qualcomm Atheros chips
>  *
> - *  Copyright (c) 2015 The Linux Foundation. All rights reserved.
> + *  Copyright (c) 2015, 2018 The Linux Foundation. All rights reserved.
>  *
>  *  This program is free software; you can redistribute it and/or modify
>  *  it under the terms of the GNU General Public License version 2
> @@ -19,82 +19,18 @@
>  */
> #include <linux/module.h>
> #include <linux/firmware.h>
> -
> #include <net/bluetooth/bluetooth.h>
> #include <net/bluetooth/hci_core.h>
> -
> #include "btqca.h"
> 
> #define VERSION "0.1"
> 
> -static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version)
> -{
> -	struct sk_buff *skb;
> -	struct edl_event_hdr *edl;
> -	struct rome_version *ver;
> -	char cmd;
> -	int err = 0;
> -
> -	BT_DBG("%s: ROME Patch Version Request", hdev->name);
> -
> -	cmd = EDL_PATCH_VER_REQ_CMD;
> -	skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN,
> -				&cmd, HCI_VENDOR_PKT, HCI_INIT_TIMEOUT);
> -	if (IS_ERR(skb)) {
> -		err = PTR_ERR(skb);
> -		BT_ERR("%s: Failed to read version of ROME (%d)", hdev->name,
> -		       err);
> -		return err;
> -	}
> -
> -	if (skb->len != sizeof(*edl) + sizeof(*ver)) {
> -		BT_ERR("%s: Version size mismatch len %d", hdev->name,
> -		       skb->len);
> -		err = -EILSEQ;
> -		goto out;
> -	}
> -
> -	edl = (struct edl_event_hdr *)(skb->data);
> -	if (!edl) {
> -		BT_ERR("%s: TLV with no header", hdev->name);
> -		err = -EILSEQ;
> -		goto out;
> -	}
> -
> -	if (edl->cresp != EDL_CMD_REQ_RES_EVT ||
> -	    edl->rtype != EDL_APP_VER_RES_EVT) {
> -		BT_ERR("%s: Wrong packet received %d %d", hdev->name,
> -		       edl->cresp, edl->rtype);
> -		err = -EIO;
> -		goto out;
> -	}
> -
> -	ver = (struct rome_version *)(edl->data);
> -
> -	BT_DBG("%s: Product:0x%08x", hdev->name, le32_to_cpu(ver->product_id));
> -	BT_DBG("%s: Patch  :0x%08x", hdev->name, le16_to_cpu(ver->patch_ver));
> -	BT_DBG("%s: ROM    :0x%08x", hdev->name, le16_to_cpu(ver->rome_ver));
> -	BT_DBG("%s: SOC    :0x%08x", hdev->name, le32_to_cpu(ver->soc_id));
> -
> -	/* ROME chipset version can be decided by patch and SoC
> -	 * version, combination with upper 2 bytes from SoC
> -	 * and lower 2 bytes from patch will be used.
> -	 */
> -	*rome_version = (le32_to_cpu(ver->soc_id) << 16) |
> -			(le16_to_cpu(ver->rome_ver) & 0x0000ffff);
> -
> -out:
> -	kfree_skb(skb);
> -
> -	return err;
> -}
> -
> -static int rome_reset(struct hci_dev *hdev)
> +static int qca_btsoc_reset(struct hci_dev *hdev)
> {
> 	struct sk_buff *skb;
> 	int err;
> 
> -	BT_DBG("%s: ROME HCI_RESET", hdev->name);
> +	BT_DBG("%s: ROME/wcn3990 HCI_RESET", hdev->name);
> 
> 	skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
> 	if (IS_ERR(skb)) {
> @@ -108,7 +44,7 @@ static int rome_reset(struct hci_dev *hdev)
> 	return 0;
> }
> 
> -static void rome_tlv_check_data(struct rome_config *config,
> +static void rome_tlv_check_data(struct qca_config *config,
> 				const struct firmware *fw)
> {
> 	const u8 *data;
> @@ -194,8 +130,121 @@ static void rome_tlv_check_data(struct rome_config *config,
> 	}
> }
> 
> -static int rome_tlv_send_segment(struct hci_dev *hdev, int idx, int seg_size,
> -				 const u8 *data)
> +static void cherokee_tlv_check_data(struct qca_config *config,
> +			const struct firmware *fw, bool *dwnd_flag)
> +{
> +	const u8 *data;
> +	u32 type_len;
> +	u16 tag_id, tag_len;
> +	int idx, length;
> +	struct tlv_type_hdr *tlv;
> +	struct cherokee_tlv_type_patch *tlv_patch;
> +	struct tlv_type_nvm *tlv_nvm;
> +
> +	tlv = (struct tlv_type_hdr *)fw->data;
> +
> +	type_len = le32_to_cpu(tlv->type_len);
> +	length = (type_len >> 8) & 0x00ffffff;
> +
> +	BT_DBG("TLV Type\t\t : 0x%x", type_len & 0x000000ff);
> +	BT_DBG("Length\t\t : %d bytes", length);
> +
> +	switch (config->type) {
> +	case TLV_TYPE_PATCH:
> +		tlv_patch = (struct tlv_type_patch *)tlv->data;
> +		BT_DBG("Total Length\t\t : %d bytes",
> +			le32_to_cpu(tlv_patch->total_size));
> +		BT_DBG("Patch Data Length\t : %d bytes",
> +			le32_to_cpu(tlv_patch->data_length));
> +		BT_DBG("Signing Format Version : 0x%x",
> +			tlv_patch->format_version);
> +		BT_DBG("Signature Algorithm\t : 0x%x",
> +			tlv_patch->signature);
> +		BT_DBG("Download flag\t : 0x%x",
> +			tlv_patch->dwnd_cfg);
> +		BT_DBG("Reserved\t\t : 0x%x",
> +			le16_to_cpu(tlv_patch->reserved1));
> +		BT_DBG("Product ID\t\t : 0x%04x",
> +			le16_to_cpu(tlv_patch->product_id));
> +		BT_DBG("Rom Build Version\t : 0x%04x",
> +			le16_to_cpu(tlv_patch->rom_build));
> +		BT_DBG("Patch Version\t\t : 0x%04x",
> +			le16_to_cpu(tlv_patch->patch_version));
> +		BT_DBG("Reserved\t\t : 0x%x",
> +			le16_to_cpu(tlv_patch->reserved2));
> +		BT_DBG("Patch Entry Address\t : 0x%x",
> +			le32_to_cpu(tlv_patch->entry));
> +		/* If the download flag is 0x03, don't wait
> +		 * for response from soc,i.e. 1 to n-1
> +		 * segment download.
> +		 */
> +		if (tlv_patch->dwnd_cfg == 0x03)
> +			*dwnd_flag = false;
> +		else
> +			*dwnd_flag = true;
> +		break;
> +
> +	case TLV_TYPE_NVM:
> +		idx = 0;
> +		data = tlv->data;
> +		while (idx < length) {
> +			tlv_nvm = (struct tlv_type_nvm *)(data + idx);
> +			tag_id = le16_to_cpu(tlv_nvm->tag_id);
> +			tag_len = le16_to_cpu(tlv_nvm->tag_len);
> +
> +			/* Update NVM tags as needed */
> +			switch (tag_id) {
> +			case EDL_TAG_ID_HCI:
> +				/* HCI transport layer parameters
> +				 * enabling software inband sleep
> +				 * onto controller side.
> +				 */
> +				tlv_nvm->data[0] |= 0x80;
> +
> +				/* UART Baud Rate */
> +				tlv_nvm->data[2] = config->user_baud_rate;
> +				break;
> +			case EDL_TAG_ID_DEEP_SLEEP:
> +				/* Sleep enable mask
> +				 * enabling deep sleep feature on controller.
> +				 */
> +				tlv_nvm->data[0] |= 0x01;
> +				break;
> +			}
> +
> +			idx += (sizeof(u16) + sizeof(u16) + 8 + tag_len);
> +		}
> +		break;
> +	default:
> +		BT_ERR("Unknown TLV type %d", config->type);
> +		break;
> +	}
> +}
> +
> +static int cherokee_tlv_send_segment(struct hci_dev *hdev, int idx,
> +					int seg_size, const u8 *data)
> +{
> +	u8 cmd[MAX_SIZE_PER_TLV_SEGMENT + 2];
> +	int err = 0;
> +
> +	BT_DBG("%s: Download segment #%d size %d", hdev->name, idx, seg_size);
> +
> +	cmd[0] = EDL_PATCH_TLV_REQ_CMD;
> +	cmd[1] = seg_size;
> +	memcpy(cmd + 2, data, seg_size);
> +
> +	err = __hci_cmd_no_event(hdev, EDL_PATCH_CMD_OPCODE, seg_size + 2,
> +					cmd);
> +	if (err < 0) {
> +		BT_ERR("%s: Failed to send TLV segment (%d)", hdev->name, err);
> +		return err;
> +	}
> +
> +	return err;
> +}
> +
> +static int qca_btsoc_tlv_send_segment(struct hci_dev *hdev, int idx,
> +					int seg_size, const u8 *data)
> {
> 	struct sk_buff *skb;
> 	struct edl_event_hdr *edl;
> @@ -264,16 +313,56 @@ static int rome_tlv_download_request(struct hci_dev *hdev,
> 	data = fw->data;
> 	for (i = 0; i < total_segment; i++) {
> 		buffer = data + i * MAX_SIZE_PER_TLV_SEGMENT;
> -		ret = rome_tlv_send_segment(hdev, i, MAX_SIZE_PER_TLV_SEGMENT,
> -					    buffer);
> +		ret = qca_btsoc_tlv_send_segment(hdev, i,
> +					MAX_SIZE_PER_TLV_SEGMENT, buffer);
> 		if (ret < 0)
> 			return -EIO;
> 	}
> 
> 	if (remain_size) {
> 		buffer = data + total_segment * MAX_SIZE_PER_TLV_SEGMENT;
> -		ret = rome_tlv_send_segment(hdev, total_segment, remain_size,
> -					    buffer);
> +		ret = qca_btsoc_tlv_send_segment(hdev, total_segment,
> +							remain_size, buffer);
> +		if (ret < 0)
> +			return -EIO;
> +	}
> +
> +	return 0;
> +}
> +static int cherokee_tlv_download_request(struct hci_dev *hdev,
> +			const struct firmware *fw)
> +{
> +	const u8 *buffer, *data;
> +	int total_segment, remain_size;
> +	int ret, i;
> +
> +	if (!fw || !fw->data)
> +		return -EINVAL;
> +
> +	total_segment = fw->size / MAX_SIZE_PER_TLV_SEGMENT;
> +	remain_size = fw->size % MAX_SIZE_PER_TLV_SEGMENT;
> +
> +	BT_DBG("%s: Total segment num %d remain size %d total size %zu",
> +			hdev->name, total_segment, remain_size, fw->size);
> +
> +	data = fw->data;
> +	for (i = 0; i < total_segment; i++) {
> +		buffer = data + i * MAX_SIZE_PER_TLV_SEGMENT;
> +		/* Read response from soc for last segment sent */
> +		if (!remain_size && ((i+1) == total_segment))
> +			ret = qca_btsoc_tlv_send_segment(hdev, i,
> +					MAX_SIZE_PER_TLV_SEGMENT, buffer);
> +		else
> +			ret = cherokee_tlv_send_segment(hdev, i,
> +					MAX_SIZE_PER_TLV_SEGMENT, buffer);
> +		if (ret < 0)
> +			return -EIO;
> +	}
> +
> +	if (remain_size) {
> +		buffer = data + total_segment * MAX_SIZE_PER_TLV_SEGMENT;
> +		ret = qca_btsoc_tlv_send_segment(hdev, total_segment,
> +							remain_size, buffer);
> 		if (ret < 0)
> 			return -EIO;
> 	}
> @@ -282,7 +371,7 @@ static int rome_tlv_download_request(struct hci_dev *hdev,
> }
> 
> static int rome_download_firmware(struct hci_dev *hdev,
> -				  struct rome_config *config)
> +				  struct qca_config *config)
> {
> 	const struct firmware *fw;
> 	int ret;
> @@ -309,7 +398,46 @@ static int rome_download_firmware(struct hci_dev *hdev,
> 	return ret;
> }
> 
> -int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
> +static int cherokee_download_firmware(struct hci_dev *hdev,
> +					struct qca_config *config)
> +{
> +	const struct firmware *fw;
> +	bool dwnd_flag = true;
> +	int ret;
> +
> +	bt_dev_info(hdev, "wcn3990  Downloading", config->fwname);
> +
> +	ret = request_firmware(&fw, config->fwname, &hdev->dev);
> +	if (ret) {
> +		BT_ERR("%s: Failed to request file: %s (%d)", hdev->name,
> +			config->fwname, ret);
> +		return ret;
> +	}
> +
> +	cherokee_tlv_check_data(config, fw, &dwnd_flag);
> +	/* check whether the download flag is set.if bit is enabled
> +	 * terminate the ram patch download. As we are not supporting,
> +	 * receiving of response from soc for every segment sent.
> +	 * We look for response from soc for last segment.
> +	 */
> +	if (dwnd_flag == true && config->type == TLV_TYPE_PATCH) {
> +		BT_ERR("%s: btsoc download flag enabled", hdev->name);
> +		return -EOPNOTSUPP;
> +	}
> +
> +	ret = cherokee_tlv_download_request(hdev, fw);
> +	if (ret) {
> +		BT_ERR("%s: Failed to download file: %s (%d)", hdev->name,
> +		config->fwname, ret);
> +	}
> +
> +	release_firmware(fw);
> +
> +	return ret;
> +}
> +
> +
> +int qca_btsoc_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
> {
> 	struct sk_buff *skb;
> 	u8 cmd[9];
> @@ -332,12 +460,12 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
> 
> 	return 0;
> }
> -EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome);
> +EXPORT_SYMBOL_GPL(qca_btsoc_set_bdaddr);

so why is this all intermixed in a single patch. And please don’t change this. If you want a qca_set_bdaddr, then fine, otherwise keep the _rome postfix. Also these things can really be cleaned up in a follow up patch.
> 
> int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate)
> {
> 	u32 rome_ver = 0;
> -	struct rome_config config;
> +	struct qca_config config;
> 	int err;
> 
> 	BT_DBG("%s: ROME setup on UART", hdev->name);
> @@ -345,7 +473,7 @@ int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate)
> 	config.user_baud_rate = baudrate;
> 
> 	/* Get ROME version information */
> -	err = rome_patch_ver_req(hdev, &rome_ver);
> +	err = qca_btsoc_patch_ver_req(hdev, &rome_ver);

So this qca_btsoc naming is not something I like at all. Please skip this renaming and make patches as simple as possible.

> 	if (err < 0 || rome_ver == 0) {
> 		BT_ERR("%s: Failed to get version 0x%x", hdev->name, err);
> 		return err;
> @@ -374,7 +502,7 @@ int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate)
> 	}
> 
> 	/* Perform HCI reset */
> -	err = rome_reset(hdev);
> +	err = qca_btsoc_reset(hdev);
> 	if (err < 0) {
> 		BT_ERR("%s: Failed to run HCI_RESET (%d)", hdev->name, err);
> 		return err;
> @@ -386,6 +514,111 @@ int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate)
> }
> EXPORT_SYMBOL_GPL(qca_uart_setup_rome);
> 
> +int qca_btsoc_patch_ver_req(struct hci_dev *hdev, u32 *soc_version)
> +{
> +	struct sk_buff *skb;
> +	struct edl_event_hdr *edl;
> +	struct qca_btsoc_version *ver;
> +	char cmd;
> +	int err = 0;
> +
> +	BT_DBG("%s: BTSOC Patch Version Request", hdev->name);
> +
> +	cmd = EDL_PATCH_VER_REQ_CMD;
> +	skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN,
> +				&cmd, HCI_VENDOR_PKT, HCI_INIT_TIMEOUT);
> +	if (IS_ERR(skb)) {
> +		err = PTR_ERR(skb);
> +		BT_ERR("%s: Failed to read version of ROME (%d)", hdev->name,
> +		       err);
> +		return err;
> +	}
> +
> +	if (skb->len != sizeof(*edl) + sizeof(*ver)) {
> +		BT_ERR("%s: Version size mismatch len %d", hdev->name,
> +		       skb->len);
> +		err = -EILSEQ;
> +		goto out;
> +	}
> +
> +	edl = (struct edl_event_hdr *)(skb->data);
> +	if (!edl) {
> +		BT_ERR("%s: TLV with no header", hdev->name);
> +		err = -EILSEQ;
> +		goto out;
> +	}
> +
> +	if (edl->cresp != EDL_CMD_REQ_RES_EVT ||
> +	    edl->rtype != EDL_APP_VER_RES_EVT) {
> +		BT_ERR("%s: Wrong packet received %d %d", hdev->name,
> +		       edl->cresp, edl->rtype);
> +		err = -EIO;
> +		goto out;
> +	}
> +
> +	ver = (struct qca_btsoc_version *)(edl->data);
> +
> +	BT_DBG("%s: Product:0x%08x", hdev->name, le32_to_cpu(ver->product_id));
> +	BT_DBG("%s: Patch  :0x%08x", hdev->name, le16_to_cpu(ver->patch_ver));
> +	BT_DBG("%s: ROM    :0x%08x", hdev->name, le16_to_cpu(ver->btsoc_ver));
> +	BT_DBG("%s: SOC    :0x%08x", hdev->name, le32_to_cpu(ver->soc_id));
> +
> +	/* BTSOC chipset version can be decided by patch and SoC
> +	 * version, combination with upper 2 bytes from SoC
> +	 * and lower 2 bytes from patch will be used.
> +	 */
> +	*soc_version = (le32_to_cpu(ver->soc_id) << 16) |
> +				(le16_to_cpu(ver->btsoc_ver) & 0x0000ffff);
> +
> +out:
> +	kfree_skb(skb);
> +
> +	return err;
> +}
> +EXPORT_SYMBOL_GPL(qca_btsoc_patch_ver_req);
> +
> +int qca_uart_setup_cherokee(struct hci_dev *hdev, uint8_t baudrate,
> +					u32 *cherokee_ver)
> +{
> +	struct qca_config config;
> +	int err;
> +
> +	BT_DBG("%s: wcn3990 setup on UART", hdev->name);
> +	config.user_baud_rate = baudrate;
> +
> +	/* Download rampatch file */
> +	config.type = TLV_TYPE_PATCH;
> +	snprintf(config.fwname, sizeof(config.fwname), "qca/rampatch_%08x.tlv",
> +		*cherokee_ver);
> +	err = cherokee_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",
> +		*cherokee_ver);
> +	err = cherokee_download_firmware(hdev, &config);
> +	if (err < 0) {
> +		BT_ERR("%s: Failed to download NVM (%d)", hdev->name, err);
> +		return err;
> +	}
> +
> +	/* Perform HCI reset */
> +	err = qca_btsoc_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 65e994b..7608423 100644
> --- a/drivers/bluetooth/btqca.h
> +++ b/drivers/bluetooth/btqca.h
> @@ -1,7 +1,7 @@
> /*
>  *  Bluetooth supports for Qualcomm Atheros ROME chips
>  *
> - *  Copyright (c) 2015 The Linux Foundation. All rights reserved.
> + *  Copyright (c) 2015, 2018 The Linux Foundation. All rights reserved.
>  *
>  *  This program is free software; you can redistribute it and/or modify
>  *  it under the terms of the GNU General Public License version 2
> @@ -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,
> @@ -66,7 +69,7 @@ enum rome_tlv_type {
> 	TLV_TYPE_NVM
> };
> 
> -struct rome_config {
> +struct qca_config {
> 	u8 type;
> 	char fwname[64];
> 	uint8_t user_baud_rate;
> @@ -78,13 +81,14 @@ struct edl_event_hdr {
> 	__u8 data[0];
> } __packed;
> 
> -struct rome_version {
> +struct qca_btsoc_version {
> 	__le32 product_id;
> 	__le16 patch_ver;
> -	__le16 rome_ver;
> +	__le16 btsoc_ver;
> 	__le32 soc_id;
> } __packed;
> 
> +
> struct tlv_seg_resp {
> 	__u8 result;
> } __packed;
> @@ -102,6 +106,21 @@ struct tlv_type_patch {
> 	__le32 entry;
> } __packed;
> 
> +struct cherokee_tlv_type_patch {
> +	__le32 total_size;
> +	__le32 data_length;
> +	__u8   format_version;
> +	__u8   signature;
> +	__u8   dwnd_cfg;
> +	__le16 reserved1;
> +	__le16 product_id;
> +	__le16 rom_build;
> +	__le16 patch_version;
> +	__le16 reserved2;
> +	__le32 entry;
> +} __packed;
> +
> +
> struct tlv_type_nvm {
> 	__le16 tag_id;
> 	__le16 tag_len;
> @@ -115,14 +134,21 @@ struct tlv_type_hdr {
> 	__u8   data[0];
> } __packed;

This all needs to be aligned with the patches from Loic first.

> 
> +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_btsoc_set_bdaddr(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 *cherokee_ver);
> +int qca_btsoc_patch_ver_req(struct hci_dev *hdev, u32 *soc_version);
> 
> #else
> 
> -static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
> +static inline int qca_btsoc_set_bdaddr(struct hci_dev *hdev,
> +						const bdaddr_t *bdaddr)
> {
> 	return -EOPNOTSUPP;
> }
> @@ -132,4 +158,15 @@ static inline int qca_uart_setup_rome(struct hci_dev *hdev, int speed)
> 	return -EOPNOTSUPP;
> }
> 
> +static inline int qca_uart_setup_cherokee(struct hci_dev *hdev,
> +					uint8_t baudrate, u32 *cherokee_ver)
> +{
> +	return -EOPNOTSUPP;
> +}
> +
> +static int qca_btsoc_patch_ver_req(struct hci_dev *hdev, u32 *cherokee_version)
> +{
> +	return -EOPNOTSUPP;
> +}
> +
> #endif
> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> index f05382b..bc08559 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,9 +35,13 @@
> #include <linux/mod_devicetable.h>
> #include <linux/module.h>
> #include <linux/serdev.h>
> -
> #include <net/bluetooth/bluetooth.h>
> #include <net/bluetooth/hci_core.h>
> +#include <asm-generic/delay.h>
> +#include <linux/platform_device.h>
> +#include <linux/delay.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/of_device.h>
> 
> #include "hci_uart.h"
> #include "btqca.h"
> @@ -119,12 +123,49 @@ 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;
> +};
> +
> +/*
> + * 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;
> +	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
> @@ -461,9 +502,11 @@ static int qca_open(struct hci_uart *hu)
> 
> 	if (hu->serdev) {
> 		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)
> +			btqca_power_setup(true);

This can not be what we are doing. If there needs to be global power on, then that needs to be done differently. This ->open callback is specific to the Bluetooth chip. And only that chip, not the 3 others in the system.

Just to make this clear, I am not taking code that thinks there is only one Bluetooth chip in the system. I refused to do this for btqcomsmd and I will refuse this here. So please get this sorted.

> +		else
> +			gpiod_set_value_cansleep(qcadev->bt_en, 1);
> 	}
> 
> 	BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u",
> @@ -552,7 +595,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 +918,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 +934,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 +971,266 @@ 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));

Don’t we have a skb_put_u8?

> +	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);

And this can not just be an msleep?

> +
> +	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, "%s: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;
> +}

I assumed we already have QCA serdev support merged into bluetooth-next. What is this doing?

> +
> 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;
> +	unsigned 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");
> +		/* clear flow control- for sync cmd*/
> +		hci_uart_set_flow_control(hu, true);
> +		/* send poweron command to btsoc */
> +		ret = qca_send_poweron_cmd(hdev);
> +		if (ret) {
> +			BT_ERR("%s:sending sync command failed", hdev->name);
> +			return ret;
> +		}
> 
> -	/* Patch downloading has to be done without IBS mode */
> -	clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
> +		/* close port */
> +		ret = qca_serdev_close(hu);
> +		if (ret)
> +			return ret;
> +		/* reopen 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;
> +		if (speed)
> +			host_set_baudrate(hu, speed);
> +		else {
> +			bt_dev_err(hdev, "initial speed %u", speed);
> +			return -1;
> +		}
> 
> -	/* Setup initial baudrate */
> -	speed = 0;
> -	if (hu->init_speed)
> -		speed = hu->init_speed;
> -	else if (hu->proto->init_speed)
> -		speed = hu->proto->init_speed;
> +		/* Enable flow control */
> +		hci_uart_set_flow_control(hu, false);
> +		/*  wait until flow control settled */
> +		mdelay(100);
> 
> -	if (speed)
> -		host_set_baudrate(hu, speed);
> +		ret = qca_btsoc_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)
> +		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 = 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);
> +		}
> 
> -	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);
> +		}
> 
> -		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;
> +		/* Setup wcn3990 bdaddr */
> +		hu->hdev->set_bdaddr = qca_btsoc_set_bdaddr;
> +
> +		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)
> +			hci_uart_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_btsoc_set_bdaddr;
> 
> -	return ret;
> +		return ret;
> +	}
> }
> 
> static struct hci_uart_proto qca_proto = {
> @@ -1002,42 +1248,142 @@ 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 },
> +		{ "vddpwd",  3312000, 3600000,  0 },
> +	},
> +	.num_vregs = 6,
> +};
> +
> +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; 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);
> +
> +			regulator_enable(qca->vreg_bulk[i].consumer);
> +		}
> +	} else if (on == false && qca->vreg_status == true) {
> +		qca->vreg_status = false;
> +		for (i = 0; i < qca->vreg_data->num_vregs; i++) {
> +			regulator_disable(qca->vreg_bulk[i].consumer);
> +			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);
> +		}
> +	}
> +
> +	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;
> +	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);
> +		}
> 
> -	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;
> +		err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
> +		if (err) {
> +			BT_ERR("wcn3990 serdev registration failed");
> +			kfree(qca);
> +		}
> +	} 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);
> +		}
> 
> -	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);
> -	}
> +		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_set_rate(qcadev->susclk, SUSCLK_RATE_32KHZ);
> -	if (err)
> -		return err;
> +		err = clk_set_rate(qcadev->susclk, SUSCLK_RATE_32KHZ);
> +		if (err)
> +			return err;
> 
> -	err = clk_prepare_enable(qcadev->susclk);
> -	if (err)
> -		return err;
> +		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);
> +		err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
> +		if (err)
> +			clk_disable_unprepare(qcadev->susclk);
> +	}
> 
> 	return err;
> }
> @@ -1047,12 +1393,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);
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index b619a19..a12e967 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -1393,7 +1393,8 @@ struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
> 			       const void *param, u32 timeout);
> struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
> 				  const void *param, u8 event, u32 timeout);
> -
> +int __hci_cmd_no_event(struct hci_dev *hdev, u16 opcode, u32 plen,
> +			const void *param);
> int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen,
> 		 const void *param);

NAK, see my comments that I send Loic for this kind of change. We also don’t intermix net/ and drivers/ unless needed. So this can be easily separated.

Regards

Marcel


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

* Re: [PATCH v3 2/2] Bluetooth: Add support for wcn3990 soc.
  2018-04-24 15:28   ` Marcel Holtmann
@ 2018-04-25  9:14     ` bgodavar
  0 siblings, 0 replies; 8+ messages in thread
From: bgodavar @ 2018-04-25  9:14 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Johan Hedberg, linux-bluetooth, rtatiya, linux-arm-msm, hemantg

Hi Marcel,

I want to give big picture what we are doing in this patch. In current 
Bluetooth-next tree we have support for Qualcomm Bluetooth chip 
"qcom,qca6174-bt" (i.e. files hci_qca.c and btqca.c). Now with this 
patch we are trying to add support for new bluetooth chip 
"qcom,wcn3990-bt". As this is latest chip with new features, along with 
some common features to old chip "qcom,qca6174-bt" we are updating names 
of functions that are used for both the chips to keep this generic and 
would help in future when we would have new BT SoC.
The below are difference between new and old chips.

Power:
New chip: we have voltage regulators to turn on/off the chip and we have 
to send a command on Tx line to turn on/off the chip completely.
Old chip: We turn on/off by setting a GPIO.
Note: Turning on sequence differs between two chips.

Firmware download:
New chip:
        For downloading RAM patch,We will download 0 to n-1 segments with 
out reading response from chip, for the last segment(n) we will read 
response form chip, based upon the response received we will decide 
whether
        download is success or not.
        For downloading NVM patch we do as same old chip.
Old chip:
       for both RAM and NVM patch downloading,we will read response from 
chip for every segment sent.

So we reused some functions/structure/variables which are used for old 
chip to New chip by generic naming (may be future chips may also use 
same functions).
Please find  my comments inline.


On 2018-04-24 20:58, Marcel Holtmann wrote:
> Hi Balakrishna,
> 
>> - Add support to set voltage/current of various regualtors
>>   to power up/down BT QCA chip wcn3990.
>> - Add firmware download support for BT QCA chip wcn3990.
>> 
>> Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
>> ---
>> drivers/bluetooth/btqca.c        | 393 ++++++++++++++++++++++++-------
>> drivers/bluetooth/btqca.h        |  49 +++-
>> drivers/bluetooth/hci_qca.c      | 496 
>> +++++++++++++++++++++++++++++++++------
>> include/net/bluetooth/hci_core.h |   3 +-
>> net/bluetooth/hci_core.c         |   2 +-
>> net/bluetooth/hci_request.c      |  23 ++
>> net/bluetooth/hci_request.h      |   2 +
>> 7 files changed, 807 insertions(+), 161 deletions(-)
>> 
>> diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
>> index 2793d41..13c0d9e 100644
>> --- a/drivers/bluetooth/btqca.c
>> +++ b/drivers/bluetooth/btqca.c
>> @@ -1,7 +1,7 @@
>> /*
>>  *  Bluetooth supports for Qualcomm Atheros chips
>>  *
>> - *  Copyright (c) 2015 The Linux Foundation. All rights reserved.
>> + *  Copyright (c) 2015, 2018 The Linux Foundation. All rights 
>> reserved.
>>  *
>>  *  This program is free software; you can redistribute it and/or 
>> modify
>>  *  it under the terms of the GNU General Public License version 2
>> @@ -19,82 +19,18 @@
>>  */
>> #include <linux/module.h>
>> #include <linux/firmware.h>
>> -
>> #include <net/bluetooth/bluetooth.h>
>> #include <net/bluetooth/hci_core.h>
>> -
>> #include "btqca.h"
>> 
>> #define VERSION "0.1"
>> 
>> -static int rome_patch_ver_req(struct hci_dev *hdev, u32 
>> *rome_version)
>> -{
>> -	struct sk_buff *skb;
>> -	struct edl_event_hdr *edl;
>> -	struct rome_version *ver;
>> -	char cmd;
>> -	int err = 0;
>> -
>> -	BT_DBG("%s: ROME Patch Version Request", hdev->name);
>> -
>> -	cmd = EDL_PATCH_VER_REQ_CMD;
>> -	skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, 
>> EDL_PATCH_CMD_LEN,
>> -				&cmd, HCI_VENDOR_PKT, HCI_INIT_TIMEOUT);
>> -	if (IS_ERR(skb)) {
>> -		err = PTR_ERR(skb);
>> -		BT_ERR("%s: Failed to read version of ROME (%d)", hdev->name,
>> -		       err);
>> -		return err;
>> -	}
>> -
>> -	if (skb->len != sizeof(*edl) + sizeof(*ver)) {
>> -		BT_ERR("%s: Version size mismatch len %d", hdev->name,
>> -		       skb->len);
>> -		err = -EILSEQ;
>> -		goto out;
>> -	}
>> -
>> -	edl = (struct edl_event_hdr *)(skb->data);
>> -	if (!edl) {
>> -		BT_ERR("%s: TLV with no header", hdev->name);
>> -		err = -EILSEQ;
>> -		goto out;
>> -	}
>> -
>> -	if (edl->cresp != EDL_CMD_REQ_RES_EVT ||
>> -	    edl->rtype != EDL_APP_VER_RES_EVT) {
>> -		BT_ERR("%s: Wrong packet received %d %d", hdev->name,
>> -		       edl->cresp, edl->rtype);
>> -		err = -EIO;
>> -		goto out;
>> -	}
>> -
>> -	ver = (struct rome_version *)(edl->data);
>> -
>> -	BT_DBG("%s: Product:0x%08x", hdev->name, 
>> le32_to_cpu(ver->product_id));
>> -	BT_DBG("%s: Patch  :0x%08x", hdev->name, 
>> le16_to_cpu(ver->patch_ver));
>> -	BT_DBG("%s: ROM    :0x%08x", hdev->name, 
>> le16_to_cpu(ver->rome_ver));
>> -	BT_DBG("%s: SOC    :0x%08x", hdev->name, le32_to_cpu(ver->soc_id));
>> -
>> -	/* ROME chipset version can be decided by patch and SoC
>> -	 * version, combination with upper 2 bytes from SoC
>> -	 * and lower 2 bytes from patch will be used.
>> -	 */
>> -	*rome_version = (le32_to_cpu(ver->soc_id) << 16) |
>> -			(le16_to_cpu(ver->rome_ver) & 0x0000ffff);
>> -
>> -out:
>> -	kfree_skb(skb);
>> -
>> -	return err;
>> -}
>> -
>> -static int rome_reset(struct hci_dev *hdev)
>> +static int qca_btsoc_reset(struct hci_dev *hdev)
>> {
>> 	struct sk_buff *skb;
>> 	int err;
>> 
>> -	BT_DBG("%s: ROME HCI_RESET", hdev->name);
>> +	BT_DBG("%s: ROME/wcn3990 HCI_RESET", hdev->name);
>> 
>> 	skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
>> 	if (IS_ERR(skb)) {
>> @@ -108,7 +44,7 @@ static int rome_reset(struct hci_dev *hdev)
>> 	return 0;
>> }
>> 
>> -static void rome_tlv_check_data(struct rome_config *config,
>> +static void rome_tlv_check_data(struct qca_config *config,
>> 				const struct firmware *fw)
>> {
>> 	const u8 *data;
>> @@ -194,8 +130,121 @@ static void rome_tlv_check_data(struct 
>> rome_config *config,
>> 	}
>> }
>> 
>> -static int rome_tlv_send_segment(struct hci_dev *hdev, int idx, int 
>> seg_size,
>> -				 const u8 *data)
>> +static void cherokee_tlv_check_data(struct qca_config *config,
>> +			const struct firmware *fw, bool *dwnd_flag)
>> +{
>> +	const u8 *data;
>> +	u32 type_len;
>> +	u16 tag_id, tag_len;
>> +	int idx, length;
>> +	struct tlv_type_hdr *tlv;
>> +	struct cherokee_tlv_type_patch *tlv_patch;
>> +	struct tlv_type_nvm *tlv_nvm;
>> +
>> +	tlv = (struct tlv_type_hdr *)fw->data;
>> +
>> +	type_len = le32_to_cpu(tlv->type_len);
>> +	length = (type_len >> 8) & 0x00ffffff;
>> +
>> +	BT_DBG("TLV Type\t\t : 0x%x", type_len & 0x000000ff);
>> +	BT_DBG("Length\t\t : %d bytes", length);
>> +
>> +	switch (config->type) {
>> +	case TLV_TYPE_PATCH:
>> +		tlv_patch = (struct tlv_type_patch *)tlv->data;
>> +		BT_DBG("Total Length\t\t : %d bytes",
>> +			le32_to_cpu(tlv_patch->total_size));
>> +		BT_DBG("Patch Data Length\t : %d bytes",
>> +			le32_to_cpu(tlv_patch->data_length));
>> +		BT_DBG("Signing Format Version : 0x%x",
>> +			tlv_patch->format_version);
>> +		BT_DBG("Signature Algorithm\t : 0x%x",
>> +			tlv_patch->signature);
>> +		BT_DBG("Download flag\t : 0x%x",
>> +			tlv_patch->dwnd_cfg);
>> +		BT_DBG("Reserved\t\t : 0x%x",
>> +			le16_to_cpu(tlv_patch->reserved1));
>> +		BT_DBG("Product ID\t\t : 0x%04x",
>> +			le16_to_cpu(tlv_patch->product_id));
>> +		BT_DBG("Rom Build Version\t : 0x%04x",
>> +			le16_to_cpu(tlv_patch->rom_build));
>> +		BT_DBG("Patch Version\t\t : 0x%04x",
>> +			le16_to_cpu(tlv_patch->patch_version));
>> +		BT_DBG("Reserved\t\t : 0x%x",
>> +			le16_to_cpu(tlv_patch->reserved2));
>> +		BT_DBG("Patch Entry Address\t : 0x%x",
>> +			le32_to_cpu(tlv_patch->entry));
>> +		/* If the download flag is 0x03, don't wait
>> +		 * for response from soc,i.e. 1 to n-1
>> +		 * segment download.
>> +		 */
>> +		if (tlv_patch->dwnd_cfg == 0x03)
>> +			*dwnd_flag = false;
>> +		else
>> +			*dwnd_flag = true;
>> +		break;
>> +
>> +	case TLV_TYPE_NVM:
>> +		idx = 0;
>> +		data = tlv->data;
>> +		while (idx < length) {
>> +			tlv_nvm = (struct tlv_type_nvm *)(data + idx);
>> +			tag_id = le16_to_cpu(tlv_nvm->tag_id);
>> +			tag_len = le16_to_cpu(tlv_nvm->tag_len);
>> +
>> +			/* Update NVM tags as needed */
>> +			switch (tag_id) {
>> +			case EDL_TAG_ID_HCI:
>> +				/* HCI transport layer parameters
>> +				 * enabling software inband sleep
>> +				 * onto controller side.
>> +				 */
>> +				tlv_nvm->data[0] |= 0x80;
>> +
>> +				/* UART Baud Rate */
>> +				tlv_nvm->data[2] = config->user_baud_rate;
>> +				break;
>> +			case EDL_TAG_ID_DEEP_SLEEP:
>> +				/* Sleep enable mask
>> +				 * enabling deep sleep feature on controller.
>> +				 */
>> +				tlv_nvm->data[0] |= 0x01;
>> +				break;
>> +			}
>> +
>> +			idx += (sizeof(u16) + sizeof(u16) + 8 + tag_len);
>> +		}
>> +		break;
>> +	default:
>> +		BT_ERR("Unknown TLV type %d", config->type);
>> +		break;
>> +	}
>> +}
>> +
>> +static int cherokee_tlv_send_segment(struct hci_dev *hdev, int idx,
>> +					int seg_size, const u8 *data)
>> +{
>> +	u8 cmd[MAX_SIZE_PER_TLV_SEGMENT + 2];
>> +	int err = 0;
>> +
>> +	BT_DBG("%s: Download segment #%d size %d", hdev->name, idx, 
>> seg_size);
>> +
>> +	cmd[0] = EDL_PATCH_TLV_REQ_CMD;
>> +	cmd[1] = seg_size;
>> +	memcpy(cmd + 2, data, seg_size);
>> +
>> +	err = __hci_cmd_no_event(hdev, EDL_PATCH_CMD_OPCODE, seg_size + 2,
>> +					cmd);
>> +	if (err < 0) {
>> +		BT_ERR("%s: Failed to send TLV segment (%d)", hdev->name, err);
>> +		return err;
>> +	}
>> +
>> +	return err;
>> +}
>> +
>> +static int qca_btsoc_tlv_send_segment(struct hci_dev *hdev, int idx,
>> +					int seg_size, const u8 *data)
>> {
>> 	struct sk_buff *skb;
>> 	struct edl_event_hdr *edl;
>> @@ -264,16 +313,56 @@ static int rome_tlv_download_request(struct 
>> hci_dev *hdev,
>> 	data = fw->data;
>> 	for (i = 0; i < total_segment; i++) {
>> 		buffer = data + i * MAX_SIZE_PER_TLV_SEGMENT;
>> -		ret = rome_tlv_send_segment(hdev, i, MAX_SIZE_PER_TLV_SEGMENT,
>> -					    buffer);
>> +		ret = qca_btsoc_tlv_send_segment(hdev, i,
>> +					MAX_SIZE_PER_TLV_SEGMENT, buffer);
>> 		if (ret < 0)
>> 			return -EIO;
>> 	}
>> 
>> 	if (remain_size) {
>> 		buffer = data + total_segment * MAX_SIZE_PER_TLV_SEGMENT;
>> -		ret = rome_tlv_send_segment(hdev, total_segment, remain_size,
>> -					    buffer);
>> +		ret = qca_btsoc_tlv_send_segment(hdev, total_segment,
>> +							remain_size, buffer);
>> +		if (ret < 0)
>> +			return -EIO;
>> +	}
>> +
>> +	return 0;
>> +}
>> +static int cherokee_tlv_download_request(struct hci_dev *hdev,
>> +			const struct firmware *fw)
>> +{
>> +	const u8 *buffer, *data;
>> +	int total_segment, remain_size;
>> +	int ret, i;
>> +
>> +	if (!fw || !fw->data)
>> +		return -EINVAL;
>> +
>> +	total_segment = fw->size / MAX_SIZE_PER_TLV_SEGMENT;
>> +	remain_size = fw->size % MAX_SIZE_PER_TLV_SEGMENT;
>> +
>> +	BT_DBG("%s: Total segment num %d remain size %d total size %zu",
>> +			hdev->name, total_segment, remain_size, fw->size);
>> +
>> +	data = fw->data;
>> +	for (i = 0; i < total_segment; i++) {
>> +		buffer = data + i * MAX_SIZE_PER_TLV_SEGMENT;
>> +		/* Read response from soc for last segment sent */
>> +		if (!remain_size && ((i+1) == total_segment))
>> +			ret = qca_btsoc_tlv_send_segment(hdev, i,
>> +					MAX_SIZE_PER_TLV_SEGMENT, buffer);
>> +		else
>> +			ret = cherokee_tlv_send_segment(hdev, i,
>> +					MAX_SIZE_PER_TLV_SEGMENT, buffer);
>> +		if (ret < 0)
>> +			return -EIO;
>> +	}
>> +
>> +	if (remain_size) {
>> +		buffer = data + total_segment * MAX_SIZE_PER_TLV_SEGMENT;
>> +		ret = qca_btsoc_tlv_send_segment(hdev, total_segment,
>> +							remain_size, buffer);
>> 		if (ret < 0)
>> 			return -EIO;
>> 	}
>> @@ -282,7 +371,7 @@ static int rome_tlv_download_request(struct 
>> hci_dev *hdev,
>> }
>> 
>> static int rome_download_firmware(struct hci_dev *hdev,
>> -				  struct rome_config *config)
>> +				  struct qca_config *config)
>> {
>> 	const struct firmware *fw;
>> 	int ret;
>> @@ -309,7 +398,46 @@ static int rome_download_firmware(struct hci_dev 
>> *hdev,
>> 	return ret;
>> }
>> 
>> -int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
>> +static int cherokee_download_firmware(struct hci_dev *hdev,
>> +					struct qca_config *config)
>> +{
>> +	const struct firmware *fw;
>> +	bool dwnd_flag = true;
>> +	int ret;
>> +
>> +	bt_dev_info(hdev, "wcn3990  Downloading", config->fwname);
>> +
>> +	ret = request_firmware(&fw, config->fwname, &hdev->dev);
>> +	if (ret) {
>> +		BT_ERR("%s: Failed to request file: %s (%d)", hdev->name,
>> +			config->fwname, ret);
>> +		return ret;
>> +	}
>> +
>> +	cherokee_tlv_check_data(config, fw, &dwnd_flag);
>> +	/* check whether the download flag is set.if bit is enabled
>> +	 * terminate the ram patch download. As we are not supporting,
>> +	 * receiving of response from soc for every segment sent.
>> +	 * We look for response from soc for last segment.
>> +	 */
>> +	if (dwnd_flag == true && config->type == TLV_TYPE_PATCH) {
>> +		BT_ERR("%s: btsoc download flag enabled", hdev->name);
>> +		return -EOPNOTSUPP;
>> +	}
>> +
>> +	ret = cherokee_tlv_download_request(hdev, fw);
>> +	if (ret) {
>> +		BT_ERR("%s: Failed to download file: %s (%d)", hdev->name,
>> +		config->fwname, ret);
>> +	}
>> +
>> +	release_firmware(fw);
>> +
>> +	return ret;
>> +}
>> +
>> +
>> +int qca_btsoc_set_bdaddr(struct hci_dev *hdev, const bdaddr_t 
>> *bdaddr)
>> {
>> 	struct sk_buff *skb;
>> 	u8 cmd[9];
>> @@ -332,12 +460,12 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, 
>> const bdaddr_t *bdaddr)
>> 
>> 	return 0;
>> }
>> -EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome);
>> +EXPORT_SYMBOL_GPL(qca_btsoc_set_bdaddr);
> 
> so why is this all intermixed in a single patch. And please don’t
> change this. If you want a qca_set_bdaddr, then fine, otherwise keep
> the _rome postfix. Also these things can really be cleaned up in a
> follow up patch.

[Bala] as we use same function for New chip too. so generic naming 
instead on *_rome.

>> 
>> int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate)
>> {
>> 	u32 rome_ver = 0;
>> -	struct rome_config config;
>> +	struct qca_config config;
>> 	int err;
>> 
>> 	BT_DBG("%s: ROME setup on UART", hdev->name);
>> @@ -345,7 +473,7 @@ int qca_uart_setup_rome(struct hci_dev *hdev, 
>> uint8_t baudrate)
>> 	config.user_baud_rate = baudrate;
>> 
>> 	/* Get ROME version information */
>> -	err = rome_patch_ver_req(hdev, &rome_ver);
>> +	err = qca_btsoc_patch_ver_req(hdev, &rome_ver);
> 
> So this qca_btsoc naming is not something I like at all. Please skip
> this renaming and make patches as simple as possible.

[Bala] for sending patch version request, we use same function for old 
SoC and New SoC. "qca_btsoc" will rename.

> 
>> 	if (err < 0 || rome_ver == 0) {
>> 		BT_ERR("%s: Failed to get version 0x%x", hdev->name, err);
>> 		return err;
>> @@ -374,7 +502,7 @@ int qca_uart_setup_rome(struct hci_dev *hdev, 
>> uint8_t baudrate)
>> 	}
>> 
>> 	/* Perform HCI reset */
>> -	err = rome_reset(hdev);
>> +	err = qca_btsoc_reset(hdev);
>> 	if (err < 0) {
>> 		BT_ERR("%s: Failed to run HCI_RESET (%d)", hdev->name, err);
>> 		return err;
>> @@ -386,6 +514,111 @@ int qca_uart_setup_rome(struct hci_dev *hdev, 
>> uint8_t baudrate)
>> }
>> EXPORT_SYMBOL_GPL(qca_uart_setup_rome);
>> 
>> +int qca_btsoc_patch_ver_req(struct hci_dev *hdev, u32 *soc_version)
>> +{
>> +	struct sk_buff *skb;
>> +	struct edl_event_hdr *edl;
>> +	struct qca_btsoc_version *ver;
>> +	char cmd;
>> +	int err = 0;
>> +
>> +	BT_DBG("%s: BTSOC Patch Version Request", hdev->name);
>> +
>> +	cmd = EDL_PATCH_VER_REQ_CMD;
>> +	skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, 
>> EDL_PATCH_CMD_LEN,
>> +				&cmd, HCI_VENDOR_PKT, HCI_INIT_TIMEOUT);
>> +	if (IS_ERR(skb)) {
>> +		err = PTR_ERR(skb);
>> +		BT_ERR("%s: Failed to read version of ROME (%d)", hdev->name,
>> +		       err);
>> +		return err;
>> +	}
>> +
>> +	if (skb->len != sizeof(*edl) + sizeof(*ver)) {
>> +		BT_ERR("%s: Version size mismatch len %d", hdev->name,
>> +		       skb->len);
>> +		err = -EILSEQ;
>> +		goto out;
>> +	}
>> +
>> +	edl = (struct edl_event_hdr *)(skb->data);
>> +	if (!edl) {
>> +		BT_ERR("%s: TLV with no header", hdev->name);
>> +		err = -EILSEQ;
>> +		goto out;
>> +	}
>> +
>> +	if (edl->cresp != EDL_CMD_REQ_RES_EVT ||
>> +	    edl->rtype != EDL_APP_VER_RES_EVT) {
>> +		BT_ERR("%s: Wrong packet received %d %d", hdev->name,
>> +		       edl->cresp, edl->rtype);
>> +		err = -EIO;
>> +		goto out;
>> +	}
>> +
>> +	ver = (struct qca_btsoc_version *)(edl->data);
>> +
>> +	BT_DBG("%s: Product:0x%08x", hdev->name, 
>> le32_to_cpu(ver->product_id));
>> +	BT_DBG("%s: Patch  :0x%08x", hdev->name, 
>> le16_to_cpu(ver->patch_ver));
>> +	BT_DBG("%s: ROM    :0x%08x", hdev->name, 
>> le16_to_cpu(ver->btsoc_ver));
>> +	BT_DBG("%s: SOC    :0x%08x", hdev->name, le32_to_cpu(ver->soc_id));
>> +
>> +	/* BTSOC chipset version can be decided by patch and SoC
>> +	 * version, combination with upper 2 bytes from SoC
>> +	 * and lower 2 bytes from patch will be used.
>> +	 */
>> +	*soc_version = (le32_to_cpu(ver->soc_id) << 16) |
>> +				(le16_to_cpu(ver->btsoc_ver) & 0x0000ffff);
>> +
>> +out:
>> +	kfree_skb(skb);
>> +
>> +	return err;
>> +}
>> +EXPORT_SYMBOL_GPL(qca_btsoc_patch_ver_req);
>> +
>> +int qca_uart_setup_cherokee(struct hci_dev *hdev, uint8_t baudrate,
>> +					u32 *cherokee_ver)
>> +{
>> +	struct qca_config config;
>> +	int err;
>> +
>> +	BT_DBG("%s: wcn3990 setup on UART", hdev->name);
>> +	config.user_baud_rate = baudrate;
>> +
>> +	/* Download rampatch file */
>> +	config.type = TLV_TYPE_PATCH;
>> +	snprintf(config.fwname, sizeof(config.fwname), 
>> "qca/rampatch_%08x.tlv",
>> +		*cherokee_ver);
>> +	err = cherokee_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",
>> +		*cherokee_ver);
>> +	err = cherokee_download_firmware(hdev, &config);
>> +	if (err < 0) {
>> +		BT_ERR("%s: Failed to download NVM (%d)", hdev->name, err);
>> +		return err;
>> +	}
>> +
>> +	/* Perform HCI reset */
>> +	err = qca_btsoc_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 65e994b..7608423 100644
>> --- a/drivers/bluetooth/btqca.h
>> +++ b/drivers/bluetooth/btqca.h
>> @@ -1,7 +1,7 @@
>> /*
>>  *  Bluetooth supports for Qualcomm Atheros ROME chips
>>  *
>> - *  Copyright (c) 2015 The Linux Foundation. All rights reserved.
>> + *  Copyright (c) 2015, 2018 The Linux Foundation. All rights 
>> reserved.
>>  *
>>  *  This program is free software; you can redistribute it and/or 
>> modify
>>  *  it under the terms of the GNU General Public License version 2
>> @@ -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,
>> @@ -66,7 +69,7 @@ enum rome_tlv_type {
>> 	TLV_TYPE_NVM
>> };
>> 
>> -struct rome_config {
>> +struct qca_config {
>> 	u8 type;
>> 	char fwname[64];
>> 	uint8_t user_baud_rate;
>> @@ -78,13 +81,14 @@ struct edl_event_hdr {
>> 	__u8 data[0];
>> } __packed;
>> 
>> -struct rome_version {
>> +struct qca_btsoc_version {
>> 	__le32 product_id;
>> 	__le16 patch_ver;
>> -	__le16 rome_ver;
>> +	__le16 btsoc_ver;
>> 	__le32 soc_id;
>> } __packed;
>> 
>> +
>> struct tlv_seg_resp {
>> 	__u8 result;
>> } __packed;
>> @@ -102,6 +106,21 @@ struct tlv_type_patch {
>> 	__le32 entry;
>> } __packed;
>> 
>> +struct cherokee_tlv_type_patch {
>> +	__le32 total_size;
>> +	__le32 data_length;
>> +	__u8   format_version;
>> +	__u8   signature;
>> +	__u8   dwnd_cfg;
>> +	__le16 reserved1;
>> +	__le16 product_id;
>> +	__le16 rom_build;
>> +	__le16 patch_version;
>> +	__le16 reserved2;
>> +	__le32 entry;
>> +} __packed;
>> +
>> +
>> struct tlv_type_nvm {
>> 	__le16 tag_id;
>> 	__le16 tag_len;
>> @@ -115,14 +134,21 @@ struct tlv_type_hdr {
>> 	__u8   data[0];
>> } __packed;

> 
> This all needs to be aligned with the patches from Loic first.
> 

[Bala]- previously defined structures for old chip, are reused for new 
chip with generic naming.
         updating this file may have some conflicts with 
btqcomsmd.c(Loic), as per initial analysis they are calling
         function "qca_set_bdaddr_rome" which is renamed as 
qca_btsoc_set_bdaddr in our patch.
         Will dig more to understand the impact on file btqcomsmd.c.

>> 
>> +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_btsoc_set_bdaddr(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 *cherokee_ver);
>> +int qca_btsoc_patch_ver_req(struct hci_dev *hdev, u32 *soc_version);
>> 
>> #else
>> 
>> -static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const 
>> bdaddr_t *bdaddr)
>> +static inline int qca_btsoc_set_bdaddr(struct hci_dev *hdev,
>> +						const bdaddr_t *bdaddr)
>> {
>> 	return -EOPNOTSUPP;
>> }
>> @@ -132,4 +158,15 @@ static inline int qca_uart_setup_rome(struct 
>> hci_dev *hdev, int speed)
>> 	return -EOPNOTSUPP;
>> }
>> 
>> +static inline int qca_uart_setup_cherokee(struct hci_dev *hdev,
>> +					uint8_t baudrate, u32 *cherokee_ver)
>> +{
>> +	return -EOPNOTSUPP;
>> +}
>> +
>> +static int qca_btsoc_patch_ver_req(struct hci_dev *hdev, u32 
>> *cherokee_version)
>> +{
>> +	return -EOPNOTSUPP;
>> +}
>> +
>> #endif
>> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
>> index f05382b..bc08559 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,9 +35,13 @@
>> #include <linux/mod_devicetable.h>
>> #include <linux/module.h>
>> #include <linux/serdev.h>
>> -
>> #include <net/bluetooth/bluetooth.h>
>> #include <net/bluetooth/hci_core.h>
>> +#include <asm-generic/delay.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/delay.h>
>> +#include <linux/regulator/consumer.h>
>> +#include <linux/of_device.h>
>> 
>> #include "hci_uart.h"
>> #include "btqca.h"
>> @@ -119,12 +123,49 @@ 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;
>> +};
>> +
>> +/*
>> + * 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;
>> +	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
>> @@ -461,9 +502,11 @@ static int qca_open(struct hci_uart *hu)
>> 
>> 	if (hu->serdev) {
>> 		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)
>> +			btqca_power_setup(true);
> 
> This can not be what we are doing. If there needs to be global power
> on, then that needs to be done differently. This ->open callback is
> specific to the Bluetooth chip. And only that chip, not the 3 others
> in the system.
> 
> Just to make this clear, I am not taking code that thinks there is
> only one Bluetooth chip in the system. I refused to do this for
> btqcomsmd and I will refuse this here. So please get this sorted.

[Bala]- we have only one Bluetooth chip in system. we are 
differentiating which btchip is attached to system.
         based upon the chip, turning on differs as New chip requires to 
vote regulators.
         where as old require to set a GPIO.

> 
>> +		else
>> +			gpiod_set_value_cansleep(qcadev->bt_en, 1);
>> 	}
>> 
>> 	BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u",
>> @@ -552,7 +595,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 +918,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 +934,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 +971,266 @@ 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));
> 
> Don’t we have a skb_put_u8?
> 
>> +	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);
> 
> And this can not just be an msleep?
> 
>> +
>> +	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, "%s: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;
>> +}
> 
> I assumed we already have QCA serdev support merged into
> bluetooth-next. What is this doing?
> 

[Bala]- we are trying to close and open the serial port in qca_setup, 
that requires qca_serdev_close().
         May be naming convention is confusing.

>> +
>> 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;
>> +	unsigned 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");
>> +		/* clear flow control- for sync cmd*/
>> +		hci_uart_set_flow_control(hu, true);
>> +		/* send poweron command to btsoc */
>> +		ret = qca_send_poweron_cmd(hdev);
>> +		if (ret) {
>> +			BT_ERR("%s:sending sync command failed", hdev->name);
>> +			return ret;
>> +		}
>> 
>> -	/* Patch downloading has to be done without IBS mode */
>> -	clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
>> +		/* close port */
>> +		ret = qca_serdev_close(hu);
>> +		if (ret)
>> +			return ret;
>> +		/* reopen 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;
>> +		if (speed)
>> +			host_set_baudrate(hu, speed);
>> +		else {
>> +			bt_dev_err(hdev, "initial speed %u", speed);
>> +			return -1;
>> +		}
>> 
>> -	/* Setup initial baudrate */
>> -	speed = 0;
>> -	if (hu->init_speed)
>> -		speed = hu->init_speed;
>> -	else if (hu->proto->init_speed)
>> -		speed = hu->proto->init_speed;
>> +		/* Enable flow control */
>> +		hci_uart_set_flow_control(hu, false);
>> +		/*  wait until flow control settled */
>> +		mdelay(100);
>> 
>> -	if (speed)
>> -		host_set_baudrate(hu, speed);
>> +		ret = qca_btsoc_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)
>> +		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 = 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);
>> +		}
>> 
>> -	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);
>> +		}
>> 
>> -		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;
>> +		/* Setup wcn3990 bdaddr */
>> +		hu->hdev->set_bdaddr = qca_btsoc_set_bdaddr;
>> +
>> +		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)
>> +			hci_uart_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_btsoc_set_bdaddr;
>> 
>> -	return ret;
>> +		return ret;
>> +	}
>> }
>> 
>> static struct hci_uart_proto qca_proto = {
>> @@ -1002,42 +1248,142 @@ 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 },
>> +		{ "vddpwd",  3312000, 3600000,  0 },
>> +	},
>> +	.num_vregs = 6,
>> +};
>> +
>> +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; 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);
>> +
>> +			regulator_enable(qca->vreg_bulk[i].consumer);
>> +		}
>> +	} else if (on == false && qca->vreg_status == true) {
>> +		qca->vreg_status = false;
>> +		for (i = 0; i < qca->vreg_data->num_vregs; i++) {
>> +			regulator_disable(qca->vreg_bulk[i].consumer);
>> +			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);
>> +		}
>> +	}
>> +
>> +	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;
>> +	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);
>> +		}
>> 
>> -	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;
>> +		err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
>> +		if (err) {
>> +			BT_ERR("wcn3990 serdev registration failed");
>> +			kfree(qca);
>> +		}
>> +	} 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);
>> +		}
>> 
>> -	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);
>> -	}
>> +		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_set_rate(qcadev->susclk, SUSCLK_RATE_32KHZ);
>> -	if (err)
>> -		return err;
>> +		err = clk_set_rate(qcadev->susclk, SUSCLK_RATE_32KHZ);
>> +		if (err)
>> +			return err;
>> 
>> -	err = clk_prepare_enable(qcadev->susclk);
>> -	if (err)
>> -		return err;
>> +		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);
>> +		err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
>> +		if (err)
>> +			clk_disable_unprepare(qcadev->susclk);
>> +	}
>> 
>> 	return err;
>> }
>> @@ -1047,12 +1393,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);
>> diff --git a/include/net/bluetooth/hci_core.h 
>> b/include/net/bluetooth/hci_core.h
>> index b619a19..a12e967 100644
>> --- a/include/net/bluetooth/hci_core.h
>> +++ b/include/net/bluetooth/hci_core.h
>> @@ -1393,7 +1393,8 @@ struct sk_buff *__hci_cmd_sync(struct hci_dev 
>> *hdev, u16 opcode, u32 plen,
>> 			       const void *param, u32 timeout);
>> struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, 
>> u32 plen,
>> 				  const void *param, u8 event, u32 timeout);
>> -
>> +int __hci_cmd_no_event(struct hci_dev *hdev, u16 opcode, u32 plen,
>> +			const void *param);
>> int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen,
>> 		 const void *param);
> 
> NAK, see my comments that I send Loic for this kind of change. We also
> don’t intermix net/ and drivers/ unless needed. So this can be easily
> separated.
> 

[Bala] yes we are calling function __hci_cmd_no_event from btqca(this 
function is added to Queue a frame to an asynchronous transfer to 
btdevice,with out any event from btdevice).
        Will check your comments for Loic.


> Regards
> 
> Marcel


Please let us know if you have queries. Meantime will also study Loic 
changes if required will align my patches according to his patch.

Regards
Balakrishna

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

* Re: [PATCH v3 2/2] Bluetooth: Add support for wcn3990 soc.
  2018-04-24 14:11 ` [PATCH v3 2/2] Bluetooth: Add support for wcn3990 soc Balakrishna Godavarthi
  2018-04-24 15:28   ` Marcel Holtmann
@ 2018-04-26  7:38   ` kbuild test robot
  2018-04-26  8:12   ` kbuild test robot
  2 siblings, 0 replies; 8+ messages in thread
From: kbuild test robot @ 2018-04-26  7:38 UTC (permalink / raw)
  To: Balakrishna Godavarthi
  Cc: kbuild-all, marcel, johan.hedberg, linux-bluetooth, rtatiya,
	linux-arm-msm, hemantg, Balakrishna Godavarthi

[-- Attachment #1: Type: text/plain, Size: 6729 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-20180424]
[cannot apply to v4.17-rc2]
[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/Enable-Bluetooth-functionality-for-WCN3990/20180426-103256
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master
config: x86_64-randconfig-x000-201816 (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 error/warnings (new ones prefixed by >>):

   In file included from drivers//bluetooth/hci_qca.c:38:0:
   drivers//bluetooth/hci_qca.c: In function 'qca_serdev_open':
>> include/net/bluetooth/bluetooth.h:146:9: warning: format '%s' expects a matching 'char *' argument [-Wformat=]
     BT_ERR("%s: " fmt, (hdev)->name, ##__VA_ARGS__)
            ^
   include/net/bluetooth/bluetooth.h:136:33: note: in definition of macro 'BT_ERR'
    #define BT_ERR(fmt, ...) bt_err(fmt "\n", ##__VA_ARGS__)
                                    ^~~
>> drivers//bluetooth/hci_qca.c:1041:3: note: in expansion of macro 'bt_dev_err'
      bt_dev_err(hu->hdev, "%s:open operation not supported");
      ^~~~~~~~~~
   drivers//bluetooth/hci_qca.c:1041:26: note: format string is defined here
      bt_dev_err(hu->hdev, "%s:open operation not supported");
                            ~^
   drivers//bluetooth/hci_qca.c: In function 'qca_serdev_probe':
>> drivers//bluetooth/hci_qca.c:1334:7: warning: assignment discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
     data = of_device_get_match_data(&serdev->dev);
          ^
   drivers//bluetooth/hci_qca.c: In function 'btqca_power_setup':
>> drivers//bluetooth/hci_qca.c:1288:4: warning: ignoring return value of 'regulator_enable', declared with attribute warn_unused_result [-Wunused-result]
       regulator_enable(qca->vreg_bulk[i].consumer);
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
   drivers//bluetooth/btqca.c: In function 'cherokee_tlv_check_data':
>> drivers//bluetooth/btqca.c:154:13: error: assignment from incompatible pointer type [-Werror=incompatible-pointer-types]
      tlv_patch = (struct tlv_type_patch *)tlv->data;
                ^
   In file included from drivers//bluetooth/btqca.c:22:0:
   drivers//bluetooth/btqca.c: In function 'cherokee_download_firmware':
>> include/net/bluetooth/bluetooth.h:142:10: warning: too many arguments for format [-Wformat-extra-args]
     BT_INFO("%s: " fmt, (hdev)->name, ##__VA_ARGS__)
             ^
   include/net/bluetooth/bluetooth.h:134:35: note: in definition of macro 'BT_INFO'
    #define BT_INFO(fmt, ...) bt_info(fmt "\n", ##__VA_ARGS__)
                                      ^~~
>> drivers//bluetooth/btqca.c:408:2: note: in expansion of macro 'bt_dev_info'
     bt_dev_info(hdev, "wcn3990  Downloading", config->fwname);
     ^~~~~~~~~~~
   cc1: some warnings being treated as errors
--
   In file included from drivers/bluetooth/hci_qca.c:38:0:
   drivers/bluetooth/hci_qca.c: In function 'qca_serdev_open':
>> include/net/bluetooth/bluetooth.h:146:9: warning: format '%s' expects a matching 'char *' argument [-Wformat=]
     BT_ERR("%s: " fmt, (hdev)->name, ##__VA_ARGS__)
            ^
   include/net/bluetooth/bluetooth.h:136:33: note: in definition of macro 'BT_ERR'
    #define BT_ERR(fmt, ...) bt_err(fmt "\n", ##__VA_ARGS__)
                                    ^~~
   drivers/bluetooth/hci_qca.c:1041:3: note: in expansion of macro 'bt_dev_err'
      bt_dev_err(hu->hdev, "%s:open operation not supported");
      ^~~~~~~~~~
   drivers/bluetooth/hci_qca.c:1041:26: note: format string is defined here
      bt_dev_err(hu->hdev, "%s:open operation not supported");
                            ~^
   drivers/bluetooth/hci_qca.c: In function 'qca_serdev_probe':
   drivers/bluetooth/hci_qca.c:1334:7: warning: assignment discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
     data = of_device_get_match_data(&serdev->dev);
          ^
   drivers/bluetooth/hci_qca.c: In function 'btqca_power_setup':
   drivers/bluetooth/hci_qca.c:1288:4: warning: ignoring return value of 'regulator_enable', declared with attribute warn_unused_result [-Wunused-result]
       regulator_enable(qca->vreg_bulk[i].consumer);
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
   drivers/bluetooth/btqca.c: In function 'cherokee_tlv_check_data':
   drivers/bluetooth/btqca.c:154:13: error: assignment from incompatible pointer type [-Werror=incompatible-pointer-types]
      tlv_patch = (struct tlv_type_patch *)tlv->data;
                ^
   In file included from drivers/bluetooth/btqca.c:22:0:
   drivers/bluetooth/btqca.c: In function 'cherokee_download_firmware':
>> include/net/bluetooth/bluetooth.h:142:10: warning: too many arguments for format [-Wformat-extra-args]
     BT_INFO("%s: " fmt, (hdev)->name, ##__VA_ARGS__)
             ^
   include/net/bluetooth/bluetooth.h:134:35: note: in definition of macro 'BT_INFO'
    #define BT_INFO(fmt, ...) bt_info(fmt "\n", ##__VA_ARGS__)
                                      ^~~
   drivers/bluetooth/btqca.c:408:2: note: in expansion of macro 'bt_dev_info'
     bt_dev_info(hdev, "wcn3990  Downloading", config->fwname);
     ^~~~~~~~~~~
   cc1: some warnings being treated as errors

vim +146 include/net/bluetooth/bluetooth.h

e781b7f7 Szymon Janc    2015-09-16  140  
6f558b70 Loic Poulain   2015-08-30  141  #define bt_dev_info(hdev, fmt, ...)				\
6f558b70 Loic Poulain   2015-08-30 @142  	BT_INFO("%s: " fmt, (hdev)->name, ##__VA_ARGS__)
594b31ea Frederic Danis 2015-09-23  143  #define bt_dev_warn(hdev, fmt, ...)				\
594b31ea Frederic Danis 2015-09-23  144  	BT_WARN("%s: " fmt, (hdev)->name, ##__VA_ARGS__)
6f558b70 Loic Poulain   2015-08-30  145  #define bt_dev_err(hdev, fmt, ...)				\
6f558b70 Loic Poulain   2015-08-30 @146  	BT_ERR("%s: " fmt, (hdev)->name, ##__VA_ARGS__)
6f558b70 Loic Poulain   2015-08-30  147  #define bt_dev_dbg(hdev, fmt, ...)				\
6f558b70 Loic Poulain   2015-08-30  148  	BT_DBG("%s: " fmt, (hdev)->name, ##__VA_ARGS__)
6f558b70 Loic Poulain   2015-08-30  149  

:::::: The code at line 146 was first introduced by commit
:::::: 6f558b70fb39fc8272fc513ecf191b3ad87d867b Bluetooth: Add bt_dev logging macros

:::::: TO: Loic Poulain <loic.poulain@intel.com>
:::::: CC: Marcel Holtmann <marcel@holtmann.org>

---
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: 29350 bytes --]

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

* Re: [PATCH v3 2/2] Bluetooth: Add support for wcn3990 soc.
  2018-04-24 14:11 ` [PATCH v3 2/2] Bluetooth: Add support for wcn3990 soc Balakrishna Godavarthi
  2018-04-24 15:28   ` Marcel Holtmann
  2018-04-26  7:38   ` kbuild test robot
@ 2018-04-26  8:12   ` kbuild test robot
  2 siblings, 0 replies; 8+ messages in thread
From: kbuild test robot @ 2018-04-26  8:12 UTC (permalink / raw)
  To: Balakrishna Godavarthi
  Cc: kbuild-all, marcel, johan.hedberg, linux-bluetooth, rtatiya,
	linux-arm-msm, hemantg, Balakrishna Godavarthi

[-- Attachment #1: Type: text/plain, Size: 6511 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-20180424]
[cannot apply to v4.17-rc2]
[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/Enable-Bluetooth-functionality-for-WCN3990/20180426-103256
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master
config: alpha-allyesconfig (attached as .config)
compiler: alpha-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=alpha 

All errors (new ones prefixed by >>):

   In file included from drivers//bluetooth/hci_qca.c:40:0:
>> include/asm-generic/delay.h:12:13: error: conflicting types for '__delay'
    extern void __delay(unsigned long loops);
                ^~~~~~~
   In file included from include/linux/delay.h:26:0,
                    from include/linux/serdev.h:19,
                    from drivers//bluetooth/hci_qca.c:37:
   arch/alpha/include/asm/delay.h:5:13: note: previous declaration of '__delay' was here
    extern void __delay(int loops);
                ^~~~~~~
   In file included from drivers//bluetooth/hci_qca.c:40:0:
   include/asm-generic/delay.h:33:0: warning: "ndelay" redefined
    #define ndelay(n)       \
    
   In file included from include/linux/delay.h:26:0,
                    from include/linux/serdev.h:19,
                    from drivers//bluetooth/hci_qca.c:37:
   arch/alpha/include/asm/delay.h:9:0: note: this is the location of the previous definition
    #define ndelay ndelay
    
   In file included from drivers//bluetooth/hci_qca.c:38:0:
   drivers//bluetooth/hci_qca.c: In function 'qca_serdev_open':
   include/net/bluetooth/bluetooth.h:146:9: warning: format '%s' expects a matching 'char *' argument [-Wformat=]
     BT_ERR("%s: " fmt, (hdev)->name, ##__VA_ARGS__)
            ^
   include/net/bluetooth/bluetooth.h:136:33: note: in definition of macro 'BT_ERR'
    #define BT_ERR(fmt, ...) bt_err(fmt "\n", ##__VA_ARGS__)
                                    ^~~
   drivers//bluetooth/hci_qca.c:1041:3: note: in expansion of macro 'bt_dev_err'
      bt_dev_err(hu->hdev, "%s:open operation not supported");
      ^~~~~~~~~~
   drivers//bluetooth/hci_qca.c:1041:26: note: format string is defined here
      bt_dev_err(hu->hdev, "%s:open operation not supported");
                            ~^
   drivers//bluetooth/hci_qca.c: In function 'qca_serdev_probe':
   drivers//bluetooth/hci_qca.c:1334:7: warning: assignment discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
     data = of_device_get_match_data(&serdev->dev);
          ^
   drivers//bluetooth/hci_qca.c: In function 'btqca_power_setup':
   drivers//bluetooth/hci_qca.c:1288:4: warning: ignoring return value of 'regulator_enable', declared with attribute warn_unused_result [-Wunused-result]
       regulator_enable(qca->vreg_bulk[i].consumer);
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
   In file included from drivers/bluetooth/hci_qca.c:40:0:
>> include/asm-generic/delay.h:12:13: error: conflicting types for '__delay'
    extern void __delay(unsigned long loops);
                ^~~~~~~
   In file included from include/linux/delay.h:26:0,
                    from include/linux/serdev.h:19,
                    from drivers/bluetooth/hci_qca.c:37:
   arch/alpha/include/asm/delay.h:5:13: note: previous declaration of '__delay' was here
    extern void __delay(int loops);
                ^~~~~~~
   In file included from drivers/bluetooth/hci_qca.c:40:0:
   include/asm-generic/delay.h:33:0: warning: "ndelay" redefined
    #define ndelay(n)       \
    
   In file included from include/linux/delay.h:26:0,
                    from include/linux/serdev.h:19,
                    from drivers/bluetooth/hci_qca.c:37:
   arch/alpha/include/asm/delay.h:9:0: note: this is the location of the previous definition
    #define ndelay ndelay
    
   In file included from drivers/bluetooth/hci_qca.c:38:0:
   drivers/bluetooth/hci_qca.c: In function 'qca_serdev_open':
   include/net/bluetooth/bluetooth.h:146:9: warning: format '%s' expects a matching 'char *' argument [-Wformat=]
     BT_ERR("%s: " fmt, (hdev)->name, ##__VA_ARGS__)
            ^
   include/net/bluetooth/bluetooth.h:136:33: note: in definition of macro 'BT_ERR'
    #define BT_ERR(fmt, ...) bt_err(fmt "\n", ##__VA_ARGS__)
                                    ^~~
   drivers/bluetooth/hci_qca.c:1041:3: note: in expansion of macro 'bt_dev_err'
      bt_dev_err(hu->hdev, "%s:open operation not supported");
      ^~~~~~~~~~
   drivers/bluetooth/hci_qca.c:1041:26: note: format string is defined here
      bt_dev_err(hu->hdev, "%s:open operation not supported");
                            ~^
   drivers/bluetooth/hci_qca.c: In function 'qca_serdev_probe':
   drivers/bluetooth/hci_qca.c:1334:7: warning: assignment discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
     data = of_device_get_match_data(&serdev->dev);
          ^
   drivers/bluetooth/hci_qca.c: In function 'btqca_power_setup':
   drivers/bluetooth/hci_qca.c:1288:4: warning: ignoring return value of 'regulator_enable', declared with attribute warn_unused_result [-Wunused-result]
       regulator_enable(qca->vreg_bulk[i].consumer);
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

vim +/__delay +12 include/asm-generic/delay.h

30ab2b03 Jonas Bonn    2011-07-02   8  
aafe4dbe Arnd Bergmann 2009-05-13   9  extern void __udelay(unsigned long usecs);
30ab2b03 Jonas Bonn    2011-07-02  10  extern void __ndelay(unsigned long nsecs);
30ab2b03 Jonas Bonn    2011-07-02  11  extern void __const_udelay(unsigned long xloops);
aafe4dbe Arnd Bergmann 2009-05-13 @12  extern void __delay(unsigned long loops);
aafe4dbe Arnd Bergmann 2009-05-13  13  

:::::: The code at line 12 was first introduced by commit
:::::: aafe4dbed0bf6cbdb2e9f03e1d42f8a540d8541d asm-generic: add generic versions of common headers

:::::: TO: Arnd Bergmann <arnd@arndb.de>
:::::: CC: Arnd Bergmann <arnd@klappe2.(none)>

---
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: 52483 bytes --]

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

end of thread, other threads:[~2018-04-26  8:12 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-24 14:11 [PATCH v3 0/2] Enable Bluetooth functionality for WCN3990 Balakrishna Godavarthi
2018-04-24 14:11 ` [PATCH v3 1/2] dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990 Balakrishna Godavarthi
2018-04-24 15:17   ` Marcel Holtmann
2018-04-24 14:11 ` [PATCH v3 2/2] Bluetooth: Add support for wcn3990 soc Balakrishna Godavarthi
2018-04-24 15:28   ` Marcel Holtmann
2018-04-25  9:14     ` bgodavar
2018-04-26  7:38   ` kbuild test robot
2018-04-26  8:12   ` 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.