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