linux-stable/include/linux/usb/typec_altmode.h
Kyle Tso 3c5960c055 usb: typec: Manage SVDM version
PD Spec Revision 3.0 Version 2.0 + ECNs 2020-12-10
  6.4.4.2.3 Structured VDM Version
  "The Structured VDM Version field of the Discover Identity Command
  sent and received during VDM discovery Shall be used to determine the
  lowest common Structured VDM Version supported by the Port Partners or
  Cable Plug and Shall continue to operate using this Specification
  Revision until they are Detached."

Add a variable in typec_capability to specify the highest SVDM version
supported by the port and another variable in typec_partner to cache the
negotiated SVDM version between the port and the partner.

Also add setter/getter functions for the negotiated SVDM version.

Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Kyle Tso <kyletso@google.com>
Link: https://lore.kernel.org/r/20210205033415.3320439-2-kyletso@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-02-09 11:48:54 +01:00

191 lines
6.5 KiB
C

/* 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);
void 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 */