linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: bgodavar@codeaurora.org
To: Thierry Escande <thierry.escande@linaro.org>
Cc: marcel@holtmann.org, johan.hedberg@gmail.com,
	linux-bluetooth@vger.kernel.org, rtatiya@codeaurora.org,
	linux-arm-msm@vger.kernel.org
Subject: Re: [PATCH v2 2/2] Bluetooth: Add support for wcn3990 soc.
Date: Mon, 23 Apr 2018 16:22:30 +0530	[thread overview]
Message-ID: <7e6b708736fab72d7f2facf43b2cf473@codeaurora.org> (raw)
In-Reply-To: <378fdaaa-a7f4-3305-ff14-d4eaa4362354@linaro.org>

Hi Thierry,

On 2018-04-20 21:41, Thierry Escande wrote:
> Hi Balakrishna,
> 
> On 19/04/2018 15:34, Balakrishna Godavarthi wrote:
>>   - 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      | 501 
>> +++++++++++++++++++++++++++++++++------
>>   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, 812 insertions(+), 161 deletions(-)
> 
> This is a pretty big patch. You should at least put the renaming of
> the rome_* functions and structures into a separate patch.

    yes this will be big patch as we have added support for qualcomm new 
bluetooth chip. In this we have changed existing function names rome_* 
to reuse it for new bluetooth chip. I feel we will not face any merge 
conflicts
    for btqca.c file. if we put rome_* function and structures into new 
patch, this make create merge conflicts for hci_qca.c file.

> 
> Also there are some coding style issues. You can use
> ./scripts/checkpatch.pl to check and fix them.
> 

   will double check the coding style issues.

> Regards,
> Thierry
> 
>> 
>> diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
>> index 0bbdfce..5b47df8 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_INFO("%s: wcn3990  Downloading %s", hdev->name, 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_INFO("%s: wcn3990 setup on UART is completed", hdev->name);
>> +
>> +	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 b7547e6..1343e63 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,15 @@
>>   #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/tty.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/delay.h>
>> +#include <linux/slab.h>
>> +#include <linux/regulator/consumer.h>
>> +#include <linux/of_device.h>
>>     #include "hci_uart.h"
>>   #include "btqca.h"
>> @@ -84,12 +90,12 @@ struct qca_data {
>>   	struct hci_uart *hu;
>>   	struct sk_buff *rx_skb;
>>   	struct sk_buff_head txq;
>> -	struct sk_buff_head tx_wait_q;	/* HCI_IBS wait queue	*/
>> -	spinlock_t hci_ibs_lock;	/* HCI_IBS state lock	*/
>> -	u8 tx_ibs_state;	/* HCI_IBS transmit side power state*/
>> -	u8 rx_ibs_state;	/* HCI_IBS receive side power state */
>> -	bool tx_vote;		/* Clock must be on for TX */
>> -	bool rx_vote;		/* Clock must be on for RX */
>> +	struct sk_buff_head tx_wait_q;  /* HCI_IBS wait queue   */
>> +	spinlock_t hci_ibs_lock;        /* HCI_IBS state lock   */
>> +	u8 tx_ibs_state;        /* HCI_IBS transmit side power state*/
>> +	u8 rx_ibs_state;        /* HCI_IBS receive side power state */
>> +	bool tx_vote;           /* Clock must be on for TX */
>> +	bool rx_vote;           /* Clock must be on for RX */
>>   	struct timer_list tx_idle_timer;
>>   	u32 tx_idle_delay;
>>   	struct timer_list wake_retrans_timer;
>> @@ -119,12 +125,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
>> @@ -462,9 +505,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",
>> @@ -553,7 +598,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);
>> @@ -873,6 +921,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:
>> @@ -887,7 +937,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;
>> @@ -924,62 +974,263 @@ 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_ERR("%s:open operation not supported", hu->hdev->name);
>> +		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_ERR("%s:close operation not supported", hu->hdev->name);
>> +		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_INFO("%s:setting up wcn3990", hdev->name);
>> +		/* 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_ERR("%s:initial speed %u", hdev->name, speed);
>> +			return -1;
>> +		}
>>   -	BT_INFO("%s: ROME setup", hdev->name);
>> +		/* 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;
>> +		}
>> +
>> +		/* 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_ERR("%s:initial speed %u", hdev->name, speed);
>> +			return -1;
>> +		}
>>   -	/* Patch downloading has to be done without IBS mode */
>> -	clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
>> +		/* Enable flow control */
>> +		hci_uart_set_flow_control(hu, false);
>> +		/*  wait until flow control settled */
>> +		mdelay(100);
>>   -	/* Setup initial baudrate */
>> -	speed = 0;
>> -	if (hu->init_speed)
>> -		speed = hu->init_speed;
>> -	else if (hu->proto->init_speed)
>> -		speed = hu->proto->init_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;
>> +		}
>>   -	if (speed)
>> -		host_set_baudrate(hu, speed);
>> +		BT_INFO("%s:wcn3990 controller version 0x%08x", hdev->name,
>> +			soc_ver);
>>   -	/* Setup user speed if needed */
>> -	speed = 0;
>> -	if (hu->oper_speed)
>> -		speed = hu->oper_speed;
>> -	else if (hu->proto->oper_speed)
>> +		/* 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_INFO("%s: Set UART speed to %d", hdev->name, speed);
>> +			ret = qca_set_baudrate(hdev, qca_baudrate);
>> +			if (ret) {
>> +				BT_ERR("%s:Failed to change the baud rate(%d)",
>> +					hdev->name, ret);
>> +				return ret;
>> +			}
>> +			if (speed)
>> +				host_set_baudrate(hu, speed);
>> +			else {
>> +				BT_ERR("%s:Error in setting operator speed:%u",
>> +					hdev->name, speed);
>> +				return -1;
>> +			}
>> +		}
>>   -	if (speed) {
>> -		qca_baudrate = qca_get_baudrate_value(speed);
>> +		/* Set flow control */
>> +		hci_uart_set_flow_control(hu, false);
>> +		/*Setup patch and  NVM configurations */
>> +		ret = qca_uart_setup_cherokee(hdev, qca_baudrate, &soc_ver);
>> +		if (!ret) {
>> +			set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
>> +			qca_debugfs_init(hdev);
>> +		}
>>   -		BT_INFO("%s: Set UART speed to %d", hdev->name, speed);
>> -		ret = qca_set_baudrate(hdev, qca_baudrate);
>> -		if (ret) {
>> -			BT_ERR("%s: Failed to change the baud rate (%d)",
>> -			       hdev->name, ret);
>> -			return ret;
>> +		/* Setup wcn3990 bdaddr */
>> +		hu->hdev->set_bdaddr = qca_btsoc_set_bdaddr;
>> +
>> +		return ret;
>> +
>> +	default:
>> +		BT_INFO("%s: ROME setup", hdev->name);
>> +		/* 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_INFO("%s: Set UART speed to %d", hdev->name, speed);
>> +			ret = qca_set_baudrate(hdev, qca_baudrate);
>> +			if (ret) {
>> +				BT_ERR("%s:Failed to change the baud rate(%d)",
>> +					hdev->name, ret);
>> +					return ret;
>> +				}
>> +			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;
>> -	}
>> +		/* 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);
>> +		}
>>   -	/* 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 = {
>> @@ -997,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;
>>   }
>> @@ -1042,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 = "qca,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 c10cb79..b932ec50 100644
>> --- a/include/net/bluetooth/hci_core.h
>> +++ b/include/net/bluetooth/hci_core.h
>> @@ -1418,7 +1418,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 97ef85e..8addd97 100644
>> --- a/net/bluetooth/hci_core.c
>> +++ b/net/bluetooth/hci_core.c
>> @@ -3370,7 +3370,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 f7d6ba6..1ffee59a 100644
>> --- a/net/bluetooth/hci_request.c
>> +++ b/net/bluetooth/hci_request.c
>> @@ -114,6 +114,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 dde77bd..a855edd 100644
>> --- a/net/bluetooth/hci_request.h
>> +++ b/net/bluetooth/hci_request.h
>> @@ -128,3 +128,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);
>> 

Regards
Balakrishna.

  reply	other threads:[~2018-04-23 10:52 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-04-19 13:34 [PATCH v2 0/2] Enable Bluetooth functionality for WCN3990 Balakrishna Godavarthi
2018-04-19 13:34 ` [PATCH v2 1/2] Bluetooth: Add device tree bindings for Atheros chips Balakrishna Godavarthi
2018-04-19 13:34 ` [PATCH v2 2/2] Bluetooth: Add support for wcn3990 soc Balakrishna Godavarthi
2018-04-20 16:11   ` Thierry Escande
2018-04-23 10:52     ` bgodavar [this message]
2018-04-20 16:10 ` [PATCH v2 0/2] Enable Bluetooth functionality for WCN3990 Thierry Escande
2018-04-23 10:39   ` bgodavar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=7e6b708736fab72d7f2facf43b2cf473@codeaurora.org \
    --to=bgodavar@codeaurora.org \
    --cc=johan.hedberg@gmail.com \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-bluetooth@vger.kernel.org \
    --cc=marcel@holtmann.org \
    --cc=rtatiya@codeaurora.org \
    --cc=thierry.escande@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).