Before a device was created for every discovered SVID, but
this will create a device for every discovered mode of every
SVID. The idea is to make it easier to create mode specific
drivers once a bus for the alternate mode is added.

Signed-off-by: Heikki Krogerus <heikki.kroge...@linux.intel.com>
---
 drivers/usb/typec/class.c | 163 +++++++++++++++-------------------------------
 drivers/usb/typec/tcpm.c  |  45 ++++++-------
 include/linux/usb/typec.h |  34 +++-------
 3 files changed, 79 insertions(+), 163 deletions(-)

diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index 53df10df2f9d..26eeab1491b7 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -13,31 +13,20 @@
 #include <linux/usb/typec.h>
 #include <linux/usb/typec_mux.h>
 
-struct typec_mode {
-       int                             index;
+struct typec_altmode {
+       struct device                   dev;
+       u16                             svid;
+       u8                              mode;
+
        u32                             vdo;
        char                            *desc;
        enum typec_port_type            roles;
-
-       struct typec_altmode            *alt_mode;
-
        unsigned int                    active:1;
 
+       struct attribute                *attrs[5];
        char                            group_name[6];
        struct attribute_group          group;
-       struct attribute                *attrs[5];
-       struct device_attribute         vdo_attr;
-       struct device_attribute         desc_attr;
-       struct device_attribute         active_attr;
-       struct device_attribute         roles_attr;
-};
-
-struct typec_altmode {
-       struct device                   dev;
-       u16                             svid;
-       int                             n_modes;
-       struct typec_mode               modes[ALTMODE_MAX_MODES];
-       const struct attribute_group    *mode_groups[ALTMODE_MAX_MODES];
+       const struct attribute_group    *groups[2];
 };
 
 struct typec_plug {
@@ -186,13 +175,12 @@ static void typec_report_identity(struct device *dev)
 void typec_altmode_update_active(struct typec_altmode *alt, int mode,
                                 bool active)
 {
-       struct typec_mode *m = &alt->modes[mode];
        char dir[6];
 
-       if (m->active == active)
+       if (alt->active == active)
                return;
 
-       m->active = active;
+       alt->active = active;
        snprintf(dir, sizeof(dir), "mode%d", mode);
        sysfs_notify(&alt->dev.kobj, dir, "active");
        kobject_uevent(&alt->dev.kobj, KOBJ_CHANGE);
@@ -220,42 +208,37 @@ struct typec_port *typec_altmode2port(struct 
typec_altmode *alt)
 EXPORT_SYMBOL_GPL(typec_altmode2port);
 
 static ssize_t
-typec_altmode_vdo_show(struct device *dev, struct device_attribute *attr,
-                      char *buf)
+vdo_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct typec_mode *mode = container_of(attr, struct typec_mode,
-                                              vdo_attr);
+       struct typec_altmode *alt = to_altmode(dev);
 
-       return sprintf(buf, "0x%08x\n", mode->vdo);
+       return sprintf(buf, "0x%08x\n", alt->vdo);
 }
+static DEVICE_ATTR_RO(vdo);
 
 static ssize_t
-typec_altmode_desc_show(struct device *dev, struct device_attribute *attr,
-                       char *buf)
+description_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct typec_mode *mode = container_of(attr, struct typec_mode,
-                                              desc_attr);
+       struct typec_altmode *alt = to_altmode(dev);
 
-       return sprintf(buf, "%s\n", mode->desc ? mode->desc : "");
+       return sprintf(buf, "%s\n", alt->desc ? alt->desc : "");
 }
+static DEVICE_ATTR_RO(description);
 
 static ssize_t
-typec_altmode_active_show(struct device *dev, struct device_attribute *attr,
-                         char *buf)
+active_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct typec_mode *mode = container_of(attr, struct typec_mode,
-                                              active_attr);
+       struct typec_altmode *alt = to_altmode(dev);
 
-       return sprintf(buf, "%s\n", mode->active ? "yes" : "no");
+       return sprintf(buf, "%s\n", alt->active ? "yes" : "no");
 }
 
 static ssize_t
-typec_altmode_active_store(struct device *dev, struct device_attribute *attr,
+active_store(struct device *dev, struct device_attribute *attr,
                           const char *buf, size_t size)
 {
-       struct typec_mode *mode = container_of(attr, struct typec_mode,
-                                              active_attr);
-       struct typec_port *port = typec_altmode2port(mode->alt_mode);
+       struct typec_altmode *alt = to_altmode(dev);
+       struct typec_port *port = typec_altmode2port(alt);
        bool activate;
        int ret;
 
@@ -266,22 +249,22 @@ typec_altmode_active_store(struct device *dev, struct 
device_attribute *attr,
        if (ret)
                return ret;
 
-       ret = port->cap->activate_mode(port->cap, mode->index, activate);
+       ret = port->cap->activate_mode(port->cap, alt->mode, activate);
        if (ret)
                return ret;
 
        return size;
 }
+static DEVICE_ATTR_RW(active);
 
 static ssize_t
-typec_altmode_roles_show(struct device *dev, struct device_attribute *attr,
-                        char *buf)
+supported_roles_show(struct device *dev, struct device_attribute *attr,
+                    char *buf)
 {
-       struct typec_mode *mode = container_of(attr, struct typec_mode,
-                                              roles_attr);
+       struct typec_altmode *alt = to_altmode(dev);
        ssize_t ret;
 
-       switch (mode->roles) {
+       switch (alt->roles) {
        case TYPEC_PORT_SRC:
                ret = sprintf(buf, "source\n");
                break;
@@ -295,61 +278,13 @@ typec_altmode_roles_show(struct device *dev, struct 
device_attribute *attr,
        }
        return ret;
 }
+static DEVICE_ATTR_RO(supported_roles);
 
-static void typec_init_modes(struct typec_altmode *alt,
-                            const struct typec_mode_desc *desc, bool is_port)
+static void typec_altmode_release(struct device *dev)
 {
-       int i;
-
-       for (i = 0; i < alt->n_modes; i++, desc++) {
-               struct typec_mode *mode = &alt->modes[i];
-
-               /* Not considering the human readable description critical */
-               mode->desc = kstrdup(desc->desc, GFP_KERNEL);
-               if (desc->desc && !mode->desc)
-                       dev_err(&alt->dev, "failed to copy mode%d desc\n", i);
-
-               mode->alt_mode = alt;
-               mode->vdo = desc->vdo;
-               mode->roles = desc->roles;
-               mode->index = desc->index;
-               sprintf(mode->group_name, "mode%d", desc->index);
-
-               sysfs_attr_init(&mode->vdo_attr.attr);
-               mode->vdo_attr.attr.name = "vdo";
-               mode->vdo_attr.attr.mode = 0444;
-               mode->vdo_attr.show = typec_altmode_vdo_show;
-
-               sysfs_attr_init(&mode->desc_attr.attr);
-               mode->desc_attr.attr.name = "description";
-               mode->desc_attr.attr.mode = 0444;
-               mode->desc_attr.show = typec_altmode_desc_show;
-
-               sysfs_attr_init(&mode->active_attr.attr);
-               mode->active_attr.attr.name = "active";
-               mode->active_attr.attr.mode = 0644;
-               mode->active_attr.show = typec_altmode_active_show;
-               mode->active_attr.store = typec_altmode_active_store;
-
-               mode->attrs[0] = &mode->vdo_attr.attr;
-               mode->attrs[1] = &mode->desc_attr.attr;
-               mode->attrs[2] = &mode->active_attr.attr;
-
-               /* With ports, list the roles that the mode is supported with */
-               if (is_port) {
-                       sysfs_attr_init(&mode->roles_attr.attr);
-                       mode->roles_attr.attr.name = "supported_roles";
-                       mode->roles_attr.attr.mode = 0444;
-                       mode->roles_attr.show = typec_altmode_roles_show;
-
-                       mode->attrs[3] = &mode->roles_attr.attr;
-               }
-
-               mode->group.attrs = mode->attrs;
-               mode->group.name = mode->group_name;
+       struct typec_altmode *alt = to_altmode(dev);
 
-               alt->mode_groups[i] = &mode->group;
-       }
+       kfree(alt);
 }
 
 static ssize_t svid_show(struct device *dev, struct device_attribute *attr,
@@ -367,16 +302,6 @@ static struct attribute *typec_altmode_attrs[] = {
 };
 ATTRIBUTE_GROUPS(typec_altmode);
 
-static void typec_altmode_release(struct device *dev)
-{
-       struct typec_altmode *alt = to_altmode(dev);
-       int i;
-
-       for (i = 0; i < alt->n_modes; i++)
-               kfree(alt->modes[i].desc);
-       kfree(alt);
-}
-
 static const struct device_type typec_altmode_dev_type = {
        .name = "typec_alternate_mode",
        .groups = typec_altmode_groups,
@@ -395,13 +320,27 @@ typec_register_altmode(struct device *parent,
                return ERR_PTR(-ENOMEM);
 
        alt->svid = desc->svid;
-       alt->n_modes = desc->n_modes;
-       typec_init_modes(alt, desc->modes, is_typec_port(parent));
+       alt->mode = desc->mode;
+       alt->vdo = desc->vdo;
+       alt->roles = desc->roles;
+
+       alt->attrs[0] = &dev_attr_vdo.attr;
+       alt->attrs[1] = &dev_attr_description.attr;
+       alt->attrs[2] = &dev_attr_active.attr;
+
+       if (is_typec_port(parent))
+               alt->attrs[3] = &dev_attr_supported_roles.attr;
+
+       sprintf(alt->group_name, "mode%d", desc->mode);
+       alt->group.name = alt->group_name;
+       alt->group.attrs = alt->attrs;
+       alt->groups[0] = &alt->group;
 
        alt->dev.parent = parent;
-       alt->dev.groups = alt->mode_groups;
+       alt->dev.groups = alt->groups;
        alt->dev.type = &typec_altmode_dev_type;
-       dev_set_name(&alt->dev, "svid-%04x", alt->svid);
+       dev_set_name(&alt->dev, "%s-%04x:%u", dev_name(parent),
+                    alt->svid, alt->mode);
 
        ret = device_register(&alt->dev);
        if (ret) {
diff --git a/drivers/usb/typec/tcpm.c b/drivers/usb/typec/tcpm.c
index 4e447e1e9ec6..bfb843ebffa6 100644
--- a/drivers/usb/typec/tcpm.c
+++ b/drivers/usb/typec/tcpm.c
@@ -280,8 +280,8 @@ struct tcpm_port {
        /* Alternate mode data */
 
        struct pd_mode_data mode_data;
-       struct typec_altmode *partner_altmode[SVID_DISCOVERY_MAX];
-       struct typec_altmode *port_altmode[SVID_DISCOVERY_MAX];
+       struct typec_altmode *partner_altmode[SVID_DISCOVERY_MAX * 6];
+       struct typec_altmode *port_altmode[SVID_DISCOVERY_MAX * 6];
 
        /* Deadline in jiffies to exit src_try_wait state */
        unsigned long max_wait;
@@ -966,7 +966,6 @@ static void svdm_consume_modes(struct tcpm_port *port, 
const __le32 *payload,
 {
        struct pd_mode_data *pmdata = &port->mode_data;
        struct typec_altmode_desc *paltmode;
-       struct typec_mode_desc *pmode;
        int i;
 
        if (pmdata->altmodes >= ARRAY_SIZE(port->partner_altmode)) {
@@ -974,32 +973,28 @@ static void svdm_consume_modes(struct tcpm_port *port, 
const __le32 *payload,
                return;
        }
 
-       paltmode = &pmdata->altmode_desc[pmdata->altmodes];
-       memset(paltmode, 0, sizeof(*paltmode));
+       for (i = 1; i < cnt; i++) {
+               paltmode = &pmdata->altmode_desc[pmdata->altmodes];
+               memset(paltmode, 0, sizeof(*paltmode));
 
-       paltmode->svid = pmdata->svids[pmdata->svid_index];
+               paltmode->svid = pmdata->svids[pmdata->svid_index];
+               paltmode->mode = i;
+               paltmode->vdo = le32_to_cpu(payload[i]);
 
-       tcpm_log(port, " Alternate mode %d: SVID 0x%04x",
-                pmdata->altmodes, paltmode->svid);
+               tcpm_log(port, " Alternate mode %d: SVID 0x%04x, VDO %d: 
0x%08x",
+                        pmdata->altmodes, paltmode->svid,
+                        paltmode->mode, paltmode->vdo);
 
-       for (i = 1; i < cnt && paltmode->n_modes < ALTMODE_MAX_MODES; i++) {
-               pmode = &paltmode->modes[paltmode->n_modes];
-               memset(pmode, 0, sizeof(*pmode));
-               pmode->vdo = le32_to_cpu(payload[i]);
-               pmode->index = i - 1;
-               paltmode->n_modes++;
-               tcpm_log(port, "  VDO %d: 0x%08x",
-                        pmode->index, pmode->vdo);
-       }
-       port->partner_altmode[pmdata->altmodes] =
-               typec_partner_register_altmode(port->partner, paltmode);
-       if (!port->partner_altmode[pmdata->altmodes]) {
-               tcpm_log(port,
-                        "Failed to register alternate modes for SVID 0x%04x",
-                        paltmode->svid);
-               return;
+               port->partner_altmode[pmdata->altmodes] =
+                       typec_partner_register_altmode(port->partner, paltmode);
+               if (!port->partner_altmode[pmdata->altmodes]) {
+                       tcpm_log(port,
+                                "Failed to register modes for SVID 0x%04x",
+                                paltmode->svid);
+                       return;
+               }
+               pmdata->altmodes++;
        }
-       pmdata->altmodes++;
 }
 
 #define supports_modal(port)   
PD_IDH_MODAL_SUPP((port)->partner_ident.id_header)
diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h
index 672b39bb0adc..278b6b42c7ea 100644
--- a/include/linux/usb/typec.h
+++ b/include/linux/usb/typec.h
@@ -93,41 +93,23 @@ int typec_partner_set_identity(struct typec_partner 
*partner);
 int typec_cable_set_identity(struct typec_cable *cable);
 
 /*
- * struct typec_mode_desc - Individual Mode of an Alternate Mode
- * @index: Index of the Mode within the SVID
+ * struct typec_altmode_desc - USB Type-C Alternate Mode Descriptor
+ * @svid: Standard or Vendor ID
+ * @mode: Index of the Mode
  * @vdo: VDO returned by Discover Modes USB PD command
- * @desc: Optional human readable description of the mode
  * @roles: Only for ports. DRP if the mode is available in both roles
  *
- * Description of a mode of an Alternate Mode which a connector, cable plug or
- * partner supports. Every mode will have it's own sysfs group. The details are
- * the VDO returned by discover modes command, description for the mode and
- * active flag telling has the mode being entered or not.
+ * Description of an Alternate Mode which a connector, cable plug or partner
+ * supports.
  */
-struct typec_mode_desc {
-       int                     index;
+struct typec_altmode_desc {
+       u16                     svid;
+       u8                      mode;
        u32                     vdo;
-       char                    *desc;
        /* Only used with ports */
        enum typec_port_type    roles;
 };
 
-/*
- * struct typec_altmode_desc - USB Type-C Alternate Mode Descriptor
- * @svid: Standard or Vendor ID
- * @n_modes: Number of modes
- * @modes: Array of modes supported by the Alternate Mode
- *
- * Representation of an Alternate Mode that has SVID assigned by USB-IF. The
- * array of modes will list the modes of a particular SVID that are supported 
by
- * a connector, partner of a cable plug.
- */
-struct typec_altmode_desc {
-       u16                     svid;
-       int                     n_modes;
-       struct typec_mode_desc  modes[ALTMODE_MAX_MODES];
-};
-
 struct typec_altmode
 *typec_partner_register_altmode(struct typec_partner *partner,
                                const struct typec_altmode_desc *desc);
-- 
2.16.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to