/* SPDX-License-Identifier: GPL-2.0 */ #ifndef __USB_TYPEC_ALTMODE_H #define __USB_TYPEC_ALTMODE_H #include <linux/mod_devicetable.h> #include <linux/usb/typec.h> #include <linux/device.h> #define MODE_DISCOVERY_MAX 6 struct typec_altmode_ops; /** * struct typec_altmode - USB Type-C alternate mode device * @dev: Driver model's view of this device * @svid: Standard or Vendor ID (SVID) of the alternate mode * @mode: Index of the Mode * @vdo: VDO returned by Discover Modes USB PD command * @active: Tells has the mode been entered or not * @desc: Optional human readable description of the mode * @ops: Operations vector from the driver */ struct typec_altmode { struct device dev; u16 svid; int mode; u32 vdo; unsigned int active:1; char *desc; const struct typec_altmode_ops *ops; }; #define to_typec_altmode(d) container_of(d, struct typec_altmode, dev) static inline void typec_altmode_set_drvdata(struct typec_altmode *altmode, void *data) { dev_set_drvdata(&altmode->dev, data); } static inline void *typec_altmode_get_drvdata(struct typec_altmode *altmode) { return dev_get_drvdata(&altmode->dev); } /** * struct typec_altmode_ops - Alternate mode specific operations vector * @enter: Operations to be executed with Enter Mode Command * @exit: Operations to be executed with Exit Mode Command * @attention: Callback for Attention Command * @vdm: Callback for SVID specific commands * @notify: Communication channel for platform and the alternate mode * @activate: User callback for Enter/Exit Mode */ struct typec_altmode_ops { int (*enter)(struct typec_altmode *altmode, u32 *vdo); int (*exit)(struct typec_altmode *altmode); void (*attention)(struct typec_altmode *altmode, u32 vdo); int (*vdm)(struct typec_altmode *altmode, const u32 hdr, const u32 *vdo, int cnt); int (*notify)(struct typec_altmode *altmode, unsigned long conf, void *data); int (*activate)(struct typec_altmode *altmode, int activate); }; int typec_altmode_enter(struct typec_altmode *altmode, u32 *vdo); int typec_altmode_exit(struct typec_altmode *altmode); int typec_altmode_attention(struct typec_altmode *altmode, u32 vdo); int typec_altmode_vdm(struct typec_altmode *altmode, const u32 header, const u32 *vdo, int count); int typec_altmode_notify(struct typec_altmode *altmode, unsigned long conf, void *data); const struct typec_altmode * typec_altmode_get_partner(struct typec_altmode *altmode); /* * These are the connector states (USB, Safe and Alt Mode) defined in USB Type-C * Specification. SVID specific connector states are expected to follow and * start from the value TYPEC_STATE_MODAL. */ enum { TYPEC_STATE_SAFE, /* USB Safe State */ TYPEC_STATE_USB, /* USB Operation */ TYPEC_STATE_MODAL, /* Alternate Modes */ }; /* * For the muxes there is no difference between Accessory Modes and Alternate * Modes, so the Accessory Modes are supplied with specific modal state values * here. Unlike with Alternate Modes, where the mux will be linked with the * alternate mode device, the mux for Accessory Modes will be linked with the * port device instead. * * Port drivers can use TYPEC_MODE_AUDIO and TYPEC_MODE_DEBUG as the mode * value for typec_set_mode() when accessory modes are supported. * * USB4 also requires that the pins on the connector are repurposed, just like * Alternate Modes. USB4 mode is however not entered with the Enter Mode Command * like the Alternate Modes are, but instead with a special Enter_USB Message. * The Enter_USB Message can also be used for setting to connector to operate in * USB 3.2 or in USB 2.0 mode instead of USB4. * * The Enter_USB specific "USB Modes" are also supplied here as special modal * state values, just like the Accessory Modes. */ enum { TYPEC_MODE_USB2 = TYPEC_STATE_MODAL, /* USB 2.0 mode */ TYPEC_MODE_USB3, /* USB 3.2 mode */ TYPEC_MODE_USB4, /* USB4 mode */ TYPEC_MODE_AUDIO, /* Audio Accessory */ TYPEC_MODE_DEBUG, /* Debug Accessory */ }; #define TYPEC_MODAL_STATE(_state_) ((_state_) + TYPEC_STATE_MODAL) struct typec_altmode *typec_altmode_get_plug(struct typec_altmode *altmode, enum typec_plug_index index); void typec_altmode_put_plug(struct typec_altmode *plug); struct typec_altmode *typec_match_altmode(struct typec_altmode **altmodes, size_t n, u16 svid, u8 mode); /** * typec_altmode_get_orientation - Get cable plug orientation * @altmode: Handle to the alternate mode */ static inline enum typec_orientation typec_altmode_get_orientation(struct typec_altmode *altmode) { return typec_get_orientation(typec_altmode2port(altmode)); } /** * typec_altmode_get_svdm_version - Get negotiated SVDM version * @altmode: Handle to the alternate mode */ static inline int typec_altmode_get_svdm_version(struct typec_altmode *altmode) { return typec_get_negotiated_svdm_version(typec_altmode2port(altmode)); } /** * struct typec_altmode_driver - USB Type-C alternate mode device driver * @id_table: Null terminated array of SVIDs * @probe: Callback for device binding * @remove: Callback for device unbinding * @driver: Device driver model driver * * These drivers will be bind to the partner alternate mode devices. They will * handle all SVID specific communication. */ struct typec_altmode_driver { const struct typec_device_id *id_table; int (*probe)(struct typec_altmode *altmode); void (*remove)(struct typec_altmode *altmode); struct device_driver driver; }; #define to_altmode_driver(d) container_of(d, struct typec_altmode_driver, \ driver) /** * typec_altmode_register_driver - registers a USB Type-C alternate mode * device driver * @drv: pointer to struct typec_altmode_driver * * These drivers will be bind to the partner alternate mode devices. They will * handle all SVID specific communication. */ #define typec_altmode_register_driver(drv) \ __typec_altmode_register_driver(drv, THIS_MODULE) int __typec_altmode_register_driver(struct typec_altmode_driver *drv, struct module *module); /** * typec_altmode_unregister_driver - unregisters a USB Type-C alternate mode * device driver * @drv: pointer to struct typec_altmode_driver * * These drivers will be bind to the partner alternate mode devices. They will * handle all SVID specific communication. */ void typec_altmode_unregister_driver(struct typec_altmode_driver *drv); #define module_typec_altmode_driver(__typec_altmode_driver) \ module_driver(__typec_altmode_driver, typec_altmode_register_driver, \ typec_altmode_unregister_driver) #endif /* __USB_TYPEC_ALTMODE_H */