Devicetree
 help / color / mirror / Atom feed
From: Chen-Yu Tsai <wenst@chromium.org>
To: Bartosz Golaszewski <brgl@kernel.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Rob Herring <robh@kernel.org>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Conor Dooley <conor+dt@kernel.org>,
	Matthias Brugger <matthias.bgg@gmail.com>,
	AngeloGioacchino Del Regno
	<angelogioacchino.delregno@collabora.com>
Cc: Chen-Yu Tsai <wenst@chromium.org>,
	linux-pm@vger.kernel.org, linux-usb@vger.kernel.org,
	devicetree@vger.kernel.org, linux-mediatek@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org,
	Manivannan Sadhasivam <mani@kernel.org>
Subject: [PATCH RFC 05/12] usb: hub: Power on connected M.2 E-key connectors
Date: Fri, 15 May 2026 17:01:41 +0800	[thread overview]
Message-ID: <20260515090149.3169406-6-wenst@chromium.org> (raw)
In-Reply-To: <20260515090149.3169406-1-wenst@chromium.org>

The new M.2 E-key connector can have a USB connection. For the USB device
on this connector to work, its power must be enabled and the W_DISABLE2#
signal deasserted. The connector driver handles this and provides a
toggle over the power sequencing API.

This feature currently only supports a directly connected (no mux in
between) M.2 E-key connector. Existing USB connector types are not
covered. The USB A connector was recently added to the onboard devices
driver. USB B connectors have historically been managed by the USB
gadget or dual-role device controller drivers. USB C connectors are
handled by TCPM drivers.

The power sequencing API does not know whether a power sequence provider
is not needed or not available yet, so we only request it for connectors
that we know need it, which at this time is just the E-key connector.

The feature is limited to OF platforms, since the connection is over an
OF graph. And it doesn't make sense to return an error when the power
sequencing framework is not enabled, as that would block all USB
devices. Therefor the function short circuits out if any of these
conditions happen.

Also, this is not implemented in the onboard USB devices driver. The
power sequencing API expects the consumer device to make the request,
but there is no device node to instantiate a platform device to tie
the driver to. The connector is not a child node of the USB host or
hub, and the graph connection is from a USB port to the connector.

Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
 drivers/usb/core/hub.c  | 17 ++++++++++++-
 drivers/usb/core/hub.h  |  2 ++
 drivers/usb/core/port.c | 54 ++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 71 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 90ea597d42ae..4165f71e212b 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -31,7 +31,9 @@
 #include <linux/minmax.h>
 #include <linux/mutex.h>
 #include <linux/random.h>
+#include <linux/of_graph.h>
 #include <linux/pm_qos.h>
+#include <linux/pwrseq/consumer.h>
 #include <linux/kobject.h>
 
 #include <linux/bitfield.h>
@@ -888,13 +890,25 @@ int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
 {
 	int ret;
 
+	if (set)
+		ret = pwrseq_power_on(hub->ports[port1 - 1]->pwrseq);
+	else
+		ret = pwrseq_power_off(hub->ports[port1 - 1]->pwrseq);
+	if (ret)
+		return ret;
+
 	if (set)
 		ret = set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
 	else
 		ret = usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
 
-	if (ret)
+	if (ret) {
+		if (set)
+			pwrseq_power_off(hub->ports[port1 - 1]->pwrseq);
+		else
+			pwrseq_power_on(hub->ports[port1 - 1]->pwrseq);
 		return ret;
+	}
 
 	if (set)
 		set_bit(port1, hub->power_bits);
@@ -1867,6 +1881,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
 	struct usb_host_interface *desc;
 	struct usb_device *hdev;
 	struct usb_hub *hub;
+	int ret;
 
 	desc = intf->cur_altsetting;
 	hdev = interface_to_usbdev(intf);
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
index 9ebc5ef54a32..6039e5f5dcd7 100644
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -85,6 +85,7 @@ struct usb_hub {
  * @port_owner: port's owner
  * @peer: related usb2 and usb3 ports (share the same connector)
  * @connector: USB Type-C connector
+ * @pwrseq: power sequencing descriptor for the port
  * @req: default pm qos request for hubs without port power control
  * @connect_type: port's connect type
  * @state: device state of the usb device attached to the port
@@ -104,6 +105,7 @@ struct usb_port {
 	struct usb_dev_state *port_owner;
 	struct usb_port *peer;
 	struct typec_connector *connector;
+	struct pwrseq_desc *pwrseq;
 	struct dev_pm_qos_request *req;
 	enum usb_port_connect_type connect_type;
 	enum usb_device_state state;
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index b1364f0c384c..2d09037fee93 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -7,11 +7,14 @@
  * Author: Lan Tianyu <tianyu.lan@intel.com>
  */
 
+#include <linux/cleanup.h>
 #include <linux/kstrtox.h>
 #include <linux/slab.h>
 #include <linux/string_choices.h>
 #include <linux/sysfs.h>
+#include <linux/of_graph.h>
 #include <linux/pm_qos.h>
+#include <linux/pwrseq/consumer.h>
 #include <linux/component.h>
 #include <linux/usb/of.h>
 
@@ -28,6 +31,9 @@ static bool usb_port_allow_power_off(struct usb_device *hdev,
 	if (hub_is_port_power_switchable(hub))
 		return true;
 
+	if (port_dev->pwrseq)
+		return true;
+
 	if (!IS_ENABLED(CONFIG_ACPI))
 		return false;
 
@@ -748,6 +754,32 @@ static const struct component_ops connector_ops = {
 	.unbind = connector_unbind,
 };
 
+static struct pwrseq_desc *usb_hub_port_pwrseq_get(struct usb_device *hub, int port1)
+{
+	struct device_node *node = dev_of_node(&hub->dev);
+	struct device_node *np __free(device_node) = NULL;
+
+	if (!IS_ENABLED(CONFIG_OF))
+		return NULL;
+
+	if (!IS_ENABLED(CONFIG_POWER_SEQUENCING))
+		return NULL;
+
+	if (!of_graph_is_present(node))
+		return NULL;
+
+	np = of_graph_get_remote_node(node, port1, -1);
+	if (!np)
+		return NULL;
+
+	if (!of_device_is_compatible(np, "pcie-m2-e-connector")) {
+		dev_dbg(&hub->dev, "remote endpoint %pOF not m2 connector", np);
+		return NULL;
+	}
+
+	return pwrseq_get_index(&hub->dev, "usb", port1);
+}
+
 int usb_hub_create_port_device(struct usb_hub *hub, int port1)
 {
 	struct usb_port *port_dev;
@@ -801,10 +833,24 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1)
 		goto err_put_kn;
 	}
 
+	port_dev->pwrseq = usb_hub_port_pwrseq_get(hdev, port1);
+	if (IS_ERR(port_dev->pwrseq)) {
+		retval = PTR_ERR(port_dev->pwrseq);
+		dev_err_probe(&port_dev->dev, retval,
+			      "failed to get power sequencing descriptor\n");
+		goto err_put_kn;
+	}
+
+	retval = pwrseq_power_on(port_dev->pwrseq);
+	if (retval) {
+		dev_err_probe(&port_dev->dev, retval, "failed to enable power\n");
+		goto err_put_pwrseq;
+	}
+
 	retval = component_add(&port_dev->dev, &connector_ops);
 	if (retval) {
 		dev_warn(&port_dev->dev, "failed to add component\n");
-		goto err_put_kn;
+		goto err_pwrseq_off;
 	}
 
 	find_and_link_peer(hub, port1);
@@ -842,6 +888,10 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1)
 	}
 	return 0;
 
+err_pwrseq_off:
+	pwrseq_power_off(port_dev->pwrseq);
+err_put_pwrseq:
+	pwrseq_put(port_dev->pwrseq);
 err_put_kn:
 	sysfs_put(port_dev->state_kn);
 err_unregister:
@@ -858,6 +908,8 @@ void usb_hub_remove_port_device(struct usb_hub *hub, int port1)
 	peer = port_dev->peer;
 	if (peer)
 		unlink_peers(port_dev, peer);
+	pwrseq_power_off(port_dev->pwrseq);
+	pwrseq_put(port_dev->pwrseq);
 	component_del(&port_dev->dev, &connector_ops);
 	sysfs_put(port_dev->state_kn);
 	device_unregister(&port_dev->dev);
-- 
2.54.0.563.g4f69b47b94-goog


  parent reply	other threads:[~2026-05-15  9:02 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-15  9:01 [PATCH RFC 00/12] arm64: mediatek: Add M.2 E-key slot on Chromebooks Chen-Yu Tsai
2026-05-15  9:01 ` [PATCH RFC 01/12] power: sequencing: Add index parameter for getting power sequencer Chen-Yu Tsai
2026-05-15  9:01 ` [PATCH RFC 02/12] power: sequencing: pcie-m2: implement port index matching Chen-Yu Tsai
2026-05-15  9:01 ` [PATCH RFC 03/12] power: sequencing: pcie-m2: Add usb and sdio targets for E-key connector Chen-Yu Tsai
2026-05-15  9:01 ` [PATCH RFC 04/12] usb: hub: Return actual error from hub_configure() in hub_probe() Chen-Yu Tsai
2026-05-15  9:01 ` Chen-Yu Tsai [this message]
2026-05-15 14:39   ` [PATCH RFC 05/12] usb: hub: Power on connected M.2 E-key connectors Alan Stern
2026-05-15  9:01 ` [PATCH RFC 06/12] Revert "dt-bindings: usb: mediatek,mtk-xhci: Add port for SuperSpeed EP" Chen-Yu Tsai
2026-05-15  9:01 ` [PATCH RFC 07/12] dt-bindings: usb: mediatek,mtk-xhci: Allow ports for USB connections Chen-Yu Tsai
2026-05-15  9:01 ` [PATCH RFC 08/12] arm64: dts: mediatek: mt8192-asurada: Add USB type-A connector Chen-Yu Tsai
2026-05-15  9:01 ` [PATCH RFC 09/12] arm64: dts: mediatek: mt8192-asurada: Add M.2 E-key slot Chen-Yu Tsai
2026-05-15  9:01 ` [PATCH RFC 10/12] arm64: dts: mediatek: mt8195-cherry: " Chen-Yu Tsai
2026-05-15  9:01 ` [PATCH RFC 11/12] arm64: dts: mediatek: mt8195-cherry: Add USB type-A connector Chen-Yu Tsai
2026-05-15  9:01 ` [PATCH RFC 12/12] arm64: dts: mediatek: mt8188-geralt: Add WiFi/BT as M.2 E-key slot Chen-Yu Tsai

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=20260515090149.3169406-6-wenst@chromium.org \
    --to=wenst@chromium.org \
    --cc=angelogioacchino.delregno@collabora.com \
    --cc=brgl@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=krzk+dt@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mediatek@lists.infradead.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=mani@kernel.org \
    --cc=matthias.bgg@gmail.com \
    --cc=robh@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