From: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
To: Liam Girdwood <lgirdwood@gmail.com>,
Mark Brown <broonie@kernel.org>, Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Bartosz Golaszewski <brgl@kernel.org>,
Marcel Holtmann <marcel@holtmann.org>,
Luiz Augusto von Dentz <luiz.dentz@gmail.com>,
Jeff Johnson <jjohnson@kernel.org>,
Bjorn Andersson <andersson@kernel.org>,
Konrad Dybcio <konradybcio@kernel.org>,
Manivannan Sadhasivam <mani@kernel.org>,
Vinod Koul <vkoul@kernel.org>,
Balakrishna Godavarthi <quic_bgodavar@quicinc.com>,
Matthias Kaehlcke <mka@chromium.org>
Cc: linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
devicetree@vger.kernel.org, linux-bluetooth@vger.kernel.org,
linux-wireless@vger.kernel.org, ath10k@lists.infradead.org,
linux-pm@vger.kernel.org, Krzysztof Kozlowski <krzk@kernel.org>
Subject: [PATCH v2 05/14] power: sequencing: qcom-wcn: add support for WCN39xx
Date: Tue, 06 Jan 2026 03:01:15 +0200 [thread overview]
Message-ID: <20260106-wcn3990-pwrctl-v2-5-0386204328be@oss.qualcomm.com> (raw)
In-Reply-To: <20260106-wcn3990-pwrctl-v2-0-0386204328be@oss.qualcomm.com>
The WCN39xx family of WiFi/BT chips incorporates a simple PMU, spreading
voltages over internal rails. Implement power sequencing support for
this generation of WCN chips. Unlike later devices, they don't have
separate enable GPIO lines, letting the chip figure out the necessary
parts on its own.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/power/sequencing/pwrseq-qcom-wcn.c | 130 +++++++++++++++++++++++++++--
1 file changed, 125 insertions(+), 5 deletions(-)
diff --git a/drivers/power/sequencing/pwrseq-qcom-wcn.c b/drivers/power/sequencing/pwrseq-qcom-wcn.c
index 663d9a537065..c5071708e85e 100644
--- a/drivers/power/sequencing/pwrseq-qcom-wcn.c
+++ b/drivers/power/sequencing/pwrseq-qcom-wcn.c
@@ -23,6 +23,8 @@ struct pwrseq_qcom_wcn_pdata {
unsigned int pwup_delay_ms;
unsigned int gpio_enable_delay_ms;
const struct pwrseq_target_data **targets;
+ bool has_vddio; /* separate VDD IO regulator */
+ int (*match)(struct pwrseq_device *pwrseq, struct device *dev);
};
struct pwrseq_qcom_wcn_ctx {
@@ -30,6 +32,7 @@ struct pwrseq_qcom_wcn_ctx {
struct device_node *of_node;
const struct pwrseq_qcom_wcn_pdata *pdata;
struct regulator_bulk_data *regs;
+ struct regulator *vddio;
struct gpio_desc *bt_gpio;
struct gpio_desc *wlan_gpio;
struct gpio_desc *xo_clk_gpio;
@@ -52,6 +55,26 @@ static void pwrseq_qcom_wcn_ensure_gpio_delay(struct pwrseq_qcom_wcn_ctx *ctx)
msleep(ctx->pdata->gpio_enable_delay_ms - diff_msecs);
}
+static int pwrseq_qcom_wcn_vddio_enable(struct pwrseq_device *pwrseq)
+{
+ struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
+
+ return regulator_enable(ctx->vddio);
+}
+
+static int pwrseq_qcom_wcn_vddio_disable(struct pwrseq_device *pwrseq)
+{
+ struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
+
+ return regulator_disable(ctx->vddio);
+}
+
+static const struct pwrseq_unit_data pwrseq_qcom_wcn_vddio_unit_data = {
+ .name = "vddio-enable",
+ .enable = pwrseq_qcom_wcn_vddio_enable,
+ .disable = pwrseq_qcom_wcn_vddio_disable,
+};
+
static int pwrseq_qcom_wcn_vregs_enable(struct pwrseq_device *pwrseq)
{
struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
@@ -94,6 +117,19 @@ static const struct pwrseq_unit_data pwrseq_qcom_wcn_clk_unit_data = {
.disable = pwrseq_qcom_wcn_clk_disable,
};
+static const struct pwrseq_unit_data *pwrseq_qcom_wcn3990_unit_deps[] = {
+ &pwrseq_qcom_wcn_vddio_unit_data,
+ &pwrseq_qcom_wcn_vregs_unit_data,
+ NULL,
+};
+
+static const struct pwrseq_unit_data pwrseq_qcom_wcn3990_unit_data = {
+ .name = "clock-enable",
+ .deps = pwrseq_qcom_wcn3990_unit_deps,
+ .enable = pwrseq_qcom_wcn_clk_enable,
+ .disable = pwrseq_qcom_wcn_clk_disable,
+};
+
static const struct pwrseq_unit_data *pwrseq_qcom_wcn_unit_deps[] = {
&pwrseq_qcom_wcn_vregs_unit_data,
&pwrseq_qcom_wcn_clk_unit_data,
@@ -229,6 +265,17 @@ static const struct pwrseq_target_data pwrseq_qcom_wcn_wlan_target_data = {
.post_enable = pwrseq_qcom_wcn_pwup_delay,
};
+/* There are no separate BT and WLAN enablement pins */
+static const struct pwrseq_target_data pwrseq_qcom_wcn3990_bt_target_data = {
+ .name = "bluetooth",
+ .unit = &pwrseq_qcom_wcn3990_unit_data,
+};
+
+static const struct pwrseq_target_data pwrseq_qcom_wcn3990_wlan_target_data = {
+ .name = "wlan",
+ .unit = &pwrseq_qcom_wcn3990_unit_data,
+};
+
static const struct pwrseq_target_data pwrseq_qcom_wcn6855_bt_target_data = {
.name = "bluetooth",
.unit = &pwrseq_qcom_wcn6855_bt_unit_data,
@@ -247,6 +294,12 @@ static const struct pwrseq_target_data *pwrseq_qcom_wcn_targets[] = {
NULL
};
+static const struct pwrseq_target_data *pwrseq_qcom_wcn3990_targets[] = {
+ &pwrseq_qcom_wcn3990_bt_target_data,
+ &pwrseq_qcom_wcn3990_wlan_target_data,
+ NULL
+};
+
static const struct pwrseq_target_data *pwrseq_qcom_wcn6855_targets[] = {
&pwrseq_qcom_wcn6855_bt_target_data,
&pwrseq_qcom_wcn6855_wlan_target_data,
@@ -272,6 +325,26 @@ static const struct pwrseq_qcom_wcn_pdata pwrseq_qca6390_of_data = {
.targets = pwrseq_qcom_wcn_targets,
};
+static const char *const pwrseq_wcn3990_vregs[] = {
+ /* vddio is handled separately */
+ "vddxo",
+ "vddrf",
+ "vddch0",
+ "vddch1",
+};
+
+static int pwrseq_qcom_wcn3990_match(struct pwrseq_device *pwrseq,
+ struct device *dev);
+
+static const struct pwrseq_qcom_wcn_pdata pwrseq_wcn3990_of_data = {
+ .vregs = pwrseq_wcn3990_vregs,
+ .num_vregs = ARRAY_SIZE(pwrseq_wcn3990_vregs),
+ .pwup_delay_ms = 50,
+ .targets = pwrseq_qcom_wcn3990_targets,
+ .has_vddio = true,
+ .match = pwrseq_qcom_wcn3990_match,
+};
+
static const char *const pwrseq_wcn6750_vregs[] = {
"vddaon",
"vddasd",
@@ -328,8 +401,9 @@ static const struct pwrseq_qcom_wcn_pdata pwrseq_wcn7850_of_data = {
.targets = pwrseq_qcom_wcn_targets,
};
-static int pwrseq_qcom_wcn_match(struct pwrseq_device *pwrseq,
- struct device *dev)
+static int pwrseq_qcom_wcn_match_regulator(struct pwrseq_device *pwrseq,
+ struct device *dev,
+ const char *name)
{
struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
struct device_node *dev_node = dev->of_node;
@@ -340,11 +414,11 @@ static int pwrseq_qcom_wcn_match(struct pwrseq_device *pwrseq,
* 'vddaon-supply' property and whether it leads us to the right
* device.
*/
- if (!of_property_present(dev_node, "vddaon-supply"))
+ if (!of_property_present(dev_node, name))
return PWRSEQ_NO_MATCH;
struct device_node *reg_node __free(device_node) =
- of_parse_phandle(dev_node, "vddaon-supply", 0);
+ of_parse_phandle(dev_node, name, 0);
if (!reg_node)
return PWRSEQ_NO_MATCH;
@@ -360,6 +434,26 @@ static int pwrseq_qcom_wcn_match(struct pwrseq_device *pwrseq,
return PWRSEQ_MATCH_OK;
}
+static int pwrseq_qcom_wcn_match(struct pwrseq_device *pwrseq,
+ struct device *dev)
+{
+ return pwrseq_qcom_wcn_match_regulator(pwrseq, dev, "vddaon-supply");
+}
+
+static int pwrseq_qcom_wcn3990_match(struct pwrseq_device *pwrseq,
+ struct device *dev)
+{
+ int ret;
+
+ /* BT device */
+ ret = pwrseq_qcom_wcn_match_regulator(pwrseq, dev, "vddio-supply");
+ if (ret == PWRSEQ_MATCH_OK)
+ return ret;
+
+ /* WiFi device match */
+ return pwrseq_qcom_wcn_match_regulator(pwrseq, dev, "vdd-1.8-xo-supply");
+}
+
static int pwrseq_qcom_wcn_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -391,6 +485,12 @@ static int pwrseq_qcom_wcn_probe(struct platform_device *pdev)
return dev_err_probe(dev, ret,
"Failed to get all regulators\n");
+ if (ctx->pdata->has_vddio) {
+ ctx->vddio = devm_regulator_get(dev, "vddio");
+ if (IS_ERR(ctx->vddio))
+ return dev_err_probe(dev, ret, "Failed to get VDDIO\n");
+ }
+
ctx->bt_gpio = devm_gpiod_get_optional(dev, "bt-enable", GPIOD_OUT_LOW);
if (IS_ERR(ctx->bt_gpio))
return dev_err_probe(dev, PTR_ERR(ctx->bt_gpio),
@@ -432,7 +532,7 @@ static int pwrseq_qcom_wcn_probe(struct platform_device *pdev)
config.parent = dev;
config.owner = THIS_MODULE;
config.drvdata = ctx;
- config.match = pwrseq_qcom_wcn_match;
+ config.match = ctx->pdata->match ? : pwrseq_qcom_wcn_match;
config.targets = ctx->pdata->targets;
ctx->pwrseq = devm_pwrseq_device_register(dev, &config);
@@ -444,6 +544,26 @@ static int pwrseq_qcom_wcn_probe(struct platform_device *pdev)
}
static const struct of_device_id pwrseq_qcom_wcn_of_match[] = {
+ {
+ .compatible = "qcom,wcn3950-pmu",
+ .data = &pwrseq_wcn3990_of_data,
+ },
+ {
+ .compatible = "qcom,wcn3988-pmu",
+ .data = &pwrseq_wcn3990_of_data,
+ },
+ {
+ .compatible = "qcom,wcn3990-pmu",
+ .data = &pwrseq_wcn3990_of_data,
+ },
+ {
+ .compatible = "qcom,wcn3991-pmu",
+ .data = &pwrseq_wcn3990_of_data,
+ },
+ {
+ .compatible = "qcom,wcn3998-pmu",
+ .data = &pwrseq_wcn3990_of_data,
+ },
{
.compatible = "qcom,qca6390-pmu",
.data = &pwrseq_qca6390_of_data,
--
2.47.3
next prev parent reply other threads:[~2026-01-06 1:01 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-06 1:01 [PATCH v2 00/14] power: sequencing: extend WCN driver to support WCN399x device Dmitry Baryshkov
2026-01-06 1:01 ` [PATCH v2 01/14] regulator: dt-bindings: qcom,wcn3990-pmu: describe PMUs on WCN39xx Dmitry Baryshkov
2026-01-06 8:00 ` Krzysztof Kozlowski
2026-01-06 11:33 ` Bartosz Golaszewski
2026-01-06 13:27 ` Mark Brown
2026-01-06 1:01 ` [PATCH v2 02/14] Bluetooth: qca: enable pwrseq support for WCN39xx devices Dmitry Baryshkov
2026-01-06 1:01 ` [PATCH v2 03/14] Bluetooth: qca: fix ROM version reading on WCN3998 chips Dmitry Baryshkov
2026-01-06 12:38 ` Bartosz Golaszewski
2026-01-06 1:01 ` [PATCH v2 04/14] wifi: ath10k: snoc: support powering on the device via pwrseq Dmitry Baryshkov
2026-01-15 22:30 ` Jeff Johnson
2026-01-16 7:48 ` Krzysztof Kozlowski
2026-01-16 15:18 ` Jeff Johnson
2026-01-16 16:08 ` Krzysztof Kozlowski
2026-01-16 16:41 ` Dmitry Baryshkov
2026-01-16 16:47 ` Krzysztof Kozlowski
2026-01-15 23:12 ` Jeff Johnson
2026-01-16 2:57 ` Dmitry Baryshkov
2026-01-06 1:01 ` Dmitry Baryshkov [this message]
2026-01-06 1:01 ` [PATCH v2 06/14] arm64: dts: qcom: qrb4210-rb2: Fix UART3 wakeup IRQ storm Dmitry Baryshkov
2026-01-06 1:01 ` [PATCH v2 07/14] arm64: dts: qcom: sdm845-db845c: drop CS from SPIO0 Dmitry Baryshkov
2026-01-06 1:01 ` [PATCH v2 08/14] arm64: dts: qcom: sdm845-db845c: specify power for WiFi CH1 Dmitry Baryshkov
2026-01-06 1:01 ` [PATCH v2 09/14] arm64: dts: qcom: sm8150: add uart13 Dmitry Baryshkov
2026-01-06 1:01 ` [PATCH v2 10/14] arm64: dts: qcom: qrb2210-rb1: describe WiFi/BT properly Dmitry Baryshkov
2026-01-06 1:01 ` [PATCH v2 11/14] arm64: dts: qcom: qrb4210-rb2: " Dmitry Baryshkov
2026-01-06 1:01 ` [PATCH v2 12/14] arm64: dts: qcom: sda660-ifc6560: " Dmitry Baryshkov
2026-01-06 1:01 ` [PATCH v2 13/14] arm64: dts: qcom: sdm845-db845c: " Dmitry Baryshkov
2026-01-06 1:01 ` [PATCH v2 14/14] arm64: dts: qcom: sm8150-hdk: " Dmitry Baryshkov
2026-01-06 16:09 ` [PATCH v2 00/14] power: sequencing: extend WCN driver to support WCN399x device Dmitry Baryshkov
2026-01-07 8:28 ` (subset) " Bartosz Golaszewski
2026-01-15 21:03 ` Bjorn Andersson
2026-03-24 3:42 ` Bjorn Andersson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260106-wcn3990-pwrctl-v2-5-0386204328be@oss.qualcomm.com \
--to=dmitry.baryshkov@oss.qualcomm.com \
--cc=andersson@kernel.org \
--cc=ath10k@lists.infradead.org \
--cc=brgl@kernel.org \
--cc=broonie@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=jjohnson@kernel.org \
--cc=konradybcio@kernel.org \
--cc=krzk+dt@kernel.org \
--cc=krzk@kernel.org \
--cc=lgirdwood@gmail.com \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-bluetooth@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=linux-wireless@vger.kernel.org \
--cc=luiz.dentz@gmail.com \
--cc=mani@kernel.org \
--cc=marcel@holtmann.org \
--cc=mka@chromium.org \
--cc=quic_bgodavar@quicinc.com \
--cc=robh@kernel.org \
--cc=vkoul@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox