Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+560 -8
+145
Documentation/devicetree/bindings/connector/pcie-m2-m-connector.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/connector/pcie-m2-m-connector.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: PCIe M.2 Mechanical Key M Connector 8 + 9 + maintainers: 10 + - Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com> 11 + 12 + description: 13 + A PCIe M.2 M connector node represents a physical PCIe M.2 Mechanical Key M 14 + connector. The Mechanical Key M connectors are used to connect SSDs to the 15 + host system over PCIe/SATA interfaces. These connectors also offer optional 16 + interfaces like USB, SMBus. 17 + 18 + properties: 19 + compatible: 20 + const: pcie-m2-m-connector 21 + 22 + vpcie3v3-supply: 23 + description: A phandle to the regulator for 3.3v supply. 24 + 25 + vpcie1v8-supply: 26 + description: A phandle to the regulator for VIO 1.8v supply. 27 + 28 + ports: 29 + $ref: /schemas/graph.yaml#/properties/ports 30 + description: OF graph bindings modeling the interfaces exposed on the 31 + connector. Since a single connector can have multiple interfaces, every 32 + interface has an assigned OF graph port number as described below. 33 + 34 + properties: 35 + port@0: 36 + $ref: /schemas/graph.yaml#/properties/port 37 + description: PCIe interface 38 + 39 + port@1: 40 + $ref: /schemas/graph.yaml#/properties/port 41 + description: SATA interface 42 + 43 + port@2: 44 + $ref: /schemas/graph.yaml#/properties/port 45 + description: USB 2.0 interface 46 + 47 + anyOf: 48 + - required: 49 + - port@0 50 + - required: 51 + - port@1 52 + 53 + i2c-parent: 54 + $ref: /schemas/types.yaml#/definitions/phandle 55 + description: I2C interface 56 + 57 + clocks: 58 + description: 32.768 KHz Suspend Clock (SUSCLK) input from the host system to 59 + the M.2 card. Refer, PCI Express M.2 Specification r4.0, sec 3.1.12.1 for 60 + more details. 61 + maxItems: 1 62 + 63 + pedet-gpios: 64 + description: GPIO input to PEDET signal. This signal is used by the host 65 + systems to determine the communication protocol that the M.2 card uses; 66 + SATA signaling (low) or PCIe signaling (high). Refer, PCI Express M.2 67 + Specification r4.0, sec 3.3.4.2 for more details. 68 + maxItems: 1 69 + 70 + viocfg-gpios: 71 + description: GPIO input to IO voltage configuration (VIO_CFG) signal. This 72 + signal is used by the host systems to determine whether the card supports 73 + an independent IO voltage domain for the sideband signals or not. Refer, 74 + PCI Express M.2 Specification r4.0, sec 3.1.15.1 for more details. 75 + maxItems: 1 76 + 77 + pwrdis-gpios: 78 + description: GPIO output to Power Disable (PWRDIS) signal. This signal is 79 + used by the host system to disable power on the M.2 card. Refer, PCI 80 + Express M.2 Specification r4.0, sec 3.3.5.2 for more details. 81 + maxItems: 1 82 + 83 + pln-gpios: 84 + description: GPIO output to Power Loss Notification (PLN#) signal. This 85 + signal is used by the host system to notify the M.2 card that the power 86 + loss event is about to occur. Refer, PCI Express M.2 Specification r4.0, 87 + sec 3.2.17.1 for more details. 88 + maxItems: 1 89 + 90 + plas3-gpios: 91 + description: GPIO input to Power Loss Acknowledge (PLA_S3#) signal. This 92 + signal is used by the host system to receive the acknowledgment of the M.2 93 + card's preparation for power loss. 94 + maxItems: 1 95 + 96 + required: 97 + - compatible 98 + - vpcie3v3-supply 99 + 100 + additionalProperties: false 101 + 102 + examples: 103 + # PCI M.2 Key M connector for SSDs with PCIe interface 104 + - | 105 + #include <dt-bindings/gpio/gpio.h> 106 + 107 + connector { 108 + compatible = "pcie-m2-m-connector"; 109 + vpcie3v3-supply = <&vreg_nvme>; 110 + i2c-parent = <&i2c0>; 111 + pedet-gpios = <&tlmm 95 GPIO_ACTIVE_HIGH>; 112 + viocfg-gpios = <&tlmm 96 GPIO_ACTIVE_HIGH>; 113 + pwrdis-gpios = <&tlmm 97 GPIO_ACTIVE_HIGH>; 114 + pln-gpios = <&tlmm 98 GPIO_ACTIVE_LOW>; 115 + plas3-gpios = <&tlmm 99 GPIO_ACTIVE_LOW>; 116 + 117 + ports { 118 + #address-cells = <1>; 119 + #size-cells = <0>; 120 + 121 + port@0 { 122 + #address-cells = <1>; 123 + #size-cells = <0>; 124 + 125 + reg = <0>; 126 + 127 + endpoint@0 { 128 + reg = <0>; 129 + remote-endpoint = <&pcie6_port0_ep>; 130 + }; 131 + }; 132 + 133 + port@2 { 134 + #address-cells = <1>; 135 + #size-cells = <0>; 136 + 137 + reg = <2>; 138 + 139 + endpoint@0 { 140 + reg = <0>; 141 + remote-endpoint = <&usb_hs_ep>; 142 + }; 143 + }; 144 + }; 145 + };
+100
Documentation/devicetree/bindings/regulator/qcom,wcn3990-pmu.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/regulator/qcom,wcn3990-pmu.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Qualcomm Technologies, Inc. WCN3990 PMU Regulators 8 + 9 + maintainers: 10 + - Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com> 11 + 12 + description: 13 + The WCN3990 package contains discrete modules for WLAN and Bluetooth. They 14 + are powered by the Power Management Unit (PMU) that takes inputs from the 15 + host and provides LDO outputs. This document describes this module. 16 + 17 + properties: 18 + compatible: 19 + enum: 20 + - qcom,wcn3950-pmu 21 + - qcom,wcn3988-pmu 22 + - qcom,wcn3990-pmu 23 + - qcom,wcn3991-pmu 24 + - qcom,wcn3998-pmu 25 + 26 + vddio-supply: 27 + description: VDD_IO supply regulator handle 28 + 29 + vddxo-supply: 30 + description: VDD_XTAL supply regulator handle 31 + 32 + vddrf-supply: 33 + description: VDD_RF supply regulator handle 34 + 35 + vddch0-supply: 36 + description: chain 0 supply regulator handle 37 + 38 + vddch1-supply: 39 + description: chain 1 supply regulator handle 40 + 41 + swctrl-gpios: 42 + maxItems: 1 43 + description: GPIO line indicating the state of the clock supply to the BT module 44 + 45 + clocks: 46 + maxItems: 1 47 + description: Reference clock handle 48 + 49 + regulators: 50 + type: object 51 + description: 52 + LDO outputs of the PMU 53 + 54 + patternProperties: 55 + "^ldo[0-9]$": 56 + $ref: regulator.yaml# 57 + type: object 58 + unevaluatedProperties: false 59 + 60 + additionalProperties: false 61 + 62 + required: 63 + - compatible 64 + - regulators 65 + - vddio-supply 66 + - vddxo-supply 67 + - vddrf-supply 68 + - vddch0-supply 69 + 70 + additionalProperties: false 71 + 72 + examples: 73 + - | 74 + #include <dt-bindings/gpio/gpio.h> 75 + pmu { 76 + compatible = "qcom,wcn3990-pmu"; 77 + 78 + vddio-supply = <&vreg_io>; 79 + vddxo-supply = <&vreg_xo>; 80 + vddrf-supply = <&vreg_rf>; 81 + vddch0-supply = <&vreg_ch0>; 82 + 83 + regulators { 84 + vreg_pmu_io: ldo0 { 85 + regulator-name = "vreg_pmu_io"; 86 + }; 87 + 88 + vreg_pmu_xo: ldo1 { 89 + regulator-name = "vreg_pmu_xo"; 90 + }; 91 + 92 + vreg_pmu_rf: ldo2 { 93 + regulator-name = "vreg_pmu_rf"; 94 + }; 95 + 96 + vreg_pmu_ch0: ldo3 { 97 + regulator-name = "vreg_pmu_ch0"; 98 + }; 99 + }; 100 + };
+7
MAINTAINERS
··· 20861 20861 F: drivers/power/sequencing/ 20862 20862 F: include/linux/pwrseq/ 20863 20863 20864 + PCIE M.2 POWER SEQUENCING 20865 + M: Manivannan Sadhasivam <mani@kernel.org> 20866 + L: linux-pci@vger.kernel.org 20867 + S: Maintained 20868 + F: Documentation/devicetree/bindings/connector/pcie-m2-m-connector.yaml 20869 + F: drivers/power/sequencing/pwrseq-pcie-m2.c 20870 + 20864 20871 POWER STATE COORDINATION INTERFACE (PSCI) 20865 20872 M: Mark Rutland <mark.rutland@arm.com> 20866 20873 M: Lorenzo Pieralisi <lpieralisi@kernel.org>
+8
drivers/power/sequencing/Kconfig
··· 35 35 GPU. This driver handles the complex clock and reset sequence 36 36 required to power on the Imagination BXM GPU on this platform. 37 37 38 + config POWER_SEQUENCING_PCIE_M2 39 + tristate "PCIe M.2 connector power sequencing driver" 40 + depends on OF || COMPILE_TEST 41 + help 42 + Say Y here to enable the power sequencing driver for PCIe M.2 43 + connectors. This driver handles the power sequencing for the M.2 44 + connectors exposing multiple interfaces like PCIe, SATA, UART, etc... 45 + 38 46 endif
+1
drivers/power/sequencing/Makefile
··· 5 5 6 6 obj-$(CONFIG_POWER_SEQUENCING_QCOM_WCN) += pwrseq-qcom-wcn.o 7 7 obj-$(CONFIG_POWER_SEQUENCING_TH1520_GPU) += pwrseq-thead-gpu.o 8 + obj-$(CONFIG_POWER_SEQUENCING_PCIE_M2) += pwrseq-pcie-m2.o
+4 -2
drivers/power/sequencing/core.c
··· 914 914 if (target->post_enable) { 915 915 ret = target->post_enable(pwrseq); 916 916 if (ret) { 917 - pwrseq_unit_disable(pwrseq, unit); 918 - desc->powered_on = false; 917 + scoped_guard(mutex, &pwrseq->state_lock) { 918 + pwrseq_unit_disable(pwrseq, unit); 919 + desc->powered_on = false; 920 + } 919 921 } 920 922 } 921 923
+168
drivers/power/sequencing/pwrseq-pcie-m2.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. 4 + * Author: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com> 5 + */ 6 + 7 + #include <linux/device.h> 8 + #include <linux/mod_devicetable.h> 9 + #include <linux/module.h> 10 + #include <linux/of.h> 11 + #include <linux/of_graph.h> 12 + #include <linux/platform_device.h> 13 + #include <linux/pwrseq/provider.h> 14 + #include <linux/regulator/consumer.h> 15 + #include <linux/slab.h> 16 + 17 + struct pwrseq_pcie_m2_pdata { 18 + const struct pwrseq_target_data **targets; 19 + }; 20 + 21 + struct pwrseq_pcie_m2_ctx { 22 + struct pwrseq_device *pwrseq; 23 + struct device_node *of_node; 24 + const struct pwrseq_pcie_m2_pdata *pdata; 25 + struct regulator_bulk_data *regs; 26 + size_t num_vregs; 27 + struct notifier_block nb; 28 + }; 29 + 30 + static int pwrseq_pcie_m2_m_vregs_enable(struct pwrseq_device *pwrseq) 31 + { 32 + struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); 33 + 34 + return regulator_bulk_enable(ctx->num_vregs, ctx->regs); 35 + } 36 + 37 + static int pwrseq_pcie_m2_m_vregs_disable(struct pwrseq_device *pwrseq) 38 + { 39 + struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); 40 + 41 + return regulator_bulk_disable(ctx->num_vregs, ctx->regs); 42 + } 43 + 44 + static const struct pwrseq_unit_data pwrseq_pcie_m2_vregs_unit_data = { 45 + .name = "regulators-enable", 46 + .enable = pwrseq_pcie_m2_m_vregs_enable, 47 + .disable = pwrseq_pcie_m2_m_vregs_disable, 48 + }; 49 + 50 + static const struct pwrseq_unit_data *pwrseq_pcie_m2_m_unit_deps[] = { 51 + &pwrseq_pcie_m2_vregs_unit_data, 52 + NULL 53 + }; 54 + 55 + static const struct pwrseq_unit_data pwrseq_pcie_m2_m_pcie_unit_data = { 56 + .name = "pcie-enable", 57 + .deps = pwrseq_pcie_m2_m_unit_deps, 58 + }; 59 + 60 + static const struct pwrseq_target_data pwrseq_pcie_m2_m_pcie_target_data = { 61 + .name = "pcie", 62 + .unit = &pwrseq_pcie_m2_m_pcie_unit_data, 63 + }; 64 + 65 + static const struct pwrseq_target_data *pwrseq_pcie_m2_m_targets[] = { 66 + &pwrseq_pcie_m2_m_pcie_target_data, 67 + NULL 68 + }; 69 + 70 + static const struct pwrseq_pcie_m2_pdata pwrseq_pcie_m2_m_of_data = { 71 + .targets = pwrseq_pcie_m2_m_targets, 72 + }; 73 + 74 + static int pwrseq_pcie_m2_match(struct pwrseq_device *pwrseq, 75 + struct device *dev) 76 + { 77 + struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); 78 + struct device_node *endpoint __free(device_node) = NULL; 79 + 80 + /* 81 + * Traverse the 'remote-endpoint' nodes and check if the remote node's 82 + * parent matches the OF node of 'dev'. 83 + */ 84 + for_each_endpoint_of_node(ctx->of_node, endpoint) { 85 + struct device_node *remote __free(device_node) = 86 + of_graph_get_remote_port_parent(endpoint); 87 + if (remote && (remote == dev_of_node(dev))) 88 + return PWRSEQ_MATCH_OK; 89 + } 90 + 91 + return PWRSEQ_NO_MATCH; 92 + } 93 + 94 + static void pwrseq_pcie_m2_free_regulators(void *data) 95 + { 96 + struct pwrseq_pcie_m2_ctx *ctx = data; 97 + 98 + regulator_bulk_free(ctx->num_vregs, ctx->regs); 99 + } 100 + 101 + static int pwrseq_pcie_m2_probe(struct platform_device *pdev) 102 + { 103 + struct device *dev = &pdev->dev; 104 + struct pwrseq_pcie_m2_ctx *ctx; 105 + struct pwrseq_config config = {}; 106 + int ret; 107 + 108 + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 109 + if (!ctx) 110 + return -ENOMEM; 111 + 112 + ctx->of_node = of_node_get(dev->of_node); 113 + ctx->pdata = device_get_match_data(dev); 114 + if (!ctx->pdata) 115 + return dev_err_probe(dev, -ENODEV, 116 + "Failed to obtain platform data\n"); 117 + 118 + /* 119 + * Currently, of_regulator_bulk_get_all() is the only regulator API that 120 + * allows to get all supplies in the devicetree node without manually 121 + * specifying them. 122 + */ 123 + ret = of_regulator_bulk_get_all(dev, dev_of_node(dev), &ctx->regs); 124 + if (ret < 0) 125 + return dev_err_probe(dev, ret, 126 + "Failed to get all regulators\n"); 127 + 128 + ctx->num_vregs = ret; 129 + 130 + ret = devm_add_action_or_reset(dev, pwrseq_pcie_m2_free_regulators, ctx); 131 + if (ret) 132 + return ret; 133 + 134 + config.parent = dev; 135 + config.owner = THIS_MODULE; 136 + config.drvdata = ctx; 137 + config.match = pwrseq_pcie_m2_match; 138 + config.targets = ctx->pdata->targets; 139 + 140 + ctx->pwrseq = devm_pwrseq_device_register(dev, &config); 141 + if (IS_ERR(ctx->pwrseq)) 142 + return dev_err_probe(dev, PTR_ERR(ctx->pwrseq), 143 + "Failed to register the power sequencer\n"); 144 + 145 + return 0; 146 + } 147 + 148 + static const struct of_device_id pwrseq_pcie_m2_of_match[] = { 149 + { 150 + .compatible = "pcie-m2-m-connector", 151 + .data = &pwrseq_pcie_m2_m_of_data, 152 + }, 153 + { } 154 + }; 155 + MODULE_DEVICE_TABLE(of, pwrseq_pcie_m2_of_match); 156 + 157 + static struct platform_driver pwrseq_pcie_m2_driver = { 158 + .driver = { 159 + .name = "pwrseq-pcie-m2", 160 + .of_match_table = pwrseq_pcie_m2_of_match, 161 + }, 162 + .probe = pwrseq_pcie_m2_probe, 163 + }; 164 + module_platform_driver(pwrseq_pcie_m2_driver); 165 + 166 + MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>"); 167 + MODULE_DESCRIPTION("Power Sequencing driver for PCIe M.2 connector"); 168 + MODULE_LICENSE("GPL");
+127 -6
drivers/power/sequencing/pwrseq-qcom-wcn.c
··· 12 12 #include <linux/module.h> 13 13 #include <linux/of.h> 14 14 #include <linux/platform_device.h> 15 + #include <linux/property.h> 15 16 #include <linux/regulator/consumer.h> 16 17 #include <linux/pwrseq/provider.h> 17 18 #include <linux/string.h> ··· 24 23 unsigned int pwup_delay_ms; 25 24 unsigned int gpio_enable_delay_ms; 26 25 const struct pwrseq_target_data **targets; 26 + bool has_vddio; /* separate VDD IO regulator */ 27 + int (*match)(struct pwrseq_device *pwrseq, struct device *dev); 27 28 }; 28 29 29 30 struct pwrseq_qcom_wcn_ctx { ··· 33 30 struct device_node *of_node; 34 31 const struct pwrseq_qcom_wcn_pdata *pdata; 35 32 struct regulator_bulk_data *regs; 33 + struct regulator *vddio; 36 34 struct gpio_desc *bt_gpio; 37 35 struct gpio_desc *wlan_gpio; 38 36 struct gpio_desc *xo_clk_gpio; ··· 55 51 if (diff_msecs < ctx->pdata->gpio_enable_delay_ms) 56 52 msleep(ctx->pdata->gpio_enable_delay_ms - diff_msecs); 57 53 } 54 + 55 + static int pwrseq_qcom_wcn_vddio_enable(struct pwrseq_device *pwrseq) 56 + { 57 + struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); 58 + 59 + return regulator_enable(ctx->vddio); 60 + } 61 + 62 + static int pwrseq_qcom_wcn_vddio_disable(struct pwrseq_device *pwrseq) 63 + { 64 + struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); 65 + 66 + return regulator_disable(ctx->vddio); 67 + } 68 + 69 + static const struct pwrseq_unit_data pwrseq_qcom_wcn_vddio_unit_data = { 70 + .name = "vddio-enable", 71 + .enable = pwrseq_qcom_wcn_vddio_enable, 72 + .disable = pwrseq_qcom_wcn_vddio_disable, 73 + }; 58 74 59 75 static int pwrseq_qcom_wcn_vregs_enable(struct pwrseq_device *pwrseq) 60 76 { ··· 114 90 115 91 static const struct pwrseq_unit_data pwrseq_qcom_wcn_clk_unit_data = { 116 92 .name = "clock-enable", 93 + .enable = pwrseq_qcom_wcn_clk_enable, 94 + .disable = pwrseq_qcom_wcn_clk_disable, 95 + }; 96 + 97 + static const struct pwrseq_unit_data *pwrseq_qcom_wcn3990_unit_deps[] = { 98 + &pwrseq_qcom_wcn_vddio_unit_data, 99 + &pwrseq_qcom_wcn_vregs_unit_data, 100 + NULL, 101 + }; 102 + 103 + static const struct pwrseq_unit_data pwrseq_qcom_wcn3990_unit_data = { 104 + .name = "clock-enable", 105 + .deps = pwrseq_qcom_wcn3990_unit_deps, 117 106 .enable = pwrseq_qcom_wcn_clk_enable, 118 107 .disable = pwrseq_qcom_wcn_clk_disable, 119 108 }; ··· 266 229 .post_enable = pwrseq_qcom_wcn_pwup_delay, 267 230 }; 268 231 232 + /* There are no separate BT and WLAN enablement pins */ 233 + static const struct pwrseq_target_data pwrseq_qcom_wcn3990_bt_target_data = { 234 + .name = "bluetooth", 235 + .unit = &pwrseq_qcom_wcn3990_unit_data, 236 + }; 237 + 238 + static const struct pwrseq_target_data pwrseq_qcom_wcn3990_wlan_target_data = { 239 + .name = "wlan", 240 + .unit = &pwrseq_qcom_wcn3990_unit_data, 241 + }; 242 + 269 243 static const struct pwrseq_target_data pwrseq_qcom_wcn6855_bt_target_data = { 270 244 .name = "bluetooth", 271 245 .unit = &pwrseq_qcom_wcn6855_bt_unit_data, ··· 292 244 static const struct pwrseq_target_data *pwrseq_qcom_wcn_targets[] = { 293 245 &pwrseq_qcom_wcn_bt_target_data, 294 246 &pwrseq_qcom_wcn_wlan_target_data, 247 + NULL 248 + }; 249 + 250 + static const struct pwrseq_target_data *pwrseq_qcom_wcn3990_targets[] = { 251 + &pwrseq_qcom_wcn3990_bt_target_data, 252 + &pwrseq_qcom_wcn3990_wlan_target_data, 295 253 NULL 296 254 }; 297 255 ··· 324 270 .pwup_delay_ms = 60, 325 271 .gpio_enable_delay_ms = 100, 326 272 .targets = pwrseq_qcom_wcn_targets, 273 + }; 274 + 275 + static const char *const pwrseq_wcn3990_vregs[] = { 276 + /* vddio is handled separately */ 277 + "vddxo", 278 + "vddrf", 279 + "vddch0", 280 + "vddch1", 281 + }; 282 + 283 + static int pwrseq_qcom_wcn3990_match(struct pwrseq_device *pwrseq, 284 + struct device *dev); 285 + 286 + static const struct pwrseq_qcom_wcn_pdata pwrseq_wcn3990_of_data = { 287 + .vregs = pwrseq_wcn3990_vregs, 288 + .num_vregs = ARRAY_SIZE(pwrseq_wcn3990_vregs), 289 + .pwup_delay_ms = 50, 290 + .targets = pwrseq_qcom_wcn3990_targets, 291 + .has_vddio = true, 292 + .match = pwrseq_qcom_wcn3990_match, 327 293 }; 328 294 329 295 static const char *const pwrseq_wcn6750_vregs[] = { ··· 402 328 .targets = pwrseq_qcom_wcn_targets, 403 329 }; 404 330 405 - static int pwrseq_qcom_wcn_match(struct pwrseq_device *pwrseq, 406 - struct device *dev) 331 + static int pwrseq_qcom_wcn_match_regulator(struct pwrseq_device *pwrseq, 332 + struct device *dev, 333 + const char *name) 407 334 { 408 335 struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); 409 336 struct device_node *dev_node = dev->of_node; ··· 415 340 * 'vddaon-supply' property and whether it leads us to the right 416 341 * device. 417 342 */ 418 - if (!of_property_present(dev_node, "vddaon-supply")) 343 + if (!of_property_present(dev_node, name)) 419 344 return PWRSEQ_NO_MATCH; 420 345 421 346 struct device_node *reg_node __free(device_node) = 422 - of_parse_phandle(dev_node, "vddaon-supply", 0); 347 + of_parse_phandle(dev_node, name, 0); 423 348 if (!reg_node) 424 349 return PWRSEQ_NO_MATCH; 425 350 ··· 435 360 return PWRSEQ_MATCH_OK; 436 361 } 437 362 363 + static int pwrseq_qcom_wcn_match(struct pwrseq_device *pwrseq, 364 + struct device *dev) 365 + { 366 + return pwrseq_qcom_wcn_match_regulator(pwrseq, dev, "vddaon-supply"); 367 + } 368 + 369 + static int pwrseq_qcom_wcn3990_match(struct pwrseq_device *pwrseq, 370 + struct device *dev) 371 + { 372 + int ret; 373 + 374 + /* BT device */ 375 + ret = pwrseq_qcom_wcn_match_regulator(pwrseq, dev, "vddio-supply"); 376 + if (ret == PWRSEQ_MATCH_OK) 377 + return ret; 378 + 379 + /* WiFi device match */ 380 + return pwrseq_qcom_wcn_match_regulator(pwrseq, dev, "vdd-1.8-xo-supply"); 381 + } 382 + 438 383 static int pwrseq_qcom_wcn_probe(struct platform_device *pdev) 439 384 { 440 385 struct device *dev = &pdev->dev; ··· 468 373 469 374 ctx->of_node = dev->of_node; 470 375 471 - ctx->pdata = of_device_get_match_data(dev); 376 + ctx->pdata = device_get_match_data(dev); 472 377 if (!ctx->pdata) 473 378 return dev_err_probe(dev, -ENODEV, 474 379 "Failed to obtain platform data\n"); ··· 485 390 if (ret < 0) 486 391 return dev_err_probe(dev, ret, 487 392 "Failed to get all regulators\n"); 393 + 394 + if (ctx->pdata->has_vddio) { 395 + ctx->vddio = devm_regulator_get(dev, "vddio"); 396 + if (IS_ERR(ctx->vddio)) 397 + return dev_err_probe(dev, PTR_ERR(ctx->vddio), "Failed to get VDDIO\n"); 398 + } 488 399 489 400 ctx->bt_gpio = devm_gpiod_get_optional(dev, "bt-enable", GPIOD_OUT_LOW); 490 401 if (IS_ERR(ctx->bt_gpio)) ··· 533 432 config.parent = dev; 534 433 config.owner = THIS_MODULE; 535 434 config.drvdata = ctx; 536 - config.match = pwrseq_qcom_wcn_match; 435 + config.match = ctx->pdata->match ? : pwrseq_qcom_wcn_match; 537 436 config.targets = ctx->pdata->targets; 538 437 539 438 ctx->pwrseq = devm_pwrseq_device_register(dev, &config); ··· 545 444 } 546 445 547 446 static const struct of_device_id pwrseq_qcom_wcn_of_match[] = { 447 + { 448 + .compatible = "qcom,wcn3950-pmu", 449 + .data = &pwrseq_wcn3990_of_data, 450 + }, 451 + { 452 + .compatible = "qcom,wcn3988-pmu", 453 + .data = &pwrseq_wcn3990_of_data, 454 + }, 455 + { 456 + .compatible = "qcom,wcn3990-pmu", 457 + .data = &pwrseq_wcn3990_of_data, 458 + }, 459 + { 460 + .compatible = "qcom,wcn3991-pmu", 461 + .data = &pwrseq_wcn3990_of_data, 462 + }, 463 + { 464 + .compatible = "qcom,wcn3998-pmu", 465 + .data = &pwrseq_wcn3990_of_data, 466 + }, 548 467 { 549 468 .compatible = "qcom,qca6390-pmu", 550 469 .data = &pwrseq_qca6390_of_data,