1 /*
2  * Copyright (c) 2022 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief USB host controller (UHC) driver API
10  */
11 
12 #ifndef ZEPHYR_INCLUDE_UHC_H
13 #define ZEPHYR_INCLUDE_UHC_H
14 
15 #include <zephyr/kernel.h>
16 #include <zephyr/device.h>
17 #include <zephyr/net/buf.h>
18 #include <zephyr/usb/usb_ch9.h>
19 #include <zephyr/sys/dlist.h>
20 
21 /**
22  * @brief USB host controller (UHC) driver API
23  * @defgroup uhc_api USB host controller driver API
24  * @ingroup io_interfaces
25  * @{
26  */
27 
28 /**
29  * @brief USB control transfer stage
30  */
31 enum uhc_control_stage {
32 	UHC_CONTROL_STAGE_SETUP = 0,
33 	UHC_CONTROL_STAGE_DATA,
34 	UHC_CONTROL_STAGE_STATUS,
35 };
36 
37 /**
38  * UHC endpoint buffer info
39  *
40  * This structure is mandatory for all UHC request.
41  * It contains the meta data about the request and FIFOs
42  * to store net_buf structures for each request.
43  *
44  * The members of this structure should not be used
45  * directly by a higher layer (host stack).
46  */
47 struct uhc_transfer {
48 	/** dlist node */
49 	sys_dnode_t node;
50 	/** Control transfer setup packet */
51 	uint8_t setup_pkt[8];
52 	/** Transfer data buffer */
53 	struct net_buf *buf;
54 	/** Device (peripheral) address */
55 	uint8_t addr;
56 	/** Endpoint to which request is associated */
57 	uint8_t ep;
58 	/** Endpoint attributes (TBD) */
59 	uint8_t attrib;
60 	/** Maximum packet size */
61 	uint16_t mps;
62 	/** Timeout in number of frames */
63 	uint16_t timeout;
64 	/** Flag marks request buffer is queued */
65 	unsigned int queued : 1;
66 	/** Control stage status, up to the driver to use it or not */
67 	unsigned int stage : 2;
68 	/** Pointer to USB device (opaque for the UHC) */
69 	void *udev;
70 	/** Pointer to transfer completion callback (opaque for the UHC) */
71 	void *cb;
72 	/** Transfer result, 0 on success, other values on error */
73 	int err;
74 };
75 
76 /**
77  * @brief USB host controller event types
78  */
79 enum uhc_event_type {
80 	/** Low speed device connected */
81 	UHC_EVT_DEV_CONNECTED_LS,
82 	/** Full speed device connected */
83 	UHC_EVT_DEV_CONNECTED_FS,
84 	/** High speed device connected */
85 	UHC_EVT_DEV_CONNECTED_HS,
86 	/** Device (peripheral) removed */
87 	UHC_EVT_DEV_REMOVED,
88 	/** Bus reset operation finished */
89 	UHC_EVT_RESETED,
90 	/** Bus suspend operation finished */
91 	UHC_EVT_SUSPENDED,
92 	/** Bus resume operation finished */
93 	UHC_EVT_RESUMED,
94 	/** Remote wakeup signal */
95 	UHC_EVT_RWUP,
96 	/** Endpoint request result event */
97 	UHC_EVT_EP_REQUEST,
98 	/**
99 	 * Non-correctable error event, requires attention from higher
100 	 * levels or application.
101 	 */
102 	UHC_EVT_ERROR,
103 };
104 
105 /**
106  * USB host controller event
107  *
108  * Common structure for all events that originate from
109  * the UHC driver and are passed to higher layer using
110  * message queue and a callback (uhc_event_cb_t) provided
111  * by higher layer during controller initialization (uhc_init).
112  */
113 struct uhc_event {
114 	/** slist node for the message queue */
115 	sys_snode_t node;
116 	/** Event type */
117 	enum uhc_event_type type;
118 	union {
119 		/** Event status value, if any */
120 		int status;
121 		/** Pointer to request used only for UHC_EVT_EP_REQUEST */
122 		struct uhc_transfer *xfer;
123 	};
124 	/** Pointer to controller's device struct */
125 	const struct device *dev;
126 };
127 
128 /**
129  * @typedef uhc_event_cb_t
130  * @brief Callback to submit UHC event to higher layer.
131  *
132  * At the higher level, the event is to be inserted into a message queue.
133  *
134  * @param[in] dev      Pointer to device struct of the driver instance
135  * @param[in] event    Point to event structure
136  *
137  * @return 0 on success, all other values should be treated as error.
138  */
139 typedef int (*uhc_event_cb_t)(const struct device *dev,
140 			      const struct uhc_event *const event);
141 
142 /**
143  * USB host controller capabilities
144  *
145  * This structure is mainly intended for the USB host stack.
146  */
147 struct uhc_device_caps {
148 	/** USB high speed capable controller */
149 	uint32_t hs : 1;
150 };
151 
152 /**
153  * Controller is initialized by uhc_init()
154  */
155 #define UHC_STATUS_INITIALIZED		0
156 /**
157  * Controller is enabled and all API functions are available
158  */
159 #define UHC_STATUS_ENABLED		1
160 
161 /**
162  * Common UHC driver data structure
163  *
164  * Mandatory structure for each UHC controller driver.
165  * To be implemented as device's private data (device->data).
166  */
167 struct uhc_data {
168 	/** Controller capabilities */
169 	struct uhc_device_caps caps;
170 	/** Driver access mutex */
171 	struct k_mutex mutex;
172 	/** dlist for control transfers */
173 	sys_dlist_t ctrl_xfers;
174 	/** dlist for bulk transfers */
175 	sys_dlist_t bulk_xfers;
176 	/** Callback to submit an UHC event to upper layer */
177 	uhc_event_cb_t event_cb;
178 	/** USB host controller status */
179 	atomic_t status;
180 	/** Driver private data */
181 	void *priv;
182 };
183 
184 /**
185  * @brief Checks whether the controller is initialized.
186  *
187  * @param[in] dev      Pointer to device struct of the driver instance
188  *
189  * @return true if controller is initialized, false otherwise
190  */
uhc_is_initialized(const struct device * dev)191 static inline bool uhc_is_initialized(const struct device *dev)
192 {
193 	struct uhc_data *data = dev->data;
194 
195 	return atomic_test_bit(&data->status, UHC_STATUS_INITIALIZED);
196 }
197 
198 /**
199  * @brief Checks whether the controller is enabled.
200  *
201  * @param[in] dev      Pointer to device struct of the driver instance
202  *
203  * @return true if controller is enabled, false otherwise
204  */
uhc_is_enabled(const struct device * dev)205 static inline bool uhc_is_enabled(const struct device *dev)
206 {
207 	struct uhc_data *data = dev->data;
208 
209 	return atomic_test_bit(&data->status, UHC_STATUS_ENABLED);
210 }
211 
212 /**
213  * @cond INTERNAL_HIDDEN
214  */
215 struct uhc_api {
216 	int (*lock)(const struct device *dev);
217 	int (*unlock)(const struct device *dev);
218 
219 	int (*init)(const struct device *dev);
220 	int (*enable)(const struct device *dev);
221 	int (*disable)(const struct device *dev);
222 	int (*shutdown)(const struct device *dev);
223 
224 	int (*bus_reset)(const struct device *dev);
225 	int (*sof_enable)(const struct device *dev);
226 	int (*bus_suspend)(const struct device *dev);
227 	int (*bus_resume)(const struct device *dev);
228 
229 	int (*ep_enqueue)(const struct device *dev,
230 			  struct uhc_transfer *const xfer);
231 	int (*ep_dequeue)(const struct device *dev,
232 			  struct uhc_transfer *const xfer);
233 };
234 /**
235  * @endcond
236  */
237 
238 /**
239  * @brief Reset USB bus
240  *
241  * Perform USB bus reset, controller may emit UHC_EVT_RESETED
242  * at the end of reset signaling.
243  *
244  * @param[in] dev      Pointer to device struct of the driver instance
245  *
246  * @return 0 on success, all other values should be treated as error.
247  * @retval -EBUSY if the controller is already performing a bus operation
248  */
uhc_bus_reset(const struct device * dev)249 static inline int uhc_bus_reset(const struct device *dev)
250 {
251 	const struct uhc_api *api = dev->api;
252 	int ret;
253 
254 	api->lock(dev);
255 	ret = api->bus_reset(dev);
256 	api->unlock(dev);
257 
258 	return ret;
259 }
260 
261 /**
262  * @brief Enable Start of Frame generator
263  *
264  * Enable SOF generator.
265  *
266  * @param[in] dev      Pointer to device struct of the driver instance
267  *
268  * @return 0 on success, all other values should be treated as error.
269  * @retval -EALREADY if already enabled
270  */
uhc_sof_enable(const struct device * dev)271 static inline int uhc_sof_enable(const struct device *dev)
272 {
273 	const struct uhc_api *api = dev->api;
274 	int ret;
275 
276 	api->lock(dev);
277 	ret = api->sof_enable(dev);
278 	api->unlock(dev);
279 
280 	return ret;
281 }
282 
283 /**
284  * @brief Suspend USB bus
285  *
286  * Disable SOF generator and emit UHC_EVT_SUSPENDED event when USB bus
287  * is suspended.
288  *
289  * @param[in] dev      Pointer to device struct of the driver instance
290  *
291  * @return 0 on success, all other values should be treated as error.
292  * @retval -EALREADY if already suspended
293  */
uhc_bus_suspend(const struct device * dev)294 static inline int uhc_bus_suspend(const struct device *dev)
295 {
296 	const struct uhc_api *api = dev->api;
297 	int ret;
298 
299 	api->lock(dev);
300 	ret = api->bus_suspend(dev);
301 	api->unlock(dev);
302 
303 	return ret;
304 }
305 
306 /**
307  * @brief Resume USB bus
308  *
309  * Signal resume for at least 20ms, emit UHC_EVT_RESUMED at the end of USB
310  * bus resume signaling. The SoF generator should subsequently start within 3ms.
311  *
312  * @param[in] dev      Pointer to device struct of the driver instance
313  *
314  * @return 0 on success, all other values should be treated as error.
315  * @retval -EBUSY if the controller is already performing a bus operation
316  */
uhc_bus_resume(const struct device * dev)317 static inline int uhc_bus_resume(const struct device *dev)
318 {
319 	const struct uhc_api *api = dev->api;
320 	int ret;
321 
322 	api->lock(dev);
323 	ret = api->bus_resume(dev);
324 	api->unlock(dev);
325 
326 	return ret;
327 }
328 
329 /**
330  * @brief Allocate UHC transfer
331  *
332  * Allocate a new transfer from common transfer pool.
333  * Transfer has no buffer after allocation, but can be allocated
334  * and added from different pools.
335  *
336  * @param[in] dev     Pointer to device struct of the driver instance
337  * @param[in] addr    Device (peripheral) address
338  * @param[in] ep      Endpoint address
339  * @param[in] attrib  Endpoint attributes
340  * @param[in] mps     Maximum packet size of the endpoint
341  * @param[in] timeout Timeout in number of frames
342  * @param[in] udev    Opaque pointer to USB device
343  * @param[in] cb      Transfer completion callback
344  *
345  * @return pointer to allocated transfer or NULL on error.
346  */
347 struct uhc_transfer *uhc_xfer_alloc(const struct device *dev,
348 				    const uint8_t addr,
349 				    const uint8_t ep,
350 				    const uint8_t attrib,
351 				    const uint16_t mps,
352 				    const uint16_t timeout,
353 				    void *const udev,
354 				    void *const cb);
355 
356 /**
357  * @brief Allocate UHC transfer with buffer
358  *
359  * Allocate a new transfer from common transfer pool with buffer.
360  *
361  * @param[in] dev     Pointer to device struct of the driver instance
362  * @param[in] addr    Device (peripheral) address
363  * @param[in] ep      Endpoint address
364  * @param[in] attrib  Endpoint attributes
365  * @param[in] mps     Maximum packet size of the endpoint
366  * @param[in] timeout Timeout in number of frames
367  * @param[in] udev    Opaque pointer to USB device
368  * @param[in] cb      Transfer completion callback
369  * @param[in] size    Size of the buffer
370  *
371  * @return pointer to allocated transfer or NULL on error.
372  */
373 struct uhc_transfer *uhc_xfer_alloc_with_buf(const struct device *dev,
374 					     const uint8_t addr,
375 					     const uint8_t ep,
376 					     const uint8_t attrib,
377 					     const uint16_t mps,
378 					     const uint16_t timeout,
379 					     void *const udev,
380 					     void *const cb,
381 					     size_t size);
382 
383 /**
384  * @brief Free UHC transfer and any buffers
385  *
386  * Free any buffers and put the transfer back into the transfer pool.
387  *
388  * @param[in] dev    Pointer to device struct of the driver instance
389  * @param[in] xfer   Pointer to UHC transfer
390  *
391  * @return 0 on success, all other values should be treated as error.
392  */
393 int uhc_xfer_free(const struct device *dev,
394 		  struct uhc_transfer *const xfer);
395 
396 /**
397  * @brief Add UHC transfer buffer
398  *
399  * Add a previously allocated buffer to the transfer.
400  *
401  * @param[in] dev    Pointer to device struct of the driver instance
402  * @param[in] xfer   Pointer to UHC transfer
403  * @param[in] buf    Pointer to UHC request buffer
404  *
405  * @return pointer to allocated request or NULL on error.
406  */
407 int uhc_xfer_buf_add(const struct device *dev,
408 		     struct uhc_transfer *const xfer,
409 		     struct net_buf *buf);
410 /**
411  * @brief Allocate UHC transfer buffer
412  *
413  * Allocate a new buffer from common request buffer pool and
414  * assign it to the transfer if the xfer parameter is not NULL.
415  *
416  * @param[in] dev    Pointer to device struct of the driver instance
417  * @param[in] size   Size of the request buffer
418  *
419  * @return pointer to allocated request or NULL on error.
420  */
421 struct net_buf *uhc_xfer_buf_alloc(const struct device *dev,
422 				   const size_t size);
423 
424 /**
425  * @brief Free UHC request buffer
426  *
427  * Put the buffer back into the request buffer pool.
428  *
429  * @param[in] dev    Pointer to device struct of the driver instance
430  * @param[in] buf    Pointer to UHC request buffer
431  */
432 void uhc_xfer_buf_free(const struct device *dev, struct net_buf *const buf);
433 
434 /**
435  * @brief Queue USB host controller transfer
436  *
437  * Add transfer to the queue. If the queue is empty, the transfer
438  * can be claimed by the controller immediately.
439  *
440  * @param[in] dev    Pointer to device struct of the driver instance
441  * @param[in] xfer   Pointer to UHC transfer
442  *
443  * @return 0 on success, all other values should be treated as error.
444  * @retval -EPERM controller is not initialized
445  */
446 int uhc_ep_enqueue(const struct device *dev, struct uhc_transfer *const xfer);
447 
448 /**
449  * @brief Remove a USB host controller transfers from queue
450  *
451  * Not implemented yet.
452  *
453  * @param[in] dev    Pointer to device struct of the driver instance
454  * @param[in] xfer   Pointer to UHC transfer
455  *
456  * @return 0 on success, all other values should be treated as error.
457  * @retval -EPERM controller is not initialized
458  */
459 int uhc_ep_dequeue(const struct device *dev, struct uhc_transfer *const xfer);
460 
461 /**
462  * @brief Initialize USB host controller
463  *
464  * Initialize USB host controller.
465  *
466  * @param[in] dev      Pointer to device struct of the driver instance
467  * @param[in] event_cb Event callback from the higher layer (USB host stack)
468  *
469  * @return 0 on success, all other values should be treated as error.
470  * @retval -EINVAL on parameter error (no callback is passed)
471  * @retval -EALREADY already initialized
472  */
473 int uhc_init(const struct device *dev, uhc_event_cb_t event_cb);
474 
475 /**
476  * @brief Enable USB host controller
477  *
478  * Enable powered USB host controller and allow host stack to
479  * recognize and enumerate devices.
480  *
481  * @param[in] dev    Pointer to device struct of the driver instance
482  *
483  * @return 0 on success, all other values should be treated as error.
484  * @retval -EPERM controller is not initialized
485  * @retval -EALREADY already enabled
486  */
487 int uhc_enable(const struct device *dev);
488 
489 /**
490  * @brief Disable USB host controller
491  *
492  * Disable enabled USB host controller.
493  *
494  * @param[in] dev    Pointer to device struct of the driver instance
495  *
496  * @return 0 on success, all other values should be treated as error.
497  * @retval -EALREADY already disabled
498  */
499 int uhc_disable(const struct device *dev);
500 
501 /**
502  * @brief Poweroff USB host controller
503  *
504  * Shut down the controller completely to reduce energy consumption
505  * or to change the role of the controller.
506  *
507  * @param[in] dev    Pointer to device struct of the driver instance
508  *
509  * @return 0 on success, all other values should be treated as error.
510  * @retval -EALREADY controller is already uninitialized
511  */
512 int uhc_shutdown(const struct device *dev);
513 
514 /**
515  * @brief Get USB host controller capabilities
516  *
517  * Obtain the capabilities of the controller
518  * such as high speed (HS), and more.
519  *
520  * @param[in] dev    Pointer to device struct of the driver instance
521  *
522  * @return USB host controller capabilities.
523  */
uhc_caps(const struct device * dev)524 static inline struct uhc_device_caps uhc_caps(const struct device *dev)
525 {
526 	struct uhc_data *data = dev->data;
527 
528 	return data->caps;
529 }
530 
531 /**
532  * @}
533  */
534 
535 #endif /* ZEPHYR_INCLUDE_UHC_H */
536