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