1 /***************************************************************************//**
2 * \file cyhal_usb_dev.h
3 *
4 * \brief
5 * Provides a high level interface for interacting with the Infineon USB Device.
6 * This interface abstracts out the chip specific details.
7 * If any chip specific functionality is necessary, or performance is critical
8 * the low level functions can be used directly.
9 *
10 ********************************************************************************
11 * \copyright
12 * Copyright 2019-2021 Cypress Semiconductor Corporation (an Infineon company) or
13 * an affiliate of Cypress Semiconductor Corporation
14 *
15 * SPDX-License-Identifier: Apache-2.0
16 *
17 * Licensed under the Apache License, Version 2.0 (the "License");
18 * you may not use this file except in compliance with the License.
19 * You may obtain a copy of the License at
20 *
21 *     http://www.apache.org/licenses/LICENSE-2.0
22 *
23 * Unless required by applicable law or agreed to in writing, software
24 * distributed under the License is distributed on an "AS IS" BASIS,
25 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26 * See the License for the specific language governing permissions and
27 * limitations under the License.
28 *******************************************************************************/
29 
30 /**
31 * \addtogroup group_hal_usb_dev USB Device
32 * \ingroup group_hal
33 * \{
34 * High level interface for interacting with the USB Device.
35 *
36 * This block supports one control endpoint (EP0) and one or more data endpoints.
37 * See the device datasheet for the number of data endpoints supported.
38 *
39 * Four transfer types are supported (see \ref cyhal_usb_dev_ep_type_t):
40 * * Bulk
41 * * Interrupt
42 * * Isochronous
43 * * Control
44 *
45 * \section section_usb_dev_features Features
46 * * Complies with USB specification 2.0
47 * * Supports full-speed peripheral device operation with a signaling bit rate of 12 Mbps.
48 * * Configurable D+ AND D- pins  using \ref cyhal_gpio_t
49 * * Configurable Interrupt and Callback assignment on USB events like SOF, Bus Reset, EP0 Setup and EP0 transaction.
50 * * Configurable USB device address.
51 * * Configurable USB Endpoints (except for Endpoint 0)
52 *
53 * \section section_usb_dev_quickstart Quick Start
54 * \ref cyhal_usb_dev_init can be used for initialization of USB by providing the USBDP and USBDM pins.
55 * See \ref subsection_usb_dev_snippet_1 for the initialization code snippet.
56 *
57 * \section section_usb_dev_snippets Code snippets
58 *
59 * \subsection subsection_usb_dev_snippet_1 Snippet 1: USB Device Initialization
60 * The following section initializes the USB Device and assigns the USBDM and USBDP pins using
61 * \ref cyhal_usb_dev_init. The clock parameter <b>clk</b> is optional and need not be provided (NULL),
62 * to generate and use an available clock resource with a default frequency. The device can be made
63 * physically visible to the USB Host by using \ref cyhal_usb_dev_connect
64 *
65 * \snippet hal_usb_dev.c snippet_cyhal_usb_dev_init
66 *
67 *
68 * \subsection subsection_usb_dev_snippet_2 Snippet 2: Handling USB Event Completion
69 * USB events (see \ref cyhal_usb_dev_event_t) like Bus Reset, EP0 transaction, EP0 Setup can be mapped to an interrupt and assigned
70 * a callback function. The callback function needs to be first registered using
71 * \ref cyhal_usb_dev_register_event_callback. Use different callback functions to handle events individually.
72 *
73 * \snippet hal_usb_dev.c snippet_cyhal_usb_dev_event
74 *
75 *
76 * \subsection subsection_usb_dev_snippet_3 Snippet 3: Custom USB Interrupt Handler
77 * The following section illustrates how to set up the IRQ interrupt handler for USB device. Inside the handler
78 * \ref cyhal_usb_dev_process_irq has been used to process the interrupts.
79 *
80 * \snippet hal_usb_dev.c snippet_cyhal_usb_dev_irq
81 *
82 *
83 * \subsection subsection_usb_dev_snippet_4 Snippet 4: Adding an Endpoint and Handling its Interrupts
84 * The following section shows how to add endpoint to the USB device and configure the endpoint using
85 * \ref cyhal_usb_dev_endpoint_add. The interrupts associated with the endpoints are handled by a
86 * callback function registered using \ref cyhal_usb_dev_register_endpoint_callback.
87 * The endpoint can also be configured using <a href="https://www.cypress.com/ModusToolboxUSBConfig">ModusToolbox™ USB Configurator</a>
88 *
89 * \snippet hal_usb_dev.c snippet_cyhal_usb_dev_endpoint
90 */
91 
92 #pragma once
93 
94 #include <stdint.h>
95 #include <stdbool.h>
96 #include "cy_result.h"
97 #include "cyhal_hw_types.h"
98 
99 #if defined(__cplusplus)
100 extern "C" {
101 #endif
102 
103 /** \addtogroup group_hal_results_usbdev USB Device HAL Results
104  *  USB Device specific return codes
105  *  \ingroup group_hal_results
106  *  \{ *//**
107  */
108 
109 /** The usb error */
110 #define CYHAL_USB_DEV_RSLT_ERR                          \
111     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_USB, 0))
112 /** The driver configuration is not supported by the HAL */
113 #define CYHAL_USB_DEV_RSLT_ERR_BAD_DRV_CFG              \
114     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_USB, 1))
115 /** The configuration of USB clock failed */
116 #define CYHAL_USB_DEV_RSLT_ERR_CLK_CFG                  \
117     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_USB, 2))
118 
119 /**
120  * \}
121  */
122 
123 /**
124  * \addtogroup group_hal_usb_dev_endpoint Endpoint
125  * \{
126  * APIs relating to endpoint management
127  */
128 
129 /** Returns true if endpoint direction is IN */
130 #define CYHAL_USB_DEV_IS_IN_EP(endpoint)        (0U != (0x80U & (uint32_t) (endpoint)))
131 
132 /** Returns endpoint number (type uint32_t) */
133 #define CYHAL_USB_DEV_GET_EP_NUM(endpoint)      ((uint32_t) (endpoint) & 0x0FU)
134 
135 /** Returns endpoint index (type uint32_t) */
136 #define CYHAL_USB_DEV_GET_EP_IDX(endpoint)      (CYHAL_USB_DEV_GET_EP_NUM(endpoint) - 1U)
137 
138 /** USB Device Endpoints types */
139 typedef enum
140 {
141     CYHAL_USB_DEV_EP_TYPE_CTRL = 0,
142     CYHAL_USB_DEV_EP_TYPE_ISO  = 1,
143     CYHAL_USB_DEV_EP_TYPE_BULK = 2,
144     CYHAL_USB_DEV_EP_TYPE_INT  = 3
145 } cyhal_usb_dev_ep_type_t;
146 
147 /** \} group_hal_usb_dev_endpoint */
148 
149 
150 /**
151  * \addtogroup group_hal_usb_dev_common Common
152  * \{
153  */
154 
155 /** Service Callback Events */
156 typedef enum
157 {
158     CYHAL_USB_DEV_EVENT_BUS_RESET,  /**< Callback hooked to bus reset interrupt */
159     CYHAL_USB_DEV_EVENT_EP0_SETUP,  /**< Callback hooked to endpoint 0 SETUP packet interrupt */
160     CYHAL_USB_DEV_EVENT_EP0_IN,     /**< Callback hooked to endpoint 0 IN packet interrupt */
161     CYHAL_USB_DEV_EVENT_EP0_OUT,    /**< Callback hooked to endpoint 0 OUT packet interrupt */
162 } cyhal_usb_dev_event_t;
163 
164 
165 /**
166  * USB endpoint address (consists from endpoint number and direction)
167  */
168 typedef uint8_t cyhal_usb_dev_ep_t;
169 
170 /**
171  * Callback handler for USB Device interrupt
172  */
173 typedef void (*cyhal_usb_dev_irq_callback_t)(void);
174 
175 /**
176  * Callback handler for the transfer completion event for data endpoints (not applicable for endpoint 0)
177  */
178 typedef void (* cyhal_usb_dev_endpoint_callback_t)(cyhal_usb_dev_ep_t endpoint);
179 
180 /** Callback handler for the events for USB Device */
181 typedef void (*cyhal_usb_dev_event_callback_t)(void);
182 
183 /** Callback handler for the events for USB Device */
184 typedef void (*cyhal_usb_dev_sof_callback_t)(uint32_t frame_number);
185 
186 
187 /**
188  * Initialize the USB instance.
189  *
190  * @param[out] obj    Pointer to a USB object. The caller must allocate the
191  *  memory for this object but the init function will initialize its contents.
192  * @param[in] dp      The D+ pin to initialize
193  * @param[in] dm      The D- pin to initialize
194  * @param[in] clk     The clock to use can be shared, if not provided a new clock will be allocated
195  *
196  * @return The status of the initialization request
197  */
198  cy_rslt_t cyhal_usb_dev_init(cyhal_usb_dev_t *obj, cyhal_gpio_t dp, cyhal_gpio_t dm, const cyhal_clock_t *clk);
199 
200 /**
201  * Power down the USB instance
202  *
203  * Disable interrupts and stop sending events.
204  *
205  * @param[in,out] obj The USB device object
206  */
207  void cyhal_usb_dev_free(cyhal_usb_dev_t *obj);
208 
209 /**
210  * Make the USB device visible to the USB host
211  *
212  * Enable either the D+ or D- pull-up so the host can detect
213  * the presence of this device.
214  *
215  * @param[in,out] obj The USB device object
216  */
217  void cyhal_usb_dev_connect(cyhal_usb_dev_t *obj);
218 
219 /**
220  * Detach the USB device
221  *
222  * Disable the D+ and D- pull-up and stop responding to
223  * USB traffic.
224  *
225  * @param[in,out] obj The USB device object
226  */
227  void cyhal_usb_dev_disconnect(cyhal_usb_dev_t *obj);
228 
229  /**
230   * Suspend the USB phy. This allows the device to enter deepsleep.
231   * Any data left any USB EP buffers will be lost, when device go into deepsleep.
232   * Call \ref cyhal_usb_dev_resume to resume USB from deepsleep.
233   *
234   * @param[in] obj The usb device object
235   */
236  void cyhal_usb_dev_suspend(cyhal_usb_dev_t *obj);
237 
238 /**
239  * Resume the USB phy from a suspended state. \see cyhal_usb_dev_suspend
240  *
241  * @param[in] obj The usb device object
242  */
243  void cyhal_usb_dev_resume(cyhal_usb_dev_t *obj);
244 
245 /**
246  * Set this device to the configured state
247  *
248  * Enable added endpoints if they are not enabled
249  * already.
250  *
251  * @param[in,out] obj The USB device object
252  */
253  void cyhal_usb_dev_set_configured(cyhal_usb_dev_t *obj);
254 
255 /**
256  * Leave the configured state
257  *
258  * This is a notification to the USBPhy indicating that the device
259  * is leaving the configured state. The USBPhy can disable all
260  * endpoints other than endpoint 0.
261  *
262  * @param[in,out] obj The USB device object
263  */
264  void cyhal_usb_dev_set_unconfigured(cyhal_usb_dev_t *obj);
265 
266 /**
267  * Configure start of frame interrupt enablement.
268  *
269  * @param[in,out] obj The USB device object
270  * @param[in] enable  True to turn on interrupt and start calling sof callback on every frame,
271  *                    False to turn off interrupt and stop calling sof callback.
272  */
273  void cyhal_usb_dev_sof_enable(cyhal_usb_dev_t *obj, bool enable);
274 
275 /**
276  * Set the USBPhy's address
277  *
278  * @param[in,out] obj The USB device object
279  * @param[in] address This device's USB address
280  */
281  void cyhal_usb_dev_set_address(cyhal_usb_dev_t *obj, uint8_t address);
282 
283 /** \} group_hal_usb_dev_common */
284 
285 /**
286  * \addtogroup group_hal_usb_dev_ep0 EP0
287  * \{
288  * APIs relating specifically to management of endpoint zero
289  */
290 
291 /**
292  * Get wMaxPacketSize of endpoint 0.
293  * The endpoint 0 has dedicated buffer.
294  *
295  * @param[in,out] obj       The USB device object
296  *
297  * @return The size allocated for endpoint 0
298  */
299 uint32_t cyhal_usb_dev_ep0_get_max_packet(cyhal_usb_dev_t *obj);
300 
301 /**
302  * Read the contents of the SETUP packet
303  *
304  * @param[in,out] obj The USB device object
305  * @param[in] buffer  Buffer to fill with data
306  * @param[in] size    Size of buffer passed in
307  */
308  void cyhal_usb_dev_ep0_setup_read_result(cyhal_usb_dev_t *obj, uint8_t *buffer, uint32_t size);
309 
310 /**
311  * Start receiving a packet of up to wMaxPacketSize on endpoint 0
312  *
313  * @param[in,out] obj The USB device object
314  * @param[in] buffer  Buffer to fill with the data read
315  * @param[in] size    Size of buffer
316  */
317  void cyhal_usb_dev_ep0_read(cyhal_usb_dev_t *obj, uint8_t *buffer, uint32_t size);
318 
319 /**
320  * Read the contents of a received packet
321  *
322  * @param[in,out] obj  The USB device object
323  *
324  * @return Actual number of bytes that was read
325  */
326  uint32_t cyhal_usb_dev_ep0_read_result(cyhal_usb_dev_t *obj);
327 
328 /**
329  * Write a packet on endpoint 0
330  *
331  * @param[in,out] obj The USB device object
332  * @param[in] buffer  Buffer fill with data to send
333  * @param[in] size    Size of data to send
334  *
335  * @return The number of bytes that were written.
336  */
337  uint32_t cyhal_usb_dev_ep0_write(cyhal_usb_dev_t *obj, uint8_t *buffer, uint32_t size);
338 
339 /**
340  * Protocol stall on endpoint 0.
341  * Stall all IN and OUT packets on endpoint 0 until a SETUP packet is received.
342  *
343  * @param[in,out] obj The USB device object
344  *
345  * @note The stall is cleared automatically when a setup packet is received
346  */
347  void cyhal_usb_dev_ep0_stall(cyhal_usb_dev_t *obj);
348 
349 /** \} group_hal_usb_dev_ep0 */
350 
351 /**
352  * \addtogroup group_hal_usb_dev_endpoint
353  * \{
354  */
355 
356 /**
357  * Configure an endpoint.
358  *
359  * @param[in,out] obj    The USB device object
360  * @param[in] alloc      True to allocates buffer for the endpoint, false to skip allocation
361  * @param[in] enable     True to enable endpoint operation, false to skip enablement
362  * @param[in] endpoint   Endpoint to configure and enable
363  * @param[in] max_packet The maximum packet size that can be sent or received
364  * @param[in] type       The type of endpoint (does not care when enable parameter is false)
365  *
366  * @return The status of the endpoint add request
367  *
368  * @note
369  * - This function cannot be used to configure endpoint 0. That must be done
370  *   with cyhal_usb_dev_ep0_get_max_packet.
371  * - After endpoint was enabled it must be removed with cyhal_usb_dev_endpoint_remove
372  *   and then enabled again.
373  */
374 cy_rslt_t cyhal_usb_dev_endpoint_add(cyhal_usb_dev_t *obj, bool alloc, bool enable ,cyhal_usb_dev_ep_t endpoint, uint32_t max_packet, cyhal_usb_dev_ep_type_t type);
375 
376 /**
377  * Disable an endpoint
378  *
379  * @param[in,out] obj  The USB device object
380  * @param[in] endpoint Endpoint to disable
381  *
382  * @return The status of the endpoint remove request
383  */
384  cy_rslt_t cyhal_usb_dev_endpoint_remove(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint);
385 
386 /**
387  * Perform a functional stall on the given endpoint
388  *
389  * Set the HALT feature for this endpoint so that all further
390  * communication is aborted.
391  *
392  * @param[in,out] obj  The USB device object
393  * @param[in] endpoint Endpoint to stall
394  *
395  * @return The status of the endpoint stall request
396  */
397  cy_rslt_t cyhal_usb_dev_endpoint_stall(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint);
398 
399 /**
400  * Unstall the endpoint
401  *
402  * Clear the HALT feature on this endpoint so communication can
403  * resume.
404  *
405  * @param[in,out] obj  The USB device object
406  * @param[in] endpoint Endpoint to stall
407  *
408  * @return The status of the endpoint unstall request
409  */
410  cy_rslt_t cyhal_usb_dev_endpoint_unstall(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint);
411 
412 /**
413  * Return the endpoint stall state
414  *
415  * @param[in,out] obj    The USB device object
416  * @param[in] endpoint   Endpoint to check stall state
417  *
418  * @return True if endpoint stalled, false otherwise.
419  */
420  bool cyhal_usb_dev_endpoint_is_stalled(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint);
421 
422 /**
423  * Start a read on the given endpoint
424  *
425  * @param[in,out] obj  The USB device object
426  * @param[in] endpoint Endpoint to start the read on
427  * @param[in] data     Buffer to fill with data
428  * @param[in] size     Size of the read buffer. This must be at least
429  *                     the max packet size for this endpoint.
430  *
431  * @return The status of start a read operation
432  */
433  cy_rslt_t cyhal_usb_dev_endpoint_read(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint, uint8_t *data, uint32_t size);
434 
435 /**
436  * Finish a read on the given endpoint
437  *
438  * @param[in,out] obj   The USB device object
439  * @param[in] endpoint  Endpoint to check
440  * @param[out] act_size Actual number of bytes that was read
441  *
442  * @return The status of a finish read
443  */
444  cy_rslt_t cyhal_usb_dev_endpoint_read_result(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint, uint32_t *act_size);
445 
446 /**
447  * Start a write on the given endpoint
448  *
449  * @param[in,out] obj  The USB device object
450  * @param[in] endpoint Endpoint to write to
451  * @param[in] data     Buffer to write
452  * @param[in] size     Size of data to write
453  *
454  * @return The status of a write request
455  */
456  cy_rslt_t cyhal_usb_dev_endpoint_write(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint, uint8_t const *data, uint32_t size);
457 
458 /**
459  * Abort the current transfer if it has not yet been sent
460  *
461  * @param[in,out] obj  The USB device object
462  * @param[in] endpoint Endpoint to abort the transfer on. It is implementation defined
463  * if this function has an effect on receive endpoints.
464  *
465  * @return The status of an abort request
466  *
467  * @note
468  * For the ISOC endpoints in pending state this function does not wait for
469  * bus activity completion because these endpoints do not have handshake and are
470  * always accessible to the Host. Therefore it is safe to call this function for
471  * ISOC endpoint when the Host will not access them during abort.
472  */
473  cy_rslt_t cyhal_usb_dev_endpoint_abort(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint);
474 
475 /** \} group_hal_usb_dev_endpoint */
476 
477 /**
478  * \addtogroup group_hal_usb_dev_common Common
479  * \{
480  */
481 
482  /** Register a USB Device callback handler
483  *
484  * This function will be called when the USB interrupt is triggered. This interrupt can be
485  * enabled or disabled using \ref cyhal_usb_dev_irq_enable.
486  *
487  * @param[in,out] obj The USB device object
488  * @param[in] callback The event handler function which will be invoked when the event fires
489  *
490  * @return The status of the register_irq_callback request
491  */
492 cy_rslt_t cyhal_usb_dev_register_irq_callback(cyhal_usb_dev_t *obj, cyhal_usb_dev_irq_callback_t callback);
493 
494 /**
495  * Configure USB Device event enablement.
496  *
497  * When the interrupt is enabled and triggered, the function specified by \ref cyhal_usb_dev_register_irq_callback will be called.
498  *
499  * @param[in,out] obj The usb device object
500  * @param[in] enable  True to turn on events, False to turn off
501  */
502 void cyhal_usb_dev_irq_enable(cyhal_usb_dev_t *obj, bool enable);
503 
504 /**
505  *  Default USB Device interrupt handler.
506  *
507  * @param[in,out] obj The USB device object
508  */
509 void cyhal_usb_dev_process_irq(cyhal_usb_dev_t *obj);
510 
511 /**
512  * The USB Device endpoint complete callback handler registration
513  *
514  * @param[in,out] obj  The USB device object
515  * @param[in] endpoint Endpoint to registers handler
516  * @param[in] callback  The callback handler which will be invoked when the endpoint comp
517  *
518  * \ingroup group_hal_usb_dev_endpoint
519  */
520 void cyhal_usb_dev_register_endpoint_callback(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint, cyhal_usb_dev_endpoint_callback_t callback);
521 
522 /**
523  * The USB Device event complete callback handler registration. The events are defined by x type.
524  *
525  * @param[in,out] obj The USB device object
526  * @param[in] event   The event that triggers the callback, see \ref cyhal_usb_dev_event_t
527  * @param[in] callback The callback handler which will be invoked when the interrupt fires
528  */
529 void cyhal_usb_dev_register_event_callback(cyhal_usb_dev_t *obj, cyhal_usb_dev_event_t event, cyhal_usb_dev_event_callback_t callback);
530 
531 /**
532  * The USB Device start of frame (SOF) complete callback handler registration.
533  *
534  * @param[in,out] obj The USB device object
535  * @param[in] callback The callback handler which will be invoked when the interrupt fires
536  */
537 void cyhal_usb_dev_register_sof_callback( cyhal_usb_dev_t *obj, cyhal_usb_dev_sof_callback_t callback);
538 
539 /** \} group_hal_usb_dev_common */
540 
541 #if defined(__cplusplus)
542 }
543 #endif
544 
545 #ifdef CYHAL_USB_DEV_IMPL_HEADER
546 #include CYHAL_USB_DEV_IMPL_HEADER
547 #endif /* CYHAL_USB_DEV_IMPL_HEADER */
548 
549 /** \} group_hal_usb_dev */
550