aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/usb/typec_altmode.h
blob: 9a88c74a1d0d0357eb052782ab2aa2739ca3690a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/* 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);
	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);
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.
 */
enum {
	TYPEC_MODE_AUDIO = TYPEC_STATE_MODAL,	/* 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);

struct typec_altmode *
typec_altmode_register_notifier(struct device *dev, u16 svid, u8 mode,
				struct notifier_block *nb);

void typec_altmode_unregister_notifier(struct typec_altmode *adev,
				       struct notifier_block *nb);

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

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

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