| 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 | * typec_altmode_get_data_role - Get port data role |
| 177 | * @altmode: Handle to the alternate mode |
| 178 | * |
| 179 | * Alt Mode drivers should only issue Enter Mode through the port if they are |
| 180 | * the DFP. |
| 181 | */ |
| 182 | static inline enum typec_data_role |
| 183 | typec_altmode_get_data_role(struct typec_altmode *altmode) |
| 184 | { |
| 185 | return typec_get_data_role(port: typec_altmode2port(alt: altmode)); |
| 186 | } |
| 187 | |
| 188 | /** |
| 189 | * struct typec_altmode_driver - USB Type-C alternate mode device driver |
| 190 | * @id_table: Null terminated array of SVIDs |
| 191 | * @probe: Callback for device binding |
| 192 | * @remove: Callback for device unbinding |
| 193 | * @driver: Device driver model driver |
| 194 | * |
| 195 | * These drivers will be bind to the partner alternate mode devices. They will |
| 196 | * handle all SVID specific communication. |
| 197 | */ |
| 198 | struct typec_altmode_driver { |
| 199 | const struct typec_device_id *id_table; |
| 200 | int (*probe)(struct typec_altmode *altmode); |
| 201 | void (*remove)(struct typec_altmode *altmode); |
| 202 | struct device_driver driver; |
| 203 | }; |
| 204 | |
| 205 | #define to_altmode_driver(d) container_of(d, struct typec_altmode_driver, \ |
| 206 | driver) |
| 207 | |
| 208 | /** |
| 209 | * typec_altmode_register_driver - registers a USB Type-C alternate mode |
| 210 | * device driver |
| 211 | * @drv: pointer to struct typec_altmode_driver |
| 212 | * |
| 213 | * These drivers will be bind to the partner alternate mode devices. They will |
| 214 | * handle all SVID specific communication. |
| 215 | */ |
| 216 | #define typec_altmode_register_driver(drv) \ |
| 217 | __typec_altmode_register_driver(drv, THIS_MODULE) |
| 218 | int __typec_altmode_register_driver(struct typec_altmode_driver *drv, |
| 219 | struct module *module); |
| 220 | /** |
| 221 | * typec_altmode_unregister_driver - unregisters a USB Type-C alternate mode |
| 222 | * device driver |
| 223 | * @drv: pointer to struct typec_altmode_driver |
| 224 | * |
| 225 | * These drivers will be bind to the partner alternate mode devices. They will |
| 226 | * handle all SVID specific communication. |
| 227 | */ |
| 228 | void typec_altmode_unregister_driver(struct typec_altmode_driver *drv); |
| 229 | |
| 230 | #define module_typec_altmode_driver(__typec_altmode_driver) \ |
| 231 | module_driver(__typec_altmode_driver, typec_altmode_register_driver, \ |
| 232 | typec_altmode_unregister_driver) |
| 233 | |
| 234 | #endif /* __USB_TYPEC_ALTMODE_H */ |
| 235 | |