Skip to content

Commit bdecb33

Browse files
Heikki Krogerusgregkh
authored andcommitted
usb: typec: API for controlling USB Type-C Multiplexers
USB Type-C connectors consist of various muxes and switches that route the pins on the connector to the right locations. The USB Type-C drivers need to be able to control the muxes, as they are the ones that know things like the cable plug orientation, and the current mode that was negotiated with the partner. This introduces a small API for registering and controlling cable plug orientation switches, and separate small API for registering and controlling pin multiplexer/demultiplexer switches that are needed with Accessory/Alternate Modes. Reviewed-by: Hans de Goede <[email protected]> Reviewed-by: Andy Shevchenko <[email protected]> Signed-off-by: Heikki Krogerus <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent f2d9b66 commit bdecb33

File tree

6 files changed

+393
-11
lines changed

6 files changed

+393
-11
lines changed

Documentation/driver-api/usb/typec.rst

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ Registering the ports
6161
The port drivers will describe every Type-C port they control with struct
6262
typec_capability data structure, and register them with the following API:
6363

64-
.. kernel-doc:: drivers/usb/typec/typec.c
64+
.. kernel-doc:: drivers/usb/typec/class.c
6565
:functions: typec_register_port typec_unregister_port
6666

6767
When registering the ports, the prefer_role member in struct typec_capability
@@ -80,7 +80,7 @@ typec_partner_desc. The class copies the details of the partner during
8080
registration. The class offers the following API for registering/unregistering
8181
partners.
8282

83-
.. kernel-doc:: drivers/usb/typec/typec.c
83+
.. kernel-doc:: drivers/usb/typec/class.c
8484
:functions: typec_register_partner typec_unregister_partner
8585

8686
The class will provide a handle to struct typec_partner if the registration was
@@ -92,7 +92,7 @@ should include handle to struct usb_pd_identity instance. The class will then
9292
create a sysfs directory for the identity under the partner device. The result
9393
of Discover Identity command can then be reported with the following API:
9494

95-
.. kernel-doc:: drivers/usb/typec/typec.c
95+
.. kernel-doc:: drivers/usb/typec/class.c
9696
:functions: typec_partner_set_identity
9797

9898
Registering Cables
@@ -113,7 +113,7 @@ typec_cable_desc and about a plug in struct typec_plug_desc. The class copies
113113
the details during registration. The class offers the following API for
114114
registering/unregistering cables and their plugs:
115115

116-
.. kernel-doc:: drivers/usb/typec/typec.c
116+
.. kernel-doc:: drivers/usb/typec/class.c
117117
:functions: typec_register_cable typec_unregister_cable typec_register_plug typec_unregister_plug
118118

119119
The class will provide a handle to struct typec_cable and struct typec_plug if
@@ -125,7 +125,7 @@ include handle to struct usb_pd_identity instance. The class will then create a
125125
sysfs directory for the identity under the cable device. The result of Discover
126126
Identity command can then be reported with the following API:
127127

128-
.. kernel-doc:: drivers/usb/typec/typec.c
128+
.. kernel-doc:: drivers/usb/typec/class.c
129129
:functions: typec_cable_set_identity
130130

131131
Notifications
@@ -135,7 +135,7 @@ When the partner has executed a role change, or when the default roles change
135135
during connection of a partner or cable, the port driver must use the following
136136
APIs to report it to the class:
137137

138-
.. kernel-doc:: drivers/usb/typec/typec.c
138+
.. kernel-doc:: drivers/usb/typec/class.c
139139
:functions: typec_set_data_role typec_set_pwr_role typec_set_vconn_role typec_set_pwr_opmode
140140

141141
Alternate Modes
@@ -150,7 +150,7 @@ and struct typec_altmode_desc which is a container for all the supported modes.
150150
Ports that support Alternate Modes need to register each SVID they support with
151151
the following API:
152152

153-
.. kernel-doc:: drivers/usb/typec/typec.c
153+
.. kernel-doc:: drivers/usb/typec/class.c
154154
:functions: typec_port_register_altmode
155155

156156
If a partner or cable plug provides a list of SVIDs as response to USB Power
@@ -159,24 +159,75 @@ registered.
159159

160160
API for the partners:
161161

162-
.. kernel-doc:: drivers/usb/typec/typec.c
162+
.. kernel-doc:: drivers/usb/typec/class.c
163163
:functions: typec_partner_register_altmode
164164

165165
API for the Cable Plugs:
166166

167-
.. kernel-doc:: drivers/usb/typec/typec.c
167+
.. kernel-doc:: drivers/usb/typec/class.c
168168
:functions: typec_plug_register_altmode
169169

170170
So ports, partners and cable plugs will register the alternate modes with their
171171
own functions, but the registration will always return a handle to struct
172172
typec_altmode on success, or NULL. The unregistration will happen with the same
173173
function:
174174

175-
.. kernel-doc:: drivers/usb/typec/typec.c
175+
.. kernel-doc:: drivers/usb/typec/class.c
176176
:functions: typec_unregister_altmode
177177

178178
If a partner or cable plug enters or exits a mode, the port driver needs to
179179
notify the class with the following API:
180180

181-
.. kernel-doc:: drivers/usb/typec/typec.c
181+
.. kernel-doc:: drivers/usb/typec/class.c
182182
:functions: typec_altmode_update_active
183+
184+
Multiplexer/DeMultiplexer Switches
185+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
186+
187+
USB Type-C connectors may have one or more mux/demux switches behind them. Since
188+
the plugs can be inserted right-side-up or upside-down, a switch is needed to
189+
route the correct data pairs from the connector to the USB controllers. If
190+
Alternate or Accessory Modes are supported, another switch is needed that can
191+
route the pins on the connector to some other component besides USB. USB Type-C
192+
Connector Class supplies an API for registering those switches.
193+
194+
.. kernel-doc:: drivers/usb/typec/mux.c
195+
:functions: typec_switch_register typec_switch_unregister typec_mux_register typec_mux_unregister
196+
197+
In most cases the same physical mux will handle both the orientation and mode.
198+
However, as the port drivers will be responsible for the orientation, and the
199+
alternate mode drivers for the mode, the two are always separated into their
200+
own logical components: "mux" for the mode and "switch" for the orientation.
201+
202+
When a port is registered, USB Type-C Connector Class requests both the mux and
203+
the switch for the port. The drivers can then use the following API for
204+
controlling them:
205+
206+
.. kernel-doc:: drivers/usb/typec/class.c
207+
:functions: typec_set_orientation typec_set_mode
208+
209+
If the connector is dual-role capable, there may also be a switch for the data
210+
role. USB Type-C Connector Class does not supply separate API for them. The
211+
port drivers can use USB Role Class API with those.
212+
213+
Illustration of the muxes behind a connector that supports an alternate mode:
214+
215+
------------------------
216+
| Connector |
217+
------------------------
218+
| |
219+
------------------------
220+
\ Orientation /
221+
--------------------
222+
|
223+
--------------------
224+
/ Mode \
225+
------------------------
226+
/ \
227+
------------------------ --------------------
228+
| Alt Mode | / USB Role \
229+
------------------------ ------------------------
230+
/ \
231+
------------------------ ------------------------
232+
| USB Host | | USB Device |
233+
------------------------ ------------------------

drivers/usb/typec/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# SPDX-License-Identifier: GPL-2.0
22
obj-$(CONFIG_TYPEC) += typec.o
3+
typec-y := class.o mux.o
34
obj-$(CONFIG_TYPEC_TCPM) += tcpm.o
45
obj-y += fusb302/
56
obj-$(CONFIG_TYPEC_WCOVE) += typec_wcove.o

drivers/usb/typec/typec.c renamed to drivers/usb/typec/class.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/mutex.h>
1212
#include <linux/slab.h>
1313
#include <linux/usb/typec.h>
14+
#include <linux/usb/typec_mux.h>
1415

1516
struct typec_mode {
1617
int index;
@@ -70,6 +71,10 @@ struct typec_port {
7071
enum typec_port_type port_type;
7172
struct mutex port_type_lock;
7273

74+
enum typec_orientation orientation;
75+
struct typec_switch *sw;
76+
struct typec_mux *mux;
77+
7378
const struct typec_capability *cap;
7479
};
7580

@@ -92,6 +97,7 @@ static const struct device_type typec_port_dev_type;
9297
static DEFINE_IDA(typec_index_ida);
9398
static struct class *typec_class;
9499

100+
/* ------------------------------------------------------------------------- */
95101
/* Common attributes */
96102

97103
static const char * const typec_accessory_modes[] = {
@@ -1137,6 +1143,8 @@ static void typec_release(struct device *dev)
11371143
struct typec_port *port = to_typec_port(dev);
11381144

11391145
ida_simple_remove(&typec_index_ida, port->id);
1146+
typec_switch_put(port->sw);
1147+
typec_mux_put(port->mux);
11401148
kfree(port);
11411149
}
11421150

@@ -1246,6 +1254,47 @@ void typec_set_pwr_opmode(struct typec_port *port,
12461254
}
12471255
EXPORT_SYMBOL_GPL(typec_set_pwr_opmode);
12481256

1257+
/* ------------------------------------------ */
1258+
/* API for Multiplexer/DeMultiplexer Switches */
1259+
1260+
/**
1261+
* typec_set_orientation - Set USB Type-C cable plug orientation
1262+
* @port: USB Type-C Port
1263+
* @orientation: USB Type-C cable plug orientation
1264+
*
1265+
* Set cable plug orientation for @port.
1266+
*/
1267+
int typec_set_orientation(struct typec_port *port,
1268+
enum typec_orientation orientation)
1269+
{
1270+
int ret;
1271+
1272+
if (port->sw) {
1273+
ret = port->sw->set(port->sw, orientation);
1274+
if (ret)
1275+
return ret;
1276+
}
1277+
1278+
port->orientation = orientation;
1279+
1280+
return 0;
1281+
}
1282+
EXPORT_SYMBOL_GPL(typec_set_orientation);
1283+
1284+
/**
1285+
* typec_set_mode - Set mode of operation for USB Type-C connector
1286+
* @port: USB Type-C port for the connector
1287+
* @mode: Operation mode for the connector
1288+
*
1289+
* Set mode @mode for @port. This function will configure the muxes needed to
1290+
* enter @mode.
1291+
*/
1292+
int typec_set_mode(struct typec_port *port, int mode)
1293+
{
1294+
return port->mux ? port->mux->set(port->mux, mode) : 0;
1295+
}
1296+
EXPORT_SYMBOL_GPL(typec_set_mode);
1297+
12491298
/* --------------------------------------- */
12501299

12511300
/**
@@ -1293,6 +1342,18 @@ struct typec_port *typec_register_port(struct device *parent,
12931342
return ERR_PTR(id);
12941343
}
12951344

1345+
port->sw = typec_switch_get(cap->fwnode ? &port->dev : parent);
1346+
if (IS_ERR(port->sw)) {
1347+
ret = PTR_ERR(port->sw);
1348+
goto err_switch;
1349+
}
1350+
1351+
port->mux = typec_mux_get(cap->fwnode ? &port->dev : parent);
1352+
if (IS_ERR(port->mux)) {
1353+
ret = PTR_ERR(port->mux);
1354+
goto err_mux;
1355+
}
1356+
12961357
if (cap->type == TYPEC_PORT_DFP)
12971358
role = TYPEC_SOURCE;
12981359
else if (cap->type == TYPEC_PORT_UFP)
@@ -1330,6 +1391,15 @@ struct typec_port *typec_register_port(struct device *parent,
13301391
}
13311392

13321393
return port;
1394+
1395+
err_mux:
1396+
typec_switch_put(port->sw);
1397+
1398+
err_switch:
1399+
ida_simple_remove(&typec_index_ida, port->id);
1400+
kfree(port);
1401+
1402+
return ERR_PTR(ret);
13331403
}
13341404
EXPORT_SYMBOL_GPL(typec_register_port);
13351405

0 commit comments

Comments
 (0)