Skip to contentSkip to conversation

Bluetooth: hci_qca: Enable clocks required for BT SOC

PATCH Superseded Venkata Lakshmi Narayana Gubba 4 participants 9 messages Jan 31, 2020 – Feb 5, 2020

Subsystems (5)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

PATCH v2 1/2 Bluetooth: hci_qca: Enable clocks required for BT SOC

Instead of relying on other subsytem to turn ON clocks required for BT SoC to operate, voting them from the driver.

---
v2:
* addressed forward declarations
* updated with devm_clk_get_optional()

---
 drivers/bluetooth/hci_qca.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)
drivers/bluetooth/hci_qca.c +25 -0
index d6e0c99..73706f3 100644
@@ -1738,6 +1738,15 @@ static int qca_power_off(struct hci_dev *hdev)
 	return 0;
 }
 
+static int qca_setup_clock(struct clk *clk, bool enable)
+{
+	if (enable)
+		return clk_prepare_enable(clk);
+
+	clk_disable_unprepare(clk);
+	return 0;
+}
+
 static int qca_regulator_enable(struct qca_serdev *qcadev)
 {
 	struct qca_power *power = qcadev->bt_power;
@@ -1755,6 +1764,13 @@ static int qca_regulator_enable(struct qca_serdev *qcadev)
 
 	power->vregs_on = true;
 
+	ret = qca_setup_clock(qcadev->susclk, true);
+	if (ret) {
+		/* Turn off regulators to overcome power leakage */
+		qca_regulator_disable(qcadev);
+		return ret;
+	}
+
 	return 0;
 }
 
@@ -1773,6 +1789,9 @@ static void qca_regulator_disable(struct qca_serdev *qcadev)
 
 	regulator_bulk_disable(power->num_vregs, power->vreg_bulk);
 	power->vregs_on = false;
+
+	if (qcadev->susclk)
+		qca_setup_clock(qcadev->susclk, false);
 }
 
 static int qca_init_regulators(struct qca_power *qca,
@@ -1839,6 +1858,12 @@ static int qca_serdev_probe(struct serdev_device *serdev)
 
 		qcadev->bt_power->vregs_on = false;
 
+		qcadev->susclk = devm_clk_get_optional(&serdev->dev, NULL);
+		if (IS_ERR(qcadev->susclk)) {
+			dev_err(&serdev->dev, "failed to acquire clk\n");
+			return PTR_ERR(qcadev->susclk);
+		}
+
 		device_property_read_u32(&serdev->dev, "max-speed",
 					 &qcadev->oper_speed);
 		if (!qcadev->oper_speed)
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member 
of Code Aurora Forum, hosted by The Linux Foundation
#1 lore raw

PATCH v2 2/2 dt-bindings: net: bluetooth: Add device tree bindings for QTI chip WCN3991

Add compatible string for the Qualcomm WCN3991 Bluetooth controller

---
 Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt | 3 +++
 1 file changed, 3 insertions(+)
Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt +3 -0
index 68b67d9..e72045d 100644
@@ -11,6 +11,7 @@ Required properties:
  - compatible: should contain one of the following:
    * "qcom,qca6174-bt"
    * "qcom,wcn3990-bt"
+   * "qcom,wcn3991-bt"
    * "qcom,wcn3998-bt"
 
 Optional properties for compatible string qcom,qca6174-bt:
@@ -30,6 +31,7 @@ Optional properties for compatible string qcom,wcn399x-bt:
 
  - max-speed: see Documentation/devicetree/bindings/serial/slave-device.txt
  - firmware-name: specify the name of nvm firmware to load
+ - clocks: clock provided to the controller
 
 Examples:
 
@@ -56,5 +58,6 @@ serial@898000 {
 		vddch0-supply = <&vreg_l25a_3p3>;
 		max-speed = <3200000>;
 		firmware-name = "crnv21.bin";
+		clocks = <&rpmhcc>;
 	};
 };
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member 
of Code Aurora Forum, hosted by The Linux Foundation
#2 lore raw

Re: [PATCH v2 2/2] dt-bindings: net: bluetooth: Add device tree bindings for QTI chip WCN3991

+ DT folks

Quoted 28 lines · Venkata Lakshmi Narayana Gubba

Add compatible string for the Qualcomm WCN3991 Bluetooth controller

---
 Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt | 3 +++
 1 file changed, 3 insertions(+)
Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt +2 -0
index 68b67d9..e72045d 100644
@@ -11,6 +11,7 @@ Required properties:
  - compatible: should contain one of the following:
    * "qcom,qca6174-bt"
    * "qcom,wcn3990-bt"
+   * "qcom,wcn3991-bt"
    * "qcom,wcn3998-bt"
 
 Optional properties for compatible string qcom,qca6174-bt:
@@ -30,6 +31,7 @@ Optional properties for compatible string qcom,wcn399x-bt:
 
  - max-speed: see Documentation/devicetree/bindings/serial/slave-device.txt
  - firmware-name: specify the name of nvm firmware to load
+ - clocks: clock provided to the controller
 
 Examples:
 

Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt serial@898000 { · line 61

Quoted 4 lines
Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt +1 -0
@@ -56,5 +58,6 @@ serial@898000 {
 		vddch0-supply = <&vreg_l25a_3p3>;
 		max-speed = <3200000>;
 		firmware-name = "crnv21.bin";
+		clocks = <&rpmhcc>;

That specifies a clock controller, not a clock.

For a device with the SC7180 SoC we use this:

		clocks = <&rpmhcc RPMH_RF_CLK2>;
Quoted 2 lines
Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt +0 -0
 	};
 };
#3 lore raw

Re: [PATCH v2 2/2] dt-bindings: net: bluetooth: Add device tree bindings for QTI chip WCN3991

Hi Matthias,

Quoted 40 lines · Matthias Kaehlcke

+ DT folks

Quoted 30 lines · Venkata Lakshmi Narayana Gubba

Add compatible string for the Qualcomm WCN3991 Bluetooth controller

---
 Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt | 3 +++
 1 file changed, 3 insertions(+)
Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt +1 -0
index 68b67d9..e72045d 100644
@@ -11,6 +11,7 @@ Required properties:
  - compatible: should contain one of the following:
    * "qcom,qca6174-bt"
    * "qcom,wcn3990-bt"
+   * "qcom,wcn3991-bt"
    * "qcom,wcn3998-bt"
 
 Optional properties for compatible string qcom,qca6174-bt:
@@ -30,6 +31,7 @@ Optional properties for compatible string 

qcom,wcn399x-bt:

- max-speed: see
Documentation/devicetree/bindings/serial/slave-device.txt
- firmware-name: specify the name of nvm firmware to load
+ - clocks: clock provided to the controller

Examples:

Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt serial@898000 { · line 61

Quoted 4 lines
Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt +1 -0
@@ -56,5 +58,6 @@ serial@898000 {
 		vddch0-supply = <&vreg_l25a_3p3>;
 		max-speed = <3200000>;
 		firmware-name = "crnv21.bin";
+		clocks = <&rpmhcc>;

That specifies a clock controller, not a clock.

Quoted 3 lines

For a device with the SC7180 SoC we use this:

		clocks = <&rpmhcc RPMH_RF_CLK2>;

[Venkata] :

Sure, we will update in next patch set.

Quoted 3 lines

Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt serial@898000 { · line 63

Quoted 3 lines
Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt +0 -0
 	};
 };

Regards,
Venkata.

maintainer
#4 lore raw
In reply to Venkata Lakshmi Narayana Gubba

Hi Venkata,

Quoted 20 lines

Instead of relying on other subsytem to turn ON clocks required for BT SoC to operate, voting them from the driver.

---
v2:
* addressed forward declarations
* updated with devm_clk_get_optional()

---
drivers/bluetooth/hci_qca.c | 25 +++++++++++++++++++++++++

1 file changed, 25 insertions(+)
drivers/bluetooth/hci_qca.c +0 -0
index d6e0c99..73706f3 100644
@@ -1738,6 +1738,15 @@ static int qca_power_off(struct hci_dev *hdev)
 	return 0;
 }

drivers/bluetooth/hci_qca.c static int qca_power_off(struct hci_dev *hdev) · line 1749

Quoted 10 lines
drivers/bluetooth/hci_qca.c +9 -0
 
+static int qca_setup_clock(struct clk *clk, bool enable)
+{
+	if (enable)
+		return clk_prepare_enable(clk);
+
+	clk_disable_unprepare(clk);
+	return 0;
+}
+

this function is pointless and it just complicated the code.

drivers/bluetooth/hci_qca.c static int qca_regulator_enable(struct qca_serdev *qcadev) · line 1767

Quoted 8 lines
drivers/bluetooth/hci_qca.c +1 -0
 static int qca_regulator_enable(struct qca_serdev *qcadev)
 {
 	struct qca_power *power = qcadev->bt_power;
@@ -1755,6 +1764,13 @@ static int qca_regulator_enable(struct qca_serdev *qcadev)
 
 	power->vregs_on = true;
 
+	ret = qca_setup_clock(qcadev->susclk, true);
	ret = clk_prepare_enable(qcadev->susclk);
Quoted 10 lines
drivers/bluetooth/hci_qca.c +6 -0
+	if (ret) {
+		/* Turn off regulators to overcome power leakage */
+		qca_regulator_disable(qcadev);
+		return ret;
+	}
+
 	return 0;
 }
 

drivers/bluetooth/hci_qca.c static void qca_regulator_disable(struct qca_serdev *qcadev) · line 1794

Quoted 6 lines
drivers/bluetooth/hci_qca.c +3 -0
@@ -1773,6 +1789,9 @@ static void qca_regulator_disable(struct qca_serdev *qcadev)
 
 	regulator_bulk_disable(power->num_vregs, power->vreg_bulk);
 	power->vregs_on = false;
+
+	if (qcadev->susclk)
+		qca_setup_clock(qcadev->susclk, false);
		clk_disable_unprepare(qcadev->susclk);
Quoted 6 lines
drivers/bluetooth/hci_qca.c +0 -0
 }
 
 static int qca_init_regulators(struct qca_power *qca,
@@ -1839,6 +1858,12 @@ static int qca_serdev_probe(struct serdev_device *serdev)
 
 		qcadev->bt_power->vregs_on = false;

drivers/bluetooth/hci_qca.c static int qca_serdev_probe(struct serdev_device *serdev) · line 1869

Quoted 10 lines
drivers/bluetooth/hci_qca.c +6 -0
 
+		qcadev->susclk = devm_clk_get_optional(&serdev->dev, NULL);
+		if (IS_ERR(qcadev->susclk)) {
+			dev_err(&serdev->dev, "failed to acquire clk\n");
+			return PTR_ERR(qcadev->susclk);
+		}
+
 		device_property_read_u32(&serdev->dev, "max-speed",
 					 &qcadev->oper_speed);
 		if (!qcadev->oper_speed)

Regards

Marcel

#5 lore raw

Hi Marcel,

Quoted 23 lines · Marcel Holtmann

Hi Venkata,

Quoted 21 lines

Instead of relying on other subsytem to turn ON clocks required for BT SoC to operate, voting them from the driver.

---
v2:
* addressed forward declarations
* updated with devm_clk_get_optional()

---
drivers/bluetooth/hci_qca.c | 25 +++++++++++++++++++++++++

1 file changed, 25 insertions(+)
drivers/bluetooth/hci_qca.c +0 -0
index d6e0c99..73706f3 100644
@@ -1738,6 +1738,15 @@ static int qca_power_off(struct hci_dev *hdev)
 	return 0;
 }
 
Quoted 11 lines

drivers/bluetooth/hci_qca.c static int qca_power_off(struct hci_dev *hdev) · line 1749

Quoted 9 lines
drivers/bluetooth/hci_qca.c +9 -0
+static int qca_setup_clock(struct clk *clk, bool enable)
+{
+	if (enable)
+		return clk_prepare_enable(clk);
+
+	clk_disable_unprepare(clk);
+	return 0;
+}
+

this function is pointless and it just complicated the code.

[Venkata] : Sure we will remove the function and will update in next patch set.

Quoted 7 lines
Quoted 7 lines
drivers/bluetooth/hci_qca.c +0 -0
 static int qca_regulator_enable(struct qca_serdev *qcadev)
 {
 	struct qca_power *power = qcadev->bt_power;
@@ -1755,6 +1764,13 @@ static int qca_regulator_enable(struct 
 qca_serdev *qcadev)
 
Quoted 5 lines

drivers/bluetooth/hci_qca.c static int qca_regulator_enable(struct qca_serdev *qcadev) · line 1767

Quoted 3 lines
drivers/bluetooth/hci_qca.c +1 -0
 	power->vregs_on = true;
 
+	ret = qca_setup_clock(qcadev->susclk, true);
	ret = clk_prepare_enable(qcadev->susclk);

[Venkata] : Sure.We will update in next patch set.

Quoted 13 lines
Quoted 13 lines
drivers/bluetooth/hci_qca.c +6 -0
+	if (ret) {
+		/* Turn off regulators to overcome power leakage */
+		qca_regulator_disable(qcadev);
+		return ret;
+	}
+
 	return 0;
 }
@@ -1773,6 +1789,9 @@ static void qca_regulator_disable(struct 
 qca_serdev *qcadev)
 
Quoted 7 lines

drivers/bluetooth/hci_qca.c static void qca_regulator_disable(struct qca_serdev *qcadev) · line 1794

Quoted 5 lines
drivers/bluetooth/hci_qca.c +3 -0
 	regulator_bulk_disable(power->num_vregs, power->vreg_bulk);
 	power->vregs_on = false;
+
+	if (qcadev->susclk)
+		qca_setup_clock(qcadev->susclk, false);
		clk_disable_unprepare(qcadev->susclk);

[Venkata] : Sure.We will update in next patch set.

Quoted 21 lines
Quoted 17 lines
drivers/bluetooth/hci_qca.c +0 -0
 }
 

static int qca_init_regulators(struct qca_power *qca,

drivers/bluetooth/hci_qca.c +6 -0
@@ -1839,6 +1858,12 @@ static int qca_serdev_probe(struct 
 serdev_device *serdev)
 
 		qcadev->bt_power->vregs_on = false;
 
+		qcadev->susclk = devm_clk_get_optional(&serdev->dev, NULL);
+		if (IS_ERR(qcadev->susclk)) {
+			dev_err(&serdev->dev, "failed to acquire clk\n");
+			return PTR_ERR(qcadev->susclk);
+		}
+
 		device_property_read_u32(&serdev->dev, "max-speed",
 					 &qcadev->oper_speed);
Quoted 1 line
		if (!qcadev->oper_speed)

Regards

Quoted 1 line

Marcel

Regards,
Venkata.

#6 lore raw
In reply to Venkata Lakshmi Narayana Gubba
Quoted 19 lines · Venkata Lakshmi Narayana Gubba

Instead of relying on other subsytem to turn ON clocks required for BT SoC to operate, voting them from the driver.

---
v2:
* addressed forward declarations
* updated with devm_clk_get_optional()

---
 drivers/bluetooth/hci_qca.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)
drivers/bluetooth/hci_qca.c +0 -0
index d6e0c99..73706f3 100644
@@ -1738,6 +1738,15 @@ static int qca_power_off(struct hci_dev *hdev)
 	return 0;

drivers/bluetooth/hci_qca.c static int qca_power_off(struct hci_dev *hdev) · line 1748

Quoted 10 lines
drivers/bluetooth/hci_qca.c +8 -0
 }
 
+static int qca_setup_clock(struct clk *clk, bool enable)
+{
+	if (enable)
+		return clk_prepare_enable(clk);
+
+	clk_disable_unprepare(clk);
+	return 0;
+}

As Marcel requested, inline these.

drivers/bluetooth/hci_qca.c static int qca_regulator_enable(struct qca_serdev *qcadev) · line 1769

Quoted 11 lines
drivers/bluetooth/hci_qca.c +4 -0
+
 static int qca_regulator_enable(struct qca_serdev *qcadev)
 {
 	struct qca_power *power = qcadev->bt_power;
@@ -1755,6 +1764,13 @@ static int qca_regulator_enable(struct qca_serdev *qcadev)
 
 	power->vregs_on = true;
 
+	ret = qca_setup_clock(qcadev->susclk, true);
+	if (ret) {
+		/* Turn off regulators to overcome power leakage */

You can omit this comment as well, as the name of the function you call is aptly named.

drivers/bluetooth/hci_qca.c static int qca_regulator_enable(struct qca_serdev *qcadev) · line 1771

Quoted 2 lines
drivers/bluetooth/hci_qca.c +2 -0
+		qca_regulator_disable(qcadev);
+		return ret;

Just return ret below instead.

drivers/bluetooth/hci_qca.c static void qca_regulator_disable(struct qca_serdev *qcadev) · line 1793

Quoted 11 lines
drivers/bluetooth/hci_qca.c +4 -0
+	}
+
 	return 0;
 }
 
@@ -1773,6 +1789,9 @@ static void qca_regulator_disable(struct qca_serdev *qcadev)
 
 	regulator_bulk_disable(power->num_vregs, power->vreg_bulk);
 	power->vregs_on = false;
+
+	if (qcadev->susclk)

In the enable path you (correctly) rely on passing NULL to the clock code, so do the same here.

Regards,
Bjorn

maintainer
#7 lore raw

Hi Bjorn,

Quoted 59 lines
Quoted 19 lines

Instead of relying on other subsytem to turn ON clocks required for BT SoC to operate, voting them from the driver.

---
v2:
* addressed forward declarations
* updated with devm_clk_get_optional()

---
drivers/bluetooth/hci_qca.c | 25 +++++++++++++++++++++++++

1 file changed, 25 insertions(+)
drivers/bluetooth/hci_qca.c +0 -0
index d6e0c99..73706f3 100644
@@ -1738,6 +1738,15 @@ static int qca_power_off(struct hci_dev *hdev)
 	return 0;

drivers/bluetooth/hci_qca.c static int qca_power_off(struct hci_dev *hdev) · line 1748

Quoted 10 lines
drivers/bluetooth/hci_qca.c +8 -0
 }
 
+static int qca_setup_clock(struct clk *clk, bool enable)
+{
+	if (enable)
+		return clk_prepare_enable(clk);
+
+	clk_disable_unprepare(clk);
+	return 0;
+}

As Marcel requested, inline these.

drivers/bluetooth/hci_qca.c static int qca_regulator_enable(struct qca_serdev *qcadev) · line 1769

Quoted 11 lines
drivers/bluetooth/hci_qca.c +4 -0
+
 static int qca_regulator_enable(struct qca_serdev *qcadev)
 {
 	struct qca_power *power = qcadev->bt_power;
@@ -1755,6 +1764,13 @@ static int qca_regulator_enable(struct qca_serdev *qcadev)
 
 	power->vregs_on = true;
 
+	ret = qca_setup_clock(qcadev->susclk, true);
+	if (ret) {
+		/* Turn off regulators to overcome power leakage */

You can omit this comment as well, as the name of the function you call is aptly named.

drivers/bluetooth/hci_qca.c static int qca_regulator_enable(struct qca_serdev *qcadev) · line 1771

Quoted 2 lines
drivers/bluetooth/hci_qca.c +2 -0
+		qca_regulator_disable(qcadev);
+		return ret;

Just return ret below instead.

Quoted 7 lines
drivers/bluetooth/hci_qca.c +2 -0
+	}
+
 	return 0;
 }
 
@@ -1773,6 +1789,9 @@ static void qca_regulator_disable(struct qca_serdev *qcadev)
 
Quoted 7 lines

drivers/bluetooth/hci_qca.c static void qca_regulator_disable(struct qca_serdev *qcadev) · line 1793

Quoted 4 lines
drivers/bluetooth/hci_qca.c +2 -0
 	regulator_bulk_disable(power->num_vregs, power->vreg_bulk);
 	power->vregs_on = false;
+
+	if (qcadev->susclk)

In the enable path you (correctly) rely on passing NULL to the clock code, so do the same here.

I already pushed the patch, but I am happy to accept a cleanup patch.

Regards

Marcel

#8 lore raw

Hi Bjorn,

Quoted 49 lines · Marcel Holtmann

Hi Bjorn,

Quoted 47 lines
Quoted 19 lines

Instead of relying on other subsytem to turn ON clocks required for BT SoC to operate, voting them from the driver.

---
v2:
* addressed forward declarations
* updated with devm_clk_get_optional()

---
drivers/bluetooth/hci_qca.c | 25 +++++++++++++++++++++++++

1 file changed, 25 insertions(+)
drivers/bluetooth/hci_qca.c +0 -0
index d6e0c99..73706f3 100644
@@ -1738,6 +1738,15 @@ static int qca_power_off(struct hci_dev *hdev)
 	return 0;

drivers/bluetooth/hci_qca.c static int qca_power_off(struct hci_dev *hdev) · line 1748

Quoted 10 lines
drivers/bluetooth/hci_qca.c +8 -0
 }
 
+static int qca_setup_clock(struct clk *clk, bool enable)
+{
+	if (enable)
+		return clk_prepare_enable(clk);
+
+	clk_disable_unprepare(clk);
+	return 0;
+}

As Marcel requested, inline these.

drivers/bluetooth/hci_qca.c static int qca_regulator_enable(struct · line 1770

Quoted 12 lines
drivers/bluetooth/hci_qca.c +4 -0
+
 static int qca_regulator_enable(struct qca_serdev *qcadev)
 {
 	struct qca_power *power = qcadev->bt_power;
@@ -1755,6 +1764,13 @@ static int qca_regulator_enable(struct 
 qca_serdev *qcadev)
 
 	power->vregs_on = true;
 
+	ret = qca_setup_clock(qcadev->susclk, true);
+	if (ret) {
+		/* Turn off regulators to overcome power leakage */

You can omit this comment as well, as the name of the function you call is aptly named.

[Venkata] :
We will update in next patch set.

Quoted 5 lines
Quoted 5 lines

drivers/bluetooth/hci_qca.c static int qca_regulator_enable(struct qca_serdev *qcadev) · line 1771

Quoted 3 lines
drivers/bluetooth/hci_qca.c +2 -0
+		qca_regulator_disable(qcadev);
+		return ret;

Just return ret below instead.

[Venkata] :
We will update in next patch set

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
drivers/bluetooth/hci_qca.c +2 -0
+	}
+
 	return 0;
 }
@@ -1773,6 +1789,9 @@ static void qca_regulator_disable(struct 
 qca_serdev *qcadev)
 
Quoted 7 lines
Quoted 7 lines

drivers/bluetooth/hci_qca.c static void qca_regulator_disable(struct qca_serdev *qcadev) · line 1793

Quoted 4 lines
drivers/bluetooth/hci_qca.c +2 -0
 	regulator_bulk_disable(power->num_vregs, power->vreg_bulk);
 	power->vregs_on = false;
+
+	if (qcadev->susclk)

In the enable path you (correctly) rely on passing NULL to the clock code, so do the same here.

[Venkata] :
We will update in next patch set.

Quoted 6 lines

I already pushed the patch, but I am happy to accept a cleanup patch.

Regards

Marcel

Regards,
Venkata.