[PATCH v10 01/11] usb: typec: Add notifier functions
Heikki Krogerus
heikki.krogerus at linux.intel.com
Wed Nov 26 04:26:49 PST 2025
Wed, Nov 26, 2025 at 07:51:33PM +0800, Chaoyi Chen kirjoitti:
> On 11/26/2025 7:44 PM, Greg Kroah-Hartman wrote:
> > On Wed, Nov 26, 2025 at 11:42:43AM +0200, Heikki Krogerus wrote:
> >> Wed, Nov 26, 2025 at 09:46:19AM +0800, Chaoyi Chen kirjoitti:
> >>> On 11/25/2025 7:49 PM, Greg Kroah-Hartman wrote:
> >>>>> +static umode_t typec_is_visible(struct kobject *kobj, struct attribute *attr, int n)
> >>>>> +{
> >>>>> + if (is_typec_port(kobj_to_dev(kobj)->parent))
> >>>>
> >>>> Why look at the parent? Doesn't the device have a type that should show
> >>>> this?
> >>>>
> >>>> Otherwise, looks good to me.
> >>>
> >>> They have same deivce type "typec_altmode_dev_type".
> >>> The parent device has a different device type to distinguish between
> >>> port device and partner device.
> >>
> >> I was already wondering would it make sense to provide separate device
> >> types for the port, and also plug, alternate modes, but I'm not sure
> >> if that's the right thing to do.
> >>
> >> There is a plan to register an "altmode" also for the USB4 mode,
> >> which of course is not an alternate mode. So USB4 will definitely need a
> >> separate device type.
> >>
> >> So if we supply separate device types for the port, plug and partner
> >> alternate modes, we need to supply separate device types for port, plug
> >> and partner USB4 mode as well.
> >>
> >> We certainly can still do that, but I'm just not sure if it makes
> >> sense?
> >>
> >> I'll prepare a new version for this and include a separate patch where
> >> instead of defining separate device types for the port and plug
> >> alternate modes I'll just supply helpers is_port_alternate_mode() and
> >> is_plug_alternate_mode().
> >
> > That feels like it would be better in the long run as it would be
> > easier to "match" on the device type.
> >
>
> It make sense. But now can we first use the current "match" device type
> operation and then modify them later?
Let's do this right from the beginning. Here's a version with the
dedicated device types.
--
heikki
-------------- next part --------------
>From c0b2afa035cff0788c68869bf454c43eab2b201f Mon Sep 17 00:00:00 2001
From: Heikki Krogerus <heikki.krogerus at linux.intel.com>
Date: Tue, 25 Nov 2025 10:38:04 +0100
Subject: [PATCH v2] usb: typec: Set the bus also for the port and plug altmodes
The port and plug altmodes can't be bound to the altmode
drivers because the altmode drivers are meant for partner
communication using the VDM (vendor defined messages), but
they can still be part of the bus. The bus will make sure
that the normal bus notifications are available also with
the port altmodes.
The previously used common device type for all alternate
modes is replaced with separate dedicated device types for
port, plug, and partner alternate modes.
Signed-off-by: Heikki Krogerus <heikki.krogerus at linux.intel.com>
---
v2: Added the dedicated device types.
---
drivers/usb/typec/bus.c | 24 +++++++++++++++++++++++-
drivers/usb/typec/bus.h | 8 ++++++--
drivers/usb/typec/class.c | 33 ++++++++++++++++++++++-----------
3 files changed, 51 insertions(+), 14 deletions(-)
diff --git a/drivers/usb/typec/bus.c b/drivers/usb/typec/bus.c
index a884cec9ab7e..048c0edf6ca4 100644
--- a/drivers/usb/typec/bus.c
+++ b/drivers/usb/typec/bus.c
@@ -445,7 +445,23 @@ static struct attribute *typec_attrs[] = {
&dev_attr_description.attr,
NULL
};
-ATTRIBUTE_GROUPS(typec);
+
+static umode_t typec_is_visible(struct kobject *kobj, struct attribute *attr, int n)
+{
+ if (is_typec_partner_altmode(kobj_to_dev(kobj)))
+ return attr->mode;
+ return 0;
+}
+
+static const struct attribute_group typec_group = {
+ .is_visible = typec_is_visible,
+ .attrs = typec_attrs,
+};
+
+static const struct attribute_group *typec_groups[] = {
+ &typec_group,
+ NULL
+};
static int typec_match(struct device *dev, const struct device_driver *driver)
{
@@ -453,6 +469,9 @@ static int typec_match(struct device *dev, const struct device_driver *driver)
struct typec_altmode *altmode = to_typec_altmode(dev);
const struct typec_device_id *id;
+ if (!is_typec_partner_altmode(dev))
+ return 0;
+
for (id = drv->id_table; id->svid; id++)
if (id->svid == altmode->svid)
return 1;
@@ -469,6 +488,9 @@ static int typec_uevent(const struct device *dev, struct kobj_uevent_env *env)
if (add_uevent_var(env, "MODE=%u", altmode->mode))
return -ENOMEM;
+ if (!is_typec_partner_altmode(dev))
+ return 0;
+
return add_uevent_var(env, "MODALIAS=typec:id%04X", altmode->svid);
}
diff --git a/drivers/usb/typec/bus.h b/drivers/usb/typec/bus.h
index 643b8c81786d..b58e131450d1 100644
--- a/drivers/usb/typec/bus.h
+++ b/drivers/usb/typec/bus.h
@@ -29,8 +29,12 @@ struct altmode {
#define to_altmode(d) container_of(d, struct altmode, adev)
extern const struct bus_type typec_bus;
-extern const struct device_type typec_altmode_dev_type;
+extern const struct device_type typec_port_altmode_dev_type;
+extern const struct device_type typec_plug_altmode_dev_type;
+extern const struct device_type typec_partner_altmode_dev_type;
-#define is_typec_altmode(_dev_) (_dev_->type == &typec_altmode_dev_type)
+#define is_typec_port_altmode(dev) ((dev)->type == &typec_port_altmode_dev_type)
+#define is_typec_plug_altmode(dev) ((dev)->type == &typec_plug_altmode_dev_type)
+#define is_typec_partner_altmode(dev) ((dev)->type == &typec_partner_altmode_dev_type)
#endif /* __USB_TYPEC_ALTMODE_H__ */
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index 9b2647cb199b..d6b88317f8a4 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -235,7 +235,7 @@ static int altmode_match(struct device *dev, const void *data)
struct typec_altmode *adev = to_typec_altmode(dev);
const struct typec_device_id *id = data;
- if (!is_typec_altmode(dev))
+ if (!is_typec_port_altmode(dev))
return 0;
return (adev->svid == id->svid);
@@ -532,15 +532,28 @@ static void typec_altmode_release(struct device *dev)
kfree(alt);
}
-const struct device_type typec_altmode_dev_type = {
- .name = "typec_alternate_mode",
+const struct device_type typec_port_altmode_dev_type = {
+ .name = "typec_port_alternate_mode",
+ .groups = typec_altmode_groups,
+ .release = typec_altmode_release,
+};
+
+const struct device_type typec_plug_altmode_dev_type = {
+ .name = "typec_plug_alternate_mode",
+ .groups = typec_altmode_groups,
+ .release = typec_altmode_release,
+};
+
+const struct device_type typec_partner_altmode_dev_type = {
+ .name = "typec_partner_alternate_mode",
.groups = typec_altmode_groups,
.release = typec_altmode_release,
};
static struct typec_altmode *
typec_register_altmode(struct device *parent,
- const struct typec_altmode_desc *desc)
+ const struct typec_altmode_desc *desc,
+ const struct device_type *type)
{
unsigned int id = altmode_id_get(parent);
bool is_port = is_typec_port(parent);
@@ -575,7 +588,7 @@ typec_register_altmode(struct device *parent,
alt->adev.dev.parent = parent;
alt->adev.dev.groups = alt->groups;
- alt->adev.dev.type = &typec_altmode_dev_type;
+ alt->adev.dev.type = type;
dev_set_name(&alt->adev.dev, "%s.%u", dev_name(parent), id);
get_device(alt->adev.dev.parent);
@@ -584,9 +597,7 @@ typec_register_altmode(struct device *parent,
if (!is_port)
typec_altmode_set_partner(alt);
- /* The partners are bind to drivers */
- if (is_typec_partner(parent))
- alt->adev.dev.bus = &typec_bus;
+ alt->adev.dev.bus = &typec_bus;
/* Plug alt modes need a class to generate udev events. */
if (is_typec_plug(parent))
@@ -963,7 +974,7 @@ struct typec_altmode *
typec_partner_register_altmode(struct typec_partner *partner,
const struct typec_altmode_desc *desc)
{
- return typec_register_altmode(&partner->dev, desc);
+ return typec_register_altmode(&partner->dev, desc, &typec_partner_altmode_dev_type);
}
EXPORT_SYMBOL_GPL(typec_partner_register_altmode);
@@ -1193,7 +1204,7 @@ struct typec_altmode *
typec_plug_register_altmode(struct typec_plug *plug,
const struct typec_altmode_desc *desc)
{
- return typec_register_altmode(&plug->dev, desc);
+ return typec_register_altmode(&plug->dev, desc, &typec_plug_altmode_dev_type);
}
EXPORT_SYMBOL_GPL(typec_plug_register_altmode);
@@ -2493,7 +2504,7 @@ typec_port_register_altmode(struct typec_port *port,
return ERR_CAST(retimer);
}
- adev = typec_register_altmode(&port->dev, desc);
+ adev = typec_register_altmode(&port->dev, desc, &typec_port_altmode_dev_type);
if (IS_ERR(adev)) {
typec_retimer_put(retimer);
typec_mux_put(mux);
--
2.50.1
More information about the linux-arm-kernel
mailing list