aboutsummaryrefslogtreecommitdiffstats
blob: 8d3934a4265471edca55e8250fe778d55f44f07a (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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
/* USB OTG (On The Go) defines */
/*
 *
 * These APIs may be used between USB controllers.  USB device drivers
 * (for either host or peripheral roles) don't use these calls; they
 * continue to use just usb_device and usb_gadget.
 */

#ifndef __LINUX_USB_OTG_H
#define __LINUX_USB_OTG_H

#include <linux/phy/phy.h>
#include <linux/device.h>
#include <linux/hrtimer.h>
#include <linux/ktime.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg-fsm.h>
#include <linux/usb/phy.h>

/**
 * struct otg_hcd - host controller state and interface
 *
 * @hcd: host controller
 * @irqnum: irq number
 * @irqflags: irq flags
 * @ops: otg to host controller interface
 */
struct otg_hcd {
	struct usb_hcd *hcd;
	unsigned int irqnum;
	unsigned long irqflags;
	struct otg_hcd_ops *ops;
};

struct usb_otg;

/**
 * struct otg_timer - otg timer data
 *
 * @timer: high resolution timer
 * @timeout: timeout value
 * @timetout_bit: pointer to variable that is set on timeout
 * @otgd: usb otg data
 */
struct otg_timer {
	struct hrtimer timer;
	ktime_t timeout;
	/* callback data */
	int *timeout_bit;
	struct usb_otg *otgd;
};

/**
 * struct usb_otg - usb otg controller state
 *
 * @default_a: Indicates we are an A device. i.e. Host.
 * @phy: USB phy interface
 * @usb_phy: old usb_phy interface
 * @host: host controller bus
 * @gadget: gadget device
 * @state: current otg state
 * @dev: otg controller device
 * @caps: otg capabilities revision, hnp, srp, etc
 * @fsm: otg finite state machine
 * @fsm_ops: controller hooks for the state machine
 * ------- internal use only -------
 * @primary_hcd: primary host state and interface
 * @shared_hcd: shared host state and interface
 * @gadget_ops: gadget interface
 * @timers: otg timers for state machine
 * @list: list of otg controllers
 * @work: otg state machine work
 * @wq: otg state machine work queue
 * @fsm_running: state machine running/stopped indicator
 * @flags: to track if host/gadget is running
 * @drd_only: dual-role mode. no otg features.
 */
struct usb_otg {
	u8			default_a;

	struct phy		*phy;
	/* old usb_phy interface */
	struct usb_phy		*usb_phy;

	struct usb_bus		*host;
	struct usb_gadget	*gadget;

	enum usb_otg_state	state;

	struct device *dev;
	struct usb_otg_caps *caps;
	struct otg_fsm fsm;
	struct otg_fsm_ops fsm_ops;

	/* internal use only */
	struct otg_hcd primary_hcd;
	struct otg_hcd shared_hcd;
	struct otg_gadget_ops *gadget_ops;
	struct otg_timer timers[NUM_OTG_FSM_TIMERS];
	struct list_head list;
	struct work_struct work;
	struct workqueue_struct *wq;
	bool fsm_running;
	u32 flags;
#define OTG_FLAG_GADGET_RUNNING (1 << 0)
#define OTG_FLAG_HOST_RUNNING (1 << 1)
	/* use otg->fsm.lock for serializing access */
	bool drd_only;

/*------------- deprecated interface -----------------------------*/
	/* bind/unbind the host controller */
	int	(*set_host)(struct usb_otg *otg, struct usb_bus *host);

	/* bind/unbind the peripheral controller */
	int	(*set_peripheral)(struct usb_otg *otg,
					struct usb_gadget *gadget);

	/* effective for A-peripheral, ignored for B devices */
	int	(*set_vbus)(struct usb_otg *otg, bool enabled);

	/* for B devices only:  start session with A-Host */
	int	(*start_srp)(struct usb_otg *otg);

	/* start or continue HNP role switch */
	int	(*start_hnp)(struct usb_otg *otg);
/*---------------------------------------------------------------*/
};

/**
 * struct usb_otg_caps - describes the otg capabilities of the device
 * @otg_rev: The OTG revision number the device is compliant with, it's
 *		in binary-coded decimal (i.e. 2.0 is 0200H).
 * @hnp_support: Indicates if the device supports HNP.
 * @srp_support: Indicates if the device supports SRP.
 * @adp_support: Indicates if the device supports ADP.
 */
struct usb_otg_caps {
	u16 otg_rev;
	bool hnp_support;
	bool srp_support;
	bool adp_support;
};

/**
 * struct usb_otg_config - otg controller configuration
 * @caps: otg capabilities of the controller
 * @ops: otg fsm operations
 * @otg_timeouts: override default otg fsm timeouts
 */
struct usb_otg_config {
	struct usb_otg_caps otg_caps;
	struct otg_fsm_ops *fsm_ops;
	unsigned otg_timeouts[NUM_OTG_FSM_TIMERS];
};

extern const char *usb_otg_state_string(enum usb_otg_state state);

#if IS_ENABLED(CONFIG_USB_OTG)
struct otg_fsm *usb_otg_register(struct device *dev,
				 struct usb_otg_config *config);
int usb_otg_unregister(struct device *dev);
int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
			 unsigned long irqflags, struct otg_hcd_ops *ops);
int usb_otg_unregister_hcd(struct usb_hcd *hcd);
int usb_otg_shutdown_hcd(struct usb_hcd *hcd);
int usb_otg_register_gadget(struct usb_gadget *gadget,
			    struct otg_gadget_ops *ops);
int usb_otg_unregister_gadget(struct usb_gadget *gadget);
void usb_otg_sync_inputs(struct otg_fsm *fsm);
int usb_otg_kick_fsm(struct device *hcd_gcd_device);
struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm);
int usb_otg_start_host(struct otg_fsm *fsm, int on);
int usb_otg_start_gadget(struct otg_fsm *fsm, int on);

#else /* CONFIG_USB_OTG */

static inline struct otg_fsm *usb_otg_register(struct device *dev,
					       struct usb_otg_config *config)
{
	return ERR_PTR(-ENOTSUPP);
}

static inline int usb_otg_unregister(struct device *dev)
{
	return -ENOTSUPP;
}

static inline int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
				       unsigned long irqflags,
				       struct otg_hcd_ops *ops)
{
	return -ENOTSUPP;
}

static inline int usb_otg_unregister_hcd(struct usb_hcd *hcd)
{
	return -ENOTSUPP;
}

static inline int usb_otg_shutdown_hcd(struct usb_hcd *hcd)
{
	return -ENOTSUPP;
}

static inline int usb_otg_register_gadget(struct usb_gadget *gadget,
					  struct otg_gadget_ops *ops)
{
	return -ENOTSUPP;
}

static inline int usb_otg_unregister_gadget(struct usb_gadget *gadget)
{
	return -ENOTSUPP;
}

static inline void usb_otg_sync_inputs(struct otg_fsm *fsm)
{
}

static inline int usb_otg_kick_fsm(struct device *hcd_gcd_device)
{
	return -ENOTSUPP;
}

static inline struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm)
{
	return NULL;
}

static inline int usb_otg_start_host(struct otg_fsm *fsm, int on)
{
	return -ENOTSUPP;
}

static inline int usb_otg_start_gadget(struct otg_fsm *fsm, int on)
{
	return -ENOTSUPP;
}
#endif /* CONFIG_USB_OTG */

/*------------- deprecated interface -----------------------------*/
/* Context: can sleep */
static inline int
otg_start_hnp(struct usb_otg *otg)
{
	if (otg && otg->start_hnp)
		return otg->start_hnp(otg);

	return -ENOTSUPP;
}

/* Context: can sleep */
static inline int
otg_set_vbus(struct usb_otg *otg, bool enabled)
{
	if (otg && otg->set_vbus)
		return otg->set_vbus(otg, enabled);

	return -ENOTSUPP;
}

/* for HCDs */
static inline int
otg_set_host(struct usb_otg *otg, struct usb_bus *host)
{
	if (otg && otg->set_host)
		return otg->set_host(otg, host);

	return -ENOTSUPP;
}

/* for usb peripheral controller drivers */

/* Context: can sleep */
static inline int
otg_set_peripheral(struct usb_otg *otg, struct usb_gadget *periph)
{
	if (otg && otg->set_peripheral)
		return otg->set_peripheral(otg, periph);

	return -ENOTSUPP;
}

static inline int
otg_start_srp(struct usb_otg *otg)
{
	if (otg && otg->start_srp)
		return otg->start_srp(otg);

	return -ENOTSUPP;
}

/*---------------------------------------------------------------*/

/* for OTG controller drivers (and maybe other stuff) */
extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num);

enum usb_dr_mode {
	USB_DR_MODE_UNKNOWN,
	USB_DR_MODE_HOST,
	USB_DR_MODE_PERIPHERAL,
	USB_DR_MODE_OTG,
};

/**
 * usb_get_dr_mode - Get dual role mode for given device
 * @dev: Pointer to the given device
 *
 * The function gets phy interface string from property 'dr_mode',
 * and returns the correspondig enum usb_dr_mode
 */
extern enum usb_dr_mode usb_get_dr_mode(struct device *dev);

#endif /* __LINUX_USB_OTG_H */