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