linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v9 0/7]  Enable Bluetooth functionality for WCN3990
@ 2018-07-05 16:55 Balakrishna Godavarthi
  2018-07-05 16:55 ` [PATCH v9 1/7] dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990 Balakrishna Godavarthi
                   ` (6 more replies)
  0 siblings, 7 replies; 24+ messages in thread
From: Balakrishna Godavarthi @ 2018-07-05 16:55 UTC (permalink / raw)
  To: marcel, johan.hedberg, mka
  Cc: linux-kernel, devicetree, linux-bluetooth, thierry.escande,
	rtatiya, hemantg, linux-arm-msm, Balakrishna Godavarthi

These patches enables Bluetooth functinalties for new Qualcomm
Bluetooth chip wnc3990. As this is latest chip with new features, 
along with some common features to old chip "qcom,qca6174-bt".
we have updated 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 use voltage regulators to turn on/off the chip and we 
  must 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:
  Only firmware file name differ from New and Old chip.
  
  So we reused some functions/structure/variables which are used for old 
  chip to New chip by generic naming (may be future chips may use same functions).

 * As we have multiple changes for functions names,we have tested these patches 
   on both chips.

v9:
 * removed smps regs.
 * hidded flow control in respective functions.
 * moved qca_soc_ver to qca_setup
 * addressed review comments.
 
v8:
  * Squashed [v7 2/8] and [v7 3/8] to one patch.
  * updated functions to set and get the UART speeds.
  * addressed review comments.

v7:
  * Renamed all the possible function of ROME to generic.
  * updated with review comments for hci_qca and btqca
  * fixed kbuild errors.
  * created wrapper functions for re-usable blocks.
 
v6:
  * Hooked up qca_power to qca_serdev.
  * renamed all the naming inconsistency functions with qca_*
  * leveraged common code of ROME for wcn3990.
  * created wrapper functions for re-usable blocks.
  * updated function of _*regulator_enable and _*regualtor_disable.  
  * removed redundant comments and functions.
  * add code to derive the firmware files based on ROM Version.
  * created new patch for common function of ROME and wcn3990.
  * enables Qualcomm chip to operate at 3.2Mbps.
  * updated names of functions that are used for both the chips to keep this generic. 

v5:
  * updated with review comments for hci_qca and btqca
 
v4:
  * rebased all changes on top of bluetooth-next.
  * addressed review comments.
  * New patch created for firmware download.

v3:
  * Rebased all changes on top of bluetooth-next.
  * dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990
    - added dt-binding snippet for bluetooth chip wcn3990.
  * Bluetooth: Add support for wcn3990 soc.
    - updated BT_INFO with bt_dev_info, where ever necessary.

v2:
   * Add support for wcn3990:
    These changes are aligned as per serdev frame work.
          We implemented these changes on top of https://patchwork.kernel.org/patch/10316093/
        As this patch enable serdev for one of the Qualcomm BT chip.

        The changes in the patch include.
        - Adding support to voting up/down regulators for WCN3990.
           - Bluetooth firmware download for wcn3990.

  * Add device tree bindings for Atheros chips:
          These changes are on top of https://patchwork.kernel.org/patch/10316097/.
          - Description of device tree bindings.

Balakrishna Godavarthi (7):
  dt-bindings: net: bluetooth: Add device tree bindings for QTI chip
    wcn3990
  Bluetooth: btqca: Rename ROME specific functions to generic functions
  Bluetooth: btqca: Redefine qca_uart_setup() to generic function.
  Bluetooth: hci_qca: Add wrapper functions for setting UART speed
  Bluetooth: hci_qca: Enable 3.2 Mbps operating speed.
  Bluetooth: btqca: Add wcn3990 firmware download support.
  Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990

 .../bindings/net/qualcomm-bluetooth.txt       |  28 +-
 drivers/bluetooth/btqca.c                     | 113 +++--
 drivers/bluetooth/btqca.h                     |  22 +-
 drivers/bluetooth/hci_qca.c                   | 468 +++++++++++++++---
 4 files changed, 518 insertions(+), 113 deletions(-)

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


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

* [PATCH v9 1/7] dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990
  2018-07-05 16:55 [PATCH v9 0/7] Enable Bluetooth functionality for WCN3990 Balakrishna Godavarthi
@ 2018-07-05 16:55 ` Balakrishna Godavarthi
  2018-07-05 20:42   ` Rob Herring
  2018-07-05 16:55 ` [PATCH v9 2/7] Bluetooth: btqca: Rename ROME specific functions to generic functions Balakrishna Godavarthi
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 24+ messages in thread
From: Balakrishna Godavarthi @ 2018-07-05 16:55 UTC (permalink / raw)
  To: marcel, johan.hedberg, mka
  Cc: linux-kernel, devicetree, linux-bluetooth, thierry.escande,
	rtatiya, hemantg, linux-arm-msm, Balakrishna Godavarthi

This patch enables regulators for the Qualcomm Bluetooth wcn3990
controller.

Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
---
Changes in v9:
    * updated with latest reg handle and names.
    * updated max-speed definition. 

Changes in v8:
    * Separated the optional entries between two chips

Changes in v7:
    * no change.

Changes in v6:

    * Changed the oper-speed to max-speed.

Changes in v5:

    * Added entry for oper-speed and init-speed.

---
 .../bindings/net/qualcomm-bluetooth.txt       | 28 +++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt b/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt
index 0ea18a53cc29..ced58575e2b8 100644
--- a/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt
+++ b/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt
@@ -10,12 +10,22 @@ device the slave device is attached to.
 Required properties:
  - compatible: should contain one of the following:
    * "qcom,qca6174-bt"
+   * "qcom,wcn3990-bt"
+
+Optional properties for compatible string qcom,qca6174-bt:
 
-Optional properties:
  - enable-gpios: gpio specifier used to enable chip
  - clocks: clock provided to the controller (SUSCLK_32KHZ)
 
-Example:
+Optional properties for compatible string qcom,wcn3990-bt:
+
+ - vddio-supply: Bluetooth wcn3990 VDD_IO supply regulator handle.
+ - vddxo-supply: Bluetooth wcn3990 VDD_XO supply regulator handle.
+ - vddrf-supply: Bluetooth wcn3990 VDD_RF supply regulator handle.
+ - vddch0-supply: Bluetooth wcn3990 VDD_CH0 supply regulator handle.
+ - max-speed: see Documentation/devicetree/bindings/serial/slave-device.txt
+
+Examples:
 
 serial@7570000 {
 	label = "BT-UART";
@@ -28,3 +38,17 @@ serial@7570000 {
 		clocks = <&divclk4>;
 	};
 };
+
+serial@898000 {
+	label = "BT-UART";
+	status = "okay";
+
+	bluetooth {
+		compatible = "qcom,wcn3990-bt";
+		vddio-supply = <&vreg_s4a_1p8>;
+		vddxosupply = <&vreg_l7a_1p8>;
+		vddrf-supply = <&vreg_l17a_1p3>;
+		vddch0-supply = <&vreg_l25a_3p3>;
+		max-speed = <3200000>;
+	};
+};
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH v9 2/7] Bluetooth: btqca: Rename ROME specific functions to generic functions
  2018-07-05 16:55 [PATCH v9 0/7] Enable Bluetooth functionality for WCN3990 Balakrishna Godavarthi
  2018-07-05 16:55 ` [PATCH v9 1/7] dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990 Balakrishna Godavarthi
@ 2018-07-05 16:55 ` Balakrishna Godavarthi
  2018-07-05 16:55 ` [PATCH v9 3/7] Bluetooth: btqca: Redefine qca_uart_setup() to generic function Balakrishna Godavarthi
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 24+ messages in thread
From: Balakrishna Godavarthi @ 2018-07-05 16:55 UTC (permalink / raw)
  To: marcel, johan.hedberg, mka
  Cc: linux-kernel, devicetree, linux-bluetooth, thierry.escande,
	rtatiya, hemantg, linux-arm-msm, Balakrishna Godavarthi

Some of the QCA BTSoC ROME functions, are used for different versions
or different make of BTSoC's. Instead of duplicating the same functions
for new chip, update names of the functions that are used for both
chips to keep this generic and would help in future when we would have
new BT SoC. To have generic text in logs updated from ROME to QCA where
ever possible. This avoids confusion to user, when using the future
Qualcomm Bluetooth SoC's. Updated BT_DBG, BT_ERR and BT_INFO with
bt_dev_dbg, bt_dev_err and bt_dev_info where ever applicable.

Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
---
 drivers/bluetooth/btqca.c   | 85 ++++++++++++++++++-------------------
 drivers/bluetooth/btqca.h   | 10 ++++-
 drivers/bluetooth/hci_qca.c |  2 +-
 3 files changed, 51 insertions(+), 46 deletions(-)

diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index 8219816c54a0..c5cf9cab438a 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -27,7 +27,7 @@
 
 #define VERSION "0.1"
 
-static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version)
+int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version)
 {
 	struct sk_buff *skb;
 	struct edl_event_hdr *edl;
@@ -35,36 +35,35 @@ static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version)
 	char cmd;
 	int err = 0;
 
-	BT_DBG("%s: ROME Patch Version Request", hdev->name);
+	bt_dev_dbg(hdev, "QCA Version Request");
 
 	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);
+		bt_dev_err(hdev, "Reading QCA version information failed (%d)",
+			   err);
 		return err;
 	}
 
 	if (skb->len != sizeof(*edl) + sizeof(*ver)) {
-		BT_ERR("%s: Version size mismatch len %d", hdev->name,
-		       skb->len);
+		bt_dev_err(hdev, "QCA Version size mismatch len %d", skb->len);
 		err = -EILSEQ;
 		goto out;
 	}
 
 	edl = (struct edl_event_hdr *)(skb->data);
 	if (!edl) {
-		BT_ERR("%s: TLV with no header", hdev->name);
+		bt_dev_err(hdev, "QCA TLV with no header");
 		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);
+		bt_dev_err(hdev, "QCA Wrong packet received %d %d", edl->cresp,
+			   edl->rtype);
 		err = -EIO;
 		goto out;
 	}
@@ -76,11 +75,11 @@ static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version)
 	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
+	/* QCA 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) |
+	*soc_version = (le32_to_cpu(ver->soc_id) << 16) |
 			(le16_to_cpu(ver->rome_ver) & 0x0000ffff);
 
 out:
@@ -88,18 +87,19 @@ static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version)
 
 	return err;
 }
+EXPORT_SYMBOL_GPL(qca_read_soc_version);
 
-static int rome_reset(struct hci_dev *hdev)
+static int qca_send_reset(struct hci_dev *hdev)
 {
 	struct sk_buff *skb;
 	int err;
 
-	BT_DBG("%s: ROME HCI_RESET", hdev->name);
+	bt_dev_dbg(hdev, "QCA HCI_RESET");
 
 	skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
 	if (IS_ERR(skb)) {
 		err = PTR_ERR(skb);
-		BT_ERR("%s: Reset failed (%d)", hdev->name, err);
+		bt_dev_err(hdev, "QCA Reset failed (%d)", err);
 		return err;
 	}
 
@@ -108,7 +108,7 @@ static int rome_reset(struct hci_dev *hdev)
 	return 0;
 }
 
-static void rome_tlv_check_data(struct rome_config *config,
+static void qca_tlv_check_data(struct rome_config *config,
 				const struct firmware *fw)
 {
 	const u8 *data;
@@ -207,7 +207,7 @@ static void rome_tlv_check_data(struct rome_config *config,
 	}
 }
 
-static int rome_tlv_send_segment(struct hci_dev *hdev, int seg_size,
+static int qca_tlv_send_segment(struct hci_dev *hdev, int seg_size,
 				 const u8 *data, enum rome_tlv_dnld_mode mode)
 {
 	struct sk_buff *skb;
@@ -228,19 +228,19 @@ static int rome_tlv_send_segment(struct hci_dev *hdev, int seg_size,
 				HCI_VENDOR_PKT, HCI_INIT_TIMEOUT);
 	if (IS_ERR(skb)) {
 		err = PTR_ERR(skb);
-		BT_ERR("%s: Failed to send TLV segment (%d)", hdev->name, err);
+		bt_dev_err(hdev, "QCA Failed to send TLV segment (%d)", err);
 		return err;
 	}
 
 	if (skb->len != sizeof(*edl) + sizeof(*tlv_resp)) {
-		BT_ERR("%s: TLV response size mismatch", hdev->name);
+		bt_dev_err(hdev, "QCA TLV response size mismatch");
 		err = -EILSEQ;
 		goto out;
 	}
 
 	edl = (struct edl_event_hdr *)(skb->data);
 	if (!edl) {
-		BT_ERR("%s: TLV with no header", hdev->name);
+		bt_dev_err(hdev, "TLV with no header");
 		err = -EILSEQ;
 		goto out;
 	}
@@ -249,8 +249,8 @@ static int rome_tlv_send_segment(struct hci_dev *hdev, int seg_size,
 
 	if (edl->cresp != EDL_CMD_REQ_RES_EVT ||
 	    edl->rtype != EDL_TVL_DNLD_RES_EVT || tlv_resp->result != 0x00) {
-		BT_ERR("%s: TLV with error stat 0x%x rtype 0x%x (0x%x)",
-		       hdev->name, edl->cresp, edl->rtype, tlv_resp->result);
+		bt_dev_err(hdev, "QCA TLV with error stat 0x%x rtype 0x%x (0x%x)",
+			   edl->cresp, edl->rtype, tlv_resp->result);
 		err = -EIO;
 	}
 
@@ -260,23 +260,23 @@ static int rome_tlv_send_segment(struct hci_dev *hdev, int seg_size,
 	return err;
 }
 
-static int rome_download_firmware(struct hci_dev *hdev,
+static int qca_download_firmware(struct hci_dev *hdev,
 				  struct rome_config *config)
 {
 	const struct firmware *fw;
 	const u8 *segment;
 	int ret, remain, i = 0;
 
-	bt_dev_info(hdev, "ROME Downloading %s", config->fwname);
+	bt_dev_info(hdev, "QCA Downloading %s", 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);
+		bt_dev_err(hdev, "QCA Failed to request file: %s (%d)",
+			   config->fwname, ret);
 		return ret;
 	}
 
-	rome_tlv_check_data(config, fw);
+	qca_tlv_check_data(config, fw);
 
 	segment = fw->data;
 	remain = fw->size;
@@ -290,7 +290,7 @@ static int rome_download_firmware(struct hci_dev *hdev,
 		if (!remain || segsize < MAX_SIZE_PER_TLV_SEGMENT)
 			config->dnld_mode = ROME_SKIP_EVT_NONE;
 
-		ret = rome_tlv_send_segment(hdev, segsize, segment,
+		ret = qca_tlv_send_segment(hdev, segsize, segment,
 					    config->dnld_mode);
 		if (ret)
 			break;
@@ -317,8 +317,7 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
 				HCI_VENDOR_PKT, HCI_INIT_TIMEOUT);
 	if (IS_ERR(skb)) {
 		err = PTR_ERR(skb);
-		BT_ERR("%s: Change address command failed (%d)",
-		       hdev->name, err);
+		bt_dev_err(hdev, "QCA Change address command failed (%d)", err);
 		return err;
 	}
 
@@ -328,32 +327,32 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
 }
 EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome);
 
-int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate)
+int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate)
 {
 	u32 rome_ver = 0;
 	struct rome_config config;
 	int err;
 
-	BT_DBG("%s: ROME setup on UART", hdev->name);
+	bt_dev_dbg(hdev, "QCA setup on UART");
 
 	config.user_baud_rate = baudrate;
 
-	/* Get ROME version information */
-	err = rome_patch_ver_req(hdev, &rome_ver);
+	/* Get QCA version information */
+	err = qca_read_soc_version(hdev, &rome_ver);
 	if (err < 0 || rome_ver == 0) {
-		BT_ERR("%s: Failed to get version 0x%x", hdev->name, err);
+		bt_dev_err(hdev, "QCA Failed to get version %d", err);
 		return err;
 	}
 
-	bt_dev_info(hdev, "ROME controller version 0x%08x", rome_ver);
+	bt_dev_info(hdev, "QCA controller version 0x%08x", rome_ver);
 
 	/* Download rampatch file */
 	config.type = TLV_TYPE_PATCH;
 	snprintf(config.fwname, sizeof(config.fwname), "qca/rampatch_%08x.bin",
 		 rome_ver);
-	err = rome_download_firmware(hdev, &config);
+	err = qca_download_firmware(hdev, &config);
 	if (err < 0) {
-		BT_ERR("%s: Failed to download patch (%d)", hdev->name, err);
+		bt_dev_err(hdev, "QCA Failed to download patch (%d)", err);
 		return err;
 	}
 
@@ -361,24 +360,24 @@ int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate)
 	config.type = TLV_TYPE_NVM;
 	snprintf(config.fwname, sizeof(config.fwname), "qca/nvm_%08x.bin",
 		 rome_ver);
-	err = rome_download_firmware(hdev, &config);
+	err = qca_download_firmware(hdev, &config);
 	if (err < 0) {
-		BT_ERR("%s: Failed to download NVM (%d)", hdev->name, err);
+		bt_dev_err(hdev, "QCA Failed to download NVM (%d)", err);
 		return err;
 	}
 
 	/* Perform HCI reset */
-	err = rome_reset(hdev);
+	err = qca_send_reset(hdev);
 	if (err < 0) {
-		BT_ERR("%s: Failed to run HCI_RESET (%d)", hdev->name, err);
+		bt_dev_err(hdev, "QCA Failed to run HCI_RESET (%d)", err);
 		return err;
 	}
 
-	bt_dev_info(hdev, "ROME setup on UART is completed");
+	bt_dev_info(hdev, "QCA setup on UART is completed");
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(qca_uart_setup_rome);
+EXPORT_SYMBOL_GPL(qca_uart_setup);
 
 MODULE_AUTHOR("Ben Young Tae Kim <ytkim@qca.qualcomm.com>");
 MODULE_DESCRIPTION("Bluetooth support for Qualcomm Atheros family ver " VERSION);
diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
index 13d77fd873b6..5c9851b11838 100644
--- a/drivers/bluetooth/btqca.h
+++ b/drivers/bluetooth/btqca.h
@@ -127,7 +127,8 @@ struct tlv_type_hdr {
 #if IS_ENABLED(CONFIG_BT_QCA)
 
 int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr);
-int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate);
+int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate);
+int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version);
 
 #else
 
@@ -136,7 +137,12 @@ static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdad
 	return -EOPNOTSUPP;
 }
 
-static inline int qca_uart_setup_rome(struct hci_dev *hdev, int speed)
+static inline int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version)
 {
 	return -EOPNOTSUPP;
 }
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 51790dd02afb..d7b60669b656 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -966,7 +966,7 @@ static int qca_setup(struct hci_uart *hu)
 	}
 
 	/* Setup patch / NVM configurations */
-	ret = qca_uart_setup_rome(hdev, qca_baudrate);
+	ret = qca_uart_setup(hdev, qca_baudrate);
 	if (!ret) {
 		set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
 		qca_debugfs_init(hdev);
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH v9 3/7] Bluetooth: btqca: Redefine qca_uart_setup() to generic function.
  2018-07-05 16:55 [PATCH v9 0/7] Enable Bluetooth functionality for WCN3990 Balakrishna Godavarthi
  2018-07-05 16:55 ` [PATCH v9 1/7] dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990 Balakrishna Godavarthi
  2018-07-05 16:55 ` [PATCH v9 2/7] Bluetooth: btqca: Rename ROME specific functions to generic functions Balakrishna Godavarthi
@ 2018-07-05 16:55 ` Balakrishna Godavarthi
  2018-07-06 22:35   ` Matthias Kaehlcke
  2018-07-05 16:55 ` [PATCH v9 4/7] Bluetooth: hci_qca: Add wrapper functions for setting UART speed Balakrishna Godavarthi
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 24+ messages in thread
From: Balakrishna Godavarthi @ 2018-07-05 16:55 UTC (permalink / raw)
  To: marcel, johan.hedberg, mka
  Cc: linux-kernel, devicetree, linux-bluetooth, thierry.escande,
	rtatiya, hemantg, linux-arm-msm, Balakrishna Godavarthi

Redefinition of qca_uart_setup will help future Qualcomm Bluetooth
SoC, to use the same function instead of duplicating the function.
Added new arguments soc_type and soc_ver to the functions.

These arguments will help to decide type of firmware files
to be loaded into Bluetooth chip.
soc_type holds the Bluetooth chip connected to APPS processor.
soc_ver holds the Bluetooth chip version.

Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
---
Changes in v9:
   * moved qca_read_soc_ver() to qca_setup().

Changes in v8:
    * updated soc_type with enum.

Changes in v7:
    * initial patch
    * redefined qca_uart_setup function to generic.
---
 drivers/bluetooth/btqca.c   | 17 ++++-------------
 drivers/bluetooth/btqca.h   | 13 +++++++++++--
 drivers/bluetooth/hci_qca.c | 11 ++++++++++-
 3 files changed, 25 insertions(+), 16 deletions(-)

diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index c5cf9cab438a..03bcbaaf1ae9 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -327,9 +327,9 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
 }
 EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome);
 
-int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate)
+int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
+		   enum qca_btsoc_type soc_type, u32 soc_ver)
 {
-	u32 rome_ver = 0;
 	struct rome_config config;
 	int err;
 
@@ -337,19 +337,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate)
 
 	config.user_baud_rate = baudrate;
 
-	/* Get QCA version information */
-	err = qca_read_soc_version(hdev, &rome_ver);
-	if (err < 0 || rome_ver == 0) {
-		bt_dev_err(hdev, "QCA Failed to get version %d", err);
-		return err;
-	}
-
-	bt_dev_info(hdev, "QCA controller version 0x%08x", rome_ver);
-
 	/* Download rampatch file */
 	config.type = TLV_TYPE_PATCH;
 	snprintf(config.fwname, sizeof(config.fwname), "qca/rampatch_%08x.bin",
-		 rome_ver);
+		 soc_ver);
 	err = qca_download_firmware(hdev, &config);
 	if (err < 0) {
 		bt_dev_err(hdev, "QCA Failed to download patch (%d)", err);
@@ -359,7 +350,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate)
 	/* Download NVM configuration */
 	config.type = TLV_TYPE_NVM;
 	snprintf(config.fwname, sizeof(config.fwname), "qca/nvm_%08x.bin",
-		 rome_ver);
+		 soc_ver);
 	err = qca_download_firmware(hdev, &config);
 	if (err < 0) {
 		bt_dev_err(hdev, "QCA Failed to download NVM (%d)", err);
diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
index 5c9851b11838..a9c2779f3e07 100644
--- a/drivers/bluetooth/btqca.h
+++ b/drivers/bluetooth/btqca.h
@@ -124,10 +124,18 @@ struct tlv_type_hdr {
 	__u8   data[0];
 } __packed;
 
+enum qca_btsoc_type {
+	QCA_INVALID = -1,
+	QCA_AR3002,
+	QCA_ROME,
+	QCA_WCN3990
+};
+
 #if IS_ENABLED(CONFIG_BT_QCA)
 
 int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr);
-int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate);
+int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
+		   enum qca_btsoc_type soc_type, u32 soc_ver);
 int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version);
 
 #else
@@ -137,7 +145,8 @@ static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdad
 	return -EOPNOTSUPP;
 }
 
-static inline int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate)
+static inline int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
+				 enum qca_btsoc_type soc_type, u32 soc_ver)
 {
 	return -EOPNOTSUPP;
 }
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index d7b60669b656..c02e1d465cca 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -929,6 +929,7 @@ static int qca_setup(struct hci_uart *hu)
 	struct qca_data *qca = hu->priv;
 	unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200;
 	int ret;
+	int soc_ver = 0;
 
 	bt_dev_info(hdev, "ROME setup");
 
@@ -965,8 +966,16 @@ static int qca_setup(struct hci_uart *hu)
 		host_set_baudrate(hu, speed);
 	}
 
+	/* Get QCA version information */
+	ret = qca_read_soc_version(hdev, &soc_ver);
+	if (ret < 0 || soc_ver == 0) {
+		bt_dev_err(hdev, "QCA Failed to get version (%d)", ret);
+		return ret;
+	}
+	bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
+
 	/* Setup patch / NVM configurations */
-	ret = qca_uart_setup(hdev, qca_baudrate);
+	ret = qca_uart_setup(hdev, qca_baudrate, QCA_ROME, soc_ver);
 	if (!ret) {
 		set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
 		qca_debugfs_init(hdev);
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH v9 4/7] Bluetooth: hci_qca: Add wrapper functions for setting UART speed
  2018-07-05 16:55 [PATCH v9 0/7] Enable Bluetooth functionality for WCN3990 Balakrishna Godavarthi
                   ` (2 preceding siblings ...)
  2018-07-05 16:55 ` [PATCH v9 3/7] Bluetooth: btqca: Redefine qca_uart_setup() to generic function Balakrishna Godavarthi
@ 2018-07-05 16:55 ` Balakrishna Godavarthi
  2018-07-06 19:40   ` Matthias Kaehlcke
  2018-07-05 16:55 ` [PATCH v9 5/7] Bluetooth: hci_qca: Enable 3.2 Mbps operating speed Balakrishna Godavarthi
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 24+ messages in thread
From: Balakrishna Godavarthi @ 2018-07-05 16:55 UTC (permalink / raw)
  To: marcel, johan.hedberg, mka
  Cc: linux-kernel, devicetree, linux-bluetooth, thierry.escande,
	rtatiya, hemantg, linux-arm-msm, Balakrishna Godavarthi

In function qca_setup, we set initial and operating speeds for Qualcomm
Bluetooth SoC's. This block of code is common across different
Qualcomm Bluetooth SoC's. Instead of duplicating the code, created
a wrapper function to set the speeds. So that future coming SoC's
can use these wrapper functions to set speeds.

Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
---
Changes in v9:
    * added corner case to fail driver if speeds are missing.

Changes in v8:
    * common function to set INIT and operating speeds.

Changes in v7:
    * initial patch
    * created wrapper functions for init and operating speeds.
---
 drivers/bluetooth/hci_qca.c | 94 ++++++++++++++++++++++++++++---------
 1 file changed, 71 insertions(+), 23 deletions(-)

diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index c02e1d465cca..9106547324fa 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -119,6 +119,11 @@ struct qca_data {
 	u64 votes_off;
 };
 
+enum qca_speed_type {
+	QCA_INIT_SPEED = 1,
+	QCA_OPER_SPEED
+};
+
 struct qca_serdev {
 	struct hci_uart	 serdev_hu;
 	struct gpio_desc *bt_en;
@@ -923,6 +928,62 @@ static inline void host_set_baudrate(struct hci_uart *hu, unsigned int speed)
 		hci_uart_set_baudrate(hu, speed);
 }
 
+static unsigned int qca_get_speed(struct hci_uart *hu,
+				  enum qca_speed_type speed_type)
+{
+	unsigned int speed = 0;
+
+	if (speed_type == QCA_INIT_SPEED) {
+		if (hu->init_speed)
+			speed = hu->init_speed;
+		else if (hu->proto->init_speed)
+			speed = hu->proto->init_speed;
+	} else {
+		if (hu->oper_speed)
+			speed = hu->oper_speed;
+		else if (hu->proto->oper_speed)
+			speed = hu->proto->oper_speed;
+	}
+
+	return speed;
+}
+
+static int qca_check_speeds(struct hci_uart *hu)
+{
+	/* One or the other speeds should be non zero. */
+	if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
+	    !qca_get_speed(hu, QCA_OPER_SPEED))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
+{
+	unsigned int speed, qca_baudrate;
+	int ret;
+
+	if (speed_type == QCA_INIT_SPEED) {
+		speed = qca_get_speed(hu, QCA_INIT_SPEED);
+		if (speed)
+			host_set_baudrate(hu, speed);
+	} else {
+		speed = qca_get_speed(hu, QCA_OPER_SPEED);
+		if (!speed)
+			return 0;
+
+		qca_baudrate = qca_get_baudrate_value(speed);
+		bt_dev_info(hu->hdev, "Set UART speed to %d", speed);
+		ret = qca_set_baudrate(hu->hdev, qca_baudrate);
+		if (ret)
+			return ret;
+
+		host_set_baudrate(hu, speed);
+	}
+
+	return 0;
+}
+
 static int qca_setup(struct hci_uart *hu)
 {
 	struct hci_dev *hdev = hu->hdev;
@@ -933,37 +994,24 @@ static int qca_setup(struct hci_uart *hu)
 
 	bt_dev_info(hdev, "ROME setup");
 
+	ret = qca_check_speeds(hu);
+	if (ret)
+		return ret;
+
 	/* 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);
+	qca_set_speed(hu, QCA_INIT_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;
-
+	speed = qca_get_speed(hu, QCA_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);
+		ret = qca_set_speed(hu, QCA_OPER_SPEED);
+		if (ret)
 			return ret;
-		}
-		host_set_baudrate(hu, speed);
+
+		qca_baudrate = qca_get_baudrate_value(speed);
 	}
 
 	/* Get QCA version information */
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH v9 5/7] Bluetooth: hci_qca: Enable 3.2 Mbps operating speed.
  2018-07-05 16:55 [PATCH v9 0/7] Enable Bluetooth functionality for WCN3990 Balakrishna Godavarthi
                   ` (3 preceding siblings ...)
  2018-07-05 16:55 ` [PATCH v9 4/7] Bluetooth: hci_qca: Add wrapper functions for setting UART speed Balakrishna Godavarthi
@ 2018-07-05 16:55 ` Balakrishna Godavarthi
  2018-07-05 16:55 ` [PATCH v9 6/7] Bluetooth: btqca: Add wcn3990 firmware download support Balakrishna Godavarthi
  2018-07-05 16:55 ` [PATCH v9 7/7] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990 Balakrishna Godavarthi
  6 siblings, 0 replies; 24+ messages in thread
From: Balakrishna Godavarthi @ 2018-07-05 16:55 UTC (permalink / raw)
  To: marcel, johan.hedberg, mka
  Cc: linux-kernel, devicetree, linux-bluetooth, thierry.escande,
	rtatiya, hemantg, linux-arm-msm, Balakrishna Godavarthi

Enable Qualcomm chips to operate at 3.2Mbps.

Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
---
 drivers/bluetooth/hci_qca.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 9106547324fa..7ebfaa0edf3f 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -877,6 +877,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:
@@ -891,7 +893,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;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH v9 6/7] Bluetooth: btqca: Add wcn3990 firmware download support.
  2018-07-05 16:55 [PATCH v9 0/7] Enable Bluetooth functionality for WCN3990 Balakrishna Godavarthi
                   ` (4 preceding siblings ...)
  2018-07-05 16:55 ` [PATCH v9 5/7] Bluetooth: hci_qca: Enable 3.2 Mbps operating speed Balakrishna Godavarthi
@ 2018-07-05 16:55 ` Balakrishna Godavarthi
  2018-07-05 16:55 ` [PATCH v9 7/7] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990 Balakrishna Godavarthi
  6 siblings, 0 replies; 24+ messages in thread
From: Balakrishna Godavarthi @ 2018-07-05 16:55 UTC (permalink / raw)
  To: marcel, johan.hedberg, mka
  Cc: linux-kernel, devicetree, linux-bluetooth, thierry.escande,
	rtatiya, hemantg, linux-arm-msm, Balakrishna Godavarthi

This patch enables the RAM and NV patch download for wcn3990.

Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
---
 drivers/bluetooth/btqca.c | 25 +++++++++++++++++++++----
 1 file changed, 21 insertions(+), 4 deletions(-)

diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index 03bcbaaf1ae9..82790a8b5928 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -332,6 +332,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
 {
 	struct rome_config config;
 	int err;
+	u8 rom_ver;
 
 	bt_dev_dbg(hdev, "QCA setup on UART");
 
@@ -339,8 +340,19 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
 
 	/* Download rampatch file */
 	config.type = TLV_TYPE_PATCH;
-	snprintf(config.fwname, sizeof(config.fwname), "qca/rampatch_%08x.bin",
-		 soc_ver);
+	if (soc_type == QCA_WCN3990) {
+		/* Firmware files to download are based on ROM version.
+		 * ROM version is derived from last two bytes of soc_ver.
+		 */
+		rom_ver = ((soc_ver & 0x00000f00) >> 0x04) |
+			    (soc_ver & 0x0000000f);
+		snprintf(config.fwname, sizeof(config.fwname),
+			 "qca/crbtfw%02x.tlv", rom_ver);
+	} else {
+		snprintf(config.fwname, sizeof(config.fwname),
+			 "qca/rampatch_%08x.bin", soc_ver);
+	}
+
 	err = qca_download_firmware(hdev, &config);
 	if (err < 0) {
 		bt_dev_err(hdev, "QCA Failed to download patch (%d)", err);
@@ -349,8 +361,13 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
 
 	/* Download NVM configuration */
 	config.type = TLV_TYPE_NVM;
-	snprintf(config.fwname, sizeof(config.fwname), "qca/nvm_%08x.bin",
-		 soc_ver);
+	if (soc_type == QCA_WCN3990)
+		snprintf(config.fwname, sizeof(config.fwname),
+			 "qca/crnv%02x.bin", rom_ver);
+	else
+		snprintf(config.fwname, sizeof(config.fwname),
+			 "qca/nvm_%08x.bin", soc_ver);
+
 	err = qca_download_firmware(hdev, &config);
 	if (err < 0) {
 		bt_dev_err(hdev, "QCA Failed to download NVM (%d)", err);
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH v9 7/7] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990
  2018-07-05 16:55 [PATCH v9 0/7] Enable Bluetooth functionality for WCN3990 Balakrishna Godavarthi
                   ` (5 preceding siblings ...)
  2018-07-05 16:55 ` [PATCH v9 6/7] Bluetooth: btqca: Add wcn3990 firmware download support Balakrishna Godavarthi
@ 2018-07-05 16:55 ` Balakrishna Godavarthi
  2018-07-06 22:21   ` Matthias Kaehlcke
  6 siblings, 1 reply; 24+ messages in thread
From: Balakrishna Godavarthi @ 2018-07-05 16:55 UTC (permalink / raw)
  To: marcel, johan.hedberg, mka
  Cc: linux-kernel, devicetree, linux-bluetooth, thierry.escande,
	rtatiya, hemantg, linux-arm-msm, Balakrishna Godavarthi

Add support to set voltage/current of various regulators
to power up/down Bluetooth chip wcn3990.

Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
---
changes in v9:
    * moved flow control to vendor and set_baudarte functions.
    * removed parent regs.

changes in v8:
    * closing qca buffer, if qca_power_setup fails
    * chnaged ibs start timer function call location.
    * updated review comments.
  
changes in v7:
    * addressed review comments.

changes in v6:
    * Hooked up qca_power to qca_serdev.
    * renamed all the naming inconsistency functions with qca_*
    * leveraged common code of ROME for wcn3990.
    * created wrapper functions for re-usable blocks.
    * updated function of _*regulator_enable and _*regualtor_disable.  
    * removed redundant comments and functions.
    * addressed review comments.

Changes in v5:
    * updated regulator vddpa min_uV to 1304000.
      * addressed review comments.
 
Changes in v4:
    * Segregated the changes of btqca from hci_qca
    * rebased all changes on top of bluetooth-next.
    * addressed review comments.

---
 drivers/bluetooth/btqca.h   |   3 +
 drivers/bluetooth/hci_qca.c | 387 +++++++++++++++++++++++++++++++-----
 2 files changed, 345 insertions(+), 45 deletions(-)

diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
index a9c2779f3e07..0c01f375fe83 100644
--- a/drivers/bluetooth/btqca.h
+++ b/drivers/bluetooth/btqca.h
@@ -37,6 +37,9 @@
 #define EDL_TAG_ID_HCI			(17)
 #define EDL_TAG_ID_DEEP_SLEEP		(27)
 
+#define QCA_WCN3990_POWERON_PULSE	0xFC
+#define QCA_WCN3990_POWEROFF_PULSE	0xC0
+
 enum qca_bardrate {
 	QCA_BAUDRATE_115200 	= 0,
 	QCA_BAUDRATE_57600,
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 7ebfaa0edf3f..d62c7785a618 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...
@@ -31,9 +31,14 @@
 #include <linux/kernel.h>
 #include <linux/clk.h>
 #include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
 #include <linux/gpio/consumer.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
 #include <linux/serdev.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -124,12 +129,46 @@ enum qca_speed_type {
 	QCA_OPER_SPEED
 };
 
+/*
+ * Voltage regulator information required for configuring the
+ * QCA Bluetooth chipset
+ */
+struct qca_vreg {
+	const char *name;
+	unsigned int min_uV;
+	unsigned int max_uV;
+	unsigned int load_uA;
+};
+
+struct qca_vreg_data {
+	enum qca_btsoc_type soc_type;
+	struct qca_vreg *vregs;
+	size_t num_vregs;
+};
+
+/*
+ * Platform data for the QCA Bluetooth power driver.
+ */
+struct qca_power {
+	struct device *dev;
+	const struct qca_vreg_data *vreg_data;
+	struct regulator_bulk_data *vreg_bulk;
+	bool vregs_on;
+};
+
 struct qca_serdev {
 	struct hci_uart	 serdev_hu;
 	struct gpio_desc *bt_en;
 	struct clk	 *susclk;
+	enum qca_btsoc_type btsoc_type;
+	struct qca_power *bt_power;
+	u32 init_speed;
+	u32 oper_speed;
 };
 
+static int qca_power_setup(struct hci_uart *hu, bool on);
+static void qca_power_shutdown(struct hci_uart *hu);
+
 static void __serial_clock_on(struct tty_struct *tty)
 {
 	/* TODO: Some chipset requires to enable UART clock on client
@@ -407,6 +446,7 @@ static int qca_open(struct hci_uart *hu)
 {
 	struct qca_serdev *qcadev;
 	struct qca_data *qca;
+	int ret;
 
 	BT_DBG("hu %p qca_open", hu);
 
@@ -458,19 +498,32 @@ static int qca_open(struct hci_uart *hu)
 
 	hu->priv = qca;
 
-	timer_setup(&qca->wake_retrans_timer, hci_ibs_wake_retrans_timeout, 0);
-	qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
-
-	timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
-	qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
-
 	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 != QCA_WCN3990) {
+			gpiod_set_value_cansleep(qcadev->bt_en, 1);
+		} else {
+			hu->init_speed = qcadev->init_speed;
+			hu->oper_speed = qcadev->oper_speed;
+			ret = qca_power_setup(hu, true);
+			if (ret) {
+				destroy_workqueue(qca->workqueue);
+				kfree_skb(qca->rx_skb);
+				hu->priv = NULL;
+				kfree(qca);
+				return ret;
+			}
+		}
 	}
 
+	timer_setup(&qca->wake_retrans_timer, hci_ibs_wake_retrans_timeout, 0);
+	qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
+
+	timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
+	qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
+
 	BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u",
 	       qca->tx_idle_delay, qca->wake_retrans);
 
@@ -554,10 +607,13 @@ static int qca_close(struct hci_uart *hu)
 	qca->hu = NULL;
 
 	if (hu->serdev) {
-		serdev_device_close(hu->serdev);
-
 		qcadev = serdev_device_get_drvdata(hu->serdev);
-		gpiod_set_value_cansleep(qcadev->bt_en, 0);
+		if (qcadev->btsoc_type == QCA_WCN3990)
+			qca_power_shutdown(hu);
+		else
+			gpiod_set_value_cansleep(qcadev->bt_en, 0);
+
+		serdev_device_close(hu->serdev);
 	}
 
 	kfree_skb(qca->rx_skb);
@@ -891,6 +947,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
 	struct hci_uart *hu = hci_get_drvdata(hdev);
 	struct qca_data *qca = hu->priv;
 	struct sk_buff *skb;
+	struct qca_serdev *qcadev;
 	u8 cmd[] = { 0x01, 0x48, 0xFC, 0x01, 0x00 };
 
 	if (baudrate > QCA_BAUDRATE_3200000)
@@ -904,6 +961,13 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
 		return -ENOMEM;
 	}
 
+	/* Disabling hardware flow control is mandate while
+	 * sending change baudrate request to wcn3990 SoC.
+	 */
+	qcadev = serdev_device_get_drvdata(hu->serdev);
+	if (qcadev->btsoc_type == QCA_WCN3990)
+		hci_uart_set_flow_control(hu, true);
+
 	/* Assign commands to change baudrate and packet type. */
 	skb_put_data(skb, cmd, sizeof(cmd));
 	hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
@@ -919,6 +983,9 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
 	schedule_timeout(msecs_to_jiffies(BAUDRATE_SETTLE_TIMEOUT_MS));
 	set_current_state(TASK_RUNNING);
 
+	if (qcadev->btsoc_type == QCA_WCN3990)
+		hci_uart_set_flow_control(hu, false);
+
 	return 0;
 }
 
@@ -930,6 +997,36 @@ static inline void host_set_baudrate(struct hci_uart *hu, unsigned int speed)
 		hci_uart_set_baudrate(hu, speed);
 }
 
+static int qca_send_vendor_cmd(struct hci_dev *hdev, u8 cmd)
+{
+	struct hci_uart *hu = hci_get_drvdata(hdev);
+	struct qca_data *qca = hu->priv;
+	struct sk_buff *skb;
+
+	bt_dev_dbg(hdev, "sending command %02x to SoC", cmd);
+
+	skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	/* Disabling hardware flow control is mandate while
+	 * sending vendor power on and off pulse to SoC.
+	 */
+	hci_uart_set_flow_control(hu, true);
+
+	skb_put_u8(skb, 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 */
+	usleep_range(100, 200);
+	hci_uart_set_flow_control(hu, false);
+
+	return 0;
+}
+
 static unsigned int qca_get_speed(struct hci_uart *hu,
 				  enum qca_speed_type speed_type)
 {
@@ -952,10 +1049,19 @@ static unsigned int qca_get_speed(struct hci_uart *hu,
 
 static int qca_check_speeds(struct hci_uart *hu)
 {
-	/* One or the other speeds should be non zero. */
-	if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
-	    !qca_get_speed(hu, QCA_OPER_SPEED))
+	struct qca_serdev *qcadev;
+
+	qcadev = serdev_device_get_drvdata(hu->serdev);
+	if ((qcadev->btsoc_type == QCA_WCN3990 &&
+	    !qca_get_speed(hu, QCA_INIT_SPEED)) ||
+	    !qca_get_speed(hu, QCA_OPER_SPEED)) {
+		/* Both INIT and OPER speed should be non zero. */
 		return -EINVAL;
+	} else if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
+		    !qca_get_speed(hu, QCA_OPER_SPEED)) {
+		/* One or the other speeds should be non zero. */
+		return -EINVAL;
+	}
 
 	return 0;
 }
@@ -986,15 +1092,40 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
 	return 0;
 }
 
+static int qca_wcn3990_init(struct hci_uart *hu)
+{
+	int ret;
+
+	ret = qca_send_vendor_cmd(hu->hdev, QCA_WCN3990_POWERON_PULSE);
+	if (ret)
+		return ret;
+
+	/* Wait for 100 ms for SoC to boot up */
+	msleep(100);
+	serdev_device_close(hu->serdev);
+	ret = serdev_device_open(hu->serdev);
+	if (ret) {
+		bt_dev_err(hu->hdev, "failed to open port");
+		return ret;
+	}
+
+	/* Setup initial baudrate */
+	qca_set_speed(hu, QCA_INIT_SPEED);
+	hci_uart_set_flow_control(hu, false);
+
+	return 0;
+}
+
 static int qca_setup(struct hci_uart *hu)
 {
 	struct hci_dev *hdev = hu->hdev;
 	struct qca_data *qca = hu->priv;
 	unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200;
+	struct qca_serdev *qcadev;
 	int ret;
 	int soc_ver = 0;
 
-	bt_dev_info(hdev, "ROME setup");
+	qcadev = serdev_device_get_drvdata(hu->serdev);
 
 	ret = qca_check_speeds(hu);
 	if (ret)
@@ -1006,6 +1137,21 @@ static int qca_setup(struct hci_uart *hu)
 	/* Setup initial baudrate */
 	qca_set_speed(hu, QCA_INIT_SPEED);
 
+	if (qcadev->btsoc_type == QCA_WCN3990) {
+		bt_dev_dbg(hdev, "setting up wcn3990");
+		ret = qca_wcn3990_init(hu);
+		if (ret)
+			return ret;
+
+		ret = qca_read_soc_version(hdev, &soc_ver);
+		if (ret < 0 || soc_ver == 0) {
+			bt_dev_err(hdev, "Failed to get version %d", ret);
+			return ret;
+		}
+	} else {
+		bt_dev_info(hdev, "ROME setup");
+	}
+
 	/* Setup user speed if needed */
 	speed = qca_get_speed(hu, QCA_OPER_SPEED);
 	if (speed) {
@@ -1016,16 +1162,18 @@ static int qca_setup(struct hci_uart *hu)
 		qca_baudrate = qca_get_baudrate_value(speed);
 	}
 
-	/* Get QCA version information */
-	ret = qca_read_soc_version(hdev, &soc_ver);
-	if (ret < 0 || soc_ver == 0) {
-		bt_dev_err(hdev, "QCA Failed to get version (%d)", ret);
-		return ret;
+	if (!soc_ver) {
+		/* Get QCA version information */
+		ret = qca_read_soc_version(hdev, &soc_ver);
+		if (ret < 0 || soc_ver == 0) {
+			bt_dev_err(hdev, "QCA Failed to get version (%d)", ret);
+			return ret;
+		}
+		bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
 	}
-	bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
 
 	/* Setup patch / NVM configurations */
-	ret = qca_uart_setup(hdev, qca_baudrate, QCA_ROME, soc_ver);
+	ret = qca_uart_setup(hdev, qca_baudrate, qcadev->btsoc_type, soc_ver);
 	if (!ret) {
 		set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
 		qca_debugfs_init(hdev);
@@ -1061,9 +1209,123 @@ static struct hci_uart_proto qca_proto = {
 	.dequeue	= qca_dequeue,
 };
 
+static const struct qca_vreg_data qca_soc_data = {
+	.soc_type = QCA_WCN3990,
+	.vregs = (struct qca_vreg []) {
+		{ "vddio",   1800000, 1800000,  0 },
+		{ "vddxo",   1800000, 1800000,  1 },
+		{ "vddrf",   1304000, 1304000,  1 },
+		{ "vddch0",  3000000, 3312000,  1 },
+	},
+	.num_vregs = 4,
+};
+
+static void qca_power_shutdown(struct hci_uart *hu)
+{
+	struct hci_dev *hdev = hu->hdev;
+
+	host_set_baudrate(hu, 2400);
+	qca_send_vendor_cmd(hdev, QCA_WCN3990_POWEROFF_PULSE);
+	qca_power_setup(hu, false);
+}
+
+static int qca_enable_regulator(struct qca_vreg vregs,
+				struct regulator *regulator)
+{
+	int ret;
+
+	ret = regulator_set_voltage(regulator, vregs.min_uV,
+				    vregs.max_uV);
+	if (ret)
+		return ret;
+
+	if (vregs.load_uA)
+		ret = regulator_set_load(regulator,
+					 vregs.load_uA);
+
+	if (ret)
+		return ret;
+
+	return regulator_enable(regulator);
+
+}
+
+static void qca_disable_regulator(struct qca_vreg vregs,
+				  struct regulator *regulator)
+{
+	regulator_disable(regulator);
+	regulator_set_voltage(regulator, 0, vregs.max_uV);
+	if (vregs.load_uA)
+		regulator_set_load(regulator, 0);
+
+}
+
+static int qca_power_setup(struct hci_uart *hu, bool on)
+{
+	struct qca_vreg *vregs;
+	struct regulator_bulk_data *vreg_bulk;
+	struct qca_serdev *qcadev;
+	int i, num_vregs, ret = 0;
+
+	qcadev = serdev_device_get_drvdata(hu->serdev);
+	if (!qcadev || !qcadev->bt_power || !qcadev->bt_power->vreg_data ||
+	    !qcadev->bt_power->vreg_bulk)
+		return -EINVAL;
+
+	vregs = qcadev->bt_power->vreg_data->vregs;
+	vreg_bulk = qcadev->bt_power->vreg_bulk;
+	num_vregs = qcadev->bt_power->vreg_data->num_vregs;
+	BT_DBG("on: %d", on);
+	if (on  && !qcadev->bt_power->vregs_on) {
+		for (i = 0; i < num_vregs; i++) {
+			ret = qca_enable_regulator(vregs[i],
+						   vreg_bulk[i].consumer);
+			if (ret)
+				break;
+		}
+
+		if (ret) {
+			BT_ERR("failed to enable regulator:%s", vregs[i].name);
+			/* turn off regulators which are enabled */
+			for (i = i - 1; i >= 0; i--)
+				qca_disable_regulator(vregs[i],
+						      vreg_bulk[i].consumer);
+		} else {
+			qcadev->bt_power->vregs_on = true;
+		}
+	} else if (!on && qcadev->bt_power->vregs_on) {
+		/* turn off regulator in reverse order */
+		i = qcadev->bt_power->vreg_data->num_vregs - 1;
+		for ( ; i >= 0; i--)
+			qca_disable_regulator(vregs[i], vreg_bulk[i].consumer);
+
+		qcadev->bt_power->vregs_on = false;
+	}
+
+	return ret;
+}
+
+static int qca_init_regulators(struct qca_power *qca,
+			       const struct qca_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;
+	const struct qca_vreg_data *data;
 	int err;
 
 	qcadev = devm_kzalloc(&serdev->dev, sizeof(*qcadev), GFP_KERNEL);
@@ -1071,47 +1333,82 @@ static int qca_serdev_probe(struct serdev_device *serdev)
 		return -ENOMEM;
 
 	qcadev->serdev_hu.serdev = serdev;
+	data = of_device_get_match_data(&serdev->dev);
 	serdev_device_set_drvdata(serdev, qcadev);
+	if (data && data->soc_type == QCA_WCN3990) {
+		qcadev->btsoc_type = QCA_WCN3990;
+		qcadev->bt_power = devm_kzalloc(&serdev->dev,
+						sizeof(struct qca_power),
+						GFP_KERNEL);
+		if (!qcadev->bt_power)
+			return -ENOMEM;
+
+		qcadev->bt_power->dev = &serdev->dev;
+		qcadev->bt_power->vreg_data = data;
+		err = qca_init_regulators(qcadev->bt_power, data->vregs,
+					  data->num_vregs);
+		if (err) {
+			BT_ERR("Failed to init regulators:%d", err);
+			goto out;
+		}
 
-	qcadev->bt_en = devm_gpiod_get(&serdev->dev, "enable",
-				       GPIOD_OUT_LOW);
-	if (IS_ERR(qcadev->bt_en)) {
-		dev_err(&serdev->dev, "failed to acquire enable gpio\n");
-		return PTR_ERR(qcadev->bt_en);
-	}
+		qcadev->bt_power->vregs_on = false;
+		device_property_read_u32(&serdev->dev, "max-speed",
+					 &qcadev->oper_speed);
+		if (!qcadev->oper_speed)
+			BT_INFO("UART will pick default operating speed");
+		err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
+		if (err) {
+			BT_ERR("wcn3990 serdev registration failed");
+			goto out;
+		}
+	} else {
+		qcadev->btsoc_type = QCA_ROME;
+		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);
+	}
+
+out:	return err;
 
-	return err;
 }
 
 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);
+	if (qcadev->btsoc_type == QCA_WCN3990)
+		qca_power_shutdown(&qcadev->serdev_hu);
+	else
+		clk_disable_unprepare(qcadev->susclk);
 
-	clk_disable_unprepare(qcadev->susclk);
+	hci_uart_unregister_device(&qcadev->serdev_hu);
 }
 
 static const struct of_device_id qca_bluetooth_of_match[] = {
 	{ .compatible = "qcom,qca6174-bt" },
+	{ .compatible = "qcom,wcn3990-bt", .data = &qca_soc_data},
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match);
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH v9 1/7] dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990
  2018-07-05 16:55 ` [PATCH v9 1/7] dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990 Balakrishna Godavarthi
@ 2018-07-05 20:42   ` Rob Herring
  2018-07-10 12:32     ` Balakrishna Godavarthi
  0 siblings, 1 reply; 24+ messages in thread
From: Rob Herring @ 2018-07-05 20:42 UTC (permalink / raw)
  To: Balakrishna Godavarthi
  Cc: marcel, johan.hedberg, mka, linux-kernel, devicetree,
	linux-bluetooth, thierry.escande, rtatiya, hemantg,
	linux-arm-msm

On Thu, Jul 05, 2018 at 10:25:09PM +0530, Balakrishna Godavarthi wrote:
> This patch enables regulators for the Qualcomm Bluetooth wcn3990
> controller.
> 
> Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
> ---
> Changes in v9:
>     * updated with latest reg handle and names.
>     * updated max-speed definition. 
> 
> Changes in v8:
>     * Separated the optional entries between two chips
> 
> Changes in v7:
>     * no change.
> 
> Changes in v6:
> 
>     * Changed the oper-speed to max-speed.
> 
> Changes in v5:
> 
>     * Added entry for oper-speed and init-speed.
> 
> ---
>  .../bindings/net/qualcomm-bluetooth.txt       | 28 +++++++++++++++++--
>  1 file changed, 26 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt b/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt
> index 0ea18a53cc29..ced58575e2b8 100644
> --- a/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt
> +++ b/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt
> @@ -10,12 +10,22 @@ device the slave device is attached to.
>  Required properties:
>   - compatible: should contain one of the following:
>     * "qcom,qca6174-bt"
> +   * "qcom,wcn3990-bt"
> +
> +Optional properties for compatible string qcom,qca6174-bt:
>  
> -Optional properties:
>   - enable-gpios: gpio specifier used to enable chip
>   - clocks: clock provided to the controller (SUSCLK_32KHZ)
>  
> -Example:
> +Optional properties for compatible string qcom,wcn3990-bt:
> +
> + - vddio-supply: Bluetooth wcn3990 VDD_IO supply regulator handle.
> + - vddxo-supply: Bluetooth wcn3990 VDD_XO supply regulator handle.
> + - vddrf-supply: Bluetooth wcn3990 VDD_RF supply regulator handle.
> + - vddch0-supply: Bluetooth wcn3990 VDD_CH0 supply regulator handle.
> + - max-speed: see Documentation/devicetree/bindings/serial/slave-device.txt
> +
> +Examples:
>  
>  serial@7570000 {
>  	label = "BT-UART";
> @@ -28,3 +38,17 @@ serial@7570000 {
>  		clocks = <&divclk4>;
>  	};
>  };
> +
> +serial@898000 {
> +	label = "BT-UART";

label is generally intended for when you need to identify the physical 
connector which wouldn't apply here.

> +	status = "okay";

Don't show status in examples.

> +
> +	bluetooth {
> +		compatible = "qcom,wcn3990-bt";
> +		vddio-supply = <&vreg_s4a_1p8>;
> +		vddxosupply = <&vreg_l7a_1p8>;

Typo.

With those fixed,

Reviewed-by: Rob Herring <robh@kernel.org>

> +		vddrf-supply = <&vreg_l17a_1p3>;
> +		vddch0-supply = <&vreg_l25a_3p3>;
> +		max-speed = <3200000>;
> +	};
> +};
> -- 
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project
> 
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v9 4/7] Bluetooth: hci_qca: Add wrapper functions for setting UART speed
  2018-07-05 16:55 ` [PATCH v9 4/7] Bluetooth: hci_qca: Add wrapper functions for setting UART speed Balakrishna Godavarthi
@ 2018-07-06 19:40   ` Matthias Kaehlcke
  2018-07-10 12:19     ` Balakrishna Godavarthi
  0 siblings, 1 reply; 24+ messages in thread
From: Matthias Kaehlcke @ 2018-07-06 19:40 UTC (permalink / raw)
  To: Balakrishna Godavarthi
  Cc: marcel, johan.hedberg, linux-kernel, devicetree, linux-bluetooth,
	thierry.escande, rtatiya, hemantg, linux-arm-msm

On Thu, Jul 05, 2018 at 10:25:12PM +0530, Balakrishna Godavarthi wrote:
> In function qca_setup, we set initial and operating speeds for Qualcomm
> Bluetooth SoC's. This block of code is common across different
> Qualcomm Bluetooth SoC's. Instead of duplicating the code, created
> a wrapper function to set the speeds. So that future coming SoC's
> can use these wrapper functions to set speeds.
> 
> Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
> ---
> Changes in v9:
>     * added corner case to fail driver if speeds are missing.
> 
> Changes in v8:
>     * common function to set INIT and operating speeds.
> 
> Changes in v7:
>     * initial patch
>     * created wrapper functions for init and operating speeds.
> ---
>  drivers/bluetooth/hci_qca.c | 94 ++++++++++++++++++++++++++++---------
>  1 file changed, 71 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> index c02e1d465cca..9106547324fa 100644
> --- a/drivers/bluetooth/hci_qca.c
> +++ b/drivers/bluetooth/hci_qca.c
> @@ -119,6 +119,11 @@ struct qca_data {
>  	u64 votes_off;
>  };
>  
> +enum qca_speed_type {
> +	QCA_INIT_SPEED = 1,
> +	QCA_OPER_SPEED
> +};
> +
>  struct qca_serdev {
>  	struct hci_uart	 serdev_hu;
>  	struct gpio_desc *bt_en;
> @@ -923,6 +928,62 @@ static inline void host_set_baudrate(struct hci_uart *hu, unsigned int speed)
>  		hci_uart_set_baudrate(hu, speed);
>  }
>  
> +static unsigned int qca_get_speed(struct hci_uart *hu,
> +				  enum qca_speed_type speed_type)
> +{
> +	unsigned int speed = 0;
> +
> +	if (speed_type == QCA_INIT_SPEED) {
> +		if (hu->init_speed)
> +			speed = hu->init_speed;
> +		else if (hu->proto->init_speed)
> +			speed = hu->proto->init_speed;
> +	} else {
> +		if (hu->oper_speed)
> +			speed = hu->oper_speed;
> +		else if (hu->proto->oper_speed)
> +			speed = hu->proto->oper_speed;
> +	}
> +
> +	return speed;
> +}
> +
> +static int qca_check_speeds(struct hci_uart *hu)
> +{
> +	/* One or the other speeds should be non zero. */
> +	if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
> +	    !qca_get_speed(hu, QCA_OPER_SPEED))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
> +{
> +	unsigned int speed, qca_baudrate;
> +	int ret;
> +
> +	if (speed_type == QCA_INIT_SPEED) {
> +		speed = qca_get_speed(hu, QCA_INIT_SPEED);
> +		if (speed)
> +			host_set_baudrate(hu, speed);

mega-nit: for consistency with the 'else' branch you could return if
'speed == 0'. Not important though, feel free to ignore.

> +	} else {
> +		speed = qca_get_speed(hu, QCA_OPER_SPEED);
> +		if (!speed)
> +			return 0;
> +
> +		qca_baudrate = qca_get_baudrate_value(speed);
> +		bt_dev_info(hu->hdev, "Set UART speed to %d", speed);
> +		ret = qca_set_baudrate(hu->hdev, qca_baudrate);
> +		if (ret)
> +			return ret;
> +
> +		host_set_baudrate(hu, speed);
> +	}
> +
> +	return 0;
> +}
> +
>  static int qca_setup(struct hci_uart *hu)
>  {
>  	struct hci_dev *hdev = hu->hdev;
> @@ -933,37 +994,24 @@ static int qca_setup(struct hci_uart *hu)
>  
>  	bt_dev_info(hdev, "ROME setup");
>  
> +	ret = qca_check_speeds(hu);
> +	if (ret)
> +		return ret;
> +
>  	/* 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);
> +	qca_set_speed(hu, QCA_INIT_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;
> -
> +	speed = qca_get_speed(hu, QCA_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);
> +		ret = qca_set_speed(hu, QCA_OPER_SPEED);
> +		if (ret)
>  			return ret;
> -		}
> -		host_set_baudrate(hu, speed);
> +
> +		qca_baudrate = qca_get_baudrate_value(speed);
>  	}

One doubt, the outcome of this change is:

	qca_set_speed(hu, QCA_INIT_SPEED);

	/* Setup user speed if needed */
	speed = qca_get_speed(hu, QCA_OPER_SPEED);
	if (speed) {
		ret = qca_set_speed(hu, QCA_OPER_SPEED);
		if (ret)
			return ret;

		qca_baudrate = qca_get_baudrate_value(speed);
	}

So we set the init speed and then directly switch to operating speed
if it is defined.

Couldn't we do this instead:

	/* Setup user speed if needed */
	speed = qca_get_speed(hu, QCA_OPER_SPEED);
	if (speed) {
		ret = qca_set_speed(hu, QCA_OPER_SPEED);
		if (ret)
			return ret;

		qca_baudrate = qca_get_baudrate_value(speed);
	} else {
	       qca_set_speed(hu, QCA_INIT_SPEED);
	}

?

Or is setting the init speed needed before the operating speed can be
set? Sorry if we discussed this earlier in this series, I know I had a
few doubts about the speed management but don't recall this one
specifically.

Other than that:

Reviewed-by: Matthias Kaehlcke <mka@chromium.org>

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

* Re: [PATCH v9 7/7] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990
  2018-07-05 16:55 ` [PATCH v9 7/7] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990 Balakrishna Godavarthi
@ 2018-07-06 22:21   ` Matthias Kaehlcke
  2018-07-10 12:52     ` Balakrishna Godavarthi
  2018-07-16 13:51     ` Balakrishna Godavarthi
  0 siblings, 2 replies; 24+ messages in thread
From: Matthias Kaehlcke @ 2018-07-06 22:21 UTC (permalink / raw)
  To: Balakrishna Godavarthi
  Cc: marcel, johan.hedberg, linux-kernel, devicetree, linux-bluetooth,
	thierry.escande, rtatiya, hemantg, linux-arm-msm, Stephen Boyd

On Thu, Jul 05, 2018 at 10:25:15PM +0530, Balakrishna Godavarthi wrote:
> Add support to set voltage/current of various regulators
> to power up/down Bluetooth chip wcn3990.
> 
> Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
> ---
> changes in v9:
>     * moved flow control to vendor and set_baudarte functions.
>     * removed parent regs.
> 
> changes in v8:
>     * closing qca buffer, if qca_power_setup fails
>     * chnaged ibs start timer function call location.
>     * updated review comments.
>   
> changes in v7:
>     * addressed review comments.
> 
> changes in v6:
>     * Hooked up qca_power to qca_serdev.
>     * renamed all the naming inconsistency functions with qca_*
>     * leveraged common code of ROME for wcn3990.
>     * created wrapper functions for re-usable blocks.
>     * updated function of _*regulator_enable and _*regualtor_disable.  
>     * removed redundant comments and functions.
>     * addressed review comments.
> 
> Changes in v5:
>     * updated regulator vddpa min_uV to 1304000.
>       * addressed review comments.
>  
> Changes in v4:
>     * Segregated the changes of btqca from hci_qca
>     * rebased all changes on top of bluetooth-next.
>     * addressed review comments.
> 
> ---
>  drivers/bluetooth/btqca.h   |   3 +
>  drivers/bluetooth/hci_qca.c | 387 +++++++++++++++++++++++++++++++-----
>  2 files changed, 345 insertions(+), 45 deletions(-)
> 
> diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
> index a9c2779f3e07..0c01f375fe83 100644
> --- a/drivers/bluetooth/btqca.h
> +++ b/drivers/bluetooth/btqca.h
> @@ -37,6 +37,9 @@
>  #define EDL_TAG_ID_HCI			(17)
>  #define EDL_TAG_ID_DEEP_SLEEP		(27)
>  
> +#define QCA_WCN3990_POWERON_PULSE	0xFC
> +#define QCA_WCN3990_POWEROFF_PULSE	0xC0
> +
>  enum qca_bardrate {
>  	QCA_BAUDRATE_115200 	= 0,
>  	QCA_BAUDRATE_57600,
> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> index 7ebfaa0edf3f..d62c7785a618 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...
> @@ -31,9 +31,14 @@
>  #include <linux/kernel.h>
>  #include <linux/clk.h>
>  #include <linux/debugfs.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
>  #include <linux/gpio/consumer.h>
>  #include <linux/mod_devicetable.h>
>  #include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/regulator/consumer.h>
>  #include <linux/serdev.h>
>  
>  #include <net/bluetooth/bluetooth.h>
> @@ -124,12 +129,46 @@ enum qca_speed_type {
>  	QCA_OPER_SPEED
>  };
>  
> +/*
> + * Voltage regulator information required for configuring the
> + * QCA Bluetooth chipset
> + */
> +struct qca_vreg {
> +	const char *name;
> +	unsigned int min_uV;
> +	unsigned int max_uV;
> +	unsigned int load_uA;
> +};
> +
> +struct qca_vreg_data {
> +	enum qca_btsoc_type soc_type;
> +	struct qca_vreg *vregs;
> +	size_t num_vregs;
> +};
> +
> +/*
> + * Platform data for the QCA Bluetooth power driver.
> + */
> +struct qca_power {
> +	struct device *dev;
> +	const struct qca_vreg_data *vreg_data;
> +	struct regulator_bulk_data *vreg_bulk;
> +	bool vregs_on;
> +};
> +
>  struct qca_serdev {
>  	struct hci_uart	 serdev_hu;
>  	struct gpio_desc *bt_en;
>  	struct clk	 *susclk;
> +	enum qca_btsoc_type btsoc_type;
> +	struct qca_power *bt_power;
> +	u32 init_speed;
> +	u32 oper_speed;
>  };
>  
> +static int qca_power_setup(struct hci_uart *hu, bool on);
> +static void qca_power_shutdown(struct hci_uart *hu);
> +
>  static void __serial_clock_on(struct tty_struct *tty)
>  {
>  	/* TODO: Some chipset requires to enable UART clock on client
> @@ -407,6 +446,7 @@ static int qca_open(struct hci_uart *hu)
>  {
>  	struct qca_serdev *qcadev;
>  	struct qca_data *qca;
> +	int ret;
>  
>  	BT_DBG("hu %p qca_open", hu);
>  
> @@ -458,19 +498,32 @@ static int qca_open(struct hci_uart *hu)
>  
>  	hu->priv = qca;
>  
> -	timer_setup(&qca->wake_retrans_timer, hci_ibs_wake_retrans_timeout, 0);
> -	qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
> -
> -	timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
> -	qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
> -
>  	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 != QCA_WCN3990) {
> +			gpiod_set_value_cansleep(qcadev->bt_en, 1);
> +		} else {
> +			hu->init_speed = qcadev->init_speed;
> +			hu->oper_speed = qcadev->oper_speed;
> +			ret = qca_power_setup(hu, true);
> +			if (ret) {
> +				destroy_workqueue(qca->workqueue);
> +				kfree_skb(qca->rx_skb);
> +				hu->priv = NULL;
> +				kfree(qca);
> +				return ret;
> +			}
> +		}
>  	}
>  
> +	timer_setup(&qca->wake_retrans_timer, hci_ibs_wake_retrans_timeout, 0);
> +	qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
> +
> +	timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
> +	qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
> +
>  	BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u",
>  	       qca->tx_idle_delay, qca->wake_retrans);
>  
> @@ -554,10 +607,13 @@ static int qca_close(struct hci_uart *hu)
>  	qca->hu = NULL;
>  
>  	if (hu->serdev) {
> -		serdev_device_close(hu->serdev);
> -
>  		qcadev = serdev_device_get_drvdata(hu->serdev);
> -		gpiod_set_value_cansleep(qcadev->bt_en, 0);
> +		if (qcadev->btsoc_type == QCA_WCN3990)
> +			qca_power_shutdown(hu);
> +		else
> +			gpiod_set_value_cansleep(qcadev->bt_en, 0);
> +
> +		serdev_device_close(hu->serdev);
>  	}
>  
>  	kfree_skb(qca->rx_skb);
> @@ -891,6 +947,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
>  	struct hci_uart *hu = hci_get_drvdata(hdev);
>  	struct qca_data *qca = hu->priv;
>  	struct sk_buff *skb;
> +	struct qca_serdev *qcadev;
>  	u8 cmd[] = { 0x01, 0x48, 0xFC, 0x01, 0x00 };
>  
>  	if (baudrate > QCA_BAUDRATE_3200000)
> @@ -904,6 +961,13 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
>  		return -ENOMEM;
>  	}
>  
> +	/* Disabling hardware flow control is mandate while

nit: s/mandate/mandatory|required/

> +	 * sending change baudrate request to wcn3990 SoC.
> +	 */
> +	qcadev = serdev_device_get_drvdata(hu->serdev);
> +	if (qcadev->btsoc_type == QCA_WCN3990)
> +		hci_uart_set_flow_control(hu, true);
> +
>  	/* Assign commands to change baudrate and packet type. */
>  	skb_put_data(skb, cmd, sizeof(cmd));
>  	hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
> @@ -919,6 +983,9 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
>  	schedule_timeout(msecs_to_jiffies(BAUDRATE_SETTLE_TIMEOUT_MS));
>  	set_current_state(TASK_RUNNING);
>  
> +	if (qcadev->btsoc_type == QCA_WCN3990)
> +		hci_uart_set_flow_control(hu, false);
> +
>  	return 0;
>  }
>  
> @@ -930,6 +997,36 @@ static inline void host_set_baudrate(struct hci_uart *hu, unsigned int speed)
>  		hci_uart_set_baudrate(hu, speed);
>  }
>  
> +static int qca_send_vendor_cmd(struct hci_dev *hdev, u8 cmd)
> +{
> +	struct hci_uart *hu = hci_get_drvdata(hdev);
> +	struct qca_data *qca = hu->priv;
> +	struct sk_buff *skb;
> +
> +	bt_dev_dbg(hdev, "sending command %02x to SoC", cmd);
> +
> +	skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	/* Disabling hardware flow control is mandate while

Same nit as above

> +	 * sending vendor power on and off pulse to SoC.
> +	 */

The function is called qca_send_vendor_cmd(), the comment about power
on/off pulses seems misplaced here. Are there other 'vendor commands'
that require a different flow control behavior?

Perhaps the function should have a different name or we need another
wrapper.

> +	hci_uart_set_flow_control(hu, true);

Should the changing of the flow control be limited to wcn3990? As of
now the function is only called for wcn3990, however this is not
stated as a requirement and might change in the future.

> +	skb_put_u8(skb, 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 */
> +	usleep_range(100, 200);

Is this needed for any 'vendor command' or directly related with the
power on/off pulses?

> +	hci_uart_set_flow_control(hu, false);
> +
> +	return 0;
> +}
> +
>  static unsigned int qca_get_speed(struct hci_uart *hu,
>  				  enum qca_speed_type speed_type)
>  {
> @@ -952,10 +1049,19 @@ static unsigned int qca_get_speed(struct hci_uart *hu,
>  
>  static int qca_check_speeds(struct hci_uart *hu)
>  {
> -	/* One or the other speeds should be non zero. */
> -	if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
> -	    !qca_get_speed(hu, QCA_OPER_SPEED))
> +	struct qca_serdev *qcadev;
> +
> +	qcadev = serdev_device_get_drvdata(hu->serdev);
> +	if ((qcadev->btsoc_type == QCA_WCN3990 &&
> +	    !qca_get_speed(hu, QCA_INIT_SPEED)) ||
> +	    !qca_get_speed(hu, QCA_OPER_SPEED)) {
> +		/* Both INIT and OPER speed should be non zero. */
>  		return -EINVAL;
> +	} else if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
> +		    !qca_get_speed(hu, QCA_OPER_SPEED)) {
> +		/* One or the other speeds should be non zero. */
> +		return -EINVAL;
> +	}

It is questionable if the comments are useful, they are basically
stating the same as the conditions.

if-else statements with a single statement in all branches shouldn't
use curly braces. Personally I don't dislike them in this case with
the multi-line conditions, but in principle they shoulnd't be there.

nit: this would be easier to read with nested if statements:

	if (qcadev->btsoc_type == QCA_WCN3990)
		if (!qca_get_speed(hu, QCA_INIT_SPEED)) ||
		    !qca_get_speed(hu, QCA_OPER_SPEED))
			return -EINVAL;
	else
		if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
		    !qca_get_speed(hu, QCA_OPER_SPEED)) {
			return -EINVAL;

>  	return 0;
>  }
> @@ -986,15 +1092,40 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
>  	return 0;
>  }
>  
> +static int qca_wcn3990_init(struct hci_uart *hu)
> +{
> +	int ret;
> +
> +	ret = qca_send_vendor_cmd(hu->hdev, QCA_WCN3990_POWERON_PULSE);
> +	if (ret)
> +		return ret;
> +
> +	/* Wait for 100 ms for SoC to boot up */
> +	msleep(100);
> +	serdev_device_close(hu->serdev);
> +	ret = serdev_device_open(hu->serdev);
> +	if (ret) {
> +		bt_dev_err(hu->hdev, "failed to open port");
> +		return ret;
> +	}
> +
> +	/* Setup initial baudrate */
> +	qca_set_speed(hu, QCA_INIT_SPEED);

The comment is a bit redundant.

> +	hci_uart_set_flow_control(hu, false);
> +
> +	return 0;
> +}
> +
>  static int qca_setup(struct hci_uart *hu)
>  {
>  	struct hci_dev *hdev = hu->hdev;
>  	struct qca_data *qca = hu->priv;
>  	unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200;
> +	struct qca_serdev *qcadev;
>  	int ret;
>  	int soc_ver = 0;
>  
> -	bt_dev_info(hdev, "ROME setup");
> +	qcadev = serdev_device_get_drvdata(hu->serdev);
>  
>  	ret = qca_check_speeds(hu);
>  	if (ret)
> @@ -1006,6 +1137,21 @@ static int qca_setup(struct hci_uart *hu)
>  	/* Setup initial baudrate */
>  	qca_set_speed(hu, QCA_INIT_SPEED);
>  
> +	if (qcadev->btsoc_type == QCA_WCN3990) {
> +		bt_dev_dbg(hdev, "setting up wcn3990");

Seems like this should be bt_dev_info() for consistency with Rome.

> +		ret = qca_wcn3990_init(hu);
> +		if (ret)
> +			return ret;
> +
> +		ret = qca_read_soc_version(hdev, &soc_ver);
> +		if (ret < 0 || soc_ver == 0) {
> +			bt_dev_err(hdev, "Failed to get version %d", ret);
> +			return ret;
> +		}
> +	} else {
> +		bt_dev_info(hdev, "ROME setup");
> +	}
> +
>  	/* Setup user speed if needed */
>  	speed = qca_get_speed(hu, QCA_OPER_SPEED);
>  	if (speed) {
> @@ -1016,16 +1162,18 @@ static int qca_setup(struct hci_uart *hu)
>  		qca_baudrate = qca_get_baudrate_value(speed);
>  	}
>  
> -	/* Get QCA version information */
> -	ret = qca_read_soc_version(hdev, &soc_ver);
> -	if (ret < 0 || soc_ver == 0) {
> -		bt_dev_err(hdev, "QCA Failed to get version (%d)", ret);
> -		return ret;
> +	if (!soc_ver) {


The following would probably be clearer:

  	if (qcadev->btsoc_type != QCA_WCN3990) {

> +		/* Get QCA version information */
> +		ret = qca_read_soc_version(hdev, &soc_ver);
> +		if (ret < 0 || soc_ver == 0) {
> +			bt_dev_err(hdev, "QCA Failed to get version (%d)", ret);
> +			return ret;
> +		}
> +		bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);

Couldn't we hide some of this in qca_read_soc_version()?

qca_read_soc_version() could at least do the logging in the error case
(the 'soc_ver == 0' case could be handled there as well), which would
leave us with:


	ret = qca_read_soc_version(hdev, &soc_ver);
	if (ret)
		return ret;

And the same above.

The controller version can be logged outside of the branch for both
wcn3990 and Rome.

>  	}
> -	bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
>  
>  	/* Setup patch / NVM configurations */
> -	ret = qca_uart_setup(hdev, qca_baudrate, QCA_ROME, soc_ver);
> +	ret = qca_uart_setup(hdev, qca_baudrate, qcadev->btsoc_type, soc_ver);
>  	if (!ret) {
>  		set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
>  		qca_debugfs_init(hdev);
> @@ -1061,9 +1209,123 @@ static struct hci_uart_proto qca_proto = {
>  	.dequeue	= qca_dequeue,
>  };
>  
> +static const struct qca_vreg_data qca_soc_data = {
> +	.soc_type = QCA_WCN3990,
> +	.vregs = (struct qca_vreg []) {
> +		{ "vddio",   1800000, 1800000,  0 },
> +		{ "vddxo",   1800000, 1800000,  1 },
> +		{ "vddrf",   1304000, 1304000,  1 },
> +		{ "vddch0",  3000000, 3312000,  1 },
> +	},
> +	.num_vregs = 4,
> +};

I didn't chime in earlier in the discussion with Stephen on the
regulators (https://patchwork.kernel.org/patch/10467911/), however I
agree with him that specifying at load of 1uA doesn't seem to make
much sense. What would happen if the load remained unspecified (or 0)?

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

* Re: [PATCH v9 3/7] Bluetooth: btqca: Redefine qca_uart_setup() to generic function.
  2018-07-05 16:55 ` [PATCH v9 3/7] Bluetooth: btqca: Redefine qca_uart_setup() to generic function Balakrishna Godavarthi
@ 2018-07-06 22:35   ` Matthias Kaehlcke
  0 siblings, 0 replies; 24+ messages in thread
From: Matthias Kaehlcke @ 2018-07-06 22:35 UTC (permalink / raw)
  To: Balakrishna Godavarthi
  Cc: marcel, johan.hedberg, linux-kernel, devicetree, linux-bluetooth,
	thierry.escande, rtatiya, hemantg, linux-arm-msm

On Thu, Jul 05, 2018 at 10:25:11PM +0530, Balakrishna Godavarthi wrote:
> Redefinition of qca_uart_setup will help future Qualcomm Bluetooth
> SoC, to use the same function instead of duplicating the function.
> Added new arguments soc_type and soc_ver to the functions.
> 
> These arguments will help to decide type of firmware files
> to be loaded into Bluetooth chip.
> soc_type holds the Bluetooth chip connected to APPS processor.
> soc_ver holds the Bluetooth chip version.
> 
> Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
> ---
> Changes in v9:
>    * moved qca_read_soc_ver() to qca_setup().
> 
> Changes in v8:
>     * updated soc_type with enum.
> 
> Changes in v7:
>     * initial patch
>     * redefined qca_uart_setup function to generic.
> ---
>  drivers/bluetooth/btqca.c   | 17 ++++-------------
>  drivers/bluetooth/btqca.h   | 13 +++++++++++--
>  drivers/bluetooth/hci_qca.c | 11 ++++++++++-
>  3 files changed, 25 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
> index c5cf9cab438a..03bcbaaf1ae9 100644
> --- a/drivers/bluetooth/btqca.c
> +++ b/drivers/bluetooth/btqca.c
> @@ -327,9 +327,9 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
>  }
>  EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome);
>  
> -int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate)
> +int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
> +		   enum qca_btsoc_type soc_type, u32 soc_ver)
>  {
> -	u32 rome_ver = 0;
>  	struct rome_config config;
>  	int err;
>  
> @@ -337,19 +337,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate)
>  
>  	config.user_baud_rate = baudrate;
>  
> -	/* Get QCA version information */
> -	err = qca_read_soc_version(hdev, &rome_ver);
> -	if (err < 0 || rome_ver == 0) {
> -		bt_dev_err(hdev, "QCA Failed to get version %d", err);
> -		return err;
> -	}
> -
> -	bt_dev_info(hdev, "QCA controller version 0x%08x", rome_ver);
> -
>  	/* Download rampatch file */
>  	config.type = TLV_TYPE_PATCH;
>  	snprintf(config.fwname, sizeof(config.fwname), "qca/rampatch_%08x.bin",
> -		 rome_ver);
> +		 soc_ver);
>  	err = qca_download_firmware(hdev, &config);
>  	if (err < 0) {
>  		bt_dev_err(hdev, "QCA Failed to download patch (%d)", err);
> @@ -359,7 +350,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate)
>  	/* Download NVM configuration */
>  	config.type = TLV_TYPE_NVM;
>  	snprintf(config.fwname, sizeof(config.fwname), "qca/nvm_%08x.bin",
> -		 rome_ver);
> +		 soc_ver);
>  	err = qca_download_firmware(hdev, &config);
>  	if (err < 0) {
>  		bt_dev_err(hdev, "QCA Failed to download NVM (%d)", err);
> diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
> index 5c9851b11838..a9c2779f3e07 100644
> --- a/drivers/bluetooth/btqca.h
> +++ b/drivers/bluetooth/btqca.h
> @@ -124,10 +124,18 @@ struct tlv_type_hdr {
>  	__u8   data[0];
>  } __packed;
>  
> +enum qca_btsoc_type {
> +	QCA_INVALID = -1,
> +	QCA_AR3002,
> +	QCA_ROME,
> +	QCA_WCN3990
> +};
> +
>  #if IS_ENABLED(CONFIG_BT_QCA)
>  
>  int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr);
> -int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate);
> +int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
> +		   enum qca_btsoc_type soc_type, u32 soc_ver);
>  int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version);
>  
>  #else
> @@ -137,7 +145,8 @@ static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdad
>  	return -EOPNOTSUPP;
>  }
>  
> -static inline int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate)
> +static inline int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
> +				 enum qca_btsoc_type soc_type, u32 soc_ver)
>  {
>  	return -EOPNOTSUPP;
>  }
> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> index d7b60669b656..c02e1d465cca 100644
> --- a/drivers/bluetooth/hci_qca.c
> +++ b/drivers/bluetooth/hci_qca.c
> @@ -929,6 +929,7 @@ static int qca_setup(struct hci_uart *hu)
>  	struct qca_data *qca = hu->priv;
>  	unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200;
>  	int ret;
> +	int soc_ver = 0;
>  
>  	bt_dev_info(hdev, "ROME setup");
>  
> @@ -965,8 +966,16 @@ static int qca_setup(struct hci_uart *hu)
>  		host_set_baudrate(hu, speed);
>  	}
>  
> +	/* Get QCA version information */
> +	ret = qca_read_soc_version(hdev, &soc_ver);
> +	if (ret < 0 || soc_ver == 0) {
> +		bt_dev_err(hdev, "QCA Failed to get version (%d)", ret);
> +		return ret;
> +	}
> +	bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);

As commented on [1] I'd suggest to move some of the logging and error
handling to qca_read_soc_version(), especially since this sequence is
duplicated later in this series.

Not really the scope of this patch though, so:

Reviewed-by: Matthias Kaehlcke <mka@chromium.org>

[1] https://patchwork.kernel.org/patch/10510029/

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

* Re: [PATCH v9 4/7] Bluetooth: hci_qca: Add wrapper functions for setting UART speed
  2018-07-06 19:40   ` Matthias Kaehlcke
@ 2018-07-10 12:19     ` Balakrishna Godavarthi
  2018-07-10 16:12       ` Matthias Kaehlcke
  0 siblings, 1 reply; 24+ messages in thread
From: Balakrishna Godavarthi @ 2018-07-10 12:19 UTC (permalink / raw)
  To: Matthias Kaehlcke
  Cc: marcel, johan.hedberg, linux-kernel, devicetree, linux-bluetooth,
	thierry.escande, rtatiya, hemantg, linux-arm-msm

Hi Matthias,

On 2018-07-07 01:10, Matthias Kaehlcke wrote:
> On Thu, Jul 05, 2018 at 10:25:12PM +0530, Balakrishna Godavarthi wrote:
>> In function qca_setup, we set initial and operating speeds for 
>> Qualcomm
>> Bluetooth SoC's. This block of code is common across different
>> Qualcomm Bluetooth SoC's. Instead of duplicating the code, created
>> a wrapper function to set the speeds. So that future coming SoC's
>> can use these wrapper functions to set speeds.
>> 
>> Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
>> ---
>> Changes in v9:
>>     * added corner case to fail driver if speeds are missing.
>> 
>> Changes in v8:
>>     * common function to set INIT and operating speeds.
>> 
>> Changes in v7:
>>     * initial patch
>>     * created wrapper functions for init and operating speeds.
>> ---
>>  drivers/bluetooth/hci_qca.c | 94 
>> ++++++++++++++++++++++++++++---------
>>  1 file changed, 71 insertions(+), 23 deletions(-)
>> 
>> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
>> index c02e1d465cca..9106547324fa 100644
>> --- a/drivers/bluetooth/hci_qca.c
>> +++ b/drivers/bluetooth/hci_qca.c
>> @@ -119,6 +119,11 @@ struct qca_data {
>>  	u64 votes_off;
>>  };
>> 
>> +enum qca_speed_type {
>> +	QCA_INIT_SPEED = 1,
>> +	QCA_OPER_SPEED
>> +};
>> +
>>  struct qca_serdev {
>>  	struct hci_uart	 serdev_hu;
>>  	struct gpio_desc *bt_en;
>> @@ -923,6 +928,62 @@ static inline void host_set_baudrate(struct 
>> hci_uart *hu, unsigned int speed)
>>  		hci_uart_set_baudrate(hu, speed);
>>  }
>> 
>> +static unsigned int qca_get_speed(struct hci_uart *hu,
>> +				  enum qca_speed_type speed_type)
>> +{
>> +	unsigned int speed = 0;
>> +
>> +	if (speed_type == QCA_INIT_SPEED) {
>> +		if (hu->init_speed)
>> +			speed = hu->init_speed;
>> +		else if (hu->proto->init_speed)
>> +			speed = hu->proto->init_speed;
>> +	} else {
>> +		if (hu->oper_speed)
>> +			speed = hu->oper_speed;
>> +		else if (hu->proto->oper_speed)
>> +			speed = hu->proto->oper_speed;
>> +	}
>> +
>> +	return speed;
>> +}
>> +
>> +static int qca_check_speeds(struct hci_uart *hu)
>> +{
>> +	/* One or the other speeds should be non zero. */
>> +	if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
>> +	    !qca_get_speed(hu, QCA_OPER_SPEED))
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>> +static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type 
>> speed_type)
>> +{
>> +	unsigned int speed, qca_baudrate;
>> +	int ret;
>> +
>> +	if (speed_type == QCA_INIT_SPEED) {
>> +		speed = qca_get_speed(hu, QCA_INIT_SPEED);
>> +		if (speed)
>> +			host_set_baudrate(hu, speed);
> 
> mega-nit: for consistency with the 'else' branch you could return if
> 'speed == 0'. Not important though, feel free to ignore.
> 
>> +	} else {
>> +		speed = qca_get_speed(hu, QCA_OPER_SPEED);
>> +		if (!speed)
>> +			return 0;
>> +
>> +		qca_baudrate = qca_get_baudrate_value(speed);
>> +		bt_dev_info(hu->hdev, "Set UART speed to %d", speed);
>> +		ret = qca_set_baudrate(hu->hdev, qca_baudrate);
>> +		if (ret)
>> +			return ret;
>> +
>> +		host_set_baudrate(hu, speed);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>>  static int qca_setup(struct hci_uart *hu)
>>  {
>>  	struct hci_dev *hdev = hu->hdev;
>> @@ -933,37 +994,24 @@ static int qca_setup(struct hci_uart *hu)
>> 
>>  	bt_dev_info(hdev, "ROME setup");
>> 
>> +	ret = qca_check_speeds(hu);
>> +	if (ret)
>> +		return ret;
>> +
>>  	/* 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);
>> +	qca_set_speed(hu, QCA_INIT_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;
>> -
>> +	speed = qca_get_speed(hu, QCA_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);
>> +		ret = qca_set_speed(hu, QCA_OPER_SPEED);
>> +		if (ret)
>>  			return ret;
>> -		}
>> -		host_set_baudrate(hu, speed);
>> +
>> +		qca_baudrate = qca_get_baudrate_value(speed);
>>  	}
> 
> One doubt, the outcome of this change is:
> 
> 	qca_set_speed(hu, QCA_INIT_SPEED);
> 
> 	/* Setup user speed if needed */
> 	speed = qca_get_speed(hu, QCA_OPER_SPEED);
> 	if (speed) {
> 		ret = qca_set_speed(hu, QCA_OPER_SPEED);
> 		if (ret)
> 			return ret;
> 
> 		qca_baudrate = qca_get_baudrate_value(speed);
> 	}
> 
> So we set the init speed and then directly switch to operating speed
> if it is defined.
> 
> Couldn't we do this instead:
> 
> 	/* Setup user speed if needed */
> 	speed = qca_get_speed(hu, QCA_OPER_SPEED);
> 	if (speed) {
> 		ret = qca_set_speed(hu, QCA_OPER_SPEED);
> 		if (ret)
> 			return ret;
> 
> 		qca_baudrate = qca_get_baudrate_value(speed);
> 	} else {
> 	       qca_set_speed(hu, QCA_INIT_SPEED);
> 	}
> 
> 

[Bala]: above else block is not required.
         if we have operating speed to set, then we need to send the baud 
rate change request to BT chip on INIT baud rate. so before sending or 
setting operating baud rate.. HOST driver should be on the HOST init 
baud rate.
         Pls refer below for more info how we set speed and hci driver 
works.
> 
> Or is setting the init speed needed before the operating speed can be
> set? Sorry if we discussed this earlier in this series, I know I had a
> few doubts about the speed management but don't recall this one
> specifically.
> 

[Bala]: Let me give a big picture how we make BT work via serdev HCI 
arch. (qca chip is taken as reference)

         1. first of all, probe is called when we have compatible string 
matches in qca_bluetooth_of_match table.
         2. that will call qca_serdev_probe() in which based on BT device 
connected to the platform, we decide IO's
            which required from HOST to chip i.e.. controls required to 
turn ON/OFF BT. which includes clocks and regulators and GPIO's.
         3. in qca_serdev_probe() we call  hci_uart_register_device() and 
pass ops (operations handler) handler for driver registration.
         4. in hci_uart_register_device(), we call qca_open().. where we 
open the port via serdev_device_open() that
            intern will call Qualcomm specific lower level UART driver 
i.e.. where we read and write to port register address.
            so serdev_device_open() is a common function to all BT chip 
vendor, but the open routine in the low level driver is completely 
vendor dependent.
            for example, some vendors will set an default UART speed 
(speed can be any) while opening the uart_port(). where as other will 
not set. Just open the port with basic configurations.

         5. coming back to qca_open(), we try to make chip to boot up by 
enabling clock from HOST for BT chip to operate..  it is purely chip 
defined.
         6. moving back to hci_uart_register_device()... we will call 
hci_register_dev() in that function we call hci_power_on().. that will 
call hci_dev_do_open()
         7. in hci_dev_do_open() we call hdev->setup() i.e. 
hci_uart_setup() in that function we set initial baud rate and operating 
bartender if we have protos defined for setting chip baud rate.(in our 
case it is null)

         8. so it will call setup function will be vendor specific.. as 
we are using an UART, HOST and chip need to stick to the agreement of 
initial UART speed for commands to send until and change baud rate 
request is
            sent.
         9. now in qca_setup(), we setup an initial host baud rate i.e. 
what we have agreement with BT chip for initial communication. Now here 
the question comes why are we setting init speed again and again
            i.e uart_open() and hci_uart_setup().. here is the answer, wt 
ever layer we have are common to all vendors may also tend to change. we 
can't take a risk, we will setup init baud rate in vendor layer i.e.
            qca_setup().
         10. then we need to change the baud rate of chip..so we need to 
send commands to chip. at wt speed we need to send change baud rate 
request is totally based on agreement with BT Chip. so here we use 
initial
             baud rate.
         11. we need to change baud rate request command to chip on init 
baud rate. if command sending is successful we change the host baud rate 
from init to operating baud rate.. else we operate on init baud rate.


         the above is based on my understanding. Pls let me know if i 
have cleared your doubt.


> Other than that:
> 
> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>



-- 
Regards
Balakrishna.

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

* Re: [PATCH v9 1/7] dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990
  2018-07-05 20:42   ` Rob Herring
@ 2018-07-10 12:32     ` Balakrishna Godavarthi
  0 siblings, 0 replies; 24+ messages in thread
From: Balakrishna Godavarthi @ 2018-07-10 12:32 UTC (permalink / raw)
  To: Rob Herring
  Cc: marcel, johan.hedberg, mka, linux-kernel, devicetree,
	linux-bluetooth, thierry.escande, rtatiya, hemantg,
	linux-arm-msm

Hi Rob,

On 2018-07-06 02:12, Rob Herring wrote:
> On Thu, Jul 05, 2018 at 10:25:09PM +0530, Balakrishna Godavarthi wrote:
>> This patch enables regulators for the Qualcomm Bluetooth wcn3990
>> controller.
>> 
>> Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
>> ---
>> Changes in v9:
>>     * updated with latest reg handle and names.
>>     * updated max-speed definition.
>> 
>> Changes in v8:
>>     * Separated the optional entries between two chips
>> 
>> Changes in v7:
>>     * no change.
>> 
>> Changes in v6:
>> 
>>     * Changed the oper-speed to max-speed.
>> 
>> Changes in v5:
>> 
>>     * Added entry for oper-speed and init-speed.
>> 
>> ---
>>  .../bindings/net/qualcomm-bluetooth.txt       | 28 
>> +++++++++++++++++--
>>  1 file changed, 26 insertions(+), 2 deletions(-)
>> 
>> diff --git 
>> a/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt 
>> b/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt
>> index 0ea18a53cc29..ced58575e2b8 100644
>> --- a/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt
>> +++ b/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt
>> @@ -10,12 +10,22 @@ device the slave device is attached to.
>>  Required properties:
>>   - compatible: should contain one of the following:
>>     * "qcom,qca6174-bt"
>> +   * "qcom,wcn3990-bt"
>> +
>> +Optional properties for compatible string qcom,qca6174-bt:
>> 
>> -Optional properties:
>>   - enable-gpios: gpio specifier used to enable chip
>>   - clocks: clock provided to the controller (SUSCLK_32KHZ)
>> 
>> -Example:
>> +Optional properties for compatible string qcom,wcn3990-bt:
>> +
>> + - vddio-supply: Bluetooth wcn3990 VDD_IO supply regulator handle.
>> + - vddxo-supply: Bluetooth wcn3990 VDD_XO supply regulator handle.
>> + - vddrf-supply: Bluetooth wcn3990 VDD_RF supply regulator handle.
>> + - vddch0-supply: Bluetooth wcn3990 VDD_CH0 supply regulator handle.
>> + - max-speed: see 
>> Documentation/devicetree/bindings/serial/slave-device.txt
>> +
>> +Examples:
>> 
>>  serial@7570000 {
>>  	label = "BT-UART";
>> @@ -28,3 +38,17 @@ serial@7570000 {
>>  		clocks = <&divclk4>;
>>  	};
>>  };
>> +
>> +serial@898000 {
>> +	label = "BT-UART";
> 
> label is generally intended for when you need to identify the physical
> connector which wouldn't apply here.
> 
>> +	status = "okay";
> 
> Don't show status in examples.
> 
>> +
>> +	bluetooth {
>> +		compatible = "qcom,wcn3990-bt";
>> +		vddio-supply = <&vreg_s4a_1p8>;
>> +		vddxosupply = <&vreg_l7a_1p8>;
> 
> Typo.
> 
> With those fixed,
> 
> Reviewed-by: Rob Herring <robh@kernel.org>
> 
>> +		vddrf-supply = <&vreg_l17a_1p3>;
>> +		vddch0-supply = <&vreg_l25a_3p3>;
>> +		max-speed = <3200000>;
>> +	};
>> +};
>> --
>> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora 
>> Forum,
>> a Linux Foundation Collaborative Project
>> 
>> --
>> To unsubscribe from this list: send the line "unsubscribe devicetree" 
>> in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html

Thanks for reviewing patch. will update those.

-- 
Regards
Balakrishna.

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

* Re: [PATCH v9 7/7] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990
  2018-07-06 22:21   ` Matthias Kaehlcke
@ 2018-07-10 12:52     ` Balakrishna Godavarthi
  2018-07-10 16:39       ` Matthias Kaehlcke
  2018-07-16 13:51     ` Balakrishna Godavarthi
  1 sibling, 1 reply; 24+ messages in thread
From: Balakrishna Godavarthi @ 2018-07-10 12:52 UTC (permalink / raw)
  To: Matthias Kaehlcke
  Cc: marcel, johan.hedberg, linux-kernel, devicetree, linux-bluetooth,
	thierry.escande, rtatiya, hemantg, linux-arm-msm, Stephen Boyd

Hi Matthias,

On 2018-07-07 03:51, Matthias Kaehlcke wrote:
> On Thu, Jul 05, 2018 at 10:25:15PM +0530, Balakrishna Godavarthi wrote:
>> Add support to set voltage/current of various regulators
>> to power up/down Bluetooth chip wcn3990.
>> 
>> Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
>> ---
>> changes in v9:
>>     * moved flow control to vendor and set_baudarte functions.
>>     * removed parent regs.
>> 
>> changes in v8:
>>     * closing qca buffer, if qca_power_setup fails
>>     * chnaged ibs start timer function call location.
>>     * updated review comments.
>> 
>> changes in v7:
>>     * addressed review comments.
>> 
>> changes in v6:
>>     * Hooked up qca_power to qca_serdev.
>>     * renamed all the naming inconsistency functions with qca_*
>>     * leveraged common code of ROME for wcn3990.
>>     * created wrapper functions for re-usable blocks.
>>     * updated function of _*regulator_enable and _*regualtor_disable.
>>     * removed redundant comments and functions.
>>     * addressed review comments.
>> 
>> Changes in v5:
>>     * updated regulator vddpa min_uV to 1304000.
>>       * addressed review comments.
>> 
>> Changes in v4:
>>     * Segregated the changes of btqca from hci_qca
>>     * rebased all changes on top of bluetooth-next.
>>     * addressed review comments.
>> 
>> ---
>>  drivers/bluetooth/btqca.h   |   3 +
>>  drivers/bluetooth/hci_qca.c | 387 
>> +++++++++++++++++++++++++++++++-----
>>  2 files changed, 345 insertions(+), 45 deletions(-)
>> 
>> diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
>> index a9c2779f3e07..0c01f375fe83 100644
>> --- a/drivers/bluetooth/btqca.h
>> +++ b/drivers/bluetooth/btqca.h
>> @@ -37,6 +37,9 @@
>>  #define EDL_TAG_ID_HCI			(17)
>>  #define EDL_TAG_ID_DEEP_SLEEP		(27)
>> 
>> +#define QCA_WCN3990_POWERON_PULSE	0xFC
>> +#define QCA_WCN3990_POWEROFF_PULSE	0xC0
>> +
>>  enum qca_bardrate {
>>  	QCA_BAUDRATE_115200 	= 0,
>>  	QCA_BAUDRATE_57600,
>> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
>> index 7ebfaa0edf3f..d62c7785a618 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...
>> @@ -31,9 +31,14 @@
>>  #include <linux/kernel.h>
>>  #include <linux/clk.h>
>>  #include <linux/debugfs.h>
>> +#include <linux/delay.h>
>> +#include <linux/device.h>
>>  #include <linux/gpio/consumer.h>
>>  #include <linux/mod_devicetable.h>
>>  #include <linux/module.h>
>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/regulator/consumer.h>
>>  #include <linux/serdev.h>
>> 
>>  #include <net/bluetooth/bluetooth.h>
>> @@ -124,12 +129,46 @@ enum qca_speed_type {
>>  	QCA_OPER_SPEED
>>  };
>> 
>> +/*
>> + * Voltage regulator information required for configuring the
>> + * QCA Bluetooth chipset
>> + */
>> +struct qca_vreg {
>> +	const char *name;
>> +	unsigned int min_uV;
>> +	unsigned int max_uV;
>> +	unsigned int load_uA;
>> +};
>> +
>> +struct qca_vreg_data {
>> +	enum qca_btsoc_type soc_type;
>> +	struct qca_vreg *vregs;
>> +	size_t num_vregs;
>> +};
>> +
>> +/*
>> + * Platform data for the QCA Bluetooth power driver.
>> + */
>> +struct qca_power {
>> +	struct device *dev;
>> +	const struct qca_vreg_data *vreg_data;
>> +	struct regulator_bulk_data *vreg_bulk;
>> +	bool vregs_on;
>> +};
>> +
>>  struct qca_serdev {
>>  	struct hci_uart	 serdev_hu;
>>  	struct gpio_desc *bt_en;
>>  	struct clk	 *susclk;
>> +	enum qca_btsoc_type btsoc_type;
>> +	struct qca_power *bt_power;
>> +	u32 init_speed;
>> +	u32 oper_speed;
>>  };
>> 
>> +static int qca_power_setup(struct hci_uart *hu, bool on);
>> +static void qca_power_shutdown(struct hci_uart *hu);
>> +
>>  static void __serial_clock_on(struct tty_struct *tty)
>>  {
>>  	/* TODO: Some chipset requires to enable UART clock on client
>> @@ -407,6 +446,7 @@ static int qca_open(struct hci_uart *hu)
>>  {
>>  	struct qca_serdev *qcadev;
>>  	struct qca_data *qca;
>> +	int ret;
>> 
>>  	BT_DBG("hu %p qca_open", hu);
>> 
>> @@ -458,19 +498,32 @@ static int qca_open(struct hci_uart *hu)
>> 
>>  	hu->priv = qca;
>> 
>> -	timer_setup(&qca->wake_retrans_timer, hci_ibs_wake_retrans_timeout, 
>> 0);
>> -	qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
>> -
>> -	timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
>> -	qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
>> -
>>  	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 != QCA_WCN3990) {
>> +			gpiod_set_value_cansleep(qcadev->bt_en, 1);
>> +		} else {
>> +			hu->init_speed = qcadev->init_speed;
>> +			hu->oper_speed = qcadev->oper_speed;
>> +			ret = qca_power_setup(hu, true);
>> +			if (ret) {
>> +				destroy_workqueue(qca->workqueue);
>> +				kfree_skb(qca->rx_skb);
>> +				hu->priv = NULL;
>> +				kfree(qca);
>> +				return ret;
>> +			}
>> +		}
>>  	}
>> 
>> +	timer_setup(&qca->wake_retrans_timer, hci_ibs_wake_retrans_timeout, 
>> 0);
>> +	qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
>> +
>> +	timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
>> +	qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
>> +
>>  	BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u",
>>  	       qca->tx_idle_delay, qca->wake_retrans);
>> 
>> @@ -554,10 +607,13 @@ static int qca_close(struct hci_uart *hu)
>>  	qca->hu = NULL;
>> 
>>  	if (hu->serdev) {
>> -		serdev_device_close(hu->serdev);
>> -
>>  		qcadev = serdev_device_get_drvdata(hu->serdev);
>> -		gpiod_set_value_cansleep(qcadev->bt_en, 0);
>> +		if (qcadev->btsoc_type == QCA_WCN3990)
>> +			qca_power_shutdown(hu);
>> +		else
>> +			gpiod_set_value_cansleep(qcadev->bt_en, 0);
>> +
>> +		serdev_device_close(hu->serdev);
>>  	}
>> 
>>  	kfree_skb(qca->rx_skb);
>> @@ -891,6 +947,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, 
>> uint8_t baudrate)
>>  	struct hci_uart *hu = hci_get_drvdata(hdev);
>>  	struct qca_data *qca = hu->priv;
>>  	struct sk_buff *skb;
>> +	struct qca_serdev *qcadev;
>>  	u8 cmd[] = { 0x01, 0x48, 0xFC, 0x01, 0x00 };
>> 
>>  	if (baudrate > QCA_BAUDRATE_3200000)
>> @@ -904,6 +961,13 @@ static int qca_set_baudrate(struct hci_dev *hdev, 
>> uint8_t baudrate)
>>  		return -ENOMEM;
>>  	}
>> 
>> +	/* Disabling hardware flow control is mandate while
> 
> nit: s/mandate/mandatory|required/
> 
[Bala]: will update.

>> +	 * sending change baudrate request to wcn3990 SoC.
>> +	 */
>> +	qcadev = serdev_device_get_drvdata(hu->serdev);
>> +	if (qcadev->btsoc_type == QCA_WCN3990)
>> +		hci_uart_set_flow_control(hu, true);
>> +
>>  	/* Assign commands to change baudrate and packet type. */
>>  	skb_put_data(skb, cmd, sizeof(cmd));
>>  	hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
>> @@ -919,6 +983,9 @@ static int qca_set_baudrate(struct hci_dev *hdev, 
>> uint8_t baudrate)
>>  	schedule_timeout(msecs_to_jiffies(BAUDRATE_SETTLE_TIMEOUT_MS));
>>  	set_current_state(TASK_RUNNING);
>> 
>> +	if (qcadev->btsoc_type == QCA_WCN3990)
>> +		hci_uart_set_flow_control(hu, false);
>> +
>>  	return 0;
>>  }
>> 
>> @@ -930,6 +997,36 @@ static inline void host_set_baudrate(struct 
>> hci_uart *hu, unsigned int speed)
>>  		hci_uart_set_baudrate(hu, speed);
>>  }
>> 
>> +static int qca_send_vendor_cmd(struct hci_dev *hdev, u8 cmd)
>> +{
>> +	struct hci_uart *hu = hci_get_drvdata(hdev);
>> +	struct qca_data *qca = hu->priv;
>> +	struct sk_buff *skb;
>> +
>> +	bt_dev_dbg(hdev, "sending command %02x to SoC", cmd);
>> +
>> +	skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
>> +	if (!skb)
>> +		return -ENOMEM;
>> +
>> +	/* Disabling hardware flow control is mandate while
> 
> Same nit as above
> 

[Bala]: will update.

>> +	 * sending vendor power on and off pulse to SoC.
>> +	 */
> 
> The function is called qca_send_vendor_cmd(), the comment about power
> on/off pulses seems misplaced here. Are there other 'vendor commands'
> that require a different flow control behavior?
> 
> Perhaps the function should have a different name or we need another
> wrapper.
> 

[Bala]: this function is used to send single byte vendor commands. like 
power on and off pulse.
         and all single byte vendor commands require an flow control off 
and on.
         so might be function name change is required.
         instead of qca_send_vendor_cmd(). i want to change function name 
to qca_send_pulse() as this will be generic.

>> +	hci_uart_set_flow_control(hu, true);
> 
> Should the changing of the flow control be limited to wcn3990? As of
> now the function is only called for wcn3990, however this is not
> stated as a requirement and might change in the future.
> 
>> +	skb_put_u8(skb, 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 */
>> +	usleep_range(100, 200);
> 
> Is this needed for any 'vendor command' or directly related with the
> power on/off pulses?
> 

[Bala] : flow control  off/on is needed for power on and off pulses 
along with
          command to set baudrate.. this is common across all the present 
chips and chips which are in development stages.
          might be function name is confusing will update the function 
name.

>> +	hci_uart_set_flow_control(hu, false);
>> +
>> +	return 0;
>> +}
>> +
>>  static unsigned int qca_get_speed(struct hci_uart *hu,
>>  				  enum qca_speed_type speed_type)
>>  {
>> @@ -952,10 +1049,19 @@ static unsigned int qca_get_speed(struct 
>> hci_uart *hu,
>> 
>>  static int qca_check_speeds(struct hci_uart *hu)
>>  {
>> -	/* One or the other speeds should be non zero. */
>> -	if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
>> -	    !qca_get_speed(hu, QCA_OPER_SPEED))
>> +	struct qca_serdev *qcadev;
>> +
>> +	qcadev = serdev_device_get_drvdata(hu->serdev);
>> +	if ((qcadev->btsoc_type == QCA_WCN3990 &&
>> +	    !qca_get_speed(hu, QCA_INIT_SPEED)) ||
>> +	    !qca_get_speed(hu, QCA_OPER_SPEED)) {
>> +		/* Both INIT and OPER speed should be non zero. */
>>  		return -EINVAL;
>> +	} else if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
>> +		    !qca_get_speed(hu, QCA_OPER_SPEED)) {
>> +		/* One or the other speeds should be non zero. */
>> +		return -EINVAL;
>> +	}
> 
> It is questionable if the comments are useful, they are basically
> stating the same as the conditions.
> 
> if-else statements with a single statement in all branches shouldn't
> use curly braces. Personally I don't dislike them in this case with
> the multi-line conditions, but in principle they shoulnd't be there.
> 
> nit: this would be easier to read with nested if statements:
> 
[Bala]: will update

> 	if (qcadev->btsoc_type == QCA_WCN3990)
> 		if (!qca_get_speed(hu, QCA_INIT_SPEED)) ||
> 		    !qca_get_speed(hu, QCA_OPER_SPEED))
> 			return -EINVAL;
> 	else
> 		if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
> 		    !qca_get_speed(hu, QCA_OPER_SPEED)) {
> 			return -EINVAL;
> 
>>  	return 0;
>>  }
>> @@ -986,15 +1092,40 @@ static int qca_set_speed(struct hci_uart *hu, 
>> enum qca_speed_type speed_type)
>>  	return 0;
>>  }
>> 
>> +static int qca_wcn3990_init(struct hci_uart *hu)
>> +{
>> +	int ret;
>> +
>> +	ret = qca_send_vendor_cmd(hu->hdev, QCA_WCN3990_POWERON_PULSE);
>> +	if (ret)
>> +		return ret;
>> +
>> +	/* Wait for 100 ms for SoC to boot up */
>> +	msleep(100);
>> +	serdev_device_close(hu->serdev);
>> +	ret = serdev_device_open(hu->serdev);
>> +	if (ret) {
>> +		bt_dev_err(hu->hdev, "failed to open port");
>> +		return ret;
>> +	}
>> +
>> +	/* Setup initial baudrate */
>> +	qca_set_speed(hu, QCA_INIT_SPEED);
> 
> The comment is a bit redundant.
> 
[Bala]: will update

>> +	hci_uart_set_flow_control(hu, false);
>> +
>> +	return 0;
>> +}
>> +
>>  static int qca_setup(struct hci_uart *hu)
>>  {
>>  	struct hci_dev *hdev = hu->hdev;
>>  	struct qca_data *qca = hu->priv;
>>  	unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200;
>> +	struct qca_serdev *qcadev;
>>  	int ret;
>>  	int soc_ver = 0;
>> 
>> -	bt_dev_info(hdev, "ROME setup");
>> +	qcadev = serdev_device_get_drvdata(hu->serdev);
>> 
>>  	ret = qca_check_speeds(hu);
>>  	if (ret)
>> @@ -1006,6 +1137,21 @@ static int qca_setup(struct hci_uart *hu)
>>  	/* Setup initial baudrate */
>>  	qca_set_speed(hu, QCA_INIT_SPEED);
>> 
>> +	if (qcadev->btsoc_type == QCA_WCN3990) {
>> +		bt_dev_dbg(hdev, "setting up wcn3990");
> 
> Seems like this should be bt_dev_info() for consistency with Rome.
> 
[Bala]: will update

>> +		ret = qca_wcn3990_init(hu);
>> +		if (ret)
>> +			return ret;
>> +
>> +		ret = qca_read_soc_version(hdev, &soc_ver);
>> +		if (ret < 0 || soc_ver == 0) {
>> +			bt_dev_err(hdev, "Failed to get version %d", ret);
>> +			return ret;
>> +		}
>> +	} else {
>> +		bt_dev_info(hdev, "ROME setup");
>> +	}
>> +
>>  	/* Setup user speed if needed */
>>  	speed = qca_get_speed(hu, QCA_OPER_SPEED);
>>  	if (speed) {
>> @@ -1016,16 +1162,18 @@ static int qca_setup(struct hci_uart *hu)
>>  		qca_baudrate = qca_get_baudrate_value(speed);
>>  	}
>> 
>> -	/* Get QCA version information */
>> -	ret = qca_read_soc_version(hdev, &soc_ver);
>> -	if (ret < 0 || soc_ver == 0) {
>> -		bt_dev_err(hdev, "QCA Failed to get version (%d)", ret);
>> -		return ret;
>> +	if (!soc_ver) {
> 
> 
> The following would probably be clearer:
> 
>   	if (qcadev->btsoc_type != QCA_WCN3990) {
> 
>> +		/* Get QCA version information */
>> +		ret = qca_read_soc_version(hdev, &soc_ver);
>> +		if (ret < 0 || soc_ver == 0) {
>> +			bt_dev_err(hdev, "QCA Failed to get version (%d)", ret);
>> +			return ret;
>> +		}
>> +		bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
> 
> Couldn't we hide some of this in qca_read_soc_version()?
> 

[Bala]: we can hide soc_ver==0 in qca_read_soc_version()
         will update.

> qca_read_soc_version() could at least do the logging in the error case
> (the 'soc_ver == 0' case could be handled there as well), which would
> leave us with:
> 
> 
> 	ret = qca_read_soc_version(hdev, &soc_ver);
> 	if (ret)
> 		return ret;
> 
> And the same above.
> 
> The controller version can be logged outside of the branch for both
> wcn3990 and Rome.
> 

[Bala]: will update.


>>  	}
>> -	bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
>> 
>>  	/* Setup patch / NVM configurations */
>> -	ret = qca_uart_setup(hdev, qca_baudrate, QCA_ROME, soc_ver);
>> +	ret = qca_uart_setup(hdev, qca_baudrate, qcadev->btsoc_type, 
>> soc_ver);
>>  	if (!ret) {
>>  		set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
>>  		qca_debugfs_init(hdev);
>> @@ -1061,9 +1209,123 @@ static struct hci_uart_proto qca_proto = {
>>  	.dequeue	= qca_dequeue,
>>  };
>> 
>> +static const struct qca_vreg_data qca_soc_data = {
>> +	.soc_type = QCA_WCN3990,
>> +	.vregs = (struct qca_vreg []) {
>> +		{ "vddio",   1800000, 1800000,  0 },
>> +		{ "vddxo",   1800000, 1800000,  1 },
>> +		{ "vddrf",   1304000, 1304000,  1 },
>> +		{ "vddch0",  3000000, 3312000,  1 },
>> +	},
>> +	.num_vregs = 4,
>> +};
> 
> I didn't chime in earlier in the discussion with Stephen on the
> regulators (https://patchwork.kernel.org/patch/10467911/), however I
> agree with him that specifying at load of 1uA doesn't seem to make
> much sense. What would happen if the load remained unspecified (or 0)?

[Bala]: will test and get back to you on this.

-- 
Regards
Balakrishna.

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

* Re: [PATCH v9 4/7] Bluetooth: hci_qca: Add wrapper functions for setting UART speed
  2018-07-10 12:19     ` Balakrishna Godavarthi
@ 2018-07-10 16:12       ` Matthias Kaehlcke
  0 siblings, 0 replies; 24+ messages in thread
From: Matthias Kaehlcke @ 2018-07-10 16:12 UTC (permalink / raw)
  To: Balakrishna Godavarthi
  Cc: marcel, johan.hedberg, linux-kernel, devicetree, linux-bluetooth,
	thierry.escande, rtatiya, hemantg, linux-arm-msm

On Tue, Jul 10, 2018 at 05:49:20PM +0530, Balakrishna Godavarthi wrote:
> Hi Matthias,
> 
> On 2018-07-07 01:10, Matthias Kaehlcke wrote:
> > On Thu, Jul 05, 2018 at 10:25:12PM +0530, Balakrishna Godavarthi wrote:
> > > In function qca_setup, we set initial and operating speeds for
> > > Qualcomm
> > > Bluetooth SoC's. This block of code is common across different
> > > Qualcomm Bluetooth SoC's. Instead of duplicating the code, created
> > > a wrapper function to set the speeds. So that future coming SoC's
> > > can use these wrapper functions to set speeds.
> > > 
> > > Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
> > > ---
> > > Changes in v9:
> > >     * added corner case to fail driver if speeds are missing.
> > > 
> > > Changes in v8:
> > >     * common function to set INIT and operating speeds.
> > > 
> > > Changes in v7:
> > >     * initial patch
> > >     * created wrapper functions for init and operating speeds.
> > > ---
> > >  drivers/bluetooth/hci_qca.c | 94
> > > ++++++++++++++++++++++++++++---------
> > >  1 file changed, 71 insertions(+), 23 deletions(-)
> > > 
> > > diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> > > index c02e1d465cca..9106547324fa 100644
> > > --- a/drivers/bluetooth/hci_qca.c
> > > +++ b/drivers/bluetooth/hci_qca.c
> > > @@ -119,6 +119,11 @@ struct qca_data {
> > >  	u64 votes_off;
> > >  };
> > > 
> > > +enum qca_speed_type {
> > > +	QCA_INIT_SPEED = 1,
> > > +	QCA_OPER_SPEED
> > > +};
> > > +
> > >  struct qca_serdev {
> > >  	struct hci_uart	 serdev_hu;
> > >  	struct gpio_desc *bt_en;
> > > @@ -923,6 +928,62 @@ static inline void host_set_baudrate(struct
> > > hci_uart *hu, unsigned int speed)
> > >  		hci_uart_set_baudrate(hu, speed);
> > >  }
> > > 
> > > +static unsigned int qca_get_speed(struct hci_uart *hu,
> > > +				  enum qca_speed_type speed_type)
> > > +{
> > > +	unsigned int speed = 0;
> > > +
> > > +	if (speed_type == QCA_INIT_SPEED) {
> > > +		if (hu->init_speed)
> > > +			speed = hu->init_speed;
> > > +		else if (hu->proto->init_speed)
> > > +			speed = hu->proto->init_speed;
> > > +	} else {
> > > +		if (hu->oper_speed)
> > > +			speed = hu->oper_speed;
> > > +		else if (hu->proto->oper_speed)
> > > +			speed = hu->proto->oper_speed;
> > > +	}
> > > +
> > > +	return speed;
> > > +}
> > > +
> > > +static int qca_check_speeds(struct hci_uart *hu)
> > > +{
> > > +	/* One or the other speeds should be non zero. */
> > > +	if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
> > > +	    !qca_get_speed(hu, QCA_OPER_SPEED))
> > > +		return -EINVAL;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type
> > > speed_type)
> > > +{
> > > +	unsigned int speed, qca_baudrate;
> > > +	int ret;
> > > +
> > > +	if (speed_type == QCA_INIT_SPEED) {
> > > +		speed = qca_get_speed(hu, QCA_INIT_SPEED);
> > > +		if (speed)
> > > +			host_set_baudrate(hu, speed);
> > 
> > mega-nit: for consistency with the 'else' branch you could return if
> > 'speed == 0'. Not important though, feel free to ignore.
> > 
> > > +	} else {
> > > +		speed = qca_get_speed(hu, QCA_OPER_SPEED);
> > > +		if (!speed)
> > > +			return 0;
> > > +
> > > +		qca_baudrate = qca_get_baudrate_value(speed);
> > > +		bt_dev_info(hu->hdev, "Set UART speed to %d", speed);
> > > +		ret = qca_set_baudrate(hu->hdev, qca_baudrate);
> > > +		if (ret)
> > > +			return ret;
> > > +
> > > +		host_set_baudrate(hu, speed);
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +
> > >  static int qca_setup(struct hci_uart *hu)
> > >  {
> > >  	struct hci_dev *hdev = hu->hdev;
> > > @@ -933,37 +994,24 @@ static int qca_setup(struct hci_uart *hu)
> > > 
> > >  	bt_dev_info(hdev, "ROME setup");
> > > 
> > > +	ret = qca_check_speeds(hu);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > >  	/* 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);
> > > +	qca_set_speed(hu, QCA_INIT_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;
> > > -
> > > +	speed = qca_get_speed(hu, QCA_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);
> > > +		ret = qca_set_speed(hu, QCA_OPER_SPEED);
> > > +		if (ret)
> > >  			return ret;
> > > -		}
> > > -		host_set_baudrate(hu, speed);
> > > +
> > > +		qca_baudrate = qca_get_baudrate_value(speed);
> > >  	}
> > 
> > One doubt, the outcome of this change is:
> > 
> > 	qca_set_speed(hu, QCA_INIT_SPEED);
> > 
> > 	/* Setup user speed if needed */
> > 	speed = qca_get_speed(hu, QCA_OPER_SPEED);
> > 	if (speed) {
> > 		ret = qca_set_speed(hu, QCA_OPER_SPEED);
> > 		if (ret)
> > 			return ret;
> > 
> > 		qca_baudrate = qca_get_baudrate_value(speed);
> > 	}
> > 
> > So we set the init speed and then directly switch to operating speed
> > if it is defined.
> > 
> > Couldn't we do this instead:
> > 
> > 	/* Setup user speed if needed */
> > 	speed = qca_get_speed(hu, QCA_OPER_SPEED);
> > 	if (speed) {
> > 		ret = qca_set_speed(hu, QCA_OPER_SPEED);
> > 		if (ret)
> > 			return ret;
> > 
> > 		qca_baudrate = qca_get_baudrate_value(speed);
> > 	} else {
> > 	       qca_set_speed(hu, QCA_INIT_SPEED);
> > 	}
> > 
> > 
> 
> [Bala]: above else block is not required.
>         if we have operating speed to set, then we need to send the baud
> rate change request to BT chip on INIT baud rate. so before sending or
> setting operating baud rate.. HOST driver should be on the HOST init baud
> rate.
>         Pls refer below for more info how we set speed and hci driver works.
> > 
> > Or is setting the init speed needed before the operating speed can be
> > set? Sorry if we discussed this earlier in this series, I know I had a
> > few doubts about the speed management but don't recall this one
> > specifically.
> > 
> 
> [Bala]: Let me give a big picture how we make BT work via serdev HCI arch.
> (qca chip is taken as reference)
> 
>         1. first of all, probe is called when we have compatible string
> matches in qca_bluetooth_of_match table.
>         2. that will call qca_serdev_probe() in which based on BT device
> connected to the platform, we decide IO's
>            which required from HOST to chip i.e.. controls required to turn
> ON/OFF BT. which includes clocks and regulators and GPIO's.
>         3. in qca_serdev_probe() we call  hci_uart_register_device() and
> pass ops (operations handler) handler for driver registration.
>         4. in hci_uart_register_device(), we call qca_open().. where we open
> the port via serdev_device_open() that
>            intern will call Qualcomm specific lower level UART driver i.e..
> where we read and write to port register address.
>            so serdev_device_open() is a common function to all BT chip
> vendor, but the open routine in the low level driver is completely vendor
> dependent.
>            for example, some vendors will set an default UART speed (speed
> can be any) while opening the uart_port(). where as other will not set. Just
> open the port with basic configurations.
> 
>         5. coming back to qca_open(), we try to make chip to boot up by
> enabling clock from HOST for BT chip to operate..  it is purely chip
> defined.
>         6. moving back to hci_uart_register_device()... we will call
> hci_register_dev() in that function we call hci_power_on().. that will call
> hci_dev_do_open()
>         7. in hci_dev_do_open() we call hdev->setup() i.e. hci_uart_setup()
> in that function we set initial baud rate and operating bartender if we have
> protos defined for setting chip baud rate.(in our case it is null)
> 
>         8. so it will call setup function will be vendor specific.. as we
> are using an UART, HOST and chip need to stick to the agreement of initial
> UART speed for commands to send until and change baud rate request is
>            sent.
>         9. now in qca_setup(), we setup an initial host baud rate i.e. what
> we have agreement with BT chip for initial communication. Now here the
> question comes why are we setting init speed again and again
>            i.e uart_open() and hci_uart_setup().. here is the answer, wt
> ever layer we have are common to all vendors may also tend to change. we
> can't take a risk, we will setup init baud rate in vendor layer i.e.
>            qca_setup().
>         10. then we need to change the baud rate of chip..so we need to send
> commands to chip. at wt speed we need to send change baud rate request is
> totally based on agreement with BT Chip. so here we use initial
>             baud rate.
>         11. we need to change baud rate request command to chip on init baud
> rate. if command sending is successful we change the host baud rate from
> init to operating baud rate.. else we operate on init baud rate.
> 
> 
>         the above is based on my understanding. Pls let me know if i have
> cleared your doubt.

Thanks for the explanation. I focussed on the final outcome (operating
speed is set) and ignored that the host port needs to be at init speed
in order to send the baud rate change command to the chip.

Cheers

Matthias

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

* Re: [PATCH v9 7/7] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990
  2018-07-10 12:52     ` Balakrishna Godavarthi
@ 2018-07-10 16:39       ` Matthias Kaehlcke
  2018-07-17 15:18         ` Balakrishna Godavarthi
  0 siblings, 1 reply; 24+ messages in thread
From: Matthias Kaehlcke @ 2018-07-10 16:39 UTC (permalink / raw)
  To: Balakrishna Godavarthi
  Cc: marcel, johan.hedberg, linux-kernel, devicetree, linux-bluetooth,
	thierry.escande, rtatiya, hemantg, linux-arm-msm, Stephen Boyd

Hi Bala,

On Tue, Jul 10, 2018 at 06:22:02PM +0530, Balakrishna Godavarthi wrote:
> Hi Matthias,
> 
> On 2018-07-07 03:51, Matthias Kaehlcke wrote:
> > On Thu, Jul 05, 2018 at 10:25:15PM +0530, Balakrishna Godavarthi wrote:
> > > +	 * sending vendor power on and off pulse to SoC.
> > > +	 */
> > 
> > The function is called qca_send_vendor_cmd(), the comment about power
> > on/off pulses seems misplaced here. Are there other 'vendor commands'
> > that require a different flow control behavior?
> > 
> > Perhaps the function should have a different name or we need another
> > wrapper.
> > 
> 
> [Bala]: this function is used to send single byte vendor commands. like
> power on and off pulse.
>         and all single byte vendor commands require an flow control off and
> on.
>         so might be function name change is required.
>         instead of qca_send_vendor_cmd(). i want to change function name to
> qca_send_pulse() as this will be generic.

'pulse' covers power on/off pulses, is it also applicable to other
single byte commands? How are these commands named in the QCA
documentation?

In any case the comment about 'vendor power on and off pulse' should
be updated to refer to 'vendor commands'/'pulses' or whatever
terminology we decide to use.

> > > +	hci_uart_set_flow_control(hu, true);
> > 
> > Should the changing of the flow control be limited to wcn3990? As of
> > now the function is only called for wcn3990, however this is not
> > stated as a requirement and might change in the future.
> > 
> > > +	skb_put_u8(skb, 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 */
> > > +	usleep_range(100, 200);
> > 
> > Is this needed for any 'vendor command' or directly related with the
> > power on/off pulses?
> > 
> 
> [Bala] : flow control  off/on is needed for power on and off pulses along
> with
>          command to set baudrate.. this is common across all the present
> chips and chips which are in development stages.
>          might be function name is confusing will update the function name.

The current name *might* be ok, depending on if we come up with
something better. If the QCA docs refer to them as 'vendor commands'
and there are no other multi-byte 'vendor commands' I'm fine with it.

Is the settling down of 100us specific to the power on/off pulses or
also applicable to other commands?

Thanks

Matthias

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

* Re: [PATCH v9 7/7] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990
  2018-07-06 22:21   ` Matthias Kaehlcke
  2018-07-10 12:52     ` Balakrishna Godavarthi
@ 2018-07-16 13:51     ` Balakrishna Godavarthi
  2018-07-16 16:05       ` Matthias Kaehlcke
  1 sibling, 1 reply; 24+ messages in thread
From: Balakrishna Godavarthi @ 2018-07-16 13:51 UTC (permalink / raw)
  To: Matthias Kaehlcke
  Cc: marcel, johan.hedberg, linux-kernel, devicetree, linux-bluetooth,
	thierry.escande, rtatiya, hemantg, linux-arm-msm, Stephen Boyd

Hi Matthias,

On 2018-07-07 03:51, Matthias Kaehlcke wrote:
> On Thu, Jul 05, 2018 at 10:25:15PM +0530, Balakrishna Godavarthi wrote:
>> Add support to set voltage/current of various regulators
>> to power up/down Bluetooth chip wcn3990.
>> 
>> Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
>> ---
>> changes in v9:
>>     * moved flow control to vendor and set_baudarte functions.
>>     * removed parent regs.
>> 
>> changes in v8:
>>     * closing qca buffer, if qca_power_setup fails
>>     * chnaged ibs start timer function call location.
>>     * updated review comments.
>> 
>> changes in v7:
>>     * addressed review comments.
>> 
>> changes in v6:
>>     * Hooked up qca_power to qca_serdev.
>>     * renamed all the naming inconsistency functions with qca_*
>>     * leveraged common code of ROME for wcn3990.
>>     * created wrapper functions for re-usable blocks.
>>     * updated function of _*regulator_enable and _*regualtor_disable.
>>     * removed redundant comments and functions.
>>     * addressed review comments.
>> 
>> Changes in v5:
>>     * updated regulator vddpa min_uV to 1304000.
>>       * addressed review comments.
>> 
>> Changes in v4:
>>     * Segregated the changes of btqca from hci_qca
>>     * rebased all changes on top of bluetooth-next.
>>     * addressed review comments.
>> 
>> ---
>>  drivers/bluetooth/btqca.h   |   3 +
>>  drivers/bluetooth/hci_qca.c | 387 
>> +++++++++++++++++++++++++++++++-----
>>  2 files changed, 345 insertions(+), 45 deletions(-)
>> 
>> diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
>> index a9c2779f3e07..0c01f375fe83 100644
>> --- a/drivers/bluetooth/btqca.h
>> +++ b/drivers/bluetooth/btqca.h
>> @@ -37,6 +37,9 @@
>>  #define EDL_TAG_ID_HCI			(17)
>>  #define EDL_TAG_ID_DEEP_SLEEP		(27)
>> 
>> +#define QCA_WCN3990_POWERON_PULSE	0xFC
>> +#define QCA_WCN3990_POWEROFF_PULSE	0xC0
>> +
>>  enum qca_bardrate {
>>  	QCA_BAUDRATE_115200 	= 0,
>>  	QCA_BAUDRATE_57600,
>> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
>> index 7ebfaa0edf3f..d62c7785a618 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...
>> @@ -31,9 +31,14 @@
>>  #include <linux/kernel.h>
>>  #include <linux/clk.h>
>>  #include <linux/debugfs.h>
>> +#include <linux/delay.h>
>> +#include <linux/device.h>
>>  #include <linux/gpio/consumer.h>
>>  #include <linux/mod_devicetable.h>
>>  #include <linux/module.h>
>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/regulator/consumer.h>
>>  #include <linux/serdev.h>
>> 
>>  #include <net/bluetooth/bluetooth.h>
>> @@ -124,12 +129,46 @@ enum qca_speed_type {
>>  	QCA_OPER_SPEED
>>  };
>> 
>> +/*
>> + * Voltage regulator information required for configuring the
>> + * QCA Bluetooth chipset
>> + */
>> +struct qca_vreg {
>> +	const char *name;
>> +	unsigned int min_uV;
>> +	unsigned int max_uV;
>> +	unsigned int load_uA;
>> +};
>> +
>> +struct qca_vreg_data {
>> +	enum qca_btsoc_type soc_type;
>> +	struct qca_vreg *vregs;
>> +	size_t num_vregs;
>> +};
>> +
>> +/*
>> + * Platform data for the QCA Bluetooth power driver.
>> + */
>> +struct qca_power {
>> +	struct device *dev;
>> +	const struct qca_vreg_data *vreg_data;
>> +	struct regulator_bulk_data *vreg_bulk;
>> +	bool vregs_on;
>> +};
>> +
>>  struct qca_serdev {
>>  	struct hci_uart	 serdev_hu;
>>  	struct gpio_desc *bt_en;
>>  	struct clk	 *susclk;
>> +	enum qca_btsoc_type btsoc_type;
>> +	struct qca_power *bt_power;
>> +	u32 init_speed;
>> +	u32 oper_speed;
>>  };
>> 
>> +static int qca_power_setup(struct hci_uart *hu, bool on);
>> +static void qca_power_shutdown(struct hci_uart *hu);
>> +
>>  static void __serial_clock_on(struct tty_struct *tty)
>>  {
>>  	/* TODO: Some chipset requires to enable UART clock on client
>> @@ -407,6 +446,7 @@ static int qca_open(struct hci_uart *hu)
>>  {
>>  	struct qca_serdev *qcadev;
>>  	struct qca_data *qca;
>> +	int ret;
>> 
>>  	BT_DBG("hu %p qca_open", hu);
>> 
>> @@ -458,19 +498,32 @@ static int qca_open(struct hci_uart *hu)
>> 
>>  	hu->priv = qca;
>> 
>> -	timer_setup(&qca->wake_retrans_timer, hci_ibs_wake_retrans_timeout, 
>> 0);
>> -	qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
>> -
>> -	timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
>> -	qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
>> -
>>  	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 != QCA_WCN3990) {
>> +			gpiod_set_value_cansleep(qcadev->bt_en, 1);
>> +		} else {
>> +			hu->init_speed = qcadev->init_speed;
>> +			hu->oper_speed = qcadev->oper_speed;
>> +			ret = qca_power_setup(hu, true);
>> +			if (ret) {
>> +				destroy_workqueue(qca->workqueue);
>> +				kfree_skb(qca->rx_skb);
>> +				hu->priv = NULL;
>> +				kfree(qca);
>> +				return ret;
>> +			}
>> +		}
>>  	}
>> 
>> +	timer_setup(&qca->wake_retrans_timer, hci_ibs_wake_retrans_timeout, 
>> 0);
>> +	qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
>> +
>> +	timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
>> +	qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
>> +
>>  	BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u",
>>  	       qca->tx_idle_delay, qca->wake_retrans);
>> 
>> @@ -554,10 +607,13 @@ static int qca_close(struct hci_uart *hu)
>>  	qca->hu = NULL;
>> 
>>  	if (hu->serdev) {
>> -		serdev_device_close(hu->serdev);
>> -
>>  		qcadev = serdev_device_get_drvdata(hu->serdev);
>> -		gpiod_set_value_cansleep(qcadev->bt_en, 0);
>> +		if (qcadev->btsoc_type == QCA_WCN3990)
>> +			qca_power_shutdown(hu);
>> +		else
>> +			gpiod_set_value_cansleep(qcadev->bt_en, 0);
>> +
>> +		serdev_device_close(hu->serdev);
>>  	}
>> 
>>  	kfree_skb(qca->rx_skb);
>> @@ -891,6 +947,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, 
>> uint8_t baudrate)
>>  	struct hci_uart *hu = hci_get_drvdata(hdev);
>>  	struct qca_data *qca = hu->priv;
>>  	struct sk_buff *skb;
>> +	struct qca_serdev *qcadev;
>>  	u8 cmd[] = { 0x01, 0x48, 0xFC, 0x01, 0x00 };
>> 
>>  	if (baudrate > QCA_BAUDRATE_3200000)
>> @@ -904,6 +961,13 @@ static int qca_set_baudrate(struct hci_dev *hdev, 
>> uint8_t baudrate)
>>  		return -ENOMEM;
>>  	}
>> 
>> +	/* Disabling hardware flow control is mandate while
> 
> nit: s/mandate/mandatory|required/
> 
>> +	 * sending change baudrate request to wcn3990 SoC.
>> +	 */
>> +	qcadev = serdev_device_get_drvdata(hu->serdev);
>> +	if (qcadev->btsoc_type == QCA_WCN3990)
>> +		hci_uart_set_flow_control(hu, true);
>> +
>>  	/* Assign commands to change baudrate and packet type. */
>>  	skb_put_data(skb, cmd, sizeof(cmd));
>>  	hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
>> @@ -919,6 +983,9 @@ static int qca_set_baudrate(struct hci_dev *hdev, 
>> uint8_t baudrate)
>>  	schedule_timeout(msecs_to_jiffies(BAUDRATE_SETTLE_TIMEOUT_MS));
>>  	set_current_state(TASK_RUNNING);
>> 
>> +	if (qcadev->btsoc_type == QCA_WCN3990)
>> +		hci_uart_set_flow_control(hu, false);
>> +
>>  	return 0;
>>  }
>> 
>> @@ -930,6 +997,36 @@ static inline void host_set_baudrate(struct 
>> hci_uart *hu, unsigned int speed)
>>  		hci_uart_set_baudrate(hu, speed);
>>  }
>> 
>> +static int qca_send_vendor_cmd(struct hci_dev *hdev, u8 cmd)
>> +{
>> +	struct hci_uart *hu = hci_get_drvdata(hdev);
>> +	struct qca_data *qca = hu->priv;
>> +	struct sk_buff *skb;
>> +
>> +	bt_dev_dbg(hdev, "sending command %02x to SoC", cmd);
>> +
>> +	skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
>> +	if (!skb)
>> +		return -ENOMEM;
>> +
>> +	/* Disabling hardware flow control is mandate while
> 
> Same nit as above
> 
>> +	 * sending vendor power on and off pulse to SoC.
>> +	 */
> 
> The function is called qca_send_vendor_cmd(), the comment about power
> on/off pulses seems misplaced here. Are there other 'vendor commands'
> that require a different flow control behavior?
> 
> Perhaps the function should have a different name or we need another
> wrapper.
> 
>> +	hci_uart_set_flow_control(hu, true);
> 
> Should the changing of the flow control be limited to wcn3990? As of
> now the function is only called for wcn3990, however this is not
> stated as a requirement and might change in the future.
> 
>> +	skb_put_u8(skb, 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 */
>> +	usleep_range(100, 200);
> 
> Is this needed for any 'vendor command' or directly related with the
> power on/off pulses?
> 
>> +	hci_uart_set_flow_control(hu, false);
>> +
>> +	return 0;
>> +}
>> +
>>  static unsigned int qca_get_speed(struct hci_uart *hu,
>>  				  enum qca_speed_type speed_type)
>>  {
>> @@ -952,10 +1049,19 @@ static unsigned int qca_get_speed(struct 
>> hci_uart *hu,
>> 
>>  static int qca_check_speeds(struct hci_uart *hu)
>>  {
>> -	/* One or the other speeds should be non zero. */
>> -	if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
>> -	    !qca_get_speed(hu, QCA_OPER_SPEED))
>> +	struct qca_serdev *qcadev;
>> +
>> +	qcadev = serdev_device_get_drvdata(hu->serdev);
>> +	if ((qcadev->btsoc_type == QCA_WCN3990 &&
>> +	    !qca_get_speed(hu, QCA_INIT_SPEED)) ||
>> +	    !qca_get_speed(hu, QCA_OPER_SPEED)) {
>> +		/* Both INIT and OPER speed should be non zero. */
>>  		return -EINVAL;
>> +	} else if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
>> +		    !qca_get_speed(hu, QCA_OPER_SPEED)) {
>> +		/* One or the other speeds should be non zero. */
>> +		return -EINVAL;
>> +	}
> 
> It is questionable if the comments are useful, they are basically
> stating the same as the conditions.
> 
> if-else statements with a single statement in all branches shouldn't
> use curly braces. Personally I don't dislike them in this case with
> the multi-line conditions, but in principle they shoulnd't be there.
> 
> nit: this would be easier to read with nested if statements:
> 
> 	if (qcadev->btsoc_type == QCA_WCN3990)
> 		if (!qca_get_speed(hu, QCA_INIT_SPEED)) ||
> 		    !qca_get_speed(hu, QCA_OPER_SPEED))
> 			return -EINVAL;
> 	else
> 		if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
> 		    !qca_get_speed(hu, QCA_OPER_SPEED)) {
> 			return -EINVAL;
> 
>>  	return 0;
>>  }
>> @@ -986,15 +1092,40 @@ static int qca_set_speed(struct hci_uart *hu, 
>> enum qca_speed_type speed_type)
>>  	return 0;
>>  }
>> 
>> +static int qca_wcn3990_init(struct hci_uart *hu)
>> +{
>> +	int ret;
>> +
>> +	ret = qca_send_vendor_cmd(hu->hdev, QCA_WCN3990_POWERON_PULSE);
>> +	if (ret)
>> +		return ret;
>> +
>> +	/* Wait for 100 ms for SoC to boot up */
>> +	msleep(100);
>> +	serdev_device_close(hu->serdev);
>> +	ret = serdev_device_open(hu->serdev);
>> +	if (ret) {
>> +		bt_dev_err(hu->hdev, "failed to open port");
>> +		return ret;
>> +	}
>> +
>> +	/* Setup initial baudrate */
>> +	qca_set_speed(hu, QCA_INIT_SPEED);
> 
> The comment is a bit redundant.
> 
>> +	hci_uart_set_flow_control(hu, false);
>> +
>> +	return 0;
>> +}
>> +
>>  static int qca_setup(struct hci_uart *hu)
>>  {
>>  	struct hci_dev *hdev = hu->hdev;
>>  	struct qca_data *qca = hu->priv;
>>  	unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200;
>> +	struct qca_serdev *qcadev;
>>  	int ret;
>>  	int soc_ver = 0;
>> 
>> -	bt_dev_info(hdev, "ROME setup");
>> +	qcadev = serdev_device_get_drvdata(hu->serdev);
>> 
>>  	ret = qca_check_speeds(hu);
>>  	if (ret)
>> @@ -1006,6 +1137,21 @@ static int qca_setup(struct hci_uart *hu)
>>  	/* Setup initial baudrate */
>>  	qca_set_speed(hu, QCA_INIT_SPEED);
>> 
>> +	if (qcadev->btsoc_type == QCA_WCN3990) {
>> +		bt_dev_dbg(hdev, "setting up wcn3990");
> 
> Seems like this should be bt_dev_info() for consistency with Rome.
> 
>> +		ret = qca_wcn3990_init(hu);
>> +		if (ret)
>> +			return ret;
>> +
>> +		ret = qca_read_soc_version(hdev, &soc_ver);
>> +		if (ret < 0 || soc_ver == 0) {
>> +			bt_dev_err(hdev, "Failed to get version %d", ret);
>> +			return ret;
>> +		}
>> +	} else {
>> +		bt_dev_info(hdev, "ROME setup");
>> +	}
>> +
>>  	/* Setup user speed if needed */
>>  	speed = qca_get_speed(hu, QCA_OPER_SPEED);
>>  	if (speed) {
>> @@ -1016,16 +1162,18 @@ static int qca_setup(struct hci_uart *hu)
>>  		qca_baudrate = qca_get_baudrate_value(speed);
>>  	}
>> 
>> -	/* Get QCA version information */
>> -	ret = qca_read_soc_version(hdev, &soc_ver);
>> -	if (ret < 0 || soc_ver == 0) {
>> -		bt_dev_err(hdev, "QCA Failed to get version (%d)", ret);
>> -		return ret;
>> +	if (!soc_ver) {
> 
> 
> The following would probably be clearer:
> 
>   	if (qcadev->btsoc_type != QCA_WCN3990) {
> 
>> +		/* Get QCA version information */
>> +		ret = qca_read_soc_version(hdev, &soc_ver);
>> +		if (ret < 0 || soc_ver == 0) {
>> +			bt_dev_err(hdev, "QCA Failed to get version (%d)", ret);
>> +			return ret;
>> +		}
>> +		bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
> 
> Couldn't we hide some of this in qca_read_soc_version()?
> 
> qca_read_soc_version() could at least do the logging in the error case
> (the 'soc_ver == 0' case could be handled there as well), which would
> leave us with:
> 
> 
> 	ret = qca_read_soc_version(hdev, &soc_ver);
> 	if (ret)
> 		return ret;
> 
> And the same above.
> 
> The controller version can be logged outside of the branch for both
> wcn3990 and Rome.
> 
>>  	}
>> -	bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
>> 
>>  	/* Setup patch / NVM configurations */
>> -	ret = qca_uart_setup(hdev, qca_baudrate, QCA_ROME, soc_ver);
>> +	ret = qca_uart_setup(hdev, qca_baudrate, qcadev->btsoc_type, 
>> soc_ver);
>>  	if (!ret) {
>>  		set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
>>  		qca_debugfs_init(hdev);
>> @@ -1061,9 +1209,123 @@ static struct hci_uart_proto qca_proto = {
>>  	.dequeue	= qca_dequeue,
>>  };
>> 
>> +static const struct qca_vreg_data qca_soc_data = {
>> +	.soc_type = QCA_WCN3990,
>> +	.vregs = (struct qca_vreg []) {
>> +		{ "vddio",   1800000, 1800000,  0 },
>> +		{ "vddxo",   1800000, 1800000,  1 },
>> +		{ "vddrf",   1304000, 1304000,  1 },
>> +		{ "vddch0",  3000000, 3312000,  1 },
>> +	},
>> +	.num_vregs = 4,
>> +};
> 
> I didn't chime in earlier in the discussion with Stephen on the
> regulators (https://patchwork.kernel.org/patch/10467911/), however I
> agree with him that specifying at load of 1uA doesn't seem to make
> much sense. What would happen if the load remained unspecified (or 0)?

[Bala]: On RPMh based designs, calling a regulator_set_load with a 
non-zero value moves the regulator to NPM (high power mode) which is 
required for BT communication.
         and call with 0uA  moves it to low-power-mode (vote from APPS). 
Basically whenever BT wants these in NPM  it calls set-load with 1.

-- 
Regards
Balakrishna.

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

* Re: [PATCH v9 7/7] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990
  2018-07-16 13:51     ` Balakrishna Godavarthi
@ 2018-07-16 16:05       ` Matthias Kaehlcke
  2018-07-17 13:46         ` Balakrishna Godavarthi
  2018-07-18 15:33         ` Balakrishna Godavarthi
  0 siblings, 2 replies; 24+ messages in thread
From: Matthias Kaehlcke @ 2018-07-16 16:05 UTC (permalink / raw)
  To: Balakrishna Godavarthi
  Cc: marcel, johan.hedberg, linux-kernel, devicetree, linux-bluetooth,
	thierry.escande, rtatiya, hemantg, linux-arm-msm, Stephen Boyd

On Mon, Jul 16, 2018 at 07:21:56PM +0530, Balakrishna Godavarthi wrote:
> Hi Matthias,
> 
> On 2018-07-07 03:51, Matthias Kaehlcke wrote:
> > On Thu, Jul 05, 2018 at 10:25:15PM +0530, Balakrishna Godavarthi wrote:
> > > Add support to set voltage/current of various regulators
> > > to power up/down Bluetooth chip wcn3990.
> > > 
> > > Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
> > > ---
> > > changes in v9:
> > >     * moved flow control to vendor and set_baudarte functions.
> > >     * removed parent regs.
> > > 
> > > changes in v8:
> > >     * closing qca buffer, if qca_power_setup fails
> > >     * chnaged ibs start timer function call location.
> > >     * updated review comments.
> > > 
> > > changes in v7:
> > >     * addressed review comments.
> > > 
> > > changes in v6:
> > >     * Hooked up qca_power to qca_serdev.
> > >     * renamed all the naming inconsistency functions with qca_*
> > >     * leveraged common code of ROME for wcn3990.
> > >     * created wrapper functions for re-usable blocks.
> > >     * updated function of _*regulator_enable and _*regualtor_disable.
> > >     * removed redundant comments and functions.
> > >     * addressed review comments.
> > > 
> > > Changes in v5:
> > >     * updated regulator vddpa min_uV to 1304000.
> > >       * addressed review comments.
> > > 
> > > Changes in v4:
> > >     * Segregated the changes of btqca from hci_qca
> > >     * rebased all changes on top of bluetooth-next.
> > >     * addressed review comments.
> > > 
> > > ---
> > >  drivers/bluetooth/btqca.h   |   3 +
> > >  drivers/bluetooth/hci_qca.c | 387
> > > +++++++++++++++++++++++++++++++-----
> > >  2 files changed, 345 insertions(+), 45 deletions(-)
> > > 
> > > diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
> > > index a9c2779f3e07..0c01f375fe83 100644
> > > --- a/drivers/bluetooth/btqca.h
> > > +++ b/drivers/bluetooth/btqca.h
> > > @@ -37,6 +37,9 @@
> > >  #define EDL_TAG_ID_HCI			(17)
> > >  #define EDL_TAG_ID_DEEP_SLEEP		(27)
> > > 
> > > +#define QCA_WCN3990_POWERON_PULSE	0xFC
> > > +#define QCA_WCN3990_POWEROFF_PULSE	0xC0
> > > +
> > >  enum qca_bardrate {
> > >  	QCA_BAUDRATE_115200 	= 0,
> > >  	QCA_BAUDRATE_57600,
> > > diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> > > index 7ebfaa0edf3f..d62c7785a618 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...
> > > @@ -31,9 +31,14 @@
> > >  #include <linux/kernel.h>
> > >  #include <linux/clk.h>
> > >  #include <linux/debugfs.h>
> > > +#include <linux/delay.h>
> > > +#include <linux/device.h>
> > >  #include <linux/gpio/consumer.h>
> > >  #include <linux/mod_devicetable.h>
> > >  #include <linux/module.h>
> > > +#include <linux/of_device.h>
> > > +#include <linux/platform_device.h>
> > > +#include <linux/regulator/consumer.h>
> > >  #include <linux/serdev.h>
> > > 
> > >  #include <net/bluetooth/bluetooth.h>
> > > @@ -124,12 +129,46 @@ enum qca_speed_type {
> > >  	QCA_OPER_SPEED
> > >  };
> > > 
> > > +/*
> > > + * Voltage regulator information required for configuring the
> > > + * QCA Bluetooth chipset
> > > + */
> > > +struct qca_vreg {
> > > +	const char *name;
> > > +	unsigned int min_uV;
> > > +	unsigned int max_uV;
> > > +	unsigned int load_uA;
> > > +};
> > > +
> > > +struct qca_vreg_data {
> > > +	enum qca_btsoc_type soc_type;
> > > +	struct qca_vreg *vregs;
> > > +	size_t num_vregs;
> > > +};
> > > +
> > > +/*
> > > + * Platform data for the QCA Bluetooth power driver.
> > > + */
> > > +struct qca_power {
> > > +	struct device *dev;
> > > +	const struct qca_vreg_data *vreg_data;
> > > +	struct regulator_bulk_data *vreg_bulk;
> > > +	bool vregs_on;
> > > +};
> > > +
> > >  struct qca_serdev {
> > >  	struct hci_uart	 serdev_hu;
> > >  	struct gpio_desc *bt_en;
> > >  	struct clk	 *susclk;
> > > +	enum qca_btsoc_type btsoc_type;
> > > +	struct qca_power *bt_power;
> > > +	u32 init_speed;
> > > +	u32 oper_speed;
> > >  };
> > > 
> > > +static int qca_power_setup(struct hci_uart *hu, bool on);
> > > +static void qca_power_shutdown(struct hci_uart *hu);
> > > +
> > >  static void __serial_clock_on(struct tty_struct *tty)
> > >  {
> > >  	/* TODO: Some chipset requires to enable UART clock on client
> > > @@ -407,6 +446,7 @@ static int qca_open(struct hci_uart *hu)
> > >  {
> > >  	struct qca_serdev *qcadev;
> > >  	struct qca_data *qca;
> > > +	int ret;
> > > 
> > >  	BT_DBG("hu %p qca_open", hu);
> > > 
> > > @@ -458,19 +498,32 @@ static int qca_open(struct hci_uart *hu)
> > > 
> > >  	hu->priv = qca;
> > > 
> > > -	timer_setup(&qca->wake_retrans_timer,
> > > hci_ibs_wake_retrans_timeout, 0);
> > > -	qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
> > > -
> > > -	timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
> > > -	qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
> > > -
> > >  	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 != QCA_WCN3990) {
> > > +			gpiod_set_value_cansleep(qcadev->bt_en, 1);
> > > +		} else {
> > > +			hu->init_speed = qcadev->init_speed;
> > > +			hu->oper_speed = qcadev->oper_speed;
> > > +			ret = qca_power_setup(hu, true);
> > > +			if (ret) {
> > > +				destroy_workqueue(qca->workqueue);
> > > +				kfree_skb(qca->rx_skb);
> > > +				hu->priv = NULL;
> > > +				kfree(qca);
> > > +				return ret;
> > > +			}
> > > +		}
> > >  	}
> > > 
> > > +	timer_setup(&qca->wake_retrans_timer,
> > > hci_ibs_wake_retrans_timeout, 0);
> > > +	qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
> > > +
> > > +	timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
> > > +	qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
> > > +
> > >  	BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u",
> > >  	       qca->tx_idle_delay, qca->wake_retrans);
> > > 
> > > @@ -554,10 +607,13 @@ static int qca_close(struct hci_uart *hu)
> > >  	qca->hu = NULL;
> > > 
> > >  	if (hu->serdev) {
> > > -		serdev_device_close(hu->serdev);
> > > -
> > >  		qcadev = serdev_device_get_drvdata(hu->serdev);
> > > -		gpiod_set_value_cansleep(qcadev->bt_en, 0);
> > > +		if (qcadev->btsoc_type == QCA_WCN3990)
> > > +			qca_power_shutdown(hu);
> > > +		else
> > > +			gpiod_set_value_cansleep(qcadev->bt_en, 0);
> > > +
> > > +		serdev_device_close(hu->serdev);
> > >  	}
> > > 
> > >  	kfree_skb(qca->rx_skb);
> > > @@ -891,6 +947,7 @@ static int qca_set_baudrate(struct hci_dev
> > > *hdev, uint8_t baudrate)
> > >  	struct hci_uart *hu = hci_get_drvdata(hdev);
> > >  	struct qca_data *qca = hu->priv;
> > >  	struct sk_buff *skb;
> > > +	struct qca_serdev *qcadev;
> > >  	u8 cmd[] = { 0x01, 0x48, 0xFC, 0x01, 0x00 };
> > > 
> > >  	if (baudrate > QCA_BAUDRATE_3200000)
> > > @@ -904,6 +961,13 @@ static int qca_set_baudrate(struct hci_dev
> > > *hdev, uint8_t baudrate)
> > >  		return -ENOMEM;
> > >  	}
> > > 
> > > +	/* Disabling hardware flow control is mandate while
> > 
> > nit: s/mandate/mandatory|required/
> > 
> > > +	 * sending change baudrate request to wcn3990 SoC.
> > > +	 */
> > > +	qcadev = serdev_device_get_drvdata(hu->serdev);
> > > +	if (qcadev->btsoc_type == QCA_WCN3990)
> > > +		hci_uart_set_flow_control(hu, true);
> > > +
> > >  	/* Assign commands to change baudrate and packet type. */
> > >  	skb_put_data(skb, cmd, sizeof(cmd));
> > >  	hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
> > > @@ -919,6 +983,9 @@ static int qca_set_baudrate(struct hci_dev
> > > *hdev, uint8_t baudrate)
> > >  	schedule_timeout(msecs_to_jiffies(BAUDRATE_SETTLE_TIMEOUT_MS));
> > >  	set_current_state(TASK_RUNNING);
> > > 
> > > +	if (qcadev->btsoc_type == QCA_WCN3990)
> > > +		hci_uart_set_flow_control(hu, false);
> > > +
> > >  	return 0;
> > >  }
> > > 
> > > @@ -930,6 +997,36 @@ static inline void host_set_baudrate(struct
> > > hci_uart *hu, unsigned int speed)
> > >  		hci_uart_set_baudrate(hu, speed);
> > >  }
> > > 
> > > +static int qca_send_vendor_cmd(struct hci_dev *hdev, u8 cmd)
> > > +{
> > > +	struct hci_uart *hu = hci_get_drvdata(hdev);
> > > +	struct qca_data *qca = hu->priv;
> > > +	struct sk_buff *skb;
> > > +
> > > +	bt_dev_dbg(hdev, "sending command %02x to SoC", cmd);
> > > +
> > > +	skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
> > > +	if (!skb)
> > > +		return -ENOMEM;
> > > +
> > > +	/* Disabling hardware flow control is mandate while
> > 
> > Same nit as above
> > 
> > > +	 * sending vendor power on and off pulse to SoC.
> > > +	 */
> > 
> > The function is called qca_send_vendor_cmd(), the comment about power
> > on/off pulses seems misplaced here. Are there other 'vendor commands'
> > that require a different flow control behavior?
> > 
> > Perhaps the function should have a different name or we need another
> > wrapper.
> > 
> > > +	hci_uart_set_flow_control(hu, true);
> > 
> > Should the changing of the flow control be limited to wcn3990? As of
> > now the function is only called for wcn3990, however this is not
> > stated as a requirement and might change in the future.
> > 
> > > +	skb_put_u8(skb, 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 */
> > > +	usleep_range(100, 200);
> > 
> > Is this needed for any 'vendor command' or directly related with the
> > power on/off pulses?
> > 
> > > +	hci_uart_set_flow_control(hu, false);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > >  static unsigned int qca_get_speed(struct hci_uart *hu,
> > >  				  enum qca_speed_type speed_type)
> > >  {
> > > @@ -952,10 +1049,19 @@ static unsigned int qca_get_speed(struct
> > > hci_uart *hu,
> > > 
> > >  static int qca_check_speeds(struct hci_uart *hu)
> > >  {
> > > -	/* One or the other speeds should be non zero. */
> > > -	if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
> > > -	    !qca_get_speed(hu, QCA_OPER_SPEED))
> > > +	struct qca_serdev *qcadev;
> > > +
> > > +	qcadev = serdev_device_get_drvdata(hu->serdev);
> > > +	if ((qcadev->btsoc_type == QCA_WCN3990 &&
> > > +	    !qca_get_speed(hu, QCA_INIT_SPEED)) ||
> > > +	    !qca_get_speed(hu, QCA_OPER_SPEED)) {
> > > +		/* Both INIT and OPER speed should be non zero. */
> > >  		return -EINVAL;
> > > +	} else if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
> > > +		    !qca_get_speed(hu, QCA_OPER_SPEED)) {
> > > +		/* One or the other speeds should be non zero. */
> > > +		return -EINVAL;
> > > +	}
> > 
> > It is questionable if the comments are useful, they are basically
> > stating the same as the conditions.
> > 
> > if-else statements with a single statement in all branches shouldn't
> > use curly braces. Personally I don't dislike them in this case with
> > the multi-line conditions, but in principle they shoulnd't be there.
> > 
> > nit: this would be easier to read with nested if statements:
> > 
> > 	if (qcadev->btsoc_type == QCA_WCN3990)
> > 		if (!qca_get_speed(hu, QCA_INIT_SPEED)) ||
> > 		    !qca_get_speed(hu, QCA_OPER_SPEED))
> > 			return -EINVAL;
> > 	else
> > 		if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
> > 		    !qca_get_speed(hu, QCA_OPER_SPEED)) {
> > 			return -EINVAL;
> > 
> > >  	return 0;
> > >  }
> > > @@ -986,15 +1092,40 @@ static int qca_set_speed(struct hci_uart *hu,
> > > enum qca_speed_type speed_type)
> > >  	return 0;
> > >  }
> > > 
> > > +static int qca_wcn3990_init(struct hci_uart *hu)
> > > +{
> > > +	int ret;
> > > +
> > > +	ret = qca_send_vendor_cmd(hu->hdev, QCA_WCN3990_POWERON_PULSE);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	/* Wait for 100 ms for SoC to boot up */
> > > +	msleep(100);
> > > +	serdev_device_close(hu->serdev);
> > > +	ret = serdev_device_open(hu->serdev);
> > > +	if (ret) {
> > > +		bt_dev_err(hu->hdev, "failed to open port");
> > > +		return ret;
> > > +	}
> > > +
> > > +	/* Setup initial baudrate */
> > > +	qca_set_speed(hu, QCA_INIT_SPEED);
> > 
> > The comment is a bit redundant.
> > 
> > > +	hci_uart_set_flow_control(hu, false);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > >  static int qca_setup(struct hci_uart *hu)
> > >  {
> > >  	struct hci_dev *hdev = hu->hdev;
> > >  	struct qca_data *qca = hu->priv;
> > >  	unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200;
> > > +	struct qca_serdev *qcadev;
> > >  	int ret;
> > >  	int soc_ver = 0;
> > > 
> > > -	bt_dev_info(hdev, "ROME setup");
> > > +	qcadev = serdev_device_get_drvdata(hu->serdev);
> > > 
> > >  	ret = qca_check_speeds(hu);
> > >  	if (ret)
> > > @@ -1006,6 +1137,21 @@ static int qca_setup(struct hci_uart *hu)
> > >  	/* Setup initial baudrate */
> > >  	qca_set_speed(hu, QCA_INIT_SPEED);
> > > 
> > > +	if (qcadev->btsoc_type == QCA_WCN3990) {
> > > +		bt_dev_dbg(hdev, "setting up wcn3990");
> > 
> > Seems like this should be bt_dev_info() for consistency with Rome.
> > 
> > > +		ret = qca_wcn3990_init(hu);
> > > +		if (ret)
> > > +			return ret;
> > > +
> > > +		ret = qca_read_soc_version(hdev, &soc_ver);
> > > +		if (ret < 0 || soc_ver == 0) {
> > > +			bt_dev_err(hdev, "Failed to get version %d", ret);
> > > +			return ret;
> > > +		}
> > > +	} else {
> > > +		bt_dev_info(hdev, "ROME setup");
> > > +	}
> > > +
> > >  	/* Setup user speed if needed */
> > >  	speed = qca_get_speed(hu, QCA_OPER_SPEED);
> > >  	if (speed) {
> > > @@ -1016,16 +1162,18 @@ static int qca_setup(struct hci_uart *hu)
> > >  		qca_baudrate = qca_get_baudrate_value(speed);
> > >  	}
> > > 
> > > -	/* Get QCA version information */
> > > -	ret = qca_read_soc_version(hdev, &soc_ver);
> > > -	if (ret < 0 || soc_ver == 0) {
> > > -		bt_dev_err(hdev, "QCA Failed to get version (%d)", ret);
> > > -		return ret;
> > > +	if (!soc_ver) {
> > 
> > 
> > The following would probably be clearer:
> > 
> >   	if (qcadev->btsoc_type != QCA_WCN3990) {
> > 
> > > +		/* Get QCA version information */
> > > +		ret = qca_read_soc_version(hdev, &soc_ver);
> > > +		if (ret < 0 || soc_ver == 0) {
> > > +			bt_dev_err(hdev, "QCA Failed to get version (%d)", ret);
> > > +			return ret;
> > > +		}
> > > +		bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
> > 
> > Couldn't we hide some of this in qca_read_soc_version()?
> > 
> > qca_read_soc_version() could at least do the logging in the error case
> > (the 'soc_ver == 0' case could be handled there as well), which would
> > leave us with:
> > 
> > 
> > 	ret = qca_read_soc_version(hdev, &soc_ver);
> > 	if (ret)
> > 		return ret;
> > 
> > And the same above.
> > 
> > The controller version can be logged outside of the branch for both
> > wcn3990 and Rome.
> > 
> > >  	}
> > > -	bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
> > > 
> > >  	/* Setup patch / NVM configurations */
> > > -	ret = qca_uart_setup(hdev, qca_baudrate, QCA_ROME, soc_ver);
> > > +	ret = qca_uart_setup(hdev, qca_baudrate, qcadev->btsoc_type,
> > > soc_ver);
> > >  	if (!ret) {
> > >  		set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
> > >  		qca_debugfs_init(hdev);
> > > @@ -1061,9 +1209,123 @@ static struct hci_uart_proto qca_proto = {
> > >  	.dequeue	= qca_dequeue,
> > >  };
> > > 
> > > +static const struct qca_vreg_data qca_soc_data = {
> > > +	.soc_type = QCA_WCN3990,
> > > +	.vregs = (struct qca_vreg []) {
> > > +		{ "vddio",   1800000, 1800000,  0 },
> > > +		{ "vddxo",   1800000, 1800000,  1 },
> > > +		{ "vddrf",   1304000, 1304000,  1 },
> > > +		{ "vddch0",  3000000, 3312000,  1 },
> > > +	},
> > > +	.num_vregs = 4,
> > > +};
> > 
> > I didn't chime in earlier in the discussion with Stephen on the
> > regulators (https://patchwork.kernel.org/patch/10467911/), however I
> > agree with him that specifying at load of 1uA doesn't seem to make
> > much sense. What would happen if the load remained unspecified (or 0)?
> 
> [Bala]: On RPMh based designs, calling a regulator_set_load with a non-zero
> value moves the regulator to NPM (high power mode) which is required for BT
> communication.
>         and call with 0uA  moves it to low-power-mode (vote from APPS).
> Basically whenever BT wants these in NPM  it calls set-load with 1.

This assumes that the chip is powered by RPMh regulators, which
depending on the system may or may not be true. On systems with other
regulators you are telling the regulator that the max load is 1uA, and
the regulator might comply, going in a low power mode that does not
provide enough current for the chip to operate properly.

Doesn't the datasheet of the chip specify actual max currents for
these consumers that could be used instead of the bogus 1uA? If not
you could ask the designers of the chip for an approximate number
(preferably erring on the upper side).


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

* Re: [PATCH v9 7/7] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990
  2018-07-16 16:05       ` Matthias Kaehlcke
@ 2018-07-17 13:46         ` Balakrishna Godavarthi
  2018-07-18 15:33         ` Balakrishna Godavarthi
  1 sibling, 0 replies; 24+ messages in thread
From: Balakrishna Godavarthi @ 2018-07-17 13:46 UTC (permalink / raw)
  To: Matthias Kaehlcke
  Cc: marcel, johan.hedberg, linux-kernel, devicetree, linux-bluetooth,
	thierry.escande, rtatiya, hemantg, linux-arm-msm, Stephen Boyd

Hi Matthias,

On 2018-07-16 21:35, Matthias Kaehlcke wrote:
> On Mon, Jul 16, 2018 at 07:21:56PM +0530, Balakrishna Godavarthi wrote:
>> Hi Matthias,
>> 
>> On 2018-07-07 03:51, Matthias Kaehlcke wrote:
>> > On Thu, Jul 05, 2018 at 10:25:15PM +0530, Balakrishna Godavarthi wrote:
>> > > Add support to set voltage/current of various regulators
>> > > to power up/down Bluetooth chip wcn3990.
>> > >
>> > > Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
>> > > ---
>> > > changes in v9:
>> > >     * moved flow control to vendor and set_baudarte functions.
>> > >     * removed parent regs.
>> > >
>> > > changes in v8:
>> > >     * closing qca buffer, if qca_power_setup fails
>> > >     * chnaged ibs start timer function call location.
>> > >     * updated review comments.
>> > >
>> > > changes in v7:
>> > >     * addressed review comments.
>> > >
>> > > changes in v6:
>> > >     * Hooked up qca_power to qca_serdev.
>> > >     * renamed all the naming inconsistency functions with qca_*
>> > >     * leveraged common code of ROME for wcn3990.
>> > >     * created wrapper functions for re-usable blocks.
>> > >     * updated function of _*regulator_enable and _*regualtor_disable.
>> > >     * removed redundant comments and functions.
>> > >     * addressed review comments.
>> > >
>> > > Changes in v5:
>> > >     * updated regulator vddpa min_uV to 1304000.
>> > >       * addressed review comments.
>> > >
>> > > Changes in v4:
>> > >     * Segregated the changes of btqca from hci_qca
>> > >     * rebased all changes on top of bluetooth-next.
>> > >     * addressed review comments.
>> > >
>> > > ---
>> > >  drivers/bluetooth/btqca.h   |   3 +
>> > >  drivers/bluetooth/hci_qca.c | 387
>> > > +++++++++++++++++++++++++++++++-----
>> > >  2 files changed, 345 insertions(+), 45 deletions(-)
>> > >
>> > > diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
>> > > index a9c2779f3e07..0c01f375fe83 100644
>> > > --- a/drivers/bluetooth/btqca.h
>> > > +++ b/drivers/bluetooth/btqca.h
>> > > @@ -37,6 +37,9 @@
>> > >  #define EDL_TAG_ID_HCI			(17)
>> > >  #define EDL_TAG_ID_DEEP_SLEEP		(27)
>> > >
>> > > +#define QCA_WCN3990_POWERON_PULSE	0xFC
>> > > +#define QCA_WCN3990_POWEROFF_PULSE	0xC0
>> > > +
>> > >  enum qca_bardrate {
>> > >  	QCA_BAUDRATE_115200 	= 0,
>> > >  	QCA_BAUDRATE_57600,
>> > > diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
>> > > index 7ebfaa0edf3f..d62c7785a618 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...
>> > > @@ -31,9 +31,14 @@
>> > >  #include <linux/kernel.h>
>> > >  #include <linux/clk.h>
>> > >  #include <linux/debugfs.h>
>> > > +#include <linux/delay.h>
>> > > +#include <linux/device.h>
>> > >  #include <linux/gpio/consumer.h>
>> > >  #include <linux/mod_devicetable.h>
>> > >  #include <linux/module.h>
>> > > +#include <linux/of_device.h>
>> > > +#include <linux/platform_device.h>
>> > > +#include <linux/regulator/consumer.h>
>> > >  #include <linux/serdev.h>
>> > >
>> > >  #include <net/bluetooth/bluetooth.h>
>> > > @@ -124,12 +129,46 @@ enum qca_speed_type {
>> > >  	QCA_OPER_SPEED
>> > >  };
>> > >
>> > > +/*
>> > > + * Voltage regulator information required for configuring the
>> > > + * QCA Bluetooth chipset
>> > > + */
>> > > +struct qca_vreg {
>> > > +	const char *name;
>> > > +	unsigned int min_uV;
>> > > +	unsigned int max_uV;
>> > > +	unsigned int load_uA;
>> > > +};
>> > > +
>> > > +struct qca_vreg_data {
>> > > +	enum qca_btsoc_type soc_type;
>> > > +	struct qca_vreg *vregs;
>> > > +	size_t num_vregs;
>> > > +};
>> > > +
>> > > +/*
>> > > + * Platform data for the QCA Bluetooth power driver.
>> > > + */
>> > > +struct qca_power {
>> > > +	struct device *dev;
>> > > +	const struct qca_vreg_data *vreg_data;
>> > > +	struct regulator_bulk_data *vreg_bulk;
>> > > +	bool vregs_on;
>> > > +};
>> > > +
>> > >  struct qca_serdev {
>> > >  	struct hci_uart	 serdev_hu;
>> > >  	struct gpio_desc *bt_en;
>> > >  	struct clk	 *susclk;
>> > > +	enum qca_btsoc_type btsoc_type;
>> > > +	struct qca_power *bt_power;
>> > > +	u32 init_speed;
>> > > +	u32 oper_speed;
>> > >  };
>> > >
>> > > +static int qca_power_setup(struct hci_uart *hu, bool on);
>> > > +static void qca_power_shutdown(struct hci_uart *hu);
>> > > +
>> > >  static void __serial_clock_on(struct tty_struct *tty)
>> > >  {
>> > >  	/* TODO: Some chipset requires to enable UART clock on client
>> > > @@ -407,6 +446,7 @@ static int qca_open(struct hci_uart *hu)
>> > >  {
>> > >  	struct qca_serdev *qcadev;
>> > >  	struct qca_data *qca;
>> > > +	int ret;
>> > >
>> > >  	BT_DBG("hu %p qca_open", hu);
>> > >
>> > > @@ -458,19 +498,32 @@ static int qca_open(struct hci_uart *hu)
>> > >
>> > >  	hu->priv = qca;
>> > >
>> > > -	timer_setup(&qca->wake_retrans_timer,
>> > > hci_ibs_wake_retrans_timeout, 0);
>> > > -	qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
>> > > -
>> > > -	timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
>> > > -	qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
>> > > -
>> > >  	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 != QCA_WCN3990) {
>> > > +			gpiod_set_value_cansleep(qcadev->bt_en, 1);
>> > > +		} else {
>> > > +			hu->init_speed = qcadev->init_speed;
>> > > +			hu->oper_speed = qcadev->oper_speed;
>> > > +			ret = qca_power_setup(hu, true);
>> > > +			if (ret) {
>> > > +				destroy_workqueue(qca->workqueue);
>> > > +				kfree_skb(qca->rx_skb);
>> > > +				hu->priv = NULL;
>> > > +				kfree(qca);
>> > > +				return ret;
>> > > +			}
>> > > +		}
>> > >  	}
>> > >
>> > > +	timer_setup(&qca->wake_retrans_timer,
>> > > hci_ibs_wake_retrans_timeout, 0);
>> > > +	qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
>> > > +
>> > > +	timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
>> > > +	qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
>> > > +
>> > >  	BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u",
>> > >  	       qca->tx_idle_delay, qca->wake_retrans);
>> > >
>> > > @@ -554,10 +607,13 @@ static int qca_close(struct hci_uart *hu)
>> > >  	qca->hu = NULL;
>> > >
>> > >  	if (hu->serdev) {
>> > > -		serdev_device_close(hu->serdev);
>> > > -
>> > >  		qcadev = serdev_device_get_drvdata(hu->serdev);
>> > > -		gpiod_set_value_cansleep(qcadev->bt_en, 0);
>> > > +		if (qcadev->btsoc_type == QCA_WCN3990)
>> > > +			qca_power_shutdown(hu);
>> > > +		else
>> > > +			gpiod_set_value_cansleep(qcadev->bt_en, 0);
>> > > +
>> > > +		serdev_device_close(hu->serdev);
>> > >  	}
>> > >
>> > >  	kfree_skb(qca->rx_skb);
>> > > @@ -891,6 +947,7 @@ static int qca_set_baudrate(struct hci_dev
>> > > *hdev, uint8_t baudrate)
>> > >  	struct hci_uart *hu = hci_get_drvdata(hdev);
>> > >  	struct qca_data *qca = hu->priv;
>> > >  	struct sk_buff *skb;
>> > > +	struct qca_serdev *qcadev;
>> > >  	u8 cmd[] = { 0x01, 0x48, 0xFC, 0x01, 0x00 };
>> > >
>> > >  	if (baudrate > QCA_BAUDRATE_3200000)
>> > > @@ -904,6 +961,13 @@ static int qca_set_baudrate(struct hci_dev
>> > > *hdev, uint8_t baudrate)
>> > >  		return -ENOMEM;
>> > >  	}
>> > >
>> > > +	/* Disabling hardware flow control is mandate while
>> >
>> > nit: s/mandate/mandatory|required/
>> >
>> > > +	 * sending change baudrate request to wcn3990 SoC.
>> > > +	 */
>> > > +	qcadev = serdev_device_get_drvdata(hu->serdev);
>> > > +	if (qcadev->btsoc_type == QCA_WCN3990)
>> > > +		hci_uart_set_flow_control(hu, true);
>> > > +
>> > >  	/* Assign commands to change baudrate and packet type. */
>> > >  	skb_put_data(skb, cmd, sizeof(cmd));
>> > >  	hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
>> > > @@ -919,6 +983,9 @@ static int qca_set_baudrate(struct hci_dev
>> > > *hdev, uint8_t baudrate)
>> > >  	schedule_timeout(msecs_to_jiffies(BAUDRATE_SETTLE_TIMEOUT_MS));
>> > >  	set_current_state(TASK_RUNNING);
>> > >
>> > > +	if (qcadev->btsoc_type == QCA_WCN3990)
>> > > +		hci_uart_set_flow_control(hu, false);
>> > > +
>> > >  	return 0;
>> > >  }
>> > >
>> > > @@ -930,6 +997,36 @@ static inline void host_set_baudrate(struct
>> > > hci_uart *hu, unsigned int speed)
>> > >  		hci_uart_set_baudrate(hu, speed);
>> > >  }
>> > >
>> > > +static int qca_send_vendor_cmd(struct hci_dev *hdev, u8 cmd)
>> > > +{
>> > > +	struct hci_uart *hu = hci_get_drvdata(hdev);
>> > > +	struct qca_data *qca = hu->priv;
>> > > +	struct sk_buff *skb;
>> > > +
>> > > +	bt_dev_dbg(hdev, "sending command %02x to SoC", cmd);
>> > > +
>> > > +	skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
>> > > +	if (!skb)
>> > > +		return -ENOMEM;
>> > > +
>> > > +	/* Disabling hardware flow control is mandate while
>> >
>> > Same nit as above
>> >
>> > > +	 * sending vendor power on and off pulse to SoC.
>> > > +	 */
>> >
>> > The function is called qca_send_vendor_cmd(), the comment about power
>> > on/off pulses seems misplaced here. Are there other 'vendor commands'
>> > that require a different flow control behavior?
>> >
>> > Perhaps the function should have a different name or we need another
>> > wrapper.
>> >
>> > > +	hci_uart_set_flow_control(hu, true);
>> >
>> > Should the changing of the flow control be limited to wcn3990? As of
>> > now the function is only called for wcn3990, however this is not
>> > stated as a requirement and might change in the future.
>> >
>> > > +	skb_put_u8(skb, 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 */
>> > > +	usleep_range(100, 200);
>> >
>> > Is this needed for any 'vendor command' or directly related with the
>> > power on/off pulses?
>> >
>> > > +	hci_uart_set_flow_control(hu, false);
>> > > +
>> > > +	return 0;
>> > > +}
>> > > +
>> > >  static unsigned int qca_get_speed(struct hci_uart *hu,
>> > >  				  enum qca_speed_type speed_type)
>> > >  {
>> > > @@ -952,10 +1049,19 @@ static unsigned int qca_get_speed(struct
>> > > hci_uart *hu,
>> > >
>> > >  static int qca_check_speeds(struct hci_uart *hu)
>> > >  {
>> > > -	/* One or the other speeds should be non zero. */
>> > > -	if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
>> > > -	    !qca_get_speed(hu, QCA_OPER_SPEED))
>> > > +	struct qca_serdev *qcadev;
>> > > +
>> > > +	qcadev = serdev_device_get_drvdata(hu->serdev);
>> > > +	if ((qcadev->btsoc_type == QCA_WCN3990 &&
>> > > +	    !qca_get_speed(hu, QCA_INIT_SPEED)) ||
>> > > +	    !qca_get_speed(hu, QCA_OPER_SPEED)) {
>> > > +		/* Both INIT and OPER speed should be non zero. */
>> > >  		return -EINVAL;
>> > > +	} else if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
>> > > +		    !qca_get_speed(hu, QCA_OPER_SPEED)) {
>> > > +		/* One or the other speeds should be non zero. */
>> > > +		return -EINVAL;
>> > > +	}
>> >
>> > It is questionable if the comments are useful, they are basically
>> > stating the same as the conditions.
>> >
>> > if-else statements with a single statement in all branches shouldn't
>> > use curly braces. Personally I don't dislike them in this case with
>> > the multi-line conditions, but in principle they shoulnd't be there.
>> >
>> > nit: this would be easier to read with nested if statements:
>> >
>> > 	if (qcadev->btsoc_type == QCA_WCN3990)
>> > 		if (!qca_get_speed(hu, QCA_INIT_SPEED)) ||
>> > 		    !qca_get_speed(hu, QCA_OPER_SPEED))
>> > 			return -EINVAL;
>> > 	else
>> > 		if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
>> > 		    !qca_get_speed(hu, QCA_OPER_SPEED)) {
>> > 			return -EINVAL;
>> >
>> > >  	return 0;
>> > >  }
>> > > @@ -986,15 +1092,40 @@ static int qca_set_speed(struct hci_uart *hu,
>> > > enum qca_speed_type speed_type)
>> > >  	return 0;
>> > >  }
>> > >
>> > > +static int qca_wcn3990_init(struct hci_uart *hu)
>> > > +{
>> > > +	int ret;
>> > > +
>> > > +	ret = qca_send_vendor_cmd(hu->hdev, QCA_WCN3990_POWERON_PULSE);
>> > > +	if (ret)
>> > > +		return ret;
>> > > +
>> > > +	/* Wait for 100 ms for SoC to boot up */
>> > > +	msleep(100);
>> > > +	serdev_device_close(hu->serdev);
>> > > +	ret = serdev_device_open(hu->serdev);
>> > > +	if (ret) {
>> > > +		bt_dev_err(hu->hdev, "failed to open port");
>> > > +		return ret;
>> > > +	}
>> > > +
>> > > +	/* Setup initial baudrate */
>> > > +	qca_set_speed(hu, QCA_INIT_SPEED);
>> >
>> > The comment is a bit redundant.
>> >
>> > > +	hci_uart_set_flow_control(hu, false);
>> > > +
>> > > +	return 0;
>> > > +}
>> > > +
>> > >  static int qca_setup(struct hci_uart *hu)
>> > >  {
>> > >  	struct hci_dev *hdev = hu->hdev;
>> > >  	struct qca_data *qca = hu->priv;
>> > >  	unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200;
>> > > +	struct qca_serdev *qcadev;
>> > >  	int ret;
>> > >  	int soc_ver = 0;
>> > >
>> > > -	bt_dev_info(hdev, "ROME setup");
>> > > +	qcadev = serdev_device_get_drvdata(hu->serdev);
>> > >
>> > >  	ret = qca_check_speeds(hu);
>> > >  	if (ret)
>> > > @@ -1006,6 +1137,21 @@ static int qca_setup(struct hci_uart *hu)
>> > >  	/* Setup initial baudrate */
>> > >  	qca_set_speed(hu, QCA_INIT_SPEED);
>> > >
>> > > +	if (qcadev->btsoc_type == QCA_WCN3990) {
>> > > +		bt_dev_dbg(hdev, "setting up wcn3990");
>> >
>> > Seems like this should be bt_dev_info() for consistency with Rome.
>> >
>> > > +		ret = qca_wcn3990_init(hu);
>> > > +		if (ret)
>> > > +			return ret;
>> > > +
>> > > +		ret = qca_read_soc_version(hdev, &soc_ver);
>> > > +		if (ret < 0 || soc_ver == 0) {
>> > > +			bt_dev_err(hdev, "Failed to get version %d", ret);
>> > > +			return ret;
>> > > +		}
>> > > +	} else {
>> > > +		bt_dev_info(hdev, "ROME setup");
>> > > +	}
>> > > +
>> > >  	/* Setup user speed if needed */
>> > >  	speed = qca_get_speed(hu, QCA_OPER_SPEED);
>> > >  	if (speed) {
>> > > @@ -1016,16 +1162,18 @@ static int qca_setup(struct hci_uart *hu)
>> > >  		qca_baudrate = qca_get_baudrate_value(speed);
>> > >  	}
>> > >
>> > > -	/* Get QCA version information */
>> > > -	ret = qca_read_soc_version(hdev, &soc_ver);
>> > > -	if (ret < 0 || soc_ver == 0) {
>> > > -		bt_dev_err(hdev, "QCA Failed to get version (%d)", ret);
>> > > -		return ret;
>> > > +	if (!soc_ver) {
>> >
>> >
>> > The following would probably be clearer:
>> >
>> >   	if (qcadev->btsoc_type != QCA_WCN3990) {
>> >
>> > > +		/* Get QCA version information */
>> > > +		ret = qca_read_soc_version(hdev, &soc_ver);
>> > > +		if (ret < 0 || soc_ver == 0) {
>> > > +			bt_dev_err(hdev, "QCA Failed to get version (%d)", ret);
>> > > +			return ret;
>> > > +		}
>> > > +		bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
>> >
>> > Couldn't we hide some of this in qca_read_soc_version()?
>> >
>> > qca_read_soc_version() could at least do the logging in the error case
>> > (the 'soc_ver == 0' case could be handled there as well), which would
>> > leave us with:
>> >
>> >
>> > 	ret = qca_read_soc_version(hdev, &soc_ver);
>> > 	if (ret)
>> > 		return ret;
>> >
>> > And the same above.
>> >
>> > The controller version can be logged outside of the branch for both
>> > wcn3990 and Rome.
>> >
>> > >  	}
>> > > -	bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
>> > >
>> > >  	/* Setup patch / NVM configurations */
>> > > -	ret = qca_uart_setup(hdev, qca_baudrate, QCA_ROME, soc_ver);
>> > > +	ret = qca_uart_setup(hdev, qca_baudrate, qcadev->btsoc_type,
>> > > soc_ver);
>> > >  	if (!ret) {
>> > >  		set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
>> > >  		qca_debugfs_init(hdev);
>> > > @@ -1061,9 +1209,123 @@ static struct hci_uart_proto qca_proto = {
>> > >  	.dequeue	= qca_dequeue,
>> > >  };
>> > >
>> > > +static const struct qca_vreg_data qca_soc_data = {
>> > > +	.soc_type = QCA_WCN3990,
>> > > +	.vregs = (struct qca_vreg []) {
>> > > +		{ "vddio",   1800000, 1800000,  0 },
>> > > +		{ "vddxo",   1800000, 1800000,  1 },
>> > > +		{ "vddrf",   1304000, 1304000,  1 },
>> > > +		{ "vddch0",  3000000, 3312000,  1 },
>> > > +	},
>> > > +	.num_vregs = 4,
>> > > +};
>> >
>> > I didn't chime in earlier in the discussion with Stephen on the
>> > regulators (https://patchwork.kernel.org/patch/10467911/), however I
>> > agree with him that specifying at load of 1uA doesn't seem to make
>> > much sense. What would happen if the load remained unspecified (or 0)?
>> 
>> [Bala]: On RPMh based designs, calling a regulator_set_load with a 
>> non-zero
>> value moves the regulator to NPM (high power mode) which is required 
>> for BT
>> communication.
>>         and call with 0uA  moves it to low-power-mode (vote from 
>> APPS).
>> Basically whenever BT wants these in NPM  it calls set-load with 1.
> 
> This assumes that the chip is powered by RPMh regulators, which
> depending on the system may or may not be true. On systems with other
> regulators you are telling the regulator that the max load is 1uA, and
> the regulator might comply, going in a low power mode that does not
> provide enough current for the chip to operate properly.
> 
> Doesn't the datasheet of the chip specify actual max currents for
> these consumers that could be used instead of the bogus 1uA? If not
> you could ask the designers of the chip for an approximate number
> (preferably erring on the upper side).

[Bala]: will check and update you on this.

-- 
Regards
Balakrishna.

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

* Re: [PATCH v9 7/7] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990
  2018-07-10 16:39       ` Matthias Kaehlcke
@ 2018-07-17 15:18         ` Balakrishna Godavarthi
  0 siblings, 0 replies; 24+ messages in thread
From: Balakrishna Godavarthi @ 2018-07-17 15:18 UTC (permalink / raw)
  To: Matthias Kaehlcke
  Cc: marcel, johan.hedberg, linux-kernel, devicetree, linux-bluetooth,
	thierry.escande, rtatiya, hemantg, linux-arm-msm, Stephen Boyd

Hi Matthias,

On 2018-07-10 22:09, Matthias Kaehlcke wrote:
> Hi Bala,
> 
> On Tue, Jul 10, 2018 at 06:22:02PM +0530, Balakrishna Godavarthi wrote:
>> Hi Matthias,
>> 
>> On 2018-07-07 03:51, Matthias Kaehlcke wrote:
>> > On Thu, Jul 05, 2018 at 10:25:15PM +0530, Balakrishna Godavarthi wrote:
>> > > +	 * sending vendor power on and off pulse to SoC.
>> > > +	 */
>> >
>> > The function is called qca_send_vendor_cmd(), the comment about power
>> > on/off pulses seems misplaced here. Are there other 'vendor commands'
>> > that require a different flow control behavior?
>> >
>> > Perhaps the function should have a different name or we need another
>> > wrapper.
>> >
>> 
>> [Bala]: this function is used to send single byte vendor commands. 
>> like
>> power on and off pulse.
>>         and all single byte vendor commands require an flow control 
>> off and
>> on.
>>         so might be function name change is required.
>>         instead of qca_send_vendor_cmd(). i want to change function 
>> name to
>> qca_send_pulse() as this will be generic.
> 
> 'pulse' covers power on/off pulses, is it also applicable to other
> single byte commands? How are these commands named in the QCA
> documentation?
> 
[Bala]: in QCA wcn3990 for these two bytes we will turn off the flow 
control while sending command and turn on back once it is enabled.
         in documentation it was mentioned as power on and power off 
pulse.
         for all other single bytes we need flow control enable.

> In any case the comment about 'vendor power on and off pulse' should
> be updated to refer to 'vendor commands'/'pulses' or whatever
> terminology we decide to use.

[Bala]: will update the the function name.

> 
>> > > +	hci_uart_set_flow_control(hu, true);
>> >
>> > Should the changing of the flow control be limited to wcn3990? As of
>> > now the function is only called for wcn3990, however this is not
>> > stated as a requirement and might change in the future.
>> >
>> > > +	skb_put_u8(skb, 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 */
>> > > +	usleep_range(100, 200);
>> >
>> > Is this needed for any 'vendor command' or directly related with the
>> > power on/off pulses?
>> >
>> 
>> [Bala] : flow control  off/on is needed for power on and off pulses 
>> along
>> with
>>          command to set baudrate.. this is common across all the 
>> present
>> chips and chips which are in development stages.
>>          might be function name is confusing will update the function 
>> name.
> 
> The current name *might* be ok, depending on if we come up with
> something better. If the QCA docs refer to them as 'vendor commands'
> and there are no other multi-byte 'vendor commands' I'm fine with it.
> 
> Is the settling down of 100us specific to the power on/off pulses or
> also applicable to other commands?
> 
[Bala]: 100 us is specific to power on and off pulses.

> Thanks
> 
> Matthias

-- 
Regards
Balakrishna.

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

* Re: [PATCH v9 7/7] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990
  2018-07-16 16:05       ` Matthias Kaehlcke
  2018-07-17 13:46         ` Balakrishna Godavarthi
@ 2018-07-18 15:33         ` Balakrishna Godavarthi
  2018-07-18 17:13           ` Matthias Kaehlcke
  1 sibling, 1 reply; 24+ messages in thread
From: Balakrishna Godavarthi @ 2018-07-18 15:33 UTC (permalink / raw)
  To: Matthias Kaehlcke
  Cc: marcel, johan.hedberg, linux-kernel, devicetree, linux-bluetooth,
	thierry.escande, rtatiya, hemantg, linux-arm-msm, Stephen Boyd

Hi Matthias,

On 2018-07-16 21:35, Matthias Kaehlcke wrote:
> On Mon, Jul 16, 2018 at 07:21:56PM +0530, Balakrishna Godavarthi wrote:
>> Hi Matthias,
>> 
>> On 2018-07-07 03:51, Matthias Kaehlcke wrote:
>> > On Thu, Jul 05, 2018 at 10:25:15PM +0530, Balakrishna Godavarthi wrote:
>> > > Add support to set voltage/current of various regulators
>> > > to power up/down Bluetooth chip wcn3990.
>> > >
>> > > Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
>> > > ---
>> > > changes in v9:
>> > >     * moved flow control to vendor and set_baudarte functions.
>> > >     * removed parent regs.
>> > >
>> > > changes in v8:
>> > >     * closing qca buffer, if qca_power_setup fails
>> > >     * chnaged ibs start timer function call location.
>> > >     * updated review comments.
>> > >
>> > > changes in v7:
>> > >     * addressed review comments.
>> > >
>> > > changes in v6:
>> > >     * Hooked up qca_power to qca_serdev.
>> > >     * renamed all the naming inconsistency functions with qca_*
>> > >     * leveraged common code of ROME for wcn3990.
>> > >     * created wrapper functions for re-usable blocks.
>> > >     * updated function of _*regulator_enable and _*regualtor_disable.
>> > >     * removed redundant comments and functions.
>> > >     * addressed review comments.
>> > >
>> > > Changes in v5:
>> > >     * updated regulator vddpa min_uV to 1304000.
>> > >       * addressed review comments.
>> > >
>> > > Changes in v4:
>> > >     * Segregated the changes of btqca from hci_qca
>> > >     * rebased all changes on top of bluetooth-next.
>> > >     * addressed review comments.
>> > >
>> > > ---
>> > >  drivers/bluetooth/btqca.h   |   3 +
>> > >  drivers/bluetooth/hci_qca.c | 387
>> > > +++++++++++++++++++++++++++++++-----
>> > >  2 files changed, 345 insertions(+), 45 deletions(-)
>> > >
>> > > diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
>> > > index a9c2779f3e07..0c01f375fe83 100644
>> > > --- a/drivers/bluetooth/btqca.h
>> > > +++ b/drivers/bluetooth/btqca.h
>> > > @@ -37,6 +37,9 @@
>> > >  #define EDL_TAG_ID_HCI			(17)
>> > >  #define EDL_TAG_ID_DEEP_SLEEP		(27)
>> > >
>> > > +#define QCA_WCN3990_POWERON_PULSE	0xFC
>> > > +#define QCA_WCN3990_POWEROFF_PULSE	0xC0
>> > > +
>> > >  enum qca_bardrate {
>> > >  	QCA_BAUDRATE_115200 	= 0,
>> > >  	QCA_BAUDRATE_57600,
>> > > diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
>> > > index 7ebfaa0edf3f..d62c7785a618 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...
>> > > @@ -31,9 +31,14 @@
>> > >  #include <linux/kernel.h>
>> > >  #include <linux/clk.h>
>> > >  #include <linux/debugfs.h>
>> > > +#include <linux/delay.h>
>> > > +#include <linux/device.h>
>> > >  #include <linux/gpio/consumer.h>
>> > >  #include <linux/mod_devicetable.h>
>> > >  #include <linux/module.h>
>> > > +#include <linux/of_device.h>
>> > > +#include <linux/platform_device.h>
>> > > +#include <linux/regulator/consumer.h>
>> > >  #include <linux/serdev.h>
>> > >
>> > >  #include <net/bluetooth/bluetooth.h>
>> > > @@ -124,12 +129,46 @@ enum qca_speed_type {
>> > >  	QCA_OPER_SPEED
>> > >  };
>> > >
>> > > +/*
>> > > + * Voltage regulator information required for configuring the
>> > > + * QCA Bluetooth chipset
>> > > + */
>> > > +struct qca_vreg {
>> > > +	const char *name;
>> > > +	unsigned int min_uV;
>> > > +	unsigned int max_uV;
>> > > +	unsigned int load_uA;
>> > > +};
>> > > +
>> > > +struct qca_vreg_data {
>> > > +	enum qca_btsoc_type soc_type;
>> > > +	struct qca_vreg *vregs;
>> > > +	size_t num_vregs;
>> > > +};
>> > > +
>> > > +/*
>> > > + * Platform data for the QCA Bluetooth power driver.
>> > > + */
>> > > +struct qca_power {
>> > > +	struct device *dev;
>> > > +	const struct qca_vreg_data *vreg_data;
>> > > +	struct regulator_bulk_data *vreg_bulk;
>> > > +	bool vregs_on;
>> > > +};
>> > > +
>> > >  struct qca_serdev {
>> > >  	struct hci_uart	 serdev_hu;
>> > >  	struct gpio_desc *bt_en;
>> > >  	struct clk	 *susclk;
>> > > +	enum qca_btsoc_type btsoc_type;
>> > > +	struct qca_power *bt_power;
>> > > +	u32 init_speed;
>> > > +	u32 oper_speed;
>> > >  };
>> > >
>> > > +static int qca_power_setup(struct hci_uart *hu, bool on);
>> > > +static void qca_power_shutdown(struct hci_uart *hu);
>> > > +
>> > >  static void __serial_clock_on(struct tty_struct *tty)
>> > >  {
>> > >  	/* TODO: Some chipset requires to enable UART clock on client
>> > > @@ -407,6 +446,7 @@ static int qca_open(struct hci_uart *hu)
>> > >  {
>> > >  	struct qca_serdev *qcadev;
>> > >  	struct qca_data *qca;
>> > > +	int ret;
>> > >
>> > >  	BT_DBG("hu %p qca_open", hu);
>> > >
>> > > @@ -458,19 +498,32 @@ static int qca_open(struct hci_uart *hu)
>> > >
>> > >  	hu->priv = qca;
>> > >
>> > > -	timer_setup(&qca->wake_retrans_timer,
>> > > hci_ibs_wake_retrans_timeout, 0);
>> > > -	qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
>> > > -
>> > > -	timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
>> > > -	qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
>> > > -
>> > >  	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 != QCA_WCN3990) {
>> > > +			gpiod_set_value_cansleep(qcadev->bt_en, 1);
>> > > +		} else {
>> > > +			hu->init_speed = qcadev->init_speed;
>> > > +			hu->oper_speed = qcadev->oper_speed;
>> > > +			ret = qca_power_setup(hu, true);
>> > > +			if (ret) {
>> > > +				destroy_workqueue(qca->workqueue);
>> > > +				kfree_skb(qca->rx_skb);
>> > > +				hu->priv = NULL;
>> > > +				kfree(qca);
>> > > +				return ret;
>> > > +			}
>> > > +		}
>> > >  	}
>> > >
>> > > +	timer_setup(&qca->wake_retrans_timer,
>> > > hci_ibs_wake_retrans_timeout, 0);
>> > > +	qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
>> > > +
>> > > +	timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
>> > > +	qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
>> > > +
>> > >  	BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u",
>> > >  	       qca->tx_idle_delay, qca->wake_retrans);
>> > >
>> > > @@ -554,10 +607,13 @@ static int qca_close(struct hci_uart *hu)
>> > >  	qca->hu = NULL;
>> > >
>> > >  	if (hu->serdev) {
>> > > -		serdev_device_close(hu->serdev);
>> > > -
>> > >  		qcadev = serdev_device_get_drvdata(hu->serdev);
>> > > -		gpiod_set_value_cansleep(qcadev->bt_en, 0);
>> > > +		if (qcadev->btsoc_type == QCA_WCN3990)
>> > > +			qca_power_shutdown(hu);
>> > > +		else
>> > > +			gpiod_set_value_cansleep(qcadev->bt_en, 0);
>> > > +
>> > > +		serdev_device_close(hu->serdev);
>> > >  	}
>> > >
>> > >  	kfree_skb(qca->rx_skb);
>> > > @@ -891,6 +947,7 @@ static int qca_set_baudrate(struct hci_dev
>> > > *hdev, uint8_t baudrate)
>> > >  	struct hci_uart *hu = hci_get_drvdata(hdev);
>> > >  	struct qca_data *qca = hu->priv;
>> > >  	struct sk_buff *skb;
>> > > +	struct qca_serdev *qcadev;
>> > >  	u8 cmd[] = { 0x01, 0x48, 0xFC, 0x01, 0x00 };
>> > >
>> > >  	if (baudrate > QCA_BAUDRATE_3200000)
>> > > @@ -904,6 +961,13 @@ static int qca_set_baudrate(struct hci_dev
>> > > *hdev, uint8_t baudrate)
>> > >  		return -ENOMEM;
>> > >  	}
>> > >
>> > > +	/* Disabling hardware flow control is mandate while
>> >
>> > nit: s/mandate/mandatory|required/
>> >
>> > > +	 * sending change baudrate request to wcn3990 SoC.
>> > > +	 */
>> > > +	qcadev = serdev_device_get_drvdata(hu->serdev);
>> > > +	if (qcadev->btsoc_type == QCA_WCN3990)
>> > > +		hci_uart_set_flow_control(hu, true);
>> > > +
>> > >  	/* Assign commands to change baudrate and packet type. */
>> > >  	skb_put_data(skb, cmd, sizeof(cmd));
>> > >  	hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
>> > > @@ -919,6 +983,9 @@ static int qca_set_baudrate(struct hci_dev
>> > > *hdev, uint8_t baudrate)
>> > >  	schedule_timeout(msecs_to_jiffies(BAUDRATE_SETTLE_TIMEOUT_MS));
>> > >  	set_current_state(TASK_RUNNING);
>> > >
>> > > +	if (qcadev->btsoc_type == QCA_WCN3990)
>> > > +		hci_uart_set_flow_control(hu, false);
>> > > +
>> > >  	return 0;
>> > >  }
>> > >
>> > > @@ -930,6 +997,36 @@ static inline void host_set_baudrate(struct
>> > > hci_uart *hu, unsigned int speed)
>> > >  		hci_uart_set_baudrate(hu, speed);
>> > >  }
>> > >
>> > > +static int qca_send_vendor_cmd(struct hci_dev *hdev, u8 cmd)
>> > > +{
>> > > +	struct hci_uart *hu = hci_get_drvdata(hdev);
>> > > +	struct qca_data *qca = hu->priv;
>> > > +	struct sk_buff *skb;
>> > > +
>> > > +	bt_dev_dbg(hdev, "sending command %02x to SoC", cmd);
>> > > +
>> > > +	skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
>> > > +	if (!skb)
>> > > +		return -ENOMEM;
>> > > +
>> > > +	/* Disabling hardware flow control is mandate while
>> >
>> > Same nit as above
>> >
>> > > +	 * sending vendor power on and off pulse to SoC.
>> > > +	 */
>> >
>> > The function is called qca_send_vendor_cmd(), the comment about power
>> > on/off pulses seems misplaced here. Are there other 'vendor commands'
>> > that require a different flow control behavior?
>> >
>> > Perhaps the function should have a different name or we need another
>> > wrapper.
>> >
>> > > +	hci_uart_set_flow_control(hu, true);
>> >
>> > Should the changing of the flow control be limited to wcn3990? As of
>> > now the function is only called for wcn3990, however this is not
>> > stated as a requirement and might change in the future.
>> >
>> > > +	skb_put_u8(skb, 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 */
>> > > +	usleep_range(100, 200);
>> >
>> > Is this needed for any 'vendor command' or directly related with the
>> > power on/off pulses?
>> >
>> > > +	hci_uart_set_flow_control(hu, false);
>> > > +
>> > > +	return 0;
>> > > +}
>> > > +
>> > >  static unsigned int qca_get_speed(struct hci_uart *hu,
>> > >  				  enum qca_speed_type speed_type)
>> > >  {
>> > > @@ -952,10 +1049,19 @@ static unsigned int qca_get_speed(struct
>> > > hci_uart *hu,
>> > >
>> > >  static int qca_check_speeds(struct hci_uart *hu)
>> > >  {
>> > > -	/* One or the other speeds should be non zero. */
>> > > -	if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
>> > > -	    !qca_get_speed(hu, QCA_OPER_SPEED))
>> > > +	struct qca_serdev *qcadev;
>> > > +
>> > > +	qcadev = serdev_device_get_drvdata(hu->serdev);
>> > > +	if ((qcadev->btsoc_type == QCA_WCN3990 &&
>> > > +	    !qca_get_speed(hu, QCA_INIT_SPEED)) ||
>> > > +	    !qca_get_speed(hu, QCA_OPER_SPEED)) {
>> > > +		/* Both INIT and OPER speed should be non zero. */
>> > >  		return -EINVAL;
>> > > +	} else if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
>> > > +		    !qca_get_speed(hu, QCA_OPER_SPEED)) {
>> > > +		/* One or the other speeds should be non zero. */
>> > > +		return -EINVAL;
>> > > +	}
>> >
>> > It is questionable if the comments are useful, they are basically
>> > stating the same as the conditions.
>> >
>> > if-else statements with a single statement in all branches shouldn't
>> > use curly braces. Personally I don't dislike them in this case with
>> > the multi-line conditions, but in principle they shoulnd't be there.
>> >
>> > nit: this would be easier to read with nested if statements:
>> >
>> > 	if (qcadev->btsoc_type == QCA_WCN3990)
>> > 		if (!qca_get_speed(hu, QCA_INIT_SPEED)) ||
>> > 		    !qca_get_speed(hu, QCA_OPER_SPEED))
>> > 			return -EINVAL;
>> > 	else
>> > 		if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
>> > 		    !qca_get_speed(hu, QCA_OPER_SPEED)) {
>> > 			return -EINVAL;
>> >
>> > >  	return 0;
>> > >  }
>> > > @@ -986,15 +1092,40 @@ static int qca_set_speed(struct hci_uart *hu,
>> > > enum qca_speed_type speed_type)
>> > >  	return 0;
>> > >  }
>> > >
>> > > +static int qca_wcn3990_init(struct hci_uart *hu)
>> > > +{
>> > > +	int ret;
>> > > +
>> > > +	ret = qca_send_vendor_cmd(hu->hdev, QCA_WCN3990_POWERON_PULSE);
>> > > +	if (ret)
>> > > +		return ret;
>> > > +
>> > > +	/* Wait for 100 ms for SoC to boot up */
>> > > +	msleep(100);
>> > > +	serdev_device_close(hu->serdev);
>> > > +	ret = serdev_device_open(hu->serdev);
>> > > +	if (ret) {
>> > > +		bt_dev_err(hu->hdev, "failed to open port");
>> > > +		return ret;
>> > > +	}
>> > > +
>> > > +	/* Setup initial baudrate */
>> > > +	qca_set_speed(hu, QCA_INIT_SPEED);
>> >
>> > The comment is a bit redundant.
>> >
>> > > +	hci_uart_set_flow_control(hu, false);
>> > > +
>> > > +	return 0;
>> > > +}
>> > > +
>> > >  static int qca_setup(struct hci_uart *hu)
>> > >  {
>> > >  	struct hci_dev *hdev = hu->hdev;
>> > >  	struct qca_data *qca = hu->priv;
>> > >  	unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200;
>> > > +	struct qca_serdev *qcadev;
>> > >  	int ret;
>> > >  	int soc_ver = 0;
>> > >
>> > > -	bt_dev_info(hdev, "ROME setup");
>> > > +	qcadev = serdev_device_get_drvdata(hu->serdev);
>> > >
>> > >  	ret = qca_check_speeds(hu);
>> > >  	if (ret)
>> > > @@ -1006,6 +1137,21 @@ static int qca_setup(struct hci_uart *hu)
>> > >  	/* Setup initial baudrate */
>> > >  	qca_set_speed(hu, QCA_INIT_SPEED);
>> > >
>> > > +	if (qcadev->btsoc_type == QCA_WCN3990) {
>> > > +		bt_dev_dbg(hdev, "setting up wcn3990");
>> >
>> > Seems like this should be bt_dev_info() for consistency with Rome.
>> >
>> > > +		ret = qca_wcn3990_init(hu);
>> > > +		if (ret)
>> > > +			return ret;
>> > > +
>> > > +		ret = qca_read_soc_version(hdev, &soc_ver);
>> > > +		if (ret < 0 || soc_ver == 0) {
>> > > +			bt_dev_err(hdev, "Failed to get version %d", ret);
>> > > +			return ret;
>> > > +		}
>> > > +	} else {
>> > > +		bt_dev_info(hdev, "ROME setup");
>> > > +	}
>> > > +
>> > >  	/* Setup user speed if needed */
>> > >  	speed = qca_get_speed(hu, QCA_OPER_SPEED);
>> > >  	if (speed) {
>> > > @@ -1016,16 +1162,18 @@ static int qca_setup(struct hci_uart *hu)
>> > >  		qca_baudrate = qca_get_baudrate_value(speed);
>> > >  	}
>> > >
>> > > -	/* Get QCA version information */
>> > > -	ret = qca_read_soc_version(hdev, &soc_ver);
>> > > -	if (ret < 0 || soc_ver == 0) {
>> > > -		bt_dev_err(hdev, "QCA Failed to get version (%d)", ret);
>> > > -		return ret;
>> > > +	if (!soc_ver) {
>> >
>> >
>> > The following would probably be clearer:
>> >
>> >   	if (qcadev->btsoc_type != QCA_WCN3990) {
>> >
>> > > +		/* Get QCA version information */
>> > > +		ret = qca_read_soc_version(hdev, &soc_ver);
>> > > +		if (ret < 0 || soc_ver == 0) {
>> > > +			bt_dev_err(hdev, "QCA Failed to get version (%d)", ret);
>> > > +			return ret;
>> > > +		}
>> > > +		bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
>> >
>> > Couldn't we hide some of this in qca_read_soc_version()?
>> >
>> > qca_read_soc_version() could at least do the logging in the error case
>> > (the 'soc_ver == 0' case could be handled there as well), which would
>> > leave us with:
>> >
>> >
>> > 	ret = qca_read_soc_version(hdev, &soc_ver);
>> > 	if (ret)
>> > 		return ret;
>> >
>> > And the same above.
>> >
>> > The controller version can be logged outside of the branch for both
>> > wcn3990 and Rome.
>> >
>> > >  	}
>> > > -	bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
>> > >
>> > >  	/* Setup patch / NVM configurations */
>> > > -	ret = qca_uart_setup(hdev, qca_baudrate, QCA_ROME, soc_ver);
>> > > +	ret = qca_uart_setup(hdev, qca_baudrate, qcadev->btsoc_type,
>> > > soc_ver);
>> > >  	if (!ret) {
>> > >  		set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
>> > >  		qca_debugfs_init(hdev);
>> > > @@ -1061,9 +1209,123 @@ static struct hci_uart_proto qca_proto = {
>> > >  	.dequeue	= qca_dequeue,
>> > >  };
>> > >
>> > > +static const struct qca_vreg_data qca_soc_data = {
>> > > +	.soc_type = QCA_WCN3990,
>> > > +	.vregs = (struct qca_vreg []) {
>> > > +		{ "vddio",   1800000, 1800000,  0 },
>> > > +		{ "vddxo",   1800000, 1800000,  1 },
>> > > +		{ "vddrf",   1304000, 1304000,  1 },
>> > > +		{ "vddch0",  3000000, 3312000,  1 },
>> > > +	},
>> > > +	.num_vregs = 4,
>> > > +};
>> >
>> > I didn't chime in earlier in the discussion with Stephen on the
>> > regulators (https://patchwork.kernel.org/patch/10467911/), however I
>> > agree with him that specifying at load of 1uA doesn't seem to make
>> > much sense. What would happen if the load remained unspecified (or 0)?
>> 
>> [Bala]: On RPMh based designs, calling a regulator_set_load with a 
>> non-zero
>> value moves the regulator to NPM (high power mode) which is required 
>> for BT
>> communication.
>>         and call with 0uA  moves it to low-power-mode (vote from 
>> APPS).
>> Basically whenever BT wants these in NPM  it calls set-load with 1.
> 
> This assumes that the chip is powered by RPMh regulators, which
> depending on the system may or may not be true. On systems with other
> regulators you are telling the regulator that the max load is 1uA, and
> the regulator might comply, going in a low power mode that does not
> provide enough current for the chip to operate properly.
> 
> Doesn't the datasheet of the chip specify actual max currents for
> these consumers that could be used instead of the bogus 1uA? If not
> you could ask the designers of the chip for an approximate number
> (preferably erring on the upper side).

[Bala]: yes your true, now current values are aligned according to the 
RPMH regs packages.
         this is not our goal. what ever the package we use wcn3990 
should be platform independent.
         I propose an idea that, we will have default current value in 
driver i.e current required by regs to turn on wcn3990 and also we will 
provide interface in driver
         to read current from dts tree.

        i.e. if we have prop for current to the reg in the dts, we will 
read the value assigned to prop else we will take default current

   <code snippets>

        qca->vreg_data->vregs[i].name = current; // holds the default 
current value taken from data provided from deb. this will value remains 
unchanged.
        if (device_property_read_bool(dev, prop_name))  // if we have 
prop name enabled then read the value.
                 device_property_read_u32(dev, prop_name, 
&vregs->load_uA);


-- 
Regards
Balakrishna.

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

* Re: [PATCH v9 7/7] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990
  2018-07-18 15:33         ` Balakrishna Godavarthi
@ 2018-07-18 17:13           ` Matthias Kaehlcke
  2018-07-20 12:46             ` Balakrishna Godavarthi
  0 siblings, 1 reply; 24+ messages in thread
From: Matthias Kaehlcke @ 2018-07-18 17:13 UTC (permalink / raw)
  To: Balakrishna Godavarthi
  Cc: marcel, johan.hedberg, linux-kernel, devicetree, linux-bluetooth,
	thierry.escande, rtatiya, hemantg, linux-arm-msm, Stephen Boyd

On Wed, Jul 18, 2018 at 09:03:08PM +0530, Balakrishna Godavarthi wrote:
> Hi Matthias,
> 
> On 2018-07-16 21:35, Matthias Kaehlcke wrote:
> > On Mon, Jul 16, 2018 at 07:21:56PM +0530, Balakrishna Godavarthi wrote:
> > > Hi Matthias,
> > > 
> > > On 2018-07-07 03:51, Matthias Kaehlcke wrote:
> > > > On Thu, Jul 05, 2018 at 10:25:15PM +0530, Balakrishna Godavarthi wrote:
> > > > > Add support to set voltage/current of various regulators
> > > > > to power up/down Bluetooth chip wcn3990.
> > > > >
> > > > > Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
> > > > > ---
> > > > > changes in v9:
> > > > >     * moved flow control to vendor and set_baudarte functions.
> > > > >     * removed parent regs.
> > > > >
> > > > > changes in v8:
> > > > >     * closing qca buffer, if qca_power_setup fails
> > > > >     * chnaged ibs start timer function call location.
> > > > >     * updated review comments.
> > > > >
> > > > > changes in v7:
> > > > >     * addressed review comments.
> > > > >
> > > > > changes in v6:
> > > > >     * Hooked up qca_power to qca_serdev.
> > > > >     * renamed all the naming inconsistency functions with qca_*
> > > > >     * leveraged common code of ROME for wcn3990.
> > > > >     * created wrapper functions for re-usable blocks.
> > > > >     * updated function of _*regulator_enable and _*regualtor_disable.
> > > > >     * removed redundant comments and functions.
> > > > >     * addressed review comments.
> > > > >
> > > > > Changes in v5:
> > > > >     * updated regulator vddpa min_uV to 1304000.
> > > > >       * addressed review comments.
> > > > >
> > > > > Changes in v4:
> > > > >     * Segregated the changes of btqca from hci_qca
> > > > >     * rebased all changes on top of bluetooth-next.
> > > > >     * addressed review comments.
> > > > >
> > > > > ---
> > > > >  drivers/bluetooth/btqca.h   |   3 +
> > > > >  drivers/bluetooth/hci_qca.c | 387
> > > > > +++++++++++++++++++++++++++++++-----
> > > > >  2 files changed, 345 insertions(+), 45 deletions(-)
> > > > >
> > > > > diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
> > > > > index a9c2779f3e07..0c01f375fe83 100644
> > > > > --- a/drivers/bluetooth/btqca.h
> > > > > +++ b/drivers/bluetooth/btqca.h
> > > > > @@ -37,6 +37,9 @@
> > > > >  #define EDL_TAG_ID_HCI			(17)
> > > > >  #define EDL_TAG_ID_DEEP_SLEEP		(27)
> > > > >
> > > > > +#define QCA_WCN3990_POWERON_PULSE	0xFC
> > > > > +#define QCA_WCN3990_POWEROFF_PULSE	0xC0
> > > > > +
> > > > >  enum qca_bardrate {
> > > > >  	QCA_BAUDRATE_115200 	= 0,
> > > > >  	QCA_BAUDRATE_57600,
> > > > > diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> > > > > index 7ebfaa0edf3f..d62c7785a618 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...
> > > > > @@ -31,9 +31,14 @@
> > > > >  #include <linux/kernel.h>
> > > > >  #include <linux/clk.h>
> > > > >  #include <linux/debugfs.h>
> > > > > +#include <linux/delay.h>
> > > > > +#include <linux/device.h>
> > > > >  #include <linux/gpio/consumer.h>
> > > > >  #include <linux/mod_devicetable.h>
> > > > >  #include <linux/module.h>
> > > > > +#include <linux/of_device.h>
> > > > > +#include <linux/platform_device.h>
> > > > > +#include <linux/regulator/consumer.h>
> > > > >  #include <linux/serdev.h>
> > > > >
> > > > >  #include <net/bluetooth/bluetooth.h>
> > > > > @@ -124,12 +129,46 @@ enum qca_speed_type {
> > > > >  	QCA_OPER_SPEED
> > > > >  };
> > > > >
> > > > > +/*
> > > > > + * Voltage regulator information required for configuring the
> > > > > + * QCA Bluetooth chipset
> > > > > + */
> > > > > +struct qca_vreg {
> > > > > +	const char *name;
> > > > > +	unsigned int min_uV;
> > > > > +	unsigned int max_uV;
> > > > > +	unsigned int load_uA;
> > > > > +};
> > > > > +
> > > > > +struct qca_vreg_data {
> > > > > +	enum qca_btsoc_type soc_type;
> > > > > +	struct qca_vreg *vregs;
> > > > > +	size_t num_vregs;
> > > > > +};
> > > > > +
> > > > > +/*
> > > > > + * Platform data for the QCA Bluetooth power driver.
> > > > > + */
> > > > > +struct qca_power {
> > > > > +	struct device *dev;
> > > > > +	const struct qca_vreg_data *vreg_data;
> > > > > +	struct regulator_bulk_data *vreg_bulk;
> > > > > +	bool vregs_on;
> > > > > +};
> > > > > +
> > > > >  struct qca_serdev {
> > > > >  	struct hci_uart	 serdev_hu;
> > > > >  	struct gpio_desc *bt_en;
> > > > >  	struct clk	 *susclk;
> > > > > +	enum qca_btsoc_type btsoc_type;
> > > > > +	struct qca_power *bt_power;
> > > > > +	u32 init_speed;
> > > > > +	u32 oper_speed;
> > > > >  };
> > > > >
> > > > > +static int qca_power_setup(struct hci_uart *hu, bool on);
> > > > > +static void qca_power_shutdown(struct hci_uart *hu);
> > > > > +
> > > > >  static void __serial_clock_on(struct tty_struct *tty)
> > > > >  {
> > > > >  	/* TODO: Some chipset requires to enable UART clock on client
> > > > > @@ -407,6 +446,7 @@ static int qca_open(struct hci_uart *hu)
> > > > >  {
> > > > >  	struct qca_serdev *qcadev;
> > > > >  	struct qca_data *qca;
> > > > > +	int ret;
> > > > >
> > > > >  	BT_DBG("hu %p qca_open", hu);
> > > > >
> > > > > @@ -458,19 +498,32 @@ static int qca_open(struct hci_uart *hu)
> > > > >
> > > > >  	hu->priv = qca;
> > > > >
> > > > > -	timer_setup(&qca->wake_retrans_timer,
> > > > > hci_ibs_wake_retrans_timeout, 0);
> > > > > -	qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
> > > > > -
> > > > > -	timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
> > > > > -	qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
> > > > > -
> > > > >  	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 != QCA_WCN3990) {
> > > > > +			gpiod_set_value_cansleep(qcadev->bt_en, 1);
> > > > > +		} else {
> > > > > +			hu->init_speed = qcadev->init_speed;
> > > > > +			hu->oper_speed = qcadev->oper_speed;
> > > > > +			ret = qca_power_setup(hu, true);
> > > > > +			if (ret) {
> > > > > +				destroy_workqueue(qca->workqueue);
> > > > > +				kfree_skb(qca->rx_skb);
> > > > > +				hu->priv = NULL;
> > > > > +				kfree(qca);
> > > > > +				return ret;
> > > > > +			}
> > > > > +		}
> > > > >  	}
> > > > >
> > > > > +	timer_setup(&qca->wake_retrans_timer,
> > > > > hci_ibs_wake_retrans_timeout, 0);
> > > > > +	qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
> > > > > +
> > > > > +	timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
> > > > > +	qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
> > > > > +
> > > > >  	BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u",
> > > > >  	       qca->tx_idle_delay, qca->wake_retrans);
> > > > >
> > > > > @@ -554,10 +607,13 @@ static int qca_close(struct hci_uart *hu)
> > > > >  	qca->hu = NULL;
> > > > >
> > > > >  	if (hu->serdev) {
> > > > > -		serdev_device_close(hu->serdev);
> > > > > -
> > > > >  		qcadev = serdev_device_get_drvdata(hu->serdev);
> > > > > -		gpiod_set_value_cansleep(qcadev->bt_en, 0);
> > > > > +		if (qcadev->btsoc_type == QCA_WCN3990)
> > > > > +			qca_power_shutdown(hu);
> > > > > +		else
> > > > > +			gpiod_set_value_cansleep(qcadev->bt_en, 0);
> > > > > +
> > > > > +		serdev_device_close(hu->serdev);
> > > > >  	}
> > > > >
> > > > >  	kfree_skb(qca->rx_skb);
> > > > > @@ -891,6 +947,7 @@ static int qca_set_baudrate(struct hci_dev
> > > > > *hdev, uint8_t baudrate)
> > > > >  	struct hci_uart *hu = hci_get_drvdata(hdev);
> > > > >  	struct qca_data *qca = hu->priv;
> > > > >  	struct sk_buff *skb;
> > > > > +	struct qca_serdev *qcadev;
> > > > >  	u8 cmd[] = { 0x01, 0x48, 0xFC, 0x01, 0x00 };
> > > > >
> > > > >  	if (baudrate > QCA_BAUDRATE_3200000)
> > > > > @@ -904,6 +961,13 @@ static int qca_set_baudrate(struct hci_dev
> > > > > *hdev, uint8_t baudrate)
> > > > >  		return -ENOMEM;
> > > > >  	}
> > > > >
> > > > > +	/* Disabling hardware flow control is mandate while
> > > >
> > > > nit: s/mandate/mandatory|required/
> > > >
> > > > > +	 * sending change baudrate request to wcn3990 SoC.
> > > > > +	 */
> > > > > +	qcadev = serdev_device_get_drvdata(hu->serdev);
> > > > > +	if (qcadev->btsoc_type == QCA_WCN3990)
> > > > > +		hci_uart_set_flow_control(hu, true);
> > > > > +
> > > > >  	/* Assign commands to change baudrate and packet type. */
> > > > >  	skb_put_data(skb, cmd, sizeof(cmd));
> > > > >  	hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
> > > > > @@ -919,6 +983,9 @@ static int qca_set_baudrate(struct hci_dev
> > > > > *hdev, uint8_t baudrate)
> > > > >  	schedule_timeout(msecs_to_jiffies(BAUDRATE_SETTLE_TIMEOUT_MS));
> > > > >  	set_current_state(TASK_RUNNING);
> > > > >
> > > > > +	if (qcadev->btsoc_type == QCA_WCN3990)
> > > > > +		hci_uart_set_flow_control(hu, false);
> > > > > +
> > > > >  	return 0;
> > > > >  }
> > > > >
> > > > > @@ -930,6 +997,36 @@ static inline void host_set_baudrate(struct
> > > > > hci_uart *hu, unsigned int speed)
> > > > >  		hci_uart_set_baudrate(hu, speed);
> > > > >  }
> > > > >
> > > > > +static int qca_send_vendor_cmd(struct hci_dev *hdev, u8 cmd)
> > > > > +{
> > > > > +	struct hci_uart *hu = hci_get_drvdata(hdev);
> > > > > +	struct qca_data *qca = hu->priv;
> > > > > +	struct sk_buff *skb;
> > > > > +
> > > > > +	bt_dev_dbg(hdev, "sending command %02x to SoC", cmd);
> > > > > +
> > > > > +	skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
> > > > > +	if (!skb)
> > > > > +		return -ENOMEM;
> > > > > +
> > > > > +	/* Disabling hardware flow control is mandate while
> > > >
> > > > Same nit as above
> > > >
> > > > > +	 * sending vendor power on and off pulse to SoC.
> > > > > +	 */
> > > >
> > > > The function is called qca_send_vendor_cmd(), the comment about power
> > > > on/off pulses seems misplaced here. Are there other 'vendor commands'
> > > > that require a different flow control behavior?
> > > >
> > > > Perhaps the function should have a different name or we need another
> > > > wrapper.
> > > >
> > > > > +	hci_uart_set_flow_control(hu, true);
> > > >
> > > > Should the changing of the flow control be limited to wcn3990? As of
> > > > now the function is only called for wcn3990, however this is not
> > > > stated as a requirement and might change in the future.
> > > >
> > > > > +	skb_put_u8(skb, 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 */
> > > > > +	usleep_range(100, 200);
> > > >
> > > > Is this needed for any 'vendor command' or directly related with the
> > > > power on/off pulses?
> > > >
> > > > > +	hci_uart_set_flow_control(hu, false);
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > >  static unsigned int qca_get_speed(struct hci_uart *hu,
> > > > >  				  enum qca_speed_type speed_type)
> > > > >  {
> > > > > @@ -952,10 +1049,19 @@ static unsigned int qca_get_speed(struct
> > > > > hci_uart *hu,
> > > > >
> > > > >  static int qca_check_speeds(struct hci_uart *hu)
> > > > >  {
> > > > > -	/* One or the other speeds should be non zero. */
> > > > > -	if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
> > > > > -	    !qca_get_speed(hu, QCA_OPER_SPEED))
> > > > > +	struct qca_serdev *qcadev;
> > > > > +
> > > > > +	qcadev = serdev_device_get_drvdata(hu->serdev);
> > > > > +	if ((qcadev->btsoc_type == QCA_WCN3990 &&
> > > > > +	    !qca_get_speed(hu, QCA_INIT_SPEED)) ||
> > > > > +	    !qca_get_speed(hu, QCA_OPER_SPEED)) {
> > > > > +		/* Both INIT and OPER speed should be non zero. */
> > > > >  		return -EINVAL;
> > > > > +	} else if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
> > > > > +		    !qca_get_speed(hu, QCA_OPER_SPEED)) {
> > > > > +		/* One or the other speeds should be non zero. */
> > > > > +		return -EINVAL;
> > > > > +	}
> > > >
> > > > It is questionable if the comments are useful, they are basically
> > > > stating the same as the conditions.
> > > >
> > > > if-else statements with a single statement in all branches shouldn't
> > > > use curly braces. Personally I don't dislike them in this case with
> > > > the multi-line conditions, but in principle they shoulnd't be there.
> > > >
> > > > nit: this would be easier to read with nested if statements:
> > > >
> > > > 	if (qcadev->btsoc_type == QCA_WCN3990)
> > > > 		if (!qca_get_speed(hu, QCA_INIT_SPEED)) ||
> > > > 		    !qca_get_speed(hu, QCA_OPER_SPEED))
> > > > 			return -EINVAL;
> > > > 	else
> > > > 		if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
> > > > 		    !qca_get_speed(hu, QCA_OPER_SPEED)) {
> > > > 			return -EINVAL;
> > > >
> > > > >  	return 0;
> > > > >  }
> > > > > @@ -986,15 +1092,40 @@ static int qca_set_speed(struct hci_uart *hu,
> > > > > enum qca_speed_type speed_type)
> > > > >  	return 0;
> > > > >  }
> > > > >
> > > > > +static int qca_wcn3990_init(struct hci_uart *hu)
> > > > > +{
> > > > > +	int ret;
> > > > > +
> > > > > +	ret = qca_send_vendor_cmd(hu->hdev, QCA_WCN3990_POWERON_PULSE);
> > > > > +	if (ret)
> > > > > +		return ret;
> > > > > +
> > > > > +	/* Wait for 100 ms for SoC to boot up */
> > > > > +	msleep(100);
> > > > > +	serdev_device_close(hu->serdev);
> > > > > +	ret = serdev_device_open(hu->serdev);
> > > > > +	if (ret) {
> > > > > +		bt_dev_err(hu->hdev, "failed to open port");
> > > > > +		return ret;
> > > > > +	}
> > > > > +
> > > > > +	/* Setup initial baudrate */
> > > > > +	qca_set_speed(hu, QCA_INIT_SPEED);
> > > >
> > > > The comment is a bit redundant.
> > > >
> > > > > +	hci_uart_set_flow_control(hu, false);
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > >  static int qca_setup(struct hci_uart *hu)
> > > > >  {
> > > > >  	struct hci_dev *hdev = hu->hdev;
> > > > >  	struct qca_data *qca = hu->priv;
> > > > >  	unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200;
> > > > > +	struct qca_serdev *qcadev;
> > > > >  	int ret;
> > > > >  	int soc_ver = 0;
> > > > >
> > > > > -	bt_dev_info(hdev, "ROME setup");
> > > > > +	qcadev = serdev_device_get_drvdata(hu->serdev);
> > > > >
> > > > >  	ret = qca_check_speeds(hu);
> > > > >  	if (ret)
> > > > > @@ -1006,6 +1137,21 @@ static int qca_setup(struct hci_uart *hu)
> > > > >  	/* Setup initial baudrate */
> > > > >  	qca_set_speed(hu, QCA_INIT_SPEED);
> > > > >
> > > > > +	if (qcadev->btsoc_type == QCA_WCN3990) {
> > > > > +		bt_dev_dbg(hdev, "setting up wcn3990");
> > > >
> > > > Seems like this should be bt_dev_info() for consistency with Rome.
> > > >
> > > > > +		ret = qca_wcn3990_init(hu);
> > > > > +		if (ret)
> > > > > +			return ret;
> > > > > +
> > > > > +		ret = qca_read_soc_version(hdev, &soc_ver);
> > > > > +		if (ret < 0 || soc_ver == 0) {
> > > > > +			bt_dev_err(hdev, "Failed to get version %d", ret);
> > > > > +			return ret;
> > > > > +		}
> > > > > +	} else {
> > > > > +		bt_dev_info(hdev, "ROME setup");
> > > > > +	}
> > > > > +
> > > > >  	/* Setup user speed if needed */
> > > > >  	speed = qca_get_speed(hu, QCA_OPER_SPEED);
> > > > >  	if (speed) {
> > > > > @@ -1016,16 +1162,18 @@ static int qca_setup(struct hci_uart *hu)
> > > > >  		qca_baudrate = qca_get_baudrate_value(speed);
> > > > >  	}
> > > > >
> > > > > -	/* Get QCA version information */
> > > > > -	ret = qca_read_soc_version(hdev, &soc_ver);
> > > > > -	if (ret < 0 || soc_ver == 0) {
> > > > > -		bt_dev_err(hdev, "QCA Failed to get version (%d)", ret);
> > > > > -		return ret;
> > > > > +	if (!soc_ver) {
> > > >
> > > >
> > > > The following would probably be clearer:
> > > >
> > > >   	if (qcadev->btsoc_type != QCA_WCN3990) {
> > > >
> > > > > +		/* Get QCA version information */
> > > > > +		ret = qca_read_soc_version(hdev, &soc_ver);
> > > > > +		if (ret < 0 || soc_ver == 0) {
> > > > > +			bt_dev_err(hdev, "QCA Failed to get version (%d)", ret);
> > > > > +			return ret;
> > > > > +		}
> > > > > +		bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
> > > >
> > > > Couldn't we hide some of this in qca_read_soc_version()?
> > > >
> > > > qca_read_soc_version() could at least do the logging in the error case
> > > > (the 'soc_ver == 0' case could be handled there as well), which would
> > > > leave us with:
> > > >
> > > >
> > > > 	ret = qca_read_soc_version(hdev, &soc_ver);
> > > > 	if (ret)
> > > > 		return ret;
> > > >
> > > > And the same above.
> > > >
> > > > The controller version can be logged outside of the branch for both
> > > > wcn3990 and Rome.
> > > >
> > > > >  	}
> > > > > -	bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
> > > > >
> > > > >  	/* Setup patch / NVM configurations */
> > > > > -	ret = qca_uart_setup(hdev, qca_baudrate, QCA_ROME, soc_ver);
> > > > > +	ret = qca_uart_setup(hdev, qca_baudrate, qcadev->btsoc_type,
> > > > > soc_ver);
> > > > >  	if (!ret) {
> > > > >  		set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
> > > > >  		qca_debugfs_init(hdev);
> > > > > @@ -1061,9 +1209,123 @@ static struct hci_uart_proto qca_proto = {
> > > > >  	.dequeue	= qca_dequeue,
> > > > >  };
> > > > >
> > > > > +static const struct qca_vreg_data qca_soc_data = {
> > > > > +	.soc_type = QCA_WCN3990,
> > > > > +	.vregs = (struct qca_vreg []) {
> > > > > +		{ "vddio",   1800000, 1800000,  0 },
> > > > > +		{ "vddxo",   1800000, 1800000,  1 },
> > > > > +		{ "vddrf",   1304000, 1304000,  1 },
> > > > > +		{ "vddch0",  3000000, 3312000,  1 },
> > > > > +	},
> > > > > +	.num_vregs = 4,
> > > > > +};
> > > >
> > > > I didn't chime in earlier in the discussion with Stephen on the
> > > > regulators (https://patchwork.kernel.org/patch/10467911/), however I
> > > > agree with him that specifying at load of 1uA doesn't seem to make
> > > > much sense. What would happen if the load remained unspecified (or 0)?
> > > 
> > > [Bala]: On RPMh based designs, calling a regulator_set_load with a
> > > non-zero
> > > value moves the regulator to NPM (high power mode) which is required
> > > for BT
> > > communication.
> > >         and call with 0uA  moves it to low-power-mode (vote from
> > > APPS).
> > > Basically whenever BT wants these in NPM  it calls set-load with 1.
> > 
> > This assumes that the chip is powered by RPMh regulators, which
> > depending on the system may or may not be true. On systems with other
> > regulators you are telling the regulator that the max load is 1uA, and
> > the regulator might comply, going in a low power mode that does not
> > provide enough current for the chip to operate properly.
> > 
> > Doesn't the datasheet of the chip specify actual max currents for
> > these consumers that could be used instead of the bogus 1uA? If not
> > you could ask the designers of the chip for an approximate number
> > (preferably erring on the upper side).
> 
> [Bala]: yes your true, now current values are aligned according to the RPMH
> regs packages.
>         this is not our goal. what ever the package we use wcn3990 should be
> platform independent.
>         I propose an idea that, we will have default current value in driver
> i.e current required by regs to turn on wcn3990 and also we will provide
> interface in driver
>         to read current from dts tree.
> 
>        i.e. if we have prop for current to the reg in the dts, we will read
> the value assigned to prop else we will take default current
> 
>   <code snippets>
> 
>        qca->vreg_data->vregs[i].name = current; // holds the default current

I suppose this should be 'qca->vreg_data->vregs[i].load_uA'

> value taken from data provided from deb. this will value remains unchanged.
>        if (device_property_read_bool(dev, prop_name))  // if we have prop
> name enabled then read the value.
>                 device_property_read_u32(dev, prop_name, &vregs->load_uA);

It's still not clear why this would be needed. Is 1uA a magic value
that is somehow used by RPMh regulators?

Earlier you said:

> > > [Bala]: On RPMh based designs, calling a regulator_set_load with a
> > > non-zero
> > > value moves the regulator to NPM (high power mode) which is required
> > > for BT
> > > communication.
> > >         and call with 0uA  moves it to low-power-mode (vote from
> > > APPS).
> > > Basically whenever BT wants these in NPM  it calls set-load with 1.

This is the ->set_load function of the RPMh regulator:

static int rpmh_regulator_vrm_set_load(struct regulator_dev *rdev, int load_uA)
{
	struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
	unsigned int mode;

	if (load_uA >= vreg->hw_data->hpm_min_load_uA)
		mode = REGULATOR_MODE_NORMAL;
	else
		mode = REGULATOR_MODE_IDLE;

	return rpmh_regulator_vrm_set_mode(rdev, mode);
}

and REGULATOR_MODE_NORMAL translates to HPM for PMIC4 LDOs:

static const int pmic_mode_map_pmic4_ldo[REGULATOR_MODE_STANDBY + 1] = {
	[REGULATOR_MODE_INVALID] = -EINVAL,
	[REGULATOR_MODE_STANDBY] = PMIC4_LDO_MODE_RETENTION,
	[REGULATOR_MODE_IDLE]    = PMIC4_LDO_MODE_LPM,
	[REGULATOR_MODE_NORMAL]  = PMIC4_LDO_MODE_HPM,
	[REGULATOR_MODE_FAST]    = -EINVAL,
};

https://patchwork.kernel.org/patch/10524299/

I don't see how a load value of 1uA would cause the regulator to enter
HPM and another higher value wouldn't. HPM is entered as long as
'load_uA >= vreg->hw_data->hpm_min_load_uA', or am I missing
something here?

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

* Re: [PATCH v9 7/7] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990
  2018-07-18 17:13           ` Matthias Kaehlcke
@ 2018-07-20 12:46             ` Balakrishna Godavarthi
  0 siblings, 0 replies; 24+ messages in thread
From: Balakrishna Godavarthi @ 2018-07-20 12:46 UTC (permalink / raw)
  To: Matthias Kaehlcke
  Cc: marcel, johan.hedberg, linux-kernel, devicetree, linux-bluetooth,
	thierry.escande, rtatiya, hemantg, linux-arm-msm, Stephen Boyd

Hi Matthias,

On 2018-07-18 22:43, Matthias Kaehlcke wrote:
> On Wed, Jul 18, 2018 at 09:03:08PM +0530, Balakrishna Godavarthi wrote:
>> Hi Matthias,
>> 
>> On 2018-07-16 21:35, Matthias Kaehlcke wrote:
>> > On Mon, Jul 16, 2018 at 07:21:56PM +0530, Balakrishna Godavarthi wrote:
>> > > Hi Matthias,
>> > >
>> > > On 2018-07-07 03:51, Matthias Kaehlcke wrote:
>> > > > On Thu, Jul 05, 2018 at 10:25:15PM +0530, Balakrishna Godavarthi wrote:
>> > > > > Add support to set voltage/current of various regulators
>> > > > > to power up/down Bluetooth chip wcn3990.
>> > > > >
>> > > > > Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org>
>> > > > > ---
>> > > > > changes in v9:
>> > > > >     * moved flow control to vendor and set_baudarte functions.
>> > > > >     * removed parent regs.
>> > > > >
>> > > > > changes in v8:
>> > > > >     * closing qca buffer, if qca_power_setup fails
>> > > > >     * chnaged ibs start timer function call location.
>> > > > >     * updated review comments.
>> > > > >
>> > > > > changes in v7:
>> > > > >     * addressed review comments.
>> > > > >
>> > > > > changes in v6:
>> > > > >     * Hooked up qca_power to qca_serdev.
>> > > > >     * renamed all the naming inconsistency functions with qca_*
>> > > > >     * leveraged common code of ROME for wcn3990.
>> > > > >     * created wrapper functions for re-usable blocks.
>> > > > >     * updated function of _*regulator_enable and _*regualtor_disable.
>> > > > >     * removed redundant comments and functions.
>> > > > >     * addressed review comments.
>> > > > >
>> > > > > Changes in v5:
>> > > > >     * updated regulator vddpa min_uV to 1304000.
>> > > > >       * addressed review comments.
>> > > > >
>> > > > > Changes in v4:
>> > > > >     * Segregated the changes of btqca from hci_qca
>> > > > >     * rebased all changes on top of bluetooth-next.
>> > > > >     * addressed review comments.
>> > > > >
>> > > > > ---
>> > > > >  drivers/bluetooth/btqca.h   |   3 +
>> > > > >  drivers/bluetooth/hci_qca.c | 387
>> > > > > +++++++++++++++++++++++++++++++-----
>> > > > >  2 files changed, 345 insertions(+), 45 deletions(-)
>> > > > >
>> > > > > diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
>> > > > > index a9c2779f3e07..0c01f375fe83 100644
>> > > > > --- a/drivers/bluetooth/btqca.h
>> > > > > +++ b/drivers/bluetooth/btqca.h
>> > > > > @@ -37,6 +37,9 @@
>> > > > >  #define EDL_TAG_ID_HCI			(17)
>> > > > >  #define EDL_TAG_ID_DEEP_SLEEP		(27)
>> > > > >
>> > > > > +#define QCA_WCN3990_POWERON_PULSE	0xFC
>> > > > > +#define QCA_WCN3990_POWEROFF_PULSE	0xC0
>> > > > > +
>> > > > >  enum qca_bardrate {
>> > > > >  	QCA_BAUDRATE_115200 	= 0,
>> > > > >  	QCA_BAUDRATE_57600,
>> > > > > diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
>> > > > > index 7ebfaa0edf3f..d62c7785a618 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...
>> > > > > @@ -31,9 +31,14 @@
>> > > > >  #include <linux/kernel.h>
>> > > > >  #include <linux/clk.h>
>> > > > >  #include <linux/debugfs.h>
>> > > > > +#include <linux/delay.h>
>> > > > > +#include <linux/device.h>
>> > > > >  #include <linux/gpio/consumer.h>
>> > > > >  #include <linux/mod_devicetable.h>
>> > > > >  #include <linux/module.h>
>> > > > > +#include <linux/of_device.h>
>> > > > > +#include <linux/platform_device.h>
>> > > > > +#include <linux/regulator/consumer.h>
>> > > > >  #include <linux/serdev.h>
>> > > > >
>> > > > >  #include <net/bluetooth/bluetooth.h>
>> > > > > @@ -124,12 +129,46 @@ enum qca_speed_type {
>> > > > >  	QCA_OPER_SPEED
>> > > > >  };
>> > > > >
>> > > > > +/*
>> > > > > + * Voltage regulator information required for configuring the
>> > > > > + * QCA Bluetooth chipset
>> > > > > + */
>> > > > > +struct qca_vreg {
>> > > > > +	const char *name;
>> > > > > +	unsigned int min_uV;
>> > > > > +	unsigned int max_uV;
>> > > > > +	unsigned int load_uA;
>> > > > > +};
>> > > > > +
>> > > > > +struct qca_vreg_data {
>> > > > > +	enum qca_btsoc_type soc_type;
>> > > > > +	struct qca_vreg *vregs;
>> > > > > +	size_t num_vregs;
>> > > > > +};
>> > > > > +
>> > > > > +/*
>> > > > > + * Platform data for the QCA Bluetooth power driver.
>> > > > > + */
>> > > > > +struct qca_power {
>> > > > > +	struct device *dev;
>> > > > > +	const struct qca_vreg_data *vreg_data;
>> > > > > +	struct regulator_bulk_data *vreg_bulk;
>> > > > > +	bool vregs_on;
>> > > > > +};
>> > > > > +
>> > > > >  struct qca_serdev {
>> > > > >  	struct hci_uart	 serdev_hu;
>> > > > >  	struct gpio_desc *bt_en;
>> > > > >  	struct clk	 *susclk;
>> > > > > +	enum qca_btsoc_type btsoc_type;
>> > > > > +	struct qca_power *bt_power;
>> > > > > +	u32 init_speed;
>> > > > > +	u32 oper_speed;
>> > > > >  };
>> > > > >
>> > > > > +static int qca_power_setup(struct hci_uart *hu, bool on);
>> > > > > +static void qca_power_shutdown(struct hci_uart *hu);
>> > > > > +
>> > > > >  static void __serial_clock_on(struct tty_struct *tty)
>> > > > >  {
>> > > > >  	/* TODO: Some chipset requires to enable UART clock on client
>> > > > > @@ -407,6 +446,7 @@ static int qca_open(struct hci_uart *hu)
>> > > > >  {
>> > > > >  	struct qca_serdev *qcadev;
>> > > > >  	struct qca_data *qca;
>> > > > > +	int ret;
>> > > > >
>> > > > >  	BT_DBG("hu %p qca_open", hu);
>> > > > >
>> > > > > @@ -458,19 +498,32 @@ static int qca_open(struct hci_uart *hu)
>> > > > >
>> > > > >  	hu->priv = qca;
>> > > > >
>> > > > > -	timer_setup(&qca->wake_retrans_timer,
>> > > > > hci_ibs_wake_retrans_timeout, 0);
>> > > > > -	qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
>> > > > > -
>> > > > > -	timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
>> > > > > -	qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
>> > > > > -
>> > > > >  	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 != QCA_WCN3990) {
>> > > > > +			gpiod_set_value_cansleep(qcadev->bt_en, 1);
>> > > > > +		} else {
>> > > > > +			hu->init_speed = qcadev->init_speed;
>> > > > > +			hu->oper_speed = qcadev->oper_speed;
>> > > > > +			ret = qca_power_setup(hu, true);
>> > > > > +			if (ret) {
>> > > > > +				destroy_workqueue(qca->workqueue);
>> > > > > +				kfree_skb(qca->rx_skb);
>> > > > > +				hu->priv = NULL;
>> > > > > +				kfree(qca);
>> > > > > +				return ret;
>> > > > > +			}
>> > > > > +		}
>> > > > >  	}
>> > > > >
>> > > > > +	timer_setup(&qca->wake_retrans_timer,
>> > > > > hci_ibs_wake_retrans_timeout, 0);
>> > > > > +	qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
>> > > > > +
>> > > > > +	timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
>> > > > > +	qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
>> > > > > +
>> > > > >  	BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u",
>> > > > >  	       qca->tx_idle_delay, qca->wake_retrans);
>> > > > >
>> > > > > @@ -554,10 +607,13 @@ static int qca_close(struct hci_uart *hu)
>> > > > >  	qca->hu = NULL;
>> > > > >
>> > > > >  	if (hu->serdev) {
>> > > > > -		serdev_device_close(hu->serdev);
>> > > > > -
>> > > > >  		qcadev = serdev_device_get_drvdata(hu->serdev);
>> > > > > -		gpiod_set_value_cansleep(qcadev->bt_en, 0);
>> > > > > +		if (qcadev->btsoc_type == QCA_WCN3990)
>> > > > > +			qca_power_shutdown(hu);
>> > > > > +		else
>> > > > > +			gpiod_set_value_cansleep(qcadev->bt_en, 0);
>> > > > > +
>> > > > > +		serdev_device_close(hu->serdev);
>> > > > >  	}
>> > > > >
>> > > > >  	kfree_skb(qca->rx_skb);
>> > > > > @@ -891,6 +947,7 @@ static int qca_set_baudrate(struct hci_dev
>> > > > > *hdev, uint8_t baudrate)
>> > > > >  	struct hci_uart *hu = hci_get_drvdata(hdev);
>> > > > >  	struct qca_data *qca = hu->priv;
>> > > > >  	struct sk_buff *skb;
>> > > > > +	struct qca_serdev *qcadev;
>> > > > >  	u8 cmd[] = { 0x01, 0x48, 0xFC, 0x01, 0x00 };
>> > > > >
>> > > > >  	if (baudrate > QCA_BAUDRATE_3200000)
>> > > > > @@ -904,6 +961,13 @@ static int qca_set_baudrate(struct hci_dev
>> > > > > *hdev, uint8_t baudrate)
>> > > > >  		return -ENOMEM;
>> > > > >  	}
>> > > > >
>> > > > > +	/* Disabling hardware flow control is mandate while
>> > > >
>> > > > nit: s/mandate/mandatory|required/
>> > > >
>> > > > > +	 * sending change baudrate request to wcn3990 SoC.
>> > > > > +	 */
>> > > > > +	qcadev = serdev_device_get_drvdata(hu->serdev);
>> > > > > +	if (qcadev->btsoc_type == QCA_WCN3990)
>> > > > > +		hci_uart_set_flow_control(hu, true);
>> > > > > +
>> > > > >  	/* Assign commands to change baudrate and packet type. */
>> > > > >  	skb_put_data(skb, cmd, sizeof(cmd));
>> > > > >  	hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
>> > > > > @@ -919,6 +983,9 @@ static int qca_set_baudrate(struct hci_dev
>> > > > > *hdev, uint8_t baudrate)
>> > > > >  	schedule_timeout(msecs_to_jiffies(BAUDRATE_SETTLE_TIMEOUT_MS));
>> > > > >  	set_current_state(TASK_RUNNING);
>> > > > >
>> > > > > +	if (qcadev->btsoc_type == QCA_WCN3990)
>> > > > > +		hci_uart_set_flow_control(hu, false);
>> > > > > +
>> > > > >  	return 0;
>> > > > >  }
>> > > > >
>> > > > > @@ -930,6 +997,36 @@ static inline void host_set_baudrate(struct
>> > > > > hci_uart *hu, unsigned int speed)
>> > > > >  		hci_uart_set_baudrate(hu, speed);
>> > > > >  }
>> > > > >
>> > > > > +static int qca_send_vendor_cmd(struct hci_dev *hdev, u8 cmd)
>> > > > > +{
>> > > > > +	struct hci_uart *hu = hci_get_drvdata(hdev);
>> > > > > +	struct qca_data *qca = hu->priv;
>> > > > > +	struct sk_buff *skb;
>> > > > > +
>> > > > > +	bt_dev_dbg(hdev, "sending command %02x to SoC", cmd);
>> > > > > +
>> > > > > +	skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
>> > > > > +	if (!skb)
>> > > > > +		return -ENOMEM;
>> > > > > +
>> > > > > +	/* Disabling hardware flow control is mandate while
>> > > >
>> > > > Same nit as above
>> > > >
>> > > > > +	 * sending vendor power on and off pulse to SoC.
>> > > > > +	 */
>> > > >
>> > > > The function is called qca_send_vendor_cmd(), the comment about power
>> > > > on/off pulses seems misplaced here. Are there other 'vendor commands'
>> > > > that require a different flow control behavior?
>> > > >
>> > > > Perhaps the function should have a different name or we need another
>> > > > wrapper.
>> > > >
>> > > > > +	hci_uart_set_flow_control(hu, true);
>> > > >
>> > > > Should the changing of the flow control be limited to wcn3990? As of
>> > > > now the function is only called for wcn3990, however this is not
>> > > > stated as a requirement and might change in the future.
>> > > >
>> > > > > +	skb_put_u8(skb, 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 */
>> > > > > +	usleep_range(100, 200);
>> > > >
>> > > > Is this needed for any 'vendor command' or directly related with the
>> > > > power on/off pulses?
>> > > >
>> > > > > +	hci_uart_set_flow_control(hu, false);
>> > > > > +
>> > > > > +	return 0;
>> > > > > +}
>> > > > > +
>> > > > >  static unsigned int qca_get_speed(struct hci_uart *hu,
>> > > > >  				  enum qca_speed_type speed_type)
>> > > > >  {
>> > > > > @@ -952,10 +1049,19 @@ static unsigned int qca_get_speed(struct
>> > > > > hci_uart *hu,
>> > > > >
>> > > > >  static int qca_check_speeds(struct hci_uart *hu)
>> > > > >  {
>> > > > > -	/* One or the other speeds should be non zero. */
>> > > > > -	if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
>> > > > > -	    !qca_get_speed(hu, QCA_OPER_SPEED))
>> > > > > +	struct qca_serdev *qcadev;
>> > > > > +
>> > > > > +	qcadev = serdev_device_get_drvdata(hu->serdev);
>> > > > > +	if ((qcadev->btsoc_type == QCA_WCN3990 &&
>> > > > > +	    !qca_get_speed(hu, QCA_INIT_SPEED)) ||
>> > > > > +	    !qca_get_speed(hu, QCA_OPER_SPEED)) {
>> > > > > +		/* Both INIT and OPER speed should be non zero. */
>> > > > >  		return -EINVAL;
>> > > > > +	} else if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
>> > > > > +		    !qca_get_speed(hu, QCA_OPER_SPEED)) {
>> > > > > +		/* One or the other speeds should be non zero. */
>> > > > > +		return -EINVAL;
>> > > > > +	}
>> > > >
>> > > > It is questionable if the comments are useful, they are basically
>> > > > stating the same as the conditions.
>> > > >
>> > > > if-else statements with a single statement in all branches shouldn't
>> > > > use curly braces. Personally I don't dislike them in this case with
>> > > > the multi-line conditions, but in principle they shoulnd't be there.
>> > > >
>> > > > nit: this would be easier to read with nested if statements:
>> > > >
>> > > > 	if (qcadev->btsoc_type == QCA_WCN3990)
>> > > > 		if (!qca_get_speed(hu, QCA_INIT_SPEED)) ||
>> > > > 		    !qca_get_speed(hu, QCA_OPER_SPEED))
>> > > > 			return -EINVAL;
>> > > > 	else
>> > > > 		if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
>> > > > 		    !qca_get_speed(hu, QCA_OPER_SPEED)) {
>> > > > 			return -EINVAL;
>> > > >
>> > > > >  	return 0;
>> > > > >  }
>> > > > > @@ -986,15 +1092,40 @@ static int qca_set_speed(struct hci_uart *hu,
>> > > > > enum qca_speed_type speed_type)
>> > > > >  	return 0;
>> > > > >  }
>> > > > >
>> > > > > +static int qca_wcn3990_init(struct hci_uart *hu)
>> > > > > +{
>> > > > > +	int ret;
>> > > > > +
>> > > > > +	ret = qca_send_vendor_cmd(hu->hdev, QCA_WCN3990_POWERON_PULSE);
>> > > > > +	if (ret)
>> > > > > +		return ret;
>> > > > > +
>> > > > > +	/* Wait for 100 ms for SoC to boot up */
>> > > > > +	msleep(100);
>> > > > > +	serdev_device_close(hu->serdev);
>> > > > > +	ret = serdev_device_open(hu->serdev);
>> > > > > +	if (ret) {
>> > > > > +		bt_dev_err(hu->hdev, "failed to open port");
>> > > > > +		return ret;
>> > > > > +	}
>> > > > > +
>> > > > > +	/* Setup initial baudrate */
>> > > > > +	qca_set_speed(hu, QCA_INIT_SPEED);
>> > > >
>> > > > The comment is a bit redundant.
>> > > >
>> > > > > +	hci_uart_set_flow_control(hu, false);
>> > > > > +
>> > > > > +	return 0;
>> > > > > +}
>> > > > > +
>> > > > >  static int qca_setup(struct hci_uart *hu)
>> > > > >  {
>> > > > >  	struct hci_dev *hdev = hu->hdev;
>> > > > >  	struct qca_data *qca = hu->priv;
>> > > > >  	unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200;
>> > > > > +	struct qca_serdev *qcadev;
>> > > > >  	int ret;
>> > > > >  	int soc_ver = 0;
>> > > > >
>> > > > > -	bt_dev_info(hdev, "ROME setup");
>> > > > > +	qcadev = serdev_device_get_drvdata(hu->serdev);
>> > > > >
>> > > > >  	ret = qca_check_speeds(hu);
>> > > > >  	if (ret)
>> > > > > @@ -1006,6 +1137,21 @@ static int qca_setup(struct hci_uart *hu)
>> > > > >  	/* Setup initial baudrate */
>> > > > >  	qca_set_speed(hu, QCA_INIT_SPEED);
>> > > > >
>> > > > > +	if (qcadev->btsoc_type == QCA_WCN3990) {
>> > > > > +		bt_dev_dbg(hdev, "setting up wcn3990");
>> > > >
>> > > > Seems like this should be bt_dev_info() for consistency with Rome.
>> > > >
>> > > > > +		ret = qca_wcn3990_init(hu);
>> > > > > +		if (ret)
>> > > > > +			return ret;
>> > > > > +
>> > > > > +		ret = qca_read_soc_version(hdev, &soc_ver);
>> > > > > +		if (ret < 0 || soc_ver == 0) {
>> > > > > +			bt_dev_err(hdev, "Failed to get version %d", ret);
>> > > > > +			return ret;
>> > > > > +		}
>> > > > > +	} else {
>> > > > > +		bt_dev_info(hdev, "ROME setup");
>> > > > > +	}
>> > > > > +
>> > > > >  	/* Setup user speed if needed */
>> > > > >  	speed = qca_get_speed(hu, QCA_OPER_SPEED);
>> > > > >  	if (speed) {
>> > > > > @@ -1016,16 +1162,18 @@ static int qca_setup(struct hci_uart *hu)
>> > > > >  		qca_baudrate = qca_get_baudrate_value(speed);
>> > > > >  	}
>> > > > >
>> > > > > -	/* Get QCA version information */
>> > > > > -	ret = qca_read_soc_version(hdev, &soc_ver);
>> > > > > -	if (ret < 0 || soc_ver == 0) {
>> > > > > -		bt_dev_err(hdev, "QCA Failed to get version (%d)", ret);
>> > > > > -		return ret;
>> > > > > +	if (!soc_ver) {
>> > > >
>> > > >
>> > > > The following would probably be clearer:
>> > > >
>> > > >   	if (qcadev->btsoc_type != QCA_WCN3990) {
>> > > >
>> > > > > +		/* Get QCA version information */
>> > > > > +		ret = qca_read_soc_version(hdev, &soc_ver);
>> > > > > +		if (ret < 0 || soc_ver == 0) {
>> > > > > +			bt_dev_err(hdev, "QCA Failed to get version (%d)", ret);
>> > > > > +			return ret;
>> > > > > +		}
>> > > > > +		bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
>> > > >
>> > > > Couldn't we hide some of this in qca_read_soc_version()?
>> > > >
>> > > > qca_read_soc_version() could at least do the logging in the error case
>> > > > (the 'soc_ver == 0' case could be handled there as well), which would
>> > > > leave us with:
>> > > >
>> > > >
>> > > > 	ret = qca_read_soc_version(hdev, &soc_ver);
>> > > > 	if (ret)
>> > > > 		return ret;
>> > > >
>> > > > And the same above.
>> > > >
>> > > > The controller version can be logged outside of the branch for both
>> > > > wcn3990 and Rome.
>> > > >
>> > > > >  	}
>> > > > > -	bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
>> > > > >
>> > > > >  	/* Setup patch / NVM configurations */
>> > > > > -	ret = qca_uart_setup(hdev, qca_baudrate, QCA_ROME, soc_ver);
>> > > > > +	ret = qca_uart_setup(hdev, qca_baudrate, qcadev->btsoc_type,
>> > > > > soc_ver);
>> > > > >  	if (!ret) {
>> > > > >  		set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
>> > > > >  		qca_debugfs_init(hdev);
>> > > > > @@ -1061,9 +1209,123 @@ static struct hci_uart_proto qca_proto = {
>> > > > >  	.dequeue	= qca_dequeue,
>> > > > >  };
>> > > > >
>> > > > > +static const struct qca_vreg_data qca_soc_data = {
>> > > > > +	.soc_type = QCA_WCN3990,
>> > > > > +	.vregs = (struct qca_vreg []) {
>> > > > > +		{ "vddio",   1800000, 1800000,  0 },
>> > > > > +		{ "vddxo",   1800000, 1800000,  1 },
>> > > > > +		{ "vddrf",   1304000, 1304000,  1 },
>> > > > > +		{ "vddch0",  3000000, 3312000,  1 },
>> > > > > +	},
>> > > > > +	.num_vregs = 4,
>> > > > > +};
>> > > >
>> > > > I didn't chime in earlier in the discussion with Stephen on the
>> > > > regulators (https://patchwork.kernel.org/patch/10467911/), however I
>> > > > agree with him that specifying at load of 1uA doesn't seem to make
>> > > > much sense. What would happen if the load remained unspecified (or 0)?
>> > >
>> > > [Bala]: On RPMh based designs, calling a regulator_set_load with a
>> > > non-zero
>> > > value moves the regulator to NPM (high power mode) which is required
>> > > for BT
>> > > communication.
>> > >         and call with 0uA  moves it to low-power-mode (vote from
>> > > APPS).
>> > > Basically whenever BT wants these in NPM  it calls set-load with 1.
>> >
>> > This assumes that the chip is powered by RPMh regulators, which
>> > depending on the system may or may not be true. On systems with other
>> > regulators you are telling the regulator that the max load is 1uA, and
>> > the regulator might comply, going in a low power mode that does not
>> > provide enough current for the chip to operate properly.
>> >
>> > Doesn't the datasheet of the chip specify actual max currents for
>> > these consumers that could be used instead of the bogus 1uA? If not
>> > you could ask the designers of the chip for an approximate number
>> > (preferably erring on the upper side).
>> 
>> [Bala]: yes your true, now current values are aligned according to the 
>> RPMH
>> regs packages.
>>         this is not our goal. what ever the package we use wcn3990 
>> should be
>> platform independent.
>>         I propose an idea that, we will have default current value in 
>> driver
>> i.e current required by regs to turn on wcn3990 and also we will 
>> provide
>> interface in driver
>>         to read current from dts tree.
>> 
>>        i.e. if we have prop for current to the reg in the dts, we will 
>> read
>> the value assigned to prop else we will take default current
>> 
>>   <code snippets>
>> 
>>        qca->vreg_data->vregs[i].name = current; // holds the default 
>> current
> 
> I suppose this should be 'qca->vreg_data->vregs[i].load_uA'
> 
>> value taken from data provided from deb. this will value remains 
>> unchanged.
>>        if (device_property_read_bool(dev, prop_name))  // if we have 
>> prop
>> name enabled then read the value.
>>                 device_property_read_u32(dev, prop_name, 
>> &vregs->load_uA);
> 
> It's still not clear why this would be needed. Is 1uA a magic value
> that is somehow used by RPMh regulators?
> 
> Earlier you said:
> 
>> > > [Bala]: On RPMh based designs, calling a regulator_set_load with a
>> > > non-zero
>> > > value moves the regulator to NPM (high power mode) which is required
>> > > for BT
>> > > communication.
>> > >         and call with 0uA  moves it to low-power-mode (vote from
>> > > APPS).
>> > > Basically whenever BT wants these in NPM  it calls set-load with 1.
> 
> This is the ->set_load function of the RPMh regulator:
> 
> static int rpmh_regulator_vrm_set_load(struct regulator_dev *rdev, int 
> load_uA)
> {
> 	struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
> 	unsigned int mode;
> 
> 	if (load_uA >= vreg->hw_data->hpm_min_load_uA)
> 		mode = REGULATOR_MODE_NORMAL;
> 	else
> 		mode = REGULATOR_MODE_IDLE;
> 
> 	return rpmh_regulator_vrm_set_mode(rdev, mode);
> }
> 
> and REGULATOR_MODE_NORMAL translates to HPM for PMIC4 LDOs:
> 
> static const int pmic_mode_map_pmic4_ldo[REGULATOR_MODE_STANDBY + 1] = 
> {
> 	[REGULATOR_MODE_INVALID] = -EINVAL,
> 	[REGULATOR_MODE_STANDBY] = PMIC4_LDO_MODE_RETENTION,
> 	[REGULATOR_MODE_IDLE]    = PMIC4_LDO_MODE_LPM,
> 	[REGULATOR_MODE_NORMAL]  = PMIC4_LDO_MODE_HPM,
> 	[REGULATOR_MODE_FAST]    = -EINVAL,
> };
> 
> https://patchwork.kernel.org/patch/10524299/
> 
> I don't see how a load value of 1uA would cause the regulator to enter
> HPM and another higher value wouldn't. HPM is entered as long as
> 'load_uA >= vreg->hw_data->hpm_min_load_uA', or am I missing
> something here?

[Bala]:  yes you are correct, both 0 and 1 uA are are entering into HPM 
mode.
          i have asked info from PMIC vendor to address this query.
          Mean time i have removed 1 uA current from the code and added 
the required current for turning on of WCN3990.

-- 
Regards
Balakrishna.

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

end of thread, other threads:[~2018-07-20 12:47 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-07-05 16:55 [PATCH v9 0/7] Enable Bluetooth functionality for WCN3990 Balakrishna Godavarthi
2018-07-05 16:55 ` [PATCH v9 1/7] dt-bindings: net: bluetooth: Add device tree bindings for QTI chip wcn3990 Balakrishna Godavarthi
2018-07-05 20:42   ` Rob Herring
2018-07-10 12:32     ` Balakrishna Godavarthi
2018-07-05 16:55 ` [PATCH v9 2/7] Bluetooth: btqca: Rename ROME specific functions to generic functions Balakrishna Godavarthi
2018-07-05 16:55 ` [PATCH v9 3/7] Bluetooth: btqca: Redefine qca_uart_setup() to generic function Balakrishna Godavarthi
2018-07-06 22:35   ` Matthias Kaehlcke
2018-07-05 16:55 ` [PATCH v9 4/7] Bluetooth: hci_qca: Add wrapper functions for setting UART speed Balakrishna Godavarthi
2018-07-06 19:40   ` Matthias Kaehlcke
2018-07-10 12:19     ` Balakrishna Godavarthi
2018-07-10 16:12       ` Matthias Kaehlcke
2018-07-05 16:55 ` [PATCH v9 5/7] Bluetooth: hci_qca: Enable 3.2 Mbps operating speed Balakrishna Godavarthi
2018-07-05 16:55 ` [PATCH v9 6/7] Bluetooth: btqca: Add wcn3990 firmware download support Balakrishna Godavarthi
2018-07-05 16:55 ` [PATCH v9 7/7] Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990 Balakrishna Godavarthi
2018-07-06 22:21   ` Matthias Kaehlcke
2018-07-10 12:52     ` Balakrishna Godavarthi
2018-07-10 16:39       ` Matthias Kaehlcke
2018-07-17 15:18         ` Balakrishna Godavarthi
2018-07-16 13:51     ` Balakrishna Godavarthi
2018-07-16 16:05       ` Matthias Kaehlcke
2018-07-17 13:46         ` Balakrishna Godavarthi
2018-07-18 15:33         ` Balakrishna Godavarthi
2018-07-18 17:13           ` Matthias Kaehlcke
2018-07-20 12:46             ` Balakrishna Godavarthi

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).