power sequencing updates for v7.0-rc1

New drivers:
 - add the power sequencing driver for PCIe M.2 connectors
 
 Driver improvements:
 - use device_get_match_data() where applicable
 - add support for the WCN39xx family of models to pwrseq-qcom-wcn
 
 Fixes:
 - fix a locking issue in pwrseq core
 - fix retval check in pwrseq-qcom-wcn
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEkeUTLeW1Rh17omX8BZ0uy/82hMMFAmmK8IkACgkQBZ0uy/82
 hMMxMxAAqDCSDB+faKHMKDoHN6Jwpn57y2ODAP7BGwoDdET/EVU6qrij2+gmHpNF
 Vgzk5hvSxv8cCzncPDPvtDoBWCNBN+6YKHW1M4aweo72wwLnhmBXYGkGV4DVqY2k
 u2afURTuSR6DsC/J2wtOQmz+TSbgwE7QbevPkJOaMR1FrahUp8KT3zgHYqRcCWcJ
 xm4Hx1w2xHMQ87+d5IK03gFfyHE/gXBKmAFH5xno/7Gwev6oCS3DulFI97tlq4lO
 YGAiVkxkYrOjHNDxw1+ePIRuVl992nNQmuahyMpujtUXfb6UxQ0ZpqxTk5wbaERX
 sZEp8AW1kpgwd2CzJqXrG/gTIBU+1dB5iDZDpviR+QeZzDFafsBiEUwS1sTfZsaP
 k22vMmhrqjxqFB1FwksyBLfbvE5+0uknzEjXkC1gwMea/0q2L8S8av1aMdJMTl9k
 iphsCKaRscfPPLNU7nHczrtj9KgSh7tSa6iAe29cyz+RPMVgXgJ0shaOWH/vEmKe
 sRsGfCPESBa5yEw8/gZqNs1WLd6jM3Xxuzh/KJnz9Z6zB5o1AiMyfC4oCV7BK+WP
 OdtLyya+2R07ZwuDPW4M2yY9pGgIrULbJJohlxb8mxL+dwZZk2pHWBvxqjlKB2B8
 NhpfW53w00ZV911KPAreGTLNHbDGJOHOaUkSD5eyAL9Lroq8frA=
 =1SR6
 -----END PGP SIGNATURE-----

Merge tag 'pwrseq-updates-for-v7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux

Pull power sequencing updates from Bartosz Golaszewski:
 "One new driver and support for more models added to the existing
  qcom-wcn driver as well as some minor tweaks and fixes.

  New drivers:
   - add the power sequencing driver for PCIe M.2 connectors

  Driver improvements:
   - use device_get_match_data() where applicable
   - add support for the WCN39xx family of models to pwrseq-qcom-wcn

  Fixes:
   - fix a locking issue in pwrseq core
   - fix retval check in pwrseq-qcom-wcn"

* tag 'pwrseq-updates-for-v7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux:
  power: sequencing: qcom-wcn: fix error path for VDDIO handling
  power: sequencing: fix missing state_lock in pwrseq_power_on() error path
  power: sequencing: Add the Power Sequencing driver for the PCIe M.2 connectors
  dt-bindings: connector: Add PCIe M.2 Mechanical Key M connector
  power: sequencing: qcom-wcn: add support for WCN39xx
  regulator: dt-bindings: qcom,wcn3990-pmu: describe PMUs on WCN39xx
  power: sequencing: qcom-wcn: use device_get_match_data()
This commit is contained in:
Linus Torvalds 2026-02-11 10:45:11 -08:00
commit 893ace4df0
8 changed files with 560 additions and 8 deletions

View file

@ -0,0 +1,145 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/connector/pcie-m2-m-connector.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: PCIe M.2 Mechanical Key M Connector
maintainers:
- Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
description:
A PCIe M.2 M connector node represents a physical PCIe M.2 Mechanical Key M
connector. The Mechanical Key M connectors are used to connect SSDs to the
host system over PCIe/SATA interfaces. These connectors also offer optional
interfaces like USB, SMBus.
properties:
compatible:
const: pcie-m2-m-connector
vpcie3v3-supply:
description: A phandle to the regulator for 3.3v supply.
vpcie1v8-supply:
description: A phandle to the regulator for VIO 1.8v supply.
ports:
$ref: /schemas/graph.yaml#/properties/ports
description: OF graph bindings modeling the interfaces exposed on the
connector. Since a single connector can have multiple interfaces, every
interface has an assigned OF graph port number as described below.
properties:
port@0:
$ref: /schemas/graph.yaml#/properties/port
description: PCIe interface
port@1:
$ref: /schemas/graph.yaml#/properties/port
description: SATA interface
port@2:
$ref: /schemas/graph.yaml#/properties/port
description: USB 2.0 interface
anyOf:
- required:
- port@0
- required:
- port@1
i2c-parent:
$ref: /schemas/types.yaml#/definitions/phandle
description: I2C interface
clocks:
description: 32.768 KHz Suspend Clock (SUSCLK) input from the host system to
the M.2 card. Refer, PCI Express M.2 Specification r4.0, sec 3.1.12.1 for
more details.
maxItems: 1
pedet-gpios:
description: GPIO input to PEDET signal. This signal is used by the host
systems to determine the communication protocol that the M.2 card uses;
SATA signaling (low) or PCIe signaling (high). Refer, PCI Express M.2
Specification r4.0, sec 3.3.4.2 for more details.
maxItems: 1
viocfg-gpios:
description: GPIO input to IO voltage configuration (VIO_CFG) signal. This
signal is used by the host systems to determine whether the card supports
an independent IO voltage domain for the sideband signals or not. Refer,
PCI Express M.2 Specification r4.0, sec 3.1.15.1 for more details.
maxItems: 1
pwrdis-gpios:
description: GPIO output to Power Disable (PWRDIS) signal. This signal is
used by the host system to disable power on the M.2 card. Refer, PCI
Express M.2 Specification r4.0, sec 3.3.5.2 for more details.
maxItems: 1
pln-gpios:
description: GPIO output to Power Loss Notification (PLN#) signal. This
signal is used by the host system to notify the M.2 card that the power
loss event is about to occur. Refer, PCI Express M.2 Specification r4.0,
sec 3.2.17.1 for more details.
maxItems: 1
plas3-gpios:
description: GPIO input to Power Loss Acknowledge (PLA_S3#) signal. This
signal is used by the host system to receive the acknowledgment of the M.2
card's preparation for power loss.
maxItems: 1
required:
- compatible
- vpcie3v3-supply
additionalProperties: false
examples:
# PCI M.2 Key M connector for SSDs with PCIe interface
- |
#include <dt-bindings/gpio/gpio.h>
connector {
compatible = "pcie-m2-m-connector";
vpcie3v3-supply = <&vreg_nvme>;
i2c-parent = <&i2c0>;
pedet-gpios = <&tlmm 95 GPIO_ACTIVE_HIGH>;
viocfg-gpios = <&tlmm 96 GPIO_ACTIVE_HIGH>;
pwrdis-gpios = <&tlmm 97 GPIO_ACTIVE_HIGH>;
pln-gpios = <&tlmm 98 GPIO_ACTIVE_LOW>;
plas3-gpios = <&tlmm 99 GPIO_ACTIVE_LOW>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
endpoint@0 {
reg = <0>;
remote-endpoint = <&pcie6_port0_ep>;
};
};
port@2 {
#address-cells = <1>;
#size-cells = <0>;
reg = <2>;
endpoint@0 {
reg = <0>;
remote-endpoint = <&usb_hs_ep>;
};
};
};
};

View file

@ -0,0 +1,100 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/regulator/qcom,wcn3990-pmu.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Technologies, Inc. WCN3990 PMU Regulators
maintainers:
- Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
description:
The WCN3990 package contains discrete modules for WLAN and Bluetooth. They
are powered by the Power Management Unit (PMU) that takes inputs from the
host and provides LDO outputs. This document describes this module.
properties:
compatible:
enum:
- qcom,wcn3950-pmu
- qcom,wcn3988-pmu
- qcom,wcn3990-pmu
- qcom,wcn3991-pmu
- qcom,wcn3998-pmu
vddio-supply:
description: VDD_IO supply regulator handle
vddxo-supply:
description: VDD_XTAL supply regulator handle
vddrf-supply:
description: VDD_RF supply regulator handle
vddch0-supply:
description: chain 0 supply regulator handle
vddch1-supply:
description: chain 1 supply regulator handle
swctrl-gpios:
maxItems: 1
description: GPIO line indicating the state of the clock supply to the BT module
clocks:
maxItems: 1
description: Reference clock handle
regulators:
type: object
description:
LDO outputs of the PMU
patternProperties:
"^ldo[0-9]$":
$ref: regulator.yaml#
type: object
unevaluatedProperties: false
additionalProperties: false
required:
- compatible
- regulators
- vddio-supply
- vddxo-supply
- vddrf-supply
- vddch0-supply
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
pmu {
compatible = "qcom,wcn3990-pmu";
vddio-supply = <&vreg_io>;
vddxo-supply = <&vreg_xo>;
vddrf-supply = <&vreg_rf>;
vddch0-supply = <&vreg_ch0>;
regulators {
vreg_pmu_io: ldo0 {
regulator-name = "vreg_pmu_io";
};
vreg_pmu_xo: ldo1 {
regulator-name = "vreg_pmu_xo";
};
vreg_pmu_rf: ldo2 {
regulator-name = "vreg_pmu_rf";
};
vreg_pmu_ch0: ldo3 {
regulator-name = "vreg_pmu_ch0";
};
};
};

View file

@ -20861,6 +20861,13 @@ F: Documentation/driver-api/pwrseq.rst
F: drivers/power/sequencing/
F: include/linux/pwrseq/
PCIE M.2 POWER SEQUENCING
M: Manivannan Sadhasivam <mani@kernel.org>
L: linux-pci@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/connector/pcie-m2-m-connector.yaml
F: drivers/power/sequencing/pwrseq-pcie-m2.c
POWER STATE COORDINATION INTERFACE (PSCI)
M: Mark Rutland <mark.rutland@arm.com>
M: Lorenzo Pieralisi <lpieralisi@kernel.org>

View file

@ -35,4 +35,12 @@ config POWER_SEQUENCING_TH1520_GPU
GPU. This driver handles the complex clock and reset sequence
required to power on the Imagination BXM GPU on this platform.
config POWER_SEQUENCING_PCIE_M2
tristate "PCIe M.2 connector power sequencing driver"
depends on OF || COMPILE_TEST
help
Say Y here to enable the power sequencing driver for PCIe M.2
connectors. This driver handles the power sequencing for the M.2
connectors exposing multiple interfaces like PCIe, SATA, UART, etc...
endif

View file

@ -5,3 +5,4 @@ pwrseq-core-y := core.o
obj-$(CONFIG_POWER_SEQUENCING_QCOM_WCN) += pwrseq-qcom-wcn.o
obj-$(CONFIG_POWER_SEQUENCING_TH1520_GPU) += pwrseq-thead-gpu.o
obj-$(CONFIG_POWER_SEQUENCING_PCIE_M2) += pwrseq-pcie-m2.o

View file

@ -914,8 +914,10 @@ int pwrseq_power_on(struct pwrseq_desc *desc)
if (target->post_enable) {
ret = target->post_enable(pwrseq);
if (ret) {
pwrseq_unit_disable(pwrseq, unit);
desc->powered_on = false;
scoped_guard(mutex, &pwrseq->state_lock) {
pwrseq_unit_disable(pwrseq, unit);
desc->powered_on = false;
}
}
}

View file

@ -0,0 +1,168 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
* Author: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
*/
#include <linux/device.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/pwrseq/provider.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
struct pwrseq_pcie_m2_pdata {
const struct pwrseq_target_data **targets;
};
struct pwrseq_pcie_m2_ctx {
struct pwrseq_device *pwrseq;
struct device_node *of_node;
const struct pwrseq_pcie_m2_pdata *pdata;
struct regulator_bulk_data *regs;
size_t num_vregs;
struct notifier_block nb;
};
static int pwrseq_pcie_m2_m_vregs_enable(struct pwrseq_device *pwrseq)
{
struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
return regulator_bulk_enable(ctx->num_vregs, ctx->regs);
}
static int pwrseq_pcie_m2_m_vregs_disable(struct pwrseq_device *pwrseq)
{
struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
return regulator_bulk_disable(ctx->num_vregs, ctx->regs);
}
static const struct pwrseq_unit_data pwrseq_pcie_m2_vregs_unit_data = {
.name = "regulators-enable",
.enable = pwrseq_pcie_m2_m_vregs_enable,
.disable = pwrseq_pcie_m2_m_vregs_disable,
};
static const struct pwrseq_unit_data *pwrseq_pcie_m2_m_unit_deps[] = {
&pwrseq_pcie_m2_vregs_unit_data,
NULL
};
static const struct pwrseq_unit_data pwrseq_pcie_m2_m_pcie_unit_data = {
.name = "pcie-enable",
.deps = pwrseq_pcie_m2_m_unit_deps,
};
static const struct pwrseq_target_data pwrseq_pcie_m2_m_pcie_target_data = {
.name = "pcie",
.unit = &pwrseq_pcie_m2_m_pcie_unit_data,
};
static const struct pwrseq_target_data *pwrseq_pcie_m2_m_targets[] = {
&pwrseq_pcie_m2_m_pcie_target_data,
NULL
};
static const struct pwrseq_pcie_m2_pdata pwrseq_pcie_m2_m_of_data = {
.targets = pwrseq_pcie_m2_m_targets,
};
static int pwrseq_pcie_m2_match(struct pwrseq_device *pwrseq,
struct device *dev)
{
struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
struct device_node *endpoint __free(device_node) = NULL;
/*
* Traverse the 'remote-endpoint' nodes and check if the remote node's
* parent matches the OF node of 'dev'.
*/
for_each_endpoint_of_node(ctx->of_node, endpoint) {
struct device_node *remote __free(device_node) =
of_graph_get_remote_port_parent(endpoint);
if (remote && (remote == dev_of_node(dev)))
return PWRSEQ_MATCH_OK;
}
return PWRSEQ_NO_MATCH;
}
static void pwrseq_pcie_m2_free_regulators(void *data)
{
struct pwrseq_pcie_m2_ctx *ctx = data;
regulator_bulk_free(ctx->num_vregs, ctx->regs);
}
static int pwrseq_pcie_m2_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct pwrseq_pcie_m2_ctx *ctx;
struct pwrseq_config config = {};
int ret;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->of_node = of_node_get(dev->of_node);
ctx->pdata = device_get_match_data(dev);
if (!ctx->pdata)
return dev_err_probe(dev, -ENODEV,
"Failed to obtain platform data\n");
/*
* Currently, of_regulator_bulk_get_all() is the only regulator API that
* allows to get all supplies in the devicetree node without manually
* specifying them.
*/
ret = of_regulator_bulk_get_all(dev, dev_of_node(dev), &ctx->regs);
if (ret < 0)
return dev_err_probe(dev, ret,
"Failed to get all regulators\n");
ctx->num_vregs = ret;
ret = devm_add_action_or_reset(dev, pwrseq_pcie_m2_free_regulators, ctx);
if (ret)
return ret;
config.parent = dev;
config.owner = THIS_MODULE;
config.drvdata = ctx;
config.match = pwrseq_pcie_m2_match;
config.targets = ctx->pdata->targets;
ctx->pwrseq = devm_pwrseq_device_register(dev, &config);
if (IS_ERR(ctx->pwrseq))
return dev_err_probe(dev, PTR_ERR(ctx->pwrseq),
"Failed to register the power sequencer\n");
return 0;
}
static const struct of_device_id pwrseq_pcie_m2_of_match[] = {
{
.compatible = "pcie-m2-m-connector",
.data = &pwrseq_pcie_m2_m_of_data,
},
{ }
};
MODULE_DEVICE_TABLE(of, pwrseq_pcie_m2_of_match);
static struct platform_driver pwrseq_pcie_m2_driver = {
.driver = {
.name = "pwrseq-pcie-m2",
.of_match_table = pwrseq_pcie_m2_of_match,
},
.probe = pwrseq_pcie_m2_probe,
};
module_platform_driver(pwrseq_pcie_m2_driver);
MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>");
MODULE_DESCRIPTION("Power Sequencing driver for PCIe M.2 connector");
MODULE_LICENSE("GPL");

View file

@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/pwrseq/provider.h>
#include <linux/string.h>
@ -23,6 +24,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 +33,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 +56,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 +118,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 +266,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 +295,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 +326,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 +402,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 +415,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 +435,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;
@ -373,7 +468,7 @@ static int pwrseq_qcom_wcn_probe(struct platform_device *pdev)
ctx->of_node = dev->of_node;
ctx->pdata = of_device_get_match_data(dev);
ctx->pdata = device_get_match_data(dev);
if (!ctx->pdata)
return dev_err_probe(dev, -ENODEV,
"Failed to obtain platform data\n");
@ -391,6 +486,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, PTR_ERR(ctx->vddio), "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 +533,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 +545,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,