[PATCH 2/3] power: sequencing: pcie-m2: Add support for PCIe M.2 Key B connectors

From: Krishna Chaitanya Chundru

Date: Wed Oct 21 2026 - 09:56:27 EST


Add support for handling the power sequence of the PCIe M.2 Key B
connectors. These connectors are used to attach WWAN Adapters to the
host machine over interfaces such as PCIe, USB3.1 Gen1, SSIC, or USB
2.0.

Currently, this driver only supports driving the 3.3V/VBAT power
supply along with the FULL_CARD_POWER_OFF#, RESET#, and W_DISABLE1#/2#
GPIOs as a single "pcie" target, since Key B Adapters expose only a
discoverable PCIe/USB interface and no non-discoverable bus (unlike
Key E's UART-attached Bluetooth device), so no serdev creation is
needed. The optional WAKE_ON_WWAN# and DPR signals are not currently
supported.

Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@xxxxxxxxxxxxxxxx>
---
drivers/power/sequencing/pwrseq-pcie-m2.c | 82 +++++++++++++++++++++++++++++++
1 file changed, 82 insertions(+)

diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index e42e85f47629..62185bf30d73 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -39,6 +39,8 @@ struct pwrseq_pcie_m2_ctx {
struct notifier_block nb;
struct gpio_desc *w_disable1_gpio;
struct gpio_desc *w_disable2_gpio;
+ struct gpio_desc *full_card_power_off_gpio;
+ struct gpio_desc *reset_gpio;
struct device *dev;
struct list_head pci_devices;
struct mutex list_lock;
@@ -111,6 +113,53 @@ static const struct pwrseq_unit_data pwrseq_pcie_m2_e_pcie_unit_data = {
.disable = pwrseq_pci_m2_e_pcie_disable,
};

+static int pwrseq_pci_m2_b_pcie_enable(struct pwrseq_device *pwrseq)
+{
+ struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
+ int ret;
+
+ ret = gpiod_set_value_cansleep(ctx->full_card_power_off_gpio, 0);
+ if (ret)
+ return ret;
+
+ ret = gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ if (ret)
+ return ret;
+
+ ret = gpiod_set_value_cansleep(ctx->w_disable1_gpio, 0);
+ if (ret)
+ return ret;
+
+ return gpiod_set_value_cansleep(ctx->w_disable2_gpio, 0);
+}
+
+static int pwrseq_pci_m2_b_pcie_disable(struct pwrseq_device *pwrseq)
+{
+ struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
+ int ret;
+
+ ret = gpiod_set_value_cansleep(ctx->w_disable2_gpio, 1);
+ if (ret)
+ return ret;
+
+ ret = gpiod_set_value_cansleep(ctx->w_disable1_gpio, 1);
+ if (ret)
+ return ret;
+
+ ret = gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ if (ret)
+ return ret;
+
+ return gpiod_set_value_cansleep(ctx->full_card_power_off_gpio, 1);
+}
+
+static const struct pwrseq_unit_data pwrseq_pcie_m2_b_pcie_unit_data = {
+ .name = "pcie-enable",
+ .deps = pwrseq_pcie_m2_unit_deps,
+ .enable = pwrseq_pci_m2_b_pcie_enable,
+ .disable = pwrseq_pci_m2_b_pcie_disable,
+};
+
static const struct pwrseq_unit_data pwrseq_pcie_m2_m_pcie_unit_data = {
.name = "pcie-enable",
.deps = pwrseq_pcie_m2_unit_deps,
@@ -140,6 +189,11 @@ static const struct pwrseq_target_data pwrseq_pcie_m2_e_pcie_target_data = {
.post_enable = pwrseq_pcie_m2_e_pwup_delay,
};

+static const struct pwrseq_target_data pwrseq_pcie_m2_b_pcie_target_data = {
+ .name = "pcie",
+ .unit = &pwrseq_pcie_m2_b_pcie_unit_data,
+};
+
static const struct pwrseq_target_data pwrseq_pcie_m2_m_pcie_target_data = {
.name = "pcie",
.unit = &pwrseq_pcie_m2_m_pcie_unit_data,
@@ -151,6 +205,11 @@ static const struct pwrseq_target_data *pwrseq_pcie_m2_e_targets[] = {
NULL
};

+static const struct pwrseq_target_data *pwrseq_pcie_m2_b_targets[] = {
+ &pwrseq_pcie_m2_b_pcie_target_data,
+ NULL
+};
+
static const struct pwrseq_target_data *pwrseq_pcie_m2_m_targets[] = {
&pwrseq_pcie_m2_m_pcie_target_data,
NULL
@@ -160,6 +219,10 @@ static const struct pwrseq_pcie_m2_pdata pwrseq_pcie_m2_e_of_data = {
.targets = pwrseq_pcie_m2_e_targets,
};

+static const struct pwrseq_pcie_m2_pdata pwrseq_pcie_m2_b_of_data = {
+ .targets = pwrseq_pcie_m2_b_targets,
+};
+
static const struct pwrseq_pcie_m2_pdata pwrseq_pcie_m2_m_of_data = {
.targets = pwrseq_pcie_m2_m_targets,
};
@@ -534,6 +597,21 @@ static int pwrseq_pcie_m2_probe(struct platform_device *pdev)
goto err_free_regulators;
}

+ ctx->full_card_power_off_gpio = devm_gpiod_get_optional(dev, "full-card-power-off",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(ctx->full_card_power_off_gpio)) {
+ ret = dev_err_probe(dev, PTR_ERR(ctx->full_card_power_off_gpio),
+ "Failed to get the FULL_CARD_POWER_OFF# GPIO\n");
+ goto err_free_regulators;
+ }
+
+ ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(ctx->reset_gpio)) {
+ ret = dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
+ "Failed to get the RESET# GPIO\n");
+ goto err_free_regulators;
+ }
+
config.parent = dev;
config.owner = THIS_MODULE;
config.drvdata = ctx;
@@ -598,6 +676,10 @@ static const struct of_device_id pwrseq_pcie_m2_of_match[] = {
.compatible = "pcie-m2-e-connector",
.data = &pwrseq_pcie_m2_e_of_data,
},
+ {
+ .compatible = "pcie-m2-b-connector",
+ .data = &pwrseq_pcie_m2_b_of_data,
+ },
{ }
};
MODULE_DEVICE_TABLE(of, pwrseq_pcie_m2_of_match);

--
2.34.1