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 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 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 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 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 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 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