From nobody Thu Apr 2 12:17:47 2026 Received: from metis.whiteo.stw.pengutronix.de (metis.whiteo.stw.pengutronix.de [185.203.201.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2707435B65F for ; Mon, 23 Feb 2026 11:27:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.203.201.7 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771846068; cv=none; b=MeEq/S8X/gedmKtqVChaKI86Ey7B9jIChcsMoZxDeoPGrGltV33gkpdBJmO7uDLFuApRHWvC5AuZYeDQICFIw1uHtAkUbGeZJ2WydTn80TcCngbU2CqYK4nbSla/hf07fWUFHmLgQcudB4mtBk4EBh0CB62CGTy6OHbdE+hJ6Jo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771846068; c=relaxed/simple; bh=iiju3CLfKh8GuTQUBQJ/jbKACfrd1x+FVzb9ZYuX1+Q=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=DEhBB2gtg4SGJ5jAK2wneXRNBFFlAw5tRH+tsqTHKTHDKQu+TU8WQRaIs4Jg01oqH36VF4l/2md6sUIojh7beb3z5NVvI7lrdrRZuaxUSeB6gK8nYCk6jJaXvKDjEl2hN04ZmvlZnU5UvyWB7lQXN7V4MpL4Khsi3yGTWNiKF+Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de; spf=pass smtp.mailfrom=pengutronix.de; arc=none smtp.client-ip=185.203.201.7 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pengutronix.de Received: from dude02.red.stw.pengutronix.de ([2a0a:edc0:0:1101:1d::28]) by metis.whiteo.stw.pengutronix.de with esmtp (Exim 4.92) (envelope-from ) id 1vuU6C-0007VH-89; Mon, 23 Feb 2026 12:27:36 +0100 From: Marco Felsch Date: Mon, 23 Feb 2026 12:27:35 +0100 Subject: [PATCH v5 2/4] usb: hub: add infrastructure to pass onboard_dev port features Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260223-v6-16-topic-usb-onboard-dev-v5-2-28d3018a8026@pengutronix.de> References: <20260223-v6-16-topic-usb-onboard-dev-v5-0-28d3018a8026@pengutronix.de> In-Reply-To: <20260223-v6-16-topic-usb-onboard-dev-v5-0-28d3018a8026@pengutronix.de> To: Greg Kroah-Hartman , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Fabio Estevam , Matthias Kaehlcke , Liam Girdwood , Mark Brown Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, kernel@pengutronix.de, Marco Felsch X-Mailer: b4 0.14.2 X-SA-Exim-Connect-IP: 2a0a:edc0:0:1101:1d::28 X-SA-Exim-Mail-From: m.felsch@pengutronix.de X-SA-Exim-Scanned: No (on metis.whiteo.stw.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-kernel@vger.kernel.org On board devices may require special handling for en-/disable port features due to PCB design decisions e.g. enable/disable the VBUS power on the port via a host controlled regulator or GPIO. This commit adds the necessary infrastructure to prepare the common code base for such use-cases. Signed-off-by: Marco Felsch --- drivers/usb/core/hub.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++= ++-- drivers/usb/core/hub.h | 2 ++ include/linux/usb.h | 3 +++ 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 24960ba9caa915f12a4f5582269808fdebd1ee11..9fdfd2f0aacc9b1994cd3761330= 968e052167c67 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -453,9 +453,19 @@ static int clear_hub_feature(struct usb_device *hdev, = int feature) */ int usb_clear_port_feature(struct usb_device *hdev, int port1, int feature) { - return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), + struct usb_hub *hub =3D usb_hub_to_struct_hub(hdev); + int ret; + + ret =3D usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1, NULL, 0, 1000); + if (ret) + return ret; + + if (hub->onboard_hub_clear_port_feature) + ret =3D hub->onboard_hub_clear_port_feature(hdev, feature, port1); + + return ret; } =20 /* @@ -463,9 +473,19 @@ int usb_clear_port_feature(struct usb_device *hdev, in= t port1, int feature) */ static int set_port_feature(struct usb_device *hdev, int port1, int featur= e) { - return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), + struct usb_hub *hub =3D usb_hub_to_struct_hub(hdev); + int ret; + + ret =3D usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port1, NULL, 0, 1000); + if (ret) + return ret; + + if (hub->onboard_hub_set_port_feature) + ret =3D hub->onboard_hub_set_port_feature(hdev, feature, port1); + + return ret; } =20 static char *to_led_name(int selector) @@ -6545,6 +6565,37 @@ void usb_hub_adjust_deviceremovable(struct usb_devic= e *hdev, } } =20 +/** + * usb_hub_register_port_feature_hooks - Register port set/get feature hoo= ks + * @hdev: USB device belonging to the usb hub + * @set_port_feature: set_feature hook which gets called by the hub core + * @clear_port_feature: clear_feature hook which gets called by the hub co= re + * + * Register set/get_port_feature hooks for a onboard_dev hub. + */ +void usb_hub_register_port_feature_hooks(struct usb_device *hdev, + int (*set_port_feature)(struct usb_device *, int, int), + int (*clear_port_feature)(struct usb_device *, int, int)) +{ + struct usb_hub *hub =3D usb_hub_to_struct_hub(hdev); + + if (WARN_ON_ONCE(is_root_hub(hdev) || !hub)) + return; + + if (set_port_feature) + hub->onboard_hub_set_port_feature =3D set_port_feature; + if (clear_port_feature) + hub->onboard_hub_clear_port_feature =3D clear_port_feature; + + /* + * Keep it simple for now. Just check the power state and re-sync it + * after adding the hooks since the onboard-dev may do some additional + * logic e.g. controlling regulators. + */ + hub_power_on(hub, false); +} +EXPORT_SYMBOL_GPL(usb_hub_register_port_feature_hooks); + #ifdef CONFIG_ACPI /** * usb_get_hub_port_acpi_handle - Get the usb port's acpi handle diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 297adf2c6078809ca582104f228e5222c464f999..31800b5922ba896dc7cac5f9e3e= d1a77e7c5a801 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -76,6 +76,8 @@ struct usb_hub { struct timer_list irq_urb_retry; struct usb_port **ports; struct list_head onboard_devs; + int (*onboard_hub_set_port_feature)(struct usb_device *udev, int feature,= int port1); + int (*onboard_hub_clear_port_feature)(struct usb_device *udev, int featur= e, int port1); }; =20 /** diff --git a/include/linux/usb.h b/include/linux/usb.h index fbfcc70b07fbe5dbaa1ca1be55af127c62294cf7..5f68a066029ea0508fad461daf7= ebe6f534778d2 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -946,6 +946,9 @@ int usb_hub_claim_port(struct usb_device *hdev, unsigne= d port1, struct usb_dev_state *owner); int usb_hub_release_port(struct usb_device *hdev, unsigned port1, struct usb_dev_state *owner); +void usb_hub_register_port_feature_hooks(struct usb_device *hdev, + int (*set_port_feature)(struct usb_device *, int, int), + int (*clear_port_feature)(struct usb_device *, int, int)); =20 /** * usb_make_path - returns stable device path in the usb tree --=20 2.47.3