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