Skip to content

Commit 0d38285

Browse files
Mani-SadhasivamBartosz Golaszewski
authored andcommitted
power: sequencing: pcie-m2: Add support for PCIe M.2 Key E connectors
Add support for handling the power sequence of the PCIe M.2 Key E connectors. These connectors are used to attach the Wireless Connectivity devices to the host machine including combinations of WiFi, BT, NFC using interfaces such as PCIe/SDIO for WiFi, USB/UART for BT and I2C for NFC. Currently, this driver supports only the PCIe interface for WiFi and UART interface for BT. The driver also only supports driving the 3.3v/1.8v power supplies and W_DISABLE{1/2}# GPIOs. The optional signals of the Key E connectors are not currently supported. Tested-by: Hans de Goede <johannes.goede@oss.qualcomm.com> # ThinkPad T14s gen6 (arm64) Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com> Link: https://patch.msgid.link/20260326-pci-m2-e-v7-7-43324a7866e6@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
1 parent 5970c1d commit 0d38285

1 file changed

Lines changed: 101 additions & 6 deletions

File tree

drivers/power/sequencing/pwrseq-pcie-m2.c

Lines changed: 101 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55
*/
66

77
#include <linux/device.h>
8+
#include <linux/delay.h>
9+
#include <linux/gpio/consumer.h>
810
#include <linux/mod_devicetable.h>
911
#include <linux/module.h>
1012
#include <linux/of.h>
1113
#include <linux/of_graph.h>
14+
#include <linux/of_platform.h>
1215
#include <linux/platform_device.h>
1316
#include <linux/pwrseq/provider.h>
1417
#include <linux/regulator/consumer.h>
@@ -25,16 +28,18 @@ struct pwrseq_pcie_m2_ctx {
2528
struct regulator_bulk_data *regs;
2629
size_t num_vregs;
2730
struct notifier_block nb;
31+
struct gpio_desc *w_disable1_gpio;
32+
struct gpio_desc *w_disable2_gpio;
2833
};
2934

30-
static int pwrseq_pcie_m2_m_vregs_enable(struct pwrseq_device *pwrseq)
35+
static int pwrseq_pcie_m2_vregs_enable(struct pwrseq_device *pwrseq)
3136
{
3237
struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
3338

3439
return regulator_bulk_enable(ctx->num_vregs, ctx->regs);
3540
}
3641

37-
static int pwrseq_pcie_m2_m_vregs_disable(struct pwrseq_device *pwrseq)
42+
static int pwrseq_pcie_m2_vregs_disable(struct pwrseq_device *pwrseq)
3843
{
3944
struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
4045

@@ -43,30 +48,106 @@ static int pwrseq_pcie_m2_m_vregs_disable(struct pwrseq_device *pwrseq)
4348

4449
static const struct pwrseq_unit_data pwrseq_pcie_m2_vregs_unit_data = {
4550
.name = "regulators-enable",
46-
.enable = pwrseq_pcie_m2_m_vregs_enable,
47-
.disable = pwrseq_pcie_m2_m_vregs_disable,
51+
.enable = pwrseq_pcie_m2_vregs_enable,
52+
.disable = pwrseq_pcie_m2_vregs_disable,
4853
};
4954

50-
static const struct pwrseq_unit_data *pwrseq_pcie_m2_m_unit_deps[] = {
55+
static const struct pwrseq_unit_data *pwrseq_pcie_m2_unit_deps[] = {
5156
&pwrseq_pcie_m2_vregs_unit_data,
5257
NULL
5358
};
5459

60+
static int pwrseq_pci_m2_e_uart_enable(struct pwrseq_device *pwrseq)
61+
{
62+
struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
63+
64+
return gpiod_set_value_cansleep(ctx->w_disable2_gpio, 0);
65+
}
66+
67+
static int pwrseq_pci_m2_e_uart_disable(struct pwrseq_device *pwrseq)
68+
{
69+
struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
70+
71+
return gpiod_set_value_cansleep(ctx->w_disable2_gpio, 1);
72+
}
73+
74+
static const struct pwrseq_unit_data pwrseq_pcie_m2_e_uart_unit_data = {
75+
.name = "uart-enable",
76+
.deps = pwrseq_pcie_m2_unit_deps,
77+
.enable = pwrseq_pci_m2_e_uart_enable,
78+
.disable = pwrseq_pci_m2_e_uart_disable,
79+
};
80+
81+
static int pwrseq_pci_m2_e_pcie_enable(struct pwrseq_device *pwrseq)
82+
{
83+
struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
84+
85+
return gpiod_set_value_cansleep(ctx->w_disable1_gpio, 0);
86+
}
87+
88+
static int pwrseq_pci_m2_e_pcie_disable(struct pwrseq_device *pwrseq)
89+
{
90+
struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
91+
92+
return gpiod_set_value_cansleep(ctx->w_disable1_gpio, 1);
93+
}
94+
95+
static const struct pwrseq_unit_data pwrseq_pcie_m2_e_pcie_unit_data = {
96+
.name = "pcie-enable",
97+
.deps = pwrseq_pcie_m2_unit_deps,
98+
.enable = pwrseq_pci_m2_e_pcie_enable,
99+
.disable = pwrseq_pci_m2_e_pcie_disable,
100+
};
101+
55102
static const struct pwrseq_unit_data pwrseq_pcie_m2_m_pcie_unit_data = {
56103
.name = "pcie-enable",
57-
.deps = pwrseq_pcie_m2_m_unit_deps,
104+
.deps = pwrseq_pcie_m2_unit_deps,
105+
};
106+
107+
static int pwrseq_pcie_m2_e_pwup_delay(struct pwrseq_device *pwrseq)
108+
{
109+
/*
110+
* FIXME: This delay is only required for some Qcom WLAN/BT cards like
111+
* WCN7850 and not for all devices. But currently, there is no way to
112+
* identify the device model before enumeration.
113+
*/
114+
msleep(50);
115+
116+
return 0;
117+
}
118+
119+
static const struct pwrseq_target_data pwrseq_pcie_m2_e_uart_target_data = {
120+
.name = "uart",
121+
.unit = &pwrseq_pcie_m2_e_uart_unit_data,
122+
.post_enable = pwrseq_pcie_m2_e_pwup_delay,
123+
};
124+
125+
static const struct pwrseq_target_data pwrseq_pcie_m2_e_pcie_target_data = {
126+
.name = "pcie",
127+
.unit = &pwrseq_pcie_m2_e_pcie_unit_data,
128+
.post_enable = pwrseq_pcie_m2_e_pwup_delay,
58129
};
59130

60131
static const struct pwrseq_target_data pwrseq_pcie_m2_m_pcie_target_data = {
61132
.name = "pcie",
62133
.unit = &pwrseq_pcie_m2_m_pcie_unit_data,
63134
};
64135

136+
static const struct pwrseq_target_data *pwrseq_pcie_m2_e_targets[] = {
137+
&pwrseq_pcie_m2_e_pcie_target_data,
138+
&pwrseq_pcie_m2_e_uart_target_data,
139+
NULL
140+
};
141+
65142
static const struct pwrseq_target_data *pwrseq_pcie_m2_m_targets[] = {
66143
&pwrseq_pcie_m2_m_pcie_target_data,
67144
NULL
68145
};
69146

147+
static const struct pwrseq_pcie_m2_pdata pwrseq_pcie_m2_e_of_data = {
148+
.targets = pwrseq_pcie_m2_e_targets,
149+
};
150+
70151
static const struct pwrseq_pcie_m2_pdata pwrseq_pcie_m2_m_of_data = {
71152
.targets = pwrseq_pcie_m2_m_targets,
72153
};
@@ -125,6 +206,16 @@ static int pwrseq_pcie_m2_probe(struct platform_device *pdev)
125206
return dev_err_probe(dev, ret,
126207
"Failed to get all regulators\n");
127208

209+
ctx->w_disable1_gpio = devm_gpiod_get_optional(dev, "w-disable1", GPIOD_OUT_HIGH);
210+
if (IS_ERR(ctx->w_disable1_gpio))
211+
return dev_err_probe(dev, PTR_ERR(ctx->w_disable1_gpio),
212+
"Failed to get the W_DISABLE_1# GPIO\n");
213+
214+
ctx->w_disable2_gpio = devm_gpiod_get_optional(dev, "w-disable2", GPIOD_OUT_HIGH);
215+
if (IS_ERR(ctx->w_disable2_gpio))
216+
return dev_err_probe(dev, PTR_ERR(ctx->w_disable2_gpio),
217+
"Failed to get the W_DISABLE_2# GPIO\n");
218+
128219
ctx->num_vregs = ret;
129220

130221
ret = devm_add_action_or_reset(dev, pwrseq_pcie_m2_free_regulators, ctx);
@@ -150,6 +241,10 @@ static const struct of_device_id pwrseq_pcie_m2_of_match[] = {
150241
.compatible = "pcie-m2-m-connector",
151242
.data = &pwrseq_pcie_m2_m_of_data,
152243
},
244+
{
245+
.compatible = "pcie-m2-e-connector",
246+
.data = &pwrseq_pcie_m2_e_of_data,
247+
},
153248
{ }
154249
};
155250
MODULE_DEVICE_TABLE(of, pwrseq_pcie_m2_of_match);

0 commit comments

Comments
 (0)