1 /* SPDX-License-Identifier: GPL-2.0 */
2
3 #ifndef __USB_TYPEC_ALTMODE_H
4 #define __USB_TYPEC_ALTMODE_H
5
6 #include <linux/mod_devicetable.h>
7 #include <linux/usb/typec.h>
8 #include <linux/device.h>
9
10 #define MODE_DISCOVERY_MAX 6
11
12 extern const struct device_type typec_port_altmode_dev_type;
13 extern const struct device_type typec_plug_altmode_dev_type;
14 extern const struct device_type typec_partner_altmode_dev_type;
15
16 #define is_typec_port_altmode(dev) ((dev)->type == &typec_port_altmode_dev_type)
17 #define is_typec_plug_altmode(dev) ((dev)->type == &typec_plug_altmode_dev_type)
18 #define is_typec_partner_altmode(dev) ((dev)->type == &typec_partner_altmode_dev_type)
19
20 struct typec_altmode_ops;
21
22 /**
23 * struct typec_altmode - USB Type-C alternate mode device
24 * @dev: Driver model's view of this device
25 * @svid: Standard or Vendor ID (SVID) of the alternate mode
26 * @mode: Index of the Mode
27 * @vdo: VDO returned by Discover Modes USB PD command
28 * @active: Tells has the mode been entered or not
29 * @desc: Optional human readable description of the mode
30 * @ops: Operations vector from the driver
31 * @cable_ops: Cable operations vector from the driver.
32 */
33 struct typec_altmode {
34 struct device dev;
35 u16 svid;
36 int mode;
37 u32 vdo;
38 unsigned int active:1;
39 u8 priority;
40 bool mode_selection;
41
42 char *desc;
43 const struct typec_altmode_ops *ops;
44 const struct typec_cable_ops *cable_ops;
45 };
46
47 #define to_typec_altmode(d) container_of(d, struct typec_altmode, dev)
48
typec_altmode_set_drvdata(struct typec_altmode * altmode,void * data)49 static inline void typec_altmode_set_drvdata(struct typec_altmode *altmode,
50 void *data)
51 {
52 dev_set_drvdata(&altmode->dev, data);
53 }
54
typec_altmode_get_drvdata(struct typec_altmode * altmode)55 static inline void *typec_altmode_get_drvdata(struct typec_altmode *altmode)
56 {
57 return dev_get_drvdata(&altmode->dev);
58 }
59
60 /**
61 * struct typec_altmode_ops - Alternate mode specific operations vector
62 * @enter: Operations to be executed with Enter Mode Command
63 * @exit: Operations to be executed with Exit Mode Command
64 * @attention: Callback for Attention Command
65 * @vdm: Callback for SVID specific commands
66 * @notify: Communication channel for platform and the alternate mode
67 * @activate: User callback for Enter/Exit Mode
68 */
69 struct typec_altmode_ops {
70 int (*enter)(struct typec_altmode *altmode, u32 *vdo);
71 int (*exit)(struct typec_altmode *altmode);
72 void (*attention)(struct typec_altmode *altmode, u32 vdo);
73 int (*vdm)(struct typec_altmode *altmode, const u32 hdr,
74 const u32 *vdo, int cnt);
75 int (*notify)(struct typec_altmode *altmode, unsigned long conf,
76 void *data);
77 int (*activate)(struct typec_altmode *altmode, int activate);
78 };
79
80 int typec_altmode_enter(struct typec_altmode *altmode, u32 *vdo);
81 int typec_altmode_exit(struct typec_altmode *altmode);
82 int typec_altmode_attention(struct typec_altmode *altmode, u32 vdo);
83 int typec_altmode_vdm(struct typec_altmode *altmode,
84 const u32 header, const u32 *vdo, int count);
85 int typec_altmode_notify(struct typec_altmode *altmode, unsigned long conf,
86 void *data);
87 const struct typec_altmode *
88 typec_altmode_get_partner(struct typec_altmode *altmode);
89
90 /**
91 * struct typec_cable_ops - Cable alternate mode operations vector
92 * @enter: Operations to be executed with Enter Mode Command
93 * @exit: Operations to be executed with Exit Mode Command
94 * @vdm: Callback for SVID specific commands
95 */
96 struct typec_cable_ops {
97 int (*enter)(struct typec_altmode *altmode, enum typec_plug_index sop, u32 *vdo);
98 int (*exit)(struct typec_altmode *altmode, enum typec_plug_index sop);
99 int (*vdm)(struct typec_altmode *altmode, enum typec_plug_index sop,
100 const u32 hdr, const u32 *vdo, int cnt);
101 };
102
103 int typec_cable_altmode_enter(struct typec_altmode *altmode, enum typec_plug_index sop, u32 *vdo);
104 int typec_cable_altmode_exit(struct typec_altmode *altmode, enum typec_plug_index sop);
105 int typec_cable_altmode_vdm(struct typec_altmode *altmode, enum typec_plug_index sop,
106 const u32 header, const u32 *vdo, int count);
107
108 /**
109 * typec_altmode_get_cable_svdm_version - Get negotiated SVDM version for cable plug
110 * @altmode: Handle to the alternate mode
111 */
112 static inline int
typec_altmode_get_cable_svdm_version(struct typec_altmode * altmode)113 typec_altmode_get_cable_svdm_version(struct typec_altmode *altmode)
114 {
115 return typec_get_cable_svdm_version(typec_altmode2port(altmode));
116 }
117
118 /*
119 * These are the connector states (USB, Safe and Alt Mode) defined in USB Type-C
120 * Specification. SVID specific connector states are expected to follow and
121 * start from the value TYPEC_STATE_MODAL.
122 */
123 enum {
124 TYPEC_STATE_SAFE, /* USB Safe State */
125 TYPEC_STATE_USB, /* USB Operation */
126 TYPEC_STATE_MODAL, /* Alternate Modes */
127 };
128
129 /*
130 * For the muxes there is no difference between Accessory Modes and Alternate
131 * Modes, so the Accessory Modes are supplied with specific modal state values
132 * here. Unlike with Alternate Modes, where the mux will be linked with the
133 * alternate mode device, the mux for Accessory Modes will be linked with the
134 * port device instead.
135 *
136 * Port drivers can use TYPEC_MODE_AUDIO and TYPEC_MODE_DEBUG as the mode
137 * value for typec_set_mode() when accessory modes are supported.
138 *
139 * USB4 also requires that the pins on the connector are repurposed, just like
140 * Alternate Modes. USB4 mode is however not entered with the Enter Mode Command
141 * like the Alternate Modes are, but instead with a special Enter_USB Message.
142 * The Enter_USB Message can also be used for setting to connector to operate in
143 * USB 3.2 or in USB 2.0 mode instead of USB4.
144 *
145 * The Enter_USB specific "USB Modes" are also supplied here as special modal
146 * state values, just like the Accessory Modes.
147 */
148 enum {
149 TYPEC_MODE_USB2 = TYPEC_STATE_MODAL, /* USB 2.0 mode */
150 TYPEC_MODE_USB3, /* USB 3.2 mode */
151 TYPEC_MODE_USB4, /* USB4 mode */
152 TYPEC_MODE_AUDIO, /* Audio Accessory */
153 TYPEC_MODE_DEBUG, /* Debug Accessory */
154 };
155
156 #define TYPEC_MODAL_STATE(_state_) ((_state_) + TYPEC_STATE_MODAL)
157
158 struct typec_altmode *typec_altmode_get_plug(struct typec_altmode *altmode,
159 enum typec_plug_index index);
160 void typec_altmode_put_plug(struct typec_altmode *plug);
161
162 struct typec_altmode *typec_match_altmode(struct typec_altmode **altmodes,
163 size_t n, u16 svid, u8 mode);
164
165 /**
166 * typec_altmode_get_orientation - Get cable plug orientation
167 * @altmode: Handle to the alternate mode
168 */
169 static inline enum typec_orientation
typec_altmode_get_orientation(struct typec_altmode * altmode)170 typec_altmode_get_orientation(struct typec_altmode *altmode)
171 {
172 return typec_get_orientation(typec_altmode2port(altmode));
173 }
174
175 /**
176 * typec_altmode_get_svdm_version - Get negotiated SVDM version
177 * @altmode: Handle to the alternate mode
178 */
179 static inline int
typec_altmode_get_svdm_version(struct typec_altmode * altmode)180 typec_altmode_get_svdm_version(struct typec_altmode *altmode)
181 {
182 return typec_get_negotiated_svdm_version(typec_altmode2port(altmode));
183 }
184
185 /**
186 * typec_altmode_get_data_role - Get port data role
187 * @altmode: Handle to the alternate mode
188 *
189 * Alt Mode drivers should only issue Enter Mode through the port if they are
190 * the DFP.
191 */
192 static inline enum typec_data_role
typec_altmode_get_data_role(struct typec_altmode * altmode)193 typec_altmode_get_data_role(struct typec_altmode *altmode)
194 {
195 return typec_get_data_role(typec_altmode2port(altmode));
196 }
197
198 /**
199 * struct typec_altmode_driver - USB Type-C alternate mode device driver
200 * @id_table: Null terminated array of SVIDs
201 * @probe: Callback for device binding
202 * @remove: Callback for device unbinding
203 * @driver: Device driver model driver
204 *
205 * These drivers will be bind to the partner alternate mode devices. They will
206 * handle all SVID specific communication.
207 */
208 struct typec_altmode_driver {
209 const struct typec_device_id *id_table;
210 int (*probe)(struct typec_altmode *altmode);
211 void (*remove)(struct typec_altmode *altmode);
212 struct device_driver driver;
213 };
214
215 #define to_altmode_driver(d) container_of(d, struct typec_altmode_driver, \
216 driver)
217
218 /**
219 * typec_altmode_register_driver - registers a USB Type-C alternate mode
220 * device driver
221 * @drv: pointer to struct typec_altmode_driver
222 *
223 * These drivers will be bind to the partner alternate mode devices. They will
224 * handle all SVID specific communication.
225 */
226 #define typec_altmode_register_driver(drv) \
227 __typec_altmode_register_driver(drv, THIS_MODULE)
228 int __typec_altmode_register_driver(struct typec_altmode_driver *drv,
229 struct module *module);
230 /**
231 * typec_altmode_unregister_driver - unregisters a USB Type-C alternate mode
232 * device driver
233 * @drv: pointer to struct typec_altmode_driver
234 *
235 * These drivers will be bind to the partner alternate mode devices. They will
236 * handle all SVID specific communication.
237 */
238 void typec_altmode_unregister_driver(struct typec_altmode_driver *drv);
239
240 #define module_typec_altmode_driver(__typec_altmode_driver) \
241 module_driver(__typec_altmode_driver, typec_altmode_register_driver, \
242 typec_altmode_unregister_driver)
243
244 /**
245 * typec_mode_selection_start - Start an alternate mode selection process
246 * @partner: Handle to the Type-C partner device
247 * @delay: Delay between mode entry/exit attempts, ms
248 * @timeout: Timeout for a mode entry attempt, ms
249 *
250 * This function initiates the process of attempting to enter an Alternate Mode
251 * supported by the connected Type-C partner.
252 * Returns 0 on success, or a negative error code on failure.
253 */
254 int typec_mode_selection_start(struct typec_partner *partner,
255 const unsigned int delay, const unsigned int timeout);
256
257 /**
258 * typec_altmode_state_update - Report the current status of an Alternate Mode
259 * negotiation
260 * @partner: Handle to the Type-C partner device
261 * @svid: Standard or Vendor ID of the Alternate Mode. A value of 0 should be
262 * passed if no mode is currently active
263 * @result: Result of the entry operation. This should be 0 on success, or a
264 * negative error code if the negotiation failed
265 *
266 * This function should be called by an Alternate Mode driver to report the
267 * result of an asynchronous alternate mode entry request. It signals what the
268 * current active SVID is (or 0 if none) and the success or failure status of
269 * the last attempt.
270 */
271 void typec_altmode_state_update(struct typec_partner *partner, const u16 svid,
272 const int result);
273
274 /**
275 * typec_mode_selection_delete - Delete an alternate mode selection instance
276 * @partner: Handle to the Type-C partner device.
277 *
278 * This function cancels a pending alternate mode selection request that was
279 * previously started with typec_mode_selection_start().
280 * This is typically called when the partner disconnects.
281 */
282 void typec_mode_selection_delete(struct typec_partner *partner);
283
284 #endif /* __USB_TYPEC_ALTMODE_H */
285