Skip to content

Commit 4ab8c18

Browse files
Heikki Krogerusgregkh
authored andcommitted
usb: typec: Register a device for every mode
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 <[email protected]> Tested-by: Hans de Goede <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 93dd211 commit 4ab8c18

File tree

3 files changed

+83
-171
lines changed

3 files changed

+83
-171
lines changed

drivers/usb/typec/class.c

Lines changed: 54 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -13,31 +13,20 @@
1313
#include <linux/usb/typec.h>
1414
#include <linux/usb/typec_mux.h>
1515

16-
struct typec_mode {
17-
int index;
16+
struct typec_altmode {
17+
struct device dev;
18+
u16 svid;
19+
u8 mode;
20+
1821
u32 vdo;
1922
char *desc;
2023
enum typec_port_type roles;
21-
22-
struct typec_altmode *alt_mode;
23-
2424
unsigned int active:1;
2525

26+
struct attribute *attrs[5];
2627
char group_name[6];
2728
struct attribute_group group;
28-
struct attribute *attrs[5];
29-
struct device_attribute vdo_attr;
30-
struct device_attribute desc_attr;
31-
struct device_attribute active_attr;
32-
struct device_attribute roles_attr;
33-
};
34-
35-
struct typec_altmode {
36-
struct device dev;
37-
u16 svid;
38-
int n_modes;
39-
struct typec_mode modes[ALTMODE_MAX_MODES];
40-
const struct attribute_group *mode_groups[ALTMODE_MAX_MODES];
29+
const struct attribute_group *groups[2];
4130
};
4231

4332
struct typec_plug {
@@ -177,23 +166,20 @@ static void typec_report_identity(struct device *dev)
177166
/**
178167
* typec_altmode_update_active - Report Enter/Exit mode
179168
* @alt: Handle to the alternate mode
180-
* @mode: Mode index
181169
* @active: True when the mode has been entered
182170
*
183171
* If a partner or cable plug executes Enter/Exit Mode command successfully, the
184172
* drivers use this routine to report the updated state of the mode.
185173
*/
186-
void typec_altmode_update_active(struct typec_altmode *alt, int mode,
187-
bool active)
174+
void typec_altmode_update_active(struct typec_altmode *alt, bool active)
188175
{
189-
struct typec_mode *m = &alt->modes[mode];
190176
char dir[6];
191177

192-
if (m->active == active)
178+
if (alt->active == active)
193179
return;
194180

195-
m->active = active;
196-
snprintf(dir, sizeof(dir), "mode%d", mode);
181+
alt->active = active;
182+
snprintf(dir, sizeof(dir), "mode%d", alt->mode);
197183
sysfs_notify(&alt->dev.kobj, dir, "active");
198184
kobject_uevent(&alt->dev.kobj, KOBJ_CHANGE);
199185
}
@@ -220,42 +206,36 @@ struct typec_port *typec_altmode2port(struct typec_altmode *alt)
220206
EXPORT_SYMBOL_GPL(typec_altmode2port);
221207

222208
static ssize_t
223-
typec_altmode_vdo_show(struct device *dev, struct device_attribute *attr,
224-
char *buf)
209+
vdo_show(struct device *dev, struct device_attribute *attr, char *buf)
225210
{
226-
struct typec_mode *mode = container_of(attr, struct typec_mode,
227-
vdo_attr);
211+
struct typec_altmode *alt = to_altmode(dev);
228212

229-
return sprintf(buf, "0x%08x\n", mode->vdo);
213+
return sprintf(buf, "0x%08x\n", alt->vdo);
230214
}
215+
static DEVICE_ATTR_RO(vdo);
231216

232217
static ssize_t
233-
typec_altmode_desc_show(struct device *dev, struct device_attribute *attr,
234-
char *buf)
218+
description_show(struct device *dev, struct device_attribute *attr, char *buf)
235219
{
236-
struct typec_mode *mode = container_of(attr, struct typec_mode,
237-
desc_attr);
220+
struct typec_altmode *alt = to_altmode(dev);
238221

239-
return sprintf(buf, "%s\n", mode->desc ? mode->desc : "");
222+
return sprintf(buf, "%s\n", alt->desc ? alt->desc : "");
240223
}
224+
static DEVICE_ATTR_RO(description);
241225

242226
static ssize_t
243-
typec_altmode_active_show(struct device *dev, struct device_attribute *attr,
244-
char *buf)
227+
active_show(struct device *dev, struct device_attribute *attr, char *buf)
245228
{
246-
struct typec_mode *mode = container_of(attr, struct typec_mode,
247-
active_attr);
229+
struct typec_altmode *alt = to_altmode(dev);
248230

249-
return sprintf(buf, "%s\n", mode->active ? "yes" : "no");
231+
return sprintf(buf, "%s\n", alt->active ? "yes" : "no");
250232
}
251233

252-
static ssize_t
253-
typec_altmode_active_store(struct device *dev, struct device_attribute *attr,
254-
const char *buf, size_t size)
234+
static ssize_t active_store(struct device *dev, struct device_attribute *attr,
235+
const char *buf, size_t size)
255236
{
256-
struct typec_mode *mode = container_of(attr, struct typec_mode,
257-
active_attr);
258-
struct typec_port *port = typec_altmode2port(mode->alt_mode);
237+
struct typec_altmode *alt = to_altmode(dev);
238+
struct typec_port *port = typec_altmode2port(alt);
259239
bool activate;
260240
int ret;
261241

@@ -266,22 +246,22 @@ typec_altmode_active_store(struct device *dev, struct device_attribute *attr,
266246
if (ret)
267247
return ret;
268248

269-
ret = port->cap->activate_mode(port->cap, mode->index, activate);
249+
ret = port->cap->activate_mode(port->cap, alt->mode, activate);
270250
if (ret)
271251
return ret;
272252

273253
return size;
274254
}
255+
static DEVICE_ATTR_RW(active);
275256

276257
static ssize_t
277-
typec_altmode_roles_show(struct device *dev, struct device_attribute *attr,
278-
char *buf)
258+
supported_roles_show(struct device *dev, struct device_attribute *attr,
259+
char *buf)
279260
{
280-
struct typec_mode *mode = container_of(attr, struct typec_mode,
281-
roles_attr);
261+
struct typec_altmode *alt = to_altmode(dev);
282262
ssize_t ret;
283263

284-
switch (mode->roles) {
264+
switch (alt->roles) {
285265
case TYPEC_PORT_SRC:
286266
ret = sprintf(buf, "source\n");
287267
break;
@@ -295,61 +275,13 @@ typec_altmode_roles_show(struct device *dev, struct device_attribute *attr,
295275
}
296276
return ret;
297277
}
278+
static DEVICE_ATTR_RO(supported_roles);
298279

299-
static void typec_init_modes(struct typec_altmode *alt,
300-
const struct typec_mode_desc *desc, bool is_port)
280+
static void typec_altmode_release(struct device *dev)
301281
{
302-
int i;
303-
304-
for (i = 0; i < alt->n_modes; i++, desc++) {
305-
struct typec_mode *mode = &alt->modes[i];
306-
307-
/* Not considering the human readable description critical */
308-
mode->desc = kstrdup(desc->desc, GFP_KERNEL);
309-
if (desc->desc && !mode->desc)
310-
dev_err(&alt->dev, "failed to copy mode%d desc\n", i);
311-
312-
mode->alt_mode = alt;
313-
mode->vdo = desc->vdo;
314-
mode->roles = desc->roles;
315-
mode->index = desc->index;
316-
sprintf(mode->group_name, "mode%d", desc->index);
317-
318-
sysfs_attr_init(&mode->vdo_attr.attr);
319-
mode->vdo_attr.attr.name = "vdo";
320-
mode->vdo_attr.attr.mode = 0444;
321-
mode->vdo_attr.show = typec_altmode_vdo_show;
322-
323-
sysfs_attr_init(&mode->desc_attr.attr);
324-
mode->desc_attr.attr.name = "description";
325-
mode->desc_attr.attr.mode = 0444;
326-
mode->desc_attr.show = typec_altmode_desc_show;
327-
328-
sysfs_attr_init(&mode->active_attr.attr);
329-
mode->active_attr.attr.name = "active";
330-
mode->active_attr.attr.mode = 0644;
331-
mode->active_attr.show = typec_altmode_active_show;
332-
mode->active_attr.store = typec_altmode_active_store;
333-
334-
mode->attrs[0] = &mode->vdo_attr.attr;
335-
mode->attrs[1] = &mode->desc_attr.attr;
336-
mode->attrs[2] = &mode->active_attr.attr;
337-
338-
/* With ports, list the roles that the mode is supported with */
339-
if (is_port) {
340-
sysfs_attr_init(&mode->roles_attr.attr);
341-
mode->roles_attr.attr.name = "supported_roles";
342-
mode->roles_attr.attr.mode = 0444;
343-
mode->roles_attr.show = typec_altmode_roles_show;
344-
345-
mode->attrs[3] = &mode->roles_attr.attr;
346-
}
347-
348-
mode->group.attrs = mode->attrs;
349-
mode->group.name = mode->group_name;
282+
struct typec_altmode *alt = to_altmode(dev);
350283

351-
alt->mode_groups[i] = &mode->group;
352-
}
284+
kfree(alt);
353285
}
354286

355287
static ssize_t svid_show(struct device *dev, struct device_attribute *attr,
@@ -367,16 +299,6 @@ static struct attribute *typec_altmode_attrs[] = {
367299
};
368300
ATTRIBUTE_GROUPS(typec_altmode);
369301

370-
static void typec_altmode_release(struct device *dev)
371-
{
372-
struct typec_altmode *alt = to_altmode(dev);
373-
int i;
374-
375-
for (i = 0; i < alt->n_modes; i++)
376-
kfree(alt->modes[i].desc);
377-
kfree(alt);
378-
}
379-
380302
static const struct device_type typec_altmode_dev_type = {
381303
.name = "typec_alternate_mode",
382304
.groups = typec_altmode_groups,
@@ -395,13 +317,27 @@ typec_register_altmode(struct device *parent,
395317
return ERR_PTR(-ENOMEM);
396318

397319
alt->svid = desc->svid;
398-
alt->n_modes = desc->n_modes;
399-
typec_init_modes(alt, desc->modes, is_typec_port(parent));
320+
alt->mode = desc->mode;
321+
alt->vdo = desc->vdo;
322+
alt->roles = desc->roles;
323+
324+
alt->attrs[0] = &dev_attr_vdo.attr;
325+
alt->attrs[1] = &dev_attr_description.attr;
326+
alt->attrs[2] = &dev_attr_active.attr;
327+
328+
if (is_typec_port(parent))
329+
alt->attrs[3] = &dev_attr_supported_roles.attr;
330+
331+
sprintf(alt->group_name, "mode%d", desc->mode);
332+
alt->group.name = alt->group_name;
333+
alt->group.attrs = alt->attrs;
334+
alt->groups[0] = &alt->group;
400335

401336
alt->dev.parent = parent;
402-
alt->dev.groups = alt->mode_groups;
337+
alt->dev.groups = alt->groups;
403338
alt->dev.type = &typec_altmode_dev_type;
404-
dev_set_name(&alt->dev, "svid-%04x", alt->svid);
339+
dev_set_name(&alt->dev, "%s-%04x:%u", dev_name(parent),
340+
alt->svid, alt->mode);
405341

406342
ret = device_register(&alt->dev);
407343
if (ret) {

drivers/usb/typec/tcpm.c

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,8 @@ struct tcpm_port {
310310

311311
/* Alternate mode data */
312312
struct pd_mode_data mode_data;
313-
struct typec_altmode *partner_altmode[SVID_DISCOVERY_MAX];
314-
struct typec_altmode *port_altmode[SVID_DISCOVERY_MAX];
313+
struct typec_altmode *partner_altmode[SVID_DISCOVERY_MAX * 6];
314+
struct typec_altmode *port_altmode[SVID_DISCOVERY_MAX * 6];
315315

316316
/* Deadline in jiffies to exit src_try_wait state */
317317
unsigned long max_wait;
@@ -995,40 +995,35 @@ static void svdm_consume_modes(struct tcpm_port *port, const __le32 *payload,
995995
{
996996
struct pd_mode_data *pmdata = &port->mode_data;
997997
struct typec_altmode_desc *paltmode;
998-
struct typec_mode_desc *pmode;
999998
int i;
1000999

10011000
if (pmdata->altmodes >= ARRAY_SIZE(port->partner_altmode)) {
10021001
/* Already logged in svdm_consume_svids() */
10031002
return;
10041003
}
10051004

1006-
paltmode = &pmdata->altmode_desc[pmdata->altmodes];
1007-
memset(paltmode, 0, sizeof(*paltmode));
1005+
for (i = 1; i < cnt; i++) {
1006+
paltmode = &pmdata->altmode_desc[pmdata->altmodes];
1007+
memset(paltmode, 0, sizeof(*paltmode));
10081008

1009-
paltmode->svid = pmdata->svids[pmdata->svid_index];
1009+
paltmode->svid = pmdata->svids[pmdata->svid_index];
1010+
paltmode->mode = i;
1011+
paltmode->vdo = le32_to_cpu(payload[i]);
10101012

1011-
tcpm_log(port, " Alternate mode %d: SVID 0x%04x",
1012-
pmdata->altmodes, paltmode->svid);
1013+
tcpm_log(port, " Alternate mode %d: SVID 0x%04x, VDO %d: 0x%08x",
1014+
pmdata->altmodes, paltmode->svid,
1015+
paltmode->mode, paltmode->vdo);
10131016

1014-
for (i = 1; i < cnt && paltmode->n_modes < ALTMODE_MAX_MODES; i++) {
1015-
pmode = &paltmode->modes[paltmode->n_modes];
1016-
memset(pmode, 0, sizeof(*pmode));
1017-
pmode->vdo = le32_to_cpu(payload[i]);
1018-
pmode->index = i - 1;
1019-
paltmode->n_modes++;
1020-
tcpm_log(port, " VDO %d: 0x%08x",
1021-
pmode->index, pmode->vdo);
1022-
}
1023-
port->partner_altmode[pmdata->altmodes] =
1024-
typec_partner_register_altmode(port->partner, paltmode);
1025-
if (!port->partner_altmode[pmdata->altmodes]) {
1026-
tcpm_log(port,
1027-
"Failed to register alternate modes for SVID 0x%04x",
1028-
paltmode->svid);
1029-
return;
1017+
port->partner_altmode[pmdata->altmodes] =
1018+
typec_partner_register_altmode(port->partner, paltmode);
1019+
if (!port->partner_altmode[pmdata->altmodes]) {
1020+
tcpm_log(port,
1021+
"Failed to register modes for SVID 0x%04x",
1022+
paltmode->svid);
1023+
return;
1024+
}
1025+
pmdata->altmodes++;
10301026
}
1031-
pmdata->altmodes++;
10321027
}
10331028

10341029
#define supports_modal(port) PD_IDH_MODAL_SUPP((port)->partner_ident.id_header)

include/linux/usb/typec.h

Lines changed: 9 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -93,41 +93,23 @@ int typec_partner_set_identity(struct typec_partner *partner);
9393
int typec_cable_set_identity(struct typec_cable *cable);
9494

9595
/*
96-
* struct typec_mode_desc - Individual Mode of an Alternate Mode
97-
* @index: Index of the Mode within the SVID
96+
* struct typec_altmode_desc - USB Type-C Alternate Mode Descriptor
97+
* @svid: Standard or Vendor ID
98+
* @mode: Index of the Mode
9899
* @vdo: VDO returned by Discover Modes USB PD command
99-
* @desc: Optional human readable description of the mode
100100
* @roles: Only for ports. DRP if the mode is available in both roles
101101
*
102-
* Description of a mode of an Alternate Mode which a connector, cable plug or
103-
* partner supports. Every mode will have it's own sysfs group. The details are
104-
* the VDO returned by discover modes command, description for the mode and
105-
* active flag telling has the mode being entered or not.
102+
* Description of an Alternate Mode which a connector, cable plug or partner
103+
* supports.
106104
*/
107-
struct typec_mode_desc {
108-
int index;
105+
struct typec_altmode_desc {
106+
u16 svid;
107+
u8 mode;
109108
u32 vdo;
110-
char *desc;
111109
/* Only used with ports */
112110
enum typec_port_type roles;
113111
};
114112

115-
/*
116-
* struct typec_altmode_desc - USB Type-C Alternate Mode Descriptor
117-
* @svid: Standard or Vendor ID
118-
* @n_modes: Number of modes
119-
* @modes: Array of modes supported by the Alternate Mode
120-
*
121-
* Representation of an Alternate Mode that has SVID assigned by USB-IF. The
122-
* array of modes will list the modes of a particular SVID that are supported by
123-
* a connector, partner of a cable plug.
124-
*/
125-
struct typec_altmode_desc {
126-
u16 svid;
127-
int n_modes;
128-
struct typec_mode_desc modes[ALTMODE_MAX_MODES];
129-
};
130-
131113
struct typec_altmode
132114
*typec_partner_register_altmode(struct typec_partner *partner,
133115
const struct typec_altmode_desc *desc);
@@ -141,8 +123,7 @@ void typec_unregister_altmode(struct typec_altmode *altmode);
141123

142124
struct typec_port *typec_altmode2port(struct typec_altmode *alt);
143125

144-
void typec_altmode_update_active(struct typec_altmode *alt, int mode,
145-
bool active);
126+
void typec_altmode_update_active(struct typec_altmode *alt, bool active);
146127

147128
enum typec_plug_index {
148129
TYPEC_PLUG_SOP_P,

0 commit comments

Comments
 (0)