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 | struct typec_altmode_ops; |
13 | |
14 | /** |
15 | * struct typec_altmode - USB Type-C alternate mode device |
16 | * @dev: Driver model's view of this device |
17 | * @svid: Standard or Vendor ID (SVID) of the alternate mode |
18 | * @mode: Index of the Mode |
19 | * @vdo: VDO returned by Discover Modes USB PD command |
20 | * @active: Tells has the mode been entered or not |
21 | * @desc: Optional human readable description of the mode |
22 | * @ops: Operations vector from the driver |
23 | * @cable_ops: Cable operations vector from the driver. |
24 | */ |
25 | struct typec_altmode { |
26 | struct device dev; |
27 | u16 svid; |
28 | int mode; |
29 | u32 vdo; |
30 | unsigned int active:1; |
31 | |
32 | char *desc; |
33 | const struct typec_altmode_ops *ops; |
34 | const struct typec_cable_ops *cable_ops; |
35 | }; |
36 | |
37 | #define to_typec_altmode(d) container_of(d, struct typec_altmode, dev) |
38 | |
39 | static inline void typec_altmode_set_drvdata(struct typec_altmode *altmode, |
40 | void *data) |
41 | { |
42 | dev_set_drvdata(dev: &altmode->dev, data); |
43 | } |
44 | |
45 | static inline void *typec_altmode_get_drvdata(struct typec_altmode *altmode) |
46 | { |
47 | return dev_get_drvdata(dev: &altmode->dev); |
48 | } |
49 | |
50 | /** |
51 | * struct typec_altmode_ops - Alternate mode specific operations vector |
52 | * @enter: Operations to be executed with Enter Mode Command |
53 | * @exit: Operations to be executed with Exit Mode Command |
54 | * @attention: Callback for Attention Command |
55 | * @vdm: Callback for SVID specific commands |
56 | * @notify: Communication channel for platform and the alternate mode |
57 | * @activate: User callback for Enter/Exit Mode |
58 | */ |
59 | struct typec_altmode_ops { |
60 | int (*enter)(struct typec_altmode *altmode, u32 *vdo); |
61 | int (*exit)(struct typec_altmode *altmode); |
62 | void (*attention)(struct typec_altmode *altmode, u32 vdo); |
63 | int (*vdm)(struct typec_altmode *altmode, const u32 hdr, |
64 | const u32 *vdo, int cnt); |
65 | int (*notify)(struct typec_altmode *altmode, unsigned long conf, |
66 | void *data); |
67 | int (*activate)(struct typec_altmode *altmode, int activate); |
68 | }; |
69 | |
70 | int typec_altmode_enter(struct typec_altmode *altmode, u32 *vdo); |
71 | int typec_altmode_exit(struct typec_altmode *altmode); |
72 | int typec_altmode_attention(struct typec_altmode *altmode, u32 vdo); |
73 | int typec_altmode_vdm(struct typec_altmode *altmode, |
74 | const u32 , const u32 *vdo, int count); |
75 | int typec_altmode_notify(struct typec_altmode *altmode, unsigned long conf, |
76 | void *data); |
77 | const struct typec_altmode * |
78 | typec_altmode_get_partner(struct typec_altmode *altmode); |
79 | |
80 | /** |
81 | * struct typec_cable_ops - Cable alternate mode operations vector |
82 | * @enter: Operations to be executed with Enter Mode Command |
83 | * @exit: Operations to be executed with Exit Mode Command |
84 | * @vdm: Callback for SVID specific commands |
85 | */ |
86 | struct typec_cable_ops { |
87 | int (*enter)(struct typec_altmode *altmode, enum typec_plug_index sop, u32 *vdo); |
88 | int (*exit)(struct typec_altmode *altmode, enum typec_plug_index sop); |
89 | int (*vdm)(struct typec_altmode *altmode, enum typec_plug_index sop, |
90 | const u32 hdr, const u32 *vdo, int cnt); |
91 | }; |
92 | |
93 | int typec_cable_altmode_enter(struct typec_altmode *altmode, enum typec_plug_index sop, u32 *vdo); |
94 | int typec_cable_altmode_exit(struct typec_altmode *altmode, enum typec_plug_index sop); |
95 | int typec_cable_altmode_vdm(struct typec_altmode *altmode, enum typec_plug_index sop, |
96 | const u32 , const u32 *vdo, int count); |
97 | |
98 | /** |
99 | * typec_altmode_get_cable_svdm_version - Get negotiated SVDM version for cable plug |
100 | * @altmode: Handle to the alternate mode |
101 | */ |
102 | static inline int |
103 | typec_altmode_get_cable_svdm_version(struct typec_altmode *altmode) |
104 | { |
105 | return typec_get_cable_svdm_version(port: typec_altmode2port(alt: altmode)); |
106 | } |
107 | |
108 | /* |
109 | * These are the connector states (USB, Safe and Alt Mode) defined in USB Type-C |
110 | * Specification. SVID specific connector states are expected to follow and |
111 | * start from the value TYPEC_STATE_MODAL. |
112 | */ |
113 | enum { |
114 | TYPEC_STATE_SAFE, /* USB Safe State */ |
115 | TYPEC_STATE_USB, /* USB Operation */ |
116 | TYPEC_STATE_MODAL, /* Alternate Modes */ |
117 | }; |
118 | |
119 | /* |
120 | * For the muxes there is no difference between Accessory Modes and Alternate |
121 | * Modes, so the Accessory Modes are supplied with specific modal state values |
122 | * here. Unlike with Alternate Modes, where the mux will be linked with the |
123 | * alternate mode device, the mux for Accessory Modes will be linked with the |
124 | * port device instead. |
125 | * |
126 | * Port drivers can use TYPEC_MODE_AUDIO and TYPEC_MODE_DEBUG as the mode |
127 | * value for typec_set_mode() when accessory modes are supported. |
128 | * |
129 | * USB4 also requires that the pins on the connector are repurposed, just like |
130 | * Alternate Modes. USB4 mode is however not entered with the Enter Mode Command |
131 | * like the Alternate Modes are, but instead with a special Enter_USB Message. |
132 | * The Enter_USB Message can also be used for setting to connector to operate in |
133 | * USB 3.2 or in USB 2.0 mode instead of USB4. |
134 | * |
135 | * The Enter_USB specific "USB Modes" are also supplied here as special modal |
136 | * state values, just like the Accessory Modes. |
137 | */ |
138 | enum { |
139 | TYPEC_MODE_USB2 = TYPEC_STATE_MODAL, /* USB 2.0 mode */ |
140 | TYPEC_MODE_USB3, /* USB 3.2 mode */ |
141 | TYPEC_MODE_USB4, /* USB4 mode */ |
142 | TYPEC_MODE_AUDIO, /* Audio Accessory */ |
143 | TYPEC_MODE_DEBUG, /* Debug Accessory */ |
144 | }; |
145 | |
146 | #define TYPEC_MODAL_STATE(_state_) ((_state_) + TYPEC_STATE_MODAL) |
147 | |
148 | struct typec_altmode *typec_altmode_get_plug(struct typec_altmode *altmode, |
149 | enum typec_plug_index index); |
150 | void typec_altmode_put_plug(struct typec_altmode *plug); |
151 | |
152 | struct typec_altmode *typec_match_altmode(struct typec_altmode **altmodes, |
153 | size_t n, u16 svid, u8 mode); |
154 | |
155 | /** |
156 | * typec_altmode_get_orientation - Get cable plug orientation |
157 | * @altmode: Handle to the alternate mode |
158 | */ |
159 | static inline enum typec_orientation |
160 | typec_altmode_get_orientation(struct typec_altmode *altmode) |
161 | { |
162 | return typec_get_orientation(port: typec_altmode2port(alt: altmode)); |
163 | } |
164 | |
165 | /** |
166 | * typec_altmode_get_svdm_version - Get negotiated SVDM version |
167 | * @altmode: Handle to the alternate mode |
168 | */ |
169 | static inline int |
170 | typec_altmode_get_svdm_version(struct typec_altmode *altmode) |
171 | { |
172 | return typec_get_negotiated_svdm_version(port: typec_altmode2port(alt: altmode)); |
173 | } |
174 | |
175 | /** |
176 | * struct typec_altmode_driver - USB Type-C alternate mode device driver |
177 | * @id_table: Null terminated array of SVIDs |
178 | * @probe: Callback for device binding |
179 | * @remove: Callback for device unbinding |
180 | * @driver: Device driver model driver |
181 | * |
182 | * These drivers will be bind to the partner alternate mode devices. They will |
183 | * handle all SVID specific communication. |
184 | */ |
185 | struct typec_altmode_driver { |
186 | const struct typec_device_id *id_table; |
187 | int (*probe)(struct typec_altmode *altmode); |
188 | void (*remove)(struct typec_altmode *altmode); |
189 | struct device_driver driver; |
190 | }; |
191 | |
192 | #define to_altmode_driver(d) container_of(d, struct typec_altmode_driver, \ |
193 | driver) |
194 | |
195 | /** |
196 | * typec_altmode_register_driver - registers a USB Type-C alternate mode |
197 | * device driver |
198 | * @drv: pointer to struct typec_altmode_driver |
199 | * |
200 | * These drivers will be bind to the partner alternate mode devices. They will |
201 | * handle all SVID specific communication. |
202 | */ |
203 | #define typec_altmode_register_driver(drv) \ |
204 | __typec_altmode_register_driver(drv, THIS_MODULE) |
205 | int __typec_altmode_register_driver(struct typec_altmode_driver *drv, |
206 | struct module *module); |
207 | /** |
208 | * typec_altmode_unregister_driver - unregisters a USB Type-C alternate mode |
209 | * device driver |
210 | * @drv: pointer to struct typec_altmode_driver |
211 | * |
212 | * These drivers will be bind to the partner alternate mode devices. They will |
213 | * handle all SVID specific communication. |
214 | */ |
215 | void typec_altmode_unregister_driver(struct typec_altmode_driver *drv); |
216 | |
217 | #define module_typec_altmode_driver(__typec_altmode_driver) \ |
218 | module_driver(__typec_altmode_driver, typec_altmode_register_driver, \ |
219 | typec_altmode_unregister_driver) |
220 | |
221 | #endif /* __USB_TYPEC_ALTMODE_H */ |
222 | |