1 /**
2   ******************************************************************************
3   * @file    stm32l4xx_hal_pcd_ex.c
4   * @author  MCD Application Team
5   * @brief   PCD Extended HAL module driver.
6   *          This file provides firmware functions to manage the following
7   *          functionalities of the USB Peripheral Controller:
8   *           + Extended features functions
9   *
10   ******************************************************************************
11   * @attention
12   *
13   * Copyright (c) 2017 STMicroelectronics.
14   * All rights reserved.
15   *
16   * This software is licensed under terms that can be found in the LICENSE file
17   * in the root directory of this software component.
18   * If no LICENSE file comes with this software, it is provided AS-IS.
19   *
20   ******************************************************************************
21   */
22 
23 /* Includes ------------------------------------------------------------------*/
24 #include "stm32l4xx_hal.h"
25 
26 /** @addtogroup STM32L4xx_HAL_Driver
27   * @{
28   */
29 
30 /** @defgroup PCDEx PCDEx
31   * @brief PCD Extended HAL module driver
32   * @{
33   */
34 
35 #ifdef HAL_PCD_MODULE_ENABLED
36 
37 #if defined (USB) || defined (USB_OTG_FS)
38 /* Private types -------------------------------------------------------------*/
39 /* Private variables ---------------------------------------------------------*/
40 /* Private constants ---------------------------------------------------------*/
41 /* Private macros ------------------------------------------------------------*/
42 /* Private functions ---------------------------------------------------------*/
43 /* Exported functions --------------------------------------------------------*/
44 
45 /** @defgroup PCDEx_Exported_Functions PCDEx Exported Functions
46   * @{
47   */
48 
49 /** @defgroup PCDEx_Exported_Functions_Group1 Peripheral Control functions
50   * @brief    PCDEx control functions
51   *
52 @verbatim
53  ===============================================================================
54                  ##### Extended features functions #####
55  ===============================================================================
56     [..]  This section provides functions allowing to:
57       (+) Update FIFO configuration
58 
59 @endverbatim
60   * @{
61   */
62 #if defined (USB_OTG_FS)
63 /**
64   * @brief  Set Tx FIFO
65   * @param  hpcd PCD handle
66   * @param  fifo The number of Tx fifo
67   * @param  size Fifo size
68   * @retval HAL status
69   */
HAL_PCDEx_SetTxFiFo(PCD_HandleTypeDef * hpcd,uint8_t fifo,uint16_t size)70 HAL_StatusTypeDef HAL_PCDEx_SetTxFiFo(PCD_HandleTypeDef *hpcd, uint8_t fifo, uint16_t size)
71 {
72   uint8_t i;
73   uint32_t Tx_Offset;
74 
75   /*  TXn min size = 16 words. (n  : Transmit FIFO index)
76       When a TxFIFO is not used, the Configuration should be as follows:
77           case 1 :  n > m    and Txn is not used    (n,m  : Transmit FIFO indexes)
78          --> Txm can use the space allocated for Txn.
79          case2  :  n < m    and Txn is not used    (n,m  : Transmit FIFO indexes)
80          --> Txn should be configured with the minimum space of 16 words
81      The FIFO is used optimally when used TxFIFOs are allocated in the top
82          of the FIFO.Ex: use EP1 and EP2 as IN instead of EP1 and EP3 as IN ones.
83      When DMA is used 3n * FIFO locations should be reserved for internal DMA registers */
84 
85   Tx_Offset = hpcd->Instance->GRXFSIZ;
86 
87   if (fifo == 0U)
88   {
89     hpcd->Instance->DIEPTXF0_HNPTXFSIZ = ((uint32_t)size << 16) | Tx_Offset;
90   }
91   else
92   {
93     Tx_Offset += (hpcd->Instance->DIEPTXF0_HNPTXFSIZ) >> 16;
94     for (i = 0U; i < (fifo - 1U); i++)
95     {
96       Tx_Offset += (hpcd->Instance->DIEPTXF[i] >> 16);
97     }
98 
99     /* Multiply Tx_Size by 2 to get higher performance */
100     hpcd->Instance->DIEPTXF[fifo - 1U] = ((uint32_t)size << 16) | Tx_Offset;
101   }
102 
103   return HAL_OK;
104 }
105 
106 /**
107   * @brief  Set Rx FIFO
108   * @param  hpcd PCD handle
109   * @param  size Size of Rx fifo
110   * @retval HAL status
111   */
HAL_PCDEx_SetRxFiFo(PCD_HandleTypeDef * hpcd,uint16_t size)112 HAL_StatusTypeDef HAL_PCDEx_SetRxFiFo(PCD_HandleTypeDef *hpcd, uint16_t size)
113 {
114   hpcd->Instance->GRXFSIZ = size;
115 
116   return HAL_OK;
117 }
118 
119 /**
120   * @brief  Activate LPM feature.
121   * @param  hpcd PCD handle
122   * @retval HAL status
123   */
HAL_PCDEx_ActivateLPM(PCD_HandleTypeDef * hpcd)124 HAL_StatusTypeDef HAL_PCDEx_ActivateLPM(PCD_HandleTypeDef *hpcd)
125 {
126   USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
127 
128   hpcd->lpm_active = 1U;
129   hpcd->LPM_State = LPM_L0;
130   USBx->GINTMSK |= USB_OTG_GINTMSK_LPMINTM;
131   USBx->GLPMCFG |= (USB_OTG_GLPMCFG_LPMEN | USB_OTG_GLPMCFG_LPMACK | USB_OTG_GLPMCFG_ENBESL);
132 
133   return HAL_OK;
134 }
135 
136 /**
137   * @brief  Deactivate LPM feature.
138   * @param  hpcd PCD handle
139   * @retval HAL status
140   */
HAL_PCDEx_DeActivateLPM(PCD_HandleTypeDef * hpcd)141 HAL_StatusTypeDef HAL_PCDEx_DeActivateLPM(PCD_HandleTypeDef *hpcd)
142 {
143   USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
144 
145   hpcd->lpm_active = 0U;
146   USBx->GINTMSK &= ~USB_OTG_GINTMSK_LPMINTM;
147   USBx->GLPMCFG &= ~(USB_OTG_GLPMCFG_LPMEN | USB_OTG_GLPMCFG_LPMACK | USB_OTG_GLPMCFG_ENBESL);
148 
149   return HAL_OK;
150 }
151 
152 
153 /**
154   * @brief  Handle BatteryCharging Process.
155   * @param  hpcd PCD handle
156   * @retval HAL status
157   */
HAL_PCDEx_BCD_VBUSDetect(PCD_HandleTypeDef * hpcd)158 void HAL_PCDEx_BCD_VBUSDetect(PCD_HandleTypeDef *hpcd)
159 {
160   USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
161   uint32_t tickstart = HAL_GetTick();
162 
163   /* Enable DCD : Data Contact Detect */
164   USBx->GCCFG |= USB_OTG_GCCFG_DCDEN;
165 
166   /* Wait for Min DCD Timeout */
167   HAL_Delay(300U);
168 
169   /* Check Detect flag */
170   if ((USBx->GCCFG & USB_OTG_GCCFG_DCDET) == USB_OTG_GCCFG_DCDET)
171   {
172 #if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
173     hpcd->BCDCallback(hpcd, PCD_BCD_CONTACT_DETECTION);
174 #else
175     HAL_PCDEx_BCD_Callback(hpcd, PCD_BCD_CONTACT_DETECTION);
176 #endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
177   }
178 
179   /* Primary detection: checks if connected to Standard Downstream Port
180   (without charging capability) */
181   USBx->GCCFG &= ~ USB_OTG_GCCFG_DCDEN;
182   HAL_Delay(50U);
183   USBx->GCCFG |=  USB_OTG_GCCFG_PDEN;
184   HAL_Delay(50U);
185 
186   if ((USBx->GCCFG & USB_OTG_GCCFG_PDET) == 0U)
187   {
188     /* Case of Standard Downstream Port */
189 #if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
190     hpcd->BCDCallback(hpcd, PCD_BCD_STD_DOWNSTREAM_PORT);
191 #else
192     HAL_PCDEx_BCD_Callback(hpcd, PCD_BCD_STD_DOWNSTREAM_PORT);
193 #endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
194   }
195   else
196   {
197     /* start secondary detection to check connection to Charging Downstream
198     Port or Dedicated Charging Port */
199     USBx->GCCFG &= ~ USB_OTG_GCCFG_PDEN;
200     HAL_Delay(50U);
201     USBx->GCCFG |=  USB_OTG_GCCFG_SDEN;
202     HAL_Delay(50U);
203 
204     if ((USBx->GCCFG & USB_OTG_GCCFG_SDET) == USB_OTG_GCCFG_SDET)
205     {
206       /* case Dedicated Charging Port  */
207 #if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
208       hpcd->BCDCallback(hpcd, PCD_BCD_DEDICATED_CHARGING_PORT);
209 #else
210       HAL_PCDEx_BCD_Callback(hpcd, PCD_BCD_DEDICATED_CHARGING_PORT);
211 #endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
212     }
213     else
214     {
215       /* case Charging Downstream Port */
216 #if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
217       hpcd->BCDCallback(hpcd, PCD_BCD_CHARGING_DOWNSTREAM_PORT);
218 #else
219       HAL_PCDEx_BCD_Callback(hpcd, PCD_BCD_CHARGING_DOWNSTREAM_PORT);
220 #endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
221     }
222   }
223 
224   /* Battery Charging capability discovery finished */
225   (void)HAL_PCDEx_DeActivateBCD(hpcd);
226 
227   /* Check for the Timeout, else start USB Device */
228   if ((HAL_GetTick() - tickstart) > 1000U)
229   {
230 #if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
231     hpcd->BCDCallback(hpcd, PCD_BCD_ERROR);
232 #else
233     HAL_PCDEx_BCD_Callback(hpcd, PCD_BCD_ERROR);
234 #endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
235   }
236   else
237   {
238 #if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
239     hpcd->BCDCallback(hpcd, PCD_BCD_DISCOVERY_COMPLETED);
240 #else
241     HAL_PCDEx_BCD_Callback(hpcd, PCD_BCD_DISCOVERY_COMPLETED);
242 #endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
243   }
244 }
245 
246 /**
247   * @brief  Activate BatteryCharging feature.
248   * @param  hpcd PCD handle
249   * @retval HAL status
250   */
HAL_PCDEx_ActivateBCD(PCD_HandleTypeDef * hpcd)251 HAL_StatusTypeDef HAL_PCDEx_ActivateBCD(PCD_HandleTypeDef *hpcd)
252 {
253   USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
254 
255   USBx->GCCFG &= ~(USB_OTG_GCCFG_PDEN);
256   USBx->GCCFG &= ~(USB_OTG_GCCFG_SDEN);
257 
258   /* Power Down USB transceiver  */
259   USBx->GCCFG &= ~(USB_OTG_GCCFG_PWRDWN);
260 
261   /* Enable Battery charging */
262   USBx->GCCFG |= USB_OTG_GCCFG_BCDEN;
263 
264   hpcd->battery_charging_active = 1U;
265 
266   return HAL_OK;
267 }
268 
269 /**
270   * @brief  Deactivate BatteryCharging feature.
271   * @param  hpcd PCD handle
272   * @retval HAL status
273   */
HAL_PCDEx_DeActivateBCD(PCD_HandleTypeDef * hpcd)274 HAL_StatusTypeDef HAL_PCDEx_DeActivateBCD(PCD_HandleTypeDef *hpcd)
275 {
276   USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
277 
278   USBx->GCCFG &= ~(USB_OTG_GCCFG_SDEN);
279   USBx->GCCFG &= ~(USB_OTG_GCCFG_PDEN);
280 
281   /* Disable Battery charging */
282   USBx->GCCFG &= ~(USB_OTG_GCCFG_BCDEN);
283 
284   hpcd->battery_charging_active = 0U;
285 
286   return HAL_OK;
287 }
288 
289 #endif /* defined (USB_OTG_FS) */
290 #if defined (USB)
291 /**
292   * @brief  Configure PMA for EP
293   * @param  hpcd  Device instance
294   * @param  ep_addr endpoint address
295   * @param  ep_kind endpoint Kind
296   *                  USB_SNG_BUF: Single Buffer used
297   *                  USB_DBL_BUF: Double Buffer used
298   * @param  pmaadress: EP address in The PMA: In case of single buffer endpoint
299   *                   this parameter is 16-bit value providing the address
300   *                   in PMA allocated to endpoint.
301   *                   In case of double buffer endpoint this parameter
302   *                   is a 32-bit value providing the endpoint buffer 0 address
303   *                   in the LSB part of 32-bit value and endpoint buffer 1 address
304   *                   in the MSB part of 32-bit value.
305   * @retval HAL status
306   */
307 
HAL_PCDEx_PMAConfig(PCD_HandleTypeDef * hpcd,uint16_t ep_addr,uint16_t ep_kind,uint32_t pmaadress)308 HAL_StatusTypeDef  HAL_PCDEx_PMAConfig(PCD_HandleTypeDef *hpcd, uint16_t ep_addr,
309                                        uint16_t ep_kind, uint32_t pmaadress)
310 {
311   PCD_EPTypeDef *ep;
312 
313   /* initialize ep structure*/
314   if ((0x80U & ep_addr) == 0x80U)
315   {
316     ep = &hpcd->IN_ep[ep_addr & EP_ADDR_MSK];
317   }
318   else
319   {
320     ep = &hpcd->OUT_ep[ep_addr];
321   }
322 
323   /* Here we check if the endpoint is single or double Buffer*/
324   if (ep_kind == PCD_SNG_BUF)
325   {
326     /* Single Buffer */
327     ep->doublebuffer = 0U;
328     /* Configure the PMA */
329     ep->pmaadress = (uint16_t)pmaadress;
330   }
331 #if (USE_USB_DOUBLE_BUFFER == 1U)
332   else /* USB_DBL_BUF */
333   {
334     /* Double Buffer Endpoint */
335     ep->doublebuffer = 1U;
336     /* Configure the PMA */
337     ep->pmaaddr0 = (uint16_t)(pmaadress & 0xFFFFU);
338     ep->pmaaddr1 = (uint16_t)((pmaadress & 0xFFFF0000U) >> 16);
339   }
340 #endif /* (USE_USB_DOUBLE_BUFFER == 1U) */
341 
342   return HAL_OK;
343 }
344 
345 /**
346   * @brief  Activate BatteryCharging feature.
347   * @param  hpcd PCD handle
348   * @retval HAL status
349   */
HAL_PCDEx_ActivateBCD(PCD_HandleTypeDef * hpcd)350 HAL_StatusTypeDef HAL_PCDEx_ActivateBCD(PCD_HandleTypeDef *hpcd)
351 {
352   USB_TypeDef *USBx = hpcd->Instance;
353   hpcd->battery_charging_active = 1U;
354 
355   /* Enable BCD feature */
356   USBx->BCDR |= USB_BCDR_BCDEN;
357 
358   /* Enable DCD : Data Contact Detect */
359   USBx->BCDR &= ~(USB_BCDR_PDEN);
360   USBx->BCDR &= ~(USB_BCDR_SDEN);
361   USBx->BCDR |= USB_BCDR_DCDEN;
362 
363   return HAL_OK;
364 }
365 
366 /**
367   * @brief  Deactivate BatteryCharging feature.
368   * @param  hpcd PCD handle
369   * @retval HAL status
370   */
HAL_PCDEx_DeActivateBCD(PCD_HandleTypeDef * hpcd)371 HAL_StatusTypeDef HAL_PCDEx_DeActivateBCD(PCD_HandleTypeDef *hpcd)
372 {
373   USB_TypeDef *USBx = hpcd->Instance;
374   hpcd->battery_charging_active = 0U;
375 
376   /* Disable BCD feature */
377   USBx->BCDR &= ~(USB_BCDR_BCDEN);
378 
379   return HAL_OK;
380 }
381 
382 /**
383   * @brief  Handle BatteryCharging Process.
384   * @param  hpcd PCD handle
385   * @retval HAL status
386   */
HAL_PCDEx_BCD_VBUSDetect(PCD_HandleTypeDef * hpcd)387 void HAL_PCDEx_BCD_VBUSDetect(PCD_HandleTypeDef *hpcd)
388 {
389   USB_TypeDef *USBx = hpcd->Instance;
390   uint32_t tickstart = HAL_GetTick();
391 
392   /* Wait for Min DCD Timeout */
393   HAL_Delay(300U);
394 
395   /* Data Pin Contact ? Check Detect flag */
396   if ((USBx->BCDR & USB_BCDR_DCDET) == USB_BCDR_DCDET)
397   {
398 #if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
399     hpcd->BCDCallback(hpcd, PCD_BCD_CONTACT_DETECTION);
400 #else
401     HAL_PCDEx_BCD_Callback(hpcd, PCD_BCD_CONTACT_DETECTION);
402 #endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
403   }
404   /* Primary detection: checks if connected to Standard Downstream Port
405   (without charging capability) */
406   USBx->BCDR &= ~(USB_BCDR_DCDEN);
407   HAL_Delay(50U);
408   USBx->BCDR |= (USB_BCDR_PDEN);
409   HAL_Delay(50U);
410 
411   /* If Charger detect ? */
412   if ((USBx->BCDR & USB_BCDR_PDET) == USB_BCDR_PDET)
413   {
414     /* Start secondary detection to check connection to Charging Downstream
415     Port or Dedicated Charging Port */
416     USBx->BCDR &= ~(USB_BCDR_PDEN);
417     HAL_Delay(50U);
418     USBx->BCDR |= (USB_BCDR_SDEN);
419     HAL_Delay(50U);
420 
421     /* If CDP ? */
422     if ((USBx->BCDR & USB_BCDR_SDET) == USB_BCDR_SDET)
423     {
424       /* Dedicated Downstream Port DCP */
425 #if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
426       hpcd->BCDCallback(hpcd, PCD_BCD_DEDICATED_CHARGING_PORT);
427 #else
428       HAL_PCDEx_BCD_Callback(hpcd, PCD_BCD_DEDICATED_CHARGING_PORT);
429 #endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
430     }
431     else
432     {
433       /* Charging Downstream Port CDP */
434 #if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
435       hpcd->BCDCallback(hpcd, PCD_BCD_CHARGING_DOWNSTREAM_PORT);
436 #else
437       HAL_PCDEx_BCD_Callback(hpcd, PCD_BCD_CHARGING_DOWNSTREAM_PORT);
438 #endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
439     }
440   }
441   else /* NO */
442   {
443     /* Standard Downstream Port */
444 #if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
445     hpcd->BCDCallback(hpcd, PCD_BCD_STD_DOWNSTREAM_PORT);
446 #else
447     HAL_PCDEx_BCD_Callback(hpcd, PCD_BCD_STD_DOWNSTREAM_PORT);
448 #endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
449   }
450 
451   /* Battery Charging capability discovery finished Start Enumeration */
452   (void)HAL_PCDEx_DeActivateBCD(hpcd);
453 
454   /* Check for the Timeout, else start USB Device */
455   if ((HAL_GetTick() - tickstart) > 1000U)
456   {
457 #if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
458     hpcd->BCDCallback(hpcd, PCD_BCD_ERROR);
459 #else
460     HAL_PCDEx_BCD_Callback(hpcd, PCD_BCD_ERROR);
461 #endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
462   }
463   else
464   {
465 #if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
466     hpcd->BCDCallback(hpcd, PCD_BCD_DISCOVERY_COMPLETED);
467 #else
468     HAL_PCDEx_BCD_Callback(hpcd, PCD_BCD_DISCOVERY_COMPLETED);
469 #endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
470   }
471 }
472 
473 
474 /**
475   * @brief  Activate LPM feature.
476   * @param  hpcd PCD handle
477   * @retval HAL status
478   */
HAL_PCDEx_ActivateLPM(PCD_HandleTypeDef * hpcd)479 HAL_StatusTypeDef HAL_PCDEx_ActivateLPM(PCD_HandleTypeDef *hpcd)
480 {
481 
482   USB_TypeDef *USBx = hpcd->Instance;
483   hpcd->lpm_active = 1U;
484   hpcd->LPM_State = LPM_L0;
485 
486   USBx->LPMCSR |= USB_LPMCSR_LMPEN;
487   USBx->LPMCSR |= USB_LPMCSR_LPMACK;
488 
489   return HAL_OK;
490 }
491 
492 /**
493   * @brief  Deactivate LPM feature.
494   * @param  hpcd PCD handle
495   * @retval HAL status
496   */
HAL_PCDEx_DeActivateLPM(PCD_HandleTypeDef * hpcd)497 HAL_StatusTypeDef HAL_PCDEx_DeActivateLPM(PCD_HandleTypeDef *hpcd)
498 {
499   USB_TypeDef *USBx = hpcd->Instance;
500 
501   hpcd->lpm_active = 0U;
502 
503   USBx->LPMCSR &= ~(USB_LPMCSR_LMPEN);
504   USBx->LPMCSR &= ~(USB_LPMCSR_LPMACK);
505 
506   return HAL_OK;
507 }
508 
509 #endif /* defined (USB) */
510 
511 /**
512   * @brief  Send LPM message to user layer callback.
513   * @param  hpcd PCD handle
514   * @param  msg LPM message
515   * @retval HAL status
516   */
HAL_PCDEx_LPM_Callback(PCD_HandleTypeDef * hpcd,PCD_LPM_MsgTypeDef msg)517 __weak void HAL_PCDEx_LPM_Callback(PCD_HandleTypeDef *hpcd, PCD_LPM_MsgTypeDef msg)
518 {
519   /* Prevent unused argument(s) compilation warning */
520   UNUSED(hpcd);
521   UNUSED(msg);
522 
523   /* NOTE : This function should not be modified, when the callback is needed,
524             the HAL_PCDEx_LPM_Callback could be implemented in the user file
525    */
526 }
527 
528 /**
529   * @brief  Send BatteryCharging message to user layer callback.
530   * @param  hpcd PCD handle
531   * @param  msg LPM message
532   * @retval HAL status
533   */
HAL_PCDEx_BCD_Callback(PCD_HandleTypeDef * hpcd,PCD_BCD_MsgTypeDef msg)534 __weak void HAL_PCDEx_BCD_Callback(PCD_HandleTypeDef *hpcd, PCD_BCD_MsgTypeDef msg)
535 {
536   /* Prevent unused argument(s) compilation warning */
537   UNUSED(hpcd);
538   UNUSED(msg);
539 
540   /* NOTE : This function should not be modified, when the callback is needed,
541             the HAL_PCDEx_BCD_Callback could be implemented in the user file
542    */
543 }
544 
545 /**
546   * @}
547   */
548 
549 /**
550   * @}
551   */
552 #endif /* defined (USB) || defined (USB_OTG_FS) */
553 #endif /* HAL_PCD_MODULE_ENABLED */
554 
555 /**
556   * @}
557   */
558 
559 /**
560   * @}
561   */
562