1 /*
2  * Copyright 2019 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 #include "usb_hsdcd.h"
8 #include "usb_hsdcd_config.h"
9 /*******************************************************************************
10  * Definitions
11  ******************************************************************************/
12 #if !(defined(FSL_FEATURE_USBPHY_HAS_DCD_ANALOG) && (FSL_FEATURE_USBPHY_HAS_DCD_ANALOG > 0U))
13 /*! @brief The sequence initiation time for the dcd module. */
14 #define USB_HSDCD_TSEQ_INIT_TIME (1000U)
15 /*! @brief Time Period to Debounce D+ Signal. */
16 #define USB_HSDCD_TDCD_DBNC (10U)
17 /*! @brief The time period comparator enabled. */
18 #define USB_HSDCD_VDPSRC_ON (200U)
19 /*! @brief The amount of time that the module waits after primary detection before start to secondary detection. */
20 #define USB_HSDCD_TWAIT_AFTER_PRD (40U)
21 /*! @brief The amount of time the module enable the Vdm_src. */
22 #define USB_HSDCD_TVDMSRC_ON (10U)
23 #endif
24 typedef enum _usb_dcd_detection_sequence_results
25 {
26     kUSB_DcdDetectionNoResults        = 0x0U,
27     kUSB_DcdDetectionStandardHost     = 0x01U,
28     kUSB_DcdDetectionChargingPort     = 0x02U,
29     kUSB_DcdDetectionDedicatedCharger = 0x03U,
30 } usb_dcd_detection_sequence_results_t;
31 typedef enum _usb_dcd_detection_sequence_status
32 {
33     kUSB_DcdDetectionNotEnabled            = 0x0U,
34     kUSB_DcdDataPinDetectionCompleted      = 0x01U,
35     kUSB_DcdChargingPortDetectionCompleted = 0x02U,
36     kUSB_DcdChargerTypeDetectionCompleted  = 0x03U,
37 } usb_dcd_detection_sequence_status_t;
38 typedef struct _usb_hsdcd_state_struct
39 {
40     USBHSDCD_Type *dcdRegisterBase;   /*!< The base address of the dcd module */
41     usb_hsdcd_callback_t dcdCallback; /*!< DCD callback function*/
42     void *dcdCallbackParam;           /*!< DCD callback parameter*/
43 #if (defined(FSL_FEATURE_USBPHY_HAS_DCD_ANALOG) && (FSL_FEATURE_USBPHY_HAS_DCD_ANALOG > 0U))
44     void *phyBase; /*!< dcd phy base address, if no phy control needed, set to NULL*/
45 #endif
46     uint8_t dcdDisable;   /*!< whether enable dcd function or not*/
47     uint8_t detectResult; /*!< dcd detect result*/
48 } usb_hsdcd_state_struct_t;
49 /*******************************************************************************
50  * Prototypes
51  ******************************************************************************/
52 /*******************************************************************************
53  * Variables
54  ******************************************************************************/
55 #if defined(USBHSDCD_STACK_BASE_ADDRS)
56 static const uint32_t s_hsdcdBaseAddrs[] = USBHSDCD_STACK_BASE_ADDRS;
57 #else
58 static const uint32_t s_hsdcdBaseAddrs[] = USBHSDCD_BASE_ADDRS;
59 #endif
60 
61 /* Apply for device dcd state structure */
62 static usb_hsdcd_state_struct_t s_UsbDeviceDcdHSState[FSL_FEATURE_SOC_USBHSDCD_COUNT];
63 /*******************************************************************************
64  * Code
65  ******************************************************************************/
66 
USB_HSDCD_GetInstance(USBHSDCD_Type * base)67 static uint32_t USB_HSDCD_GetInstance(USBHSDCD_Type *base)
68 {
69     uint32_t i;
70     uint32_t index = 0;
71 
72     for (i = 0U; i < (uint32_t)(sizeof(s_hsdcdBaseAddrs) / sizeof(s_hsdcdBaseAddrs[0])); i++)
73     {
74         if ((uint32_t)base == s_hsdcdBaseAddrs[i])
75         {
76             return index;
77         }
78         index++;
79     }
80     return 0xFF;
81 }
82 
USB_HSDCD_Init(USBHSDCD_Type * base,usb_hsdcd_config_struct_t * config,usb_hsdcd_handle * dcdHandle)83 usb_hsdcd_status_t USB_HSDCD_Init(USBHSDCD_Type *base, usb_hsdcd_config_struct_t *config, usb_hsdcd_handle *dcdHandle)
84 {
85     usb_hsdcd_state_struct_t *dcdHSState;
86     uint32_t speed;
87     uint32_t index;
88 #if (defined(FSL_FEATURE_USBPHY_HAS_DCD_ANALOG) && (FSL_FEATURE_USBPHY_HAS_DCD_ANALOG > 0U))
89 #if defined(USBPHY_STACK_BASE_ADDRS)
90     uint32_t phyBase[] = USBPHY_STACK_BASE_ADDRS;
91 #else
92     uint32_t phyBase[] = USBPHY_BASE_ADDRS;
93 #endif
94 #endif
95     if (NULL == base)
96     {
97         return kStatus_hsdcd_Error;
98     }
99     index = USB_HSDCD_GetInstance(base);
100     if (0xFFU == index)
101     {
102         return kStatus_hsdcd_Error;
103     }
104 
105     dcdHSState                  = &s_UsbDeviceDcdHSState[index];
106     *dcdHandle                  = dcdHSState;
107     dcdHSState->dcdRegisterBase = base;
108     if ((NULL == config) || (NULL == config->dcdCallback))
109     {
110         /* don't need init */
111     }
112     else
113     {
114 #if (defined(FSL_FEATURE_USBPHY_HAS_DCD_ANALOG) && (FSL_FEATURE_USBPHY_HAS_DCD_ANALOG > 0U))
115         dcdHSState->phyBase = (void *)(uint8_t *)phyBase[index];
116 #endif
117         dcdHSState->dcdCallbackParam = config->dcdCallbackParam;
118         /*initialize the dcd controller*/
119         dcdHSState->dcdCallback = config->dcdCallback;
120     }
121     dcdHSState->dcdDisable = 0U;
122     /*misra 14.3*/
123 #if (USB_HSDCD_CLOCK_SPEED > 1000000U)
124     /*clock speed unit is MHz*/
125     speed = USB_HSDCD_CLOCK_SPEED / 1000000U;
126 #else
127     speed = USB_HSDCD_CLOCK_SPEED / 1000U;
128     dcdHSState->dcdRegisterBase->CLOCK &= ~(USBHSDCD_CLOCK_CLOCK_UNIT_MASK);
129 #endif
130     dcdHSState->dcdRegisterBase->CLOCK &= ~USBHSDCD_CLOCK_CLOCK_SPEED_MASK;
131     dcdHSState->dcdRegisterBase->CLOCK |= USBHSDCD_CLOCK_CLOCK_SPEED(speed);
132 
133 #if !(defined(FSL_FEATURE_USBPHY_HAS_DCD_ANALOG) && (FSL_FEATURE_USBPHY_HAS_DCD_ANALOG > 0U))
134     /*Valid values are 0-1023*/
135     dcdHSState->dcdRegisterBase->TIMER0 &= ~(USBHSDCD_TIMER0_TSEQ_INIT_MASK);
136     dcdHSState->dcdRegisterBase->TIMER0 |= USBHSDCD_TIMER0_TSEQ_INIT(USB_HSDCD_TSEQ_INIT_TIME);
137     /*Valid values are 1-1023*/
138 #if (USB_HSDCD_VDPSRC_ON > 0U)
139     dcdHSState->dcdRegisterBase->TIMER1 &= ~(USBHSDCD_TIMER1_TVDPSRC_ON_MASK);
140     dcdHSState->dcdRegisterBase->TIMER1 |= USBHSDCD_TIMER1_TVDPSRC_ON(USB_HSDCD_VDPSRC_ON);
141 #endif
142     /*Valid values are 1-1023*/
143 #if (USB_HSDCD_TDCD_DBNC > 0U)
144     dcdHSState->dcdRegisterBase->TIMER1 &= ~(USBHSDCD_TIMER1_TDCD_DBNC_MASK);
145     dcdHSState->dcdRegisterBase->TIMER1 |= USBHSDCD_TIMER1_TDCD_DBNC(USB_HSDCD_TDCD_DBNC);
146 #endif
147     /*Valid values are 0-40ms*/
148     dcdHSState->dcdRegisterBase->TIMER2_BC12 &= ~(USBHSDCD_TIMER2_BC12_TVDMSRC_ON_MASK);
149     dcdHSState->dcdRegisterBase->TIMER2_BC12 |= USBHSDCD_TIMER2_BC12_TVDMSRC_ON(USB_HSDCD_TVDMSRC_ON);
150 
151     /*Valid values are 1-1023ms*/
152 #if (USB_HSDCD_TWAIT_AFTER_PRD > 0U)
153     dcdHSState->dcdRegisterBase->TIMER2_BC12 &= ~(USBHSDCD_TIMER2_BC12_TWAIT_AFTER_PRD_MASK);
154     dcdHSState->dcdRegisterBase->TIMER2_BC12 |= USBHSDCD_TIMER2_BC12_TWAIT_AFTER_PRD(USB_HSDCD_TWAIT_AFTER_PRD);
155 #endif
156 
157 #endif
158     dcdHSState->dcdRegisterBase->CONTROL |= USBHSDCD_CONTROL_BC12_MASK;
159 
160     return kStatus_hsdcd_Success;
161 }
USB_HSDCD_Deinit(usb_hsdcd_handle handle)162 usb_hsdcd_status_t USB_HSDCD_Deinit(usb_hsdcd_handle handle)
163 {
164     usb_hsdcd_state_struct_t *dcdHSState;
165     dcdHSState = (usb_hsdcd_state_struct_t *)handle;
166     if (NULL == handle)
167     {
168         return kStatus_hsdcd_Error;
169     }
170     dcdHSState->dcdRegisterBase->CONTROL |= USBHSDCD_CONTROL_SR_MASK;
171     return kStatus_hsdcd_Success;
172 }
173 #if (defined(FSL_FEATURE_USBPHY_HAS_DCD_ANALOG) && (FSL_FEATURE_USBPHY_HAS_DCD_ANALOG > 0U))
174 /*The USB PHY is shared between DCD function and USB function, but different configurations should be used
175 in these two functions. If DCD function is desired, USB_HSDCDResetEHCIPhy should be called to set the USB PHY
176 to DCD function; If USB function is desired, USB_HSDCDSetPHYToUSBMode should be called to set the USB PHY to USB
177 function*/
USB_HSDCDSetPHYtoDCDMode(void * phyBase)178 static usb_hsdcd_status_t USB_HSDCDSetPHYtoDCDMode(void *phyBase)
179 {
180     USBPHY_Type *usbPhyBase = (USBPHY_Type *)phyBase;
181 
182     if (NULL == usbPhyBase)
183     {
184         return kStatus_hsdcd_Error;
185     }
186     usbPhyBase->PWD_SET |= USBPHY_PWD_TXPWDFS_MASK;
187     usbPhyBase->ANACTRL &= ~(USBPHY_ANACTRL_DEV_PULLDOWN_MASK);
188     usbPhyBase->PLL_SIC |= (USBPHY_PLL_SIC_REFBIAS_PWD_SEL_MASK);
189     usbPhyBase->PLL_SIC &= ~(USBPHY_PLL_SIC_REFBIAS_PWD_MASK);
190     usbPhyBase->USB1_CHRG_DETECT_SET = USBPHY_USB1_CHRG_DETECT_CLR_BGR_IBIAS_MASK;
191     return kStatus_hsdcd_Success;
192 }
USB_HSDCDSetPHYtoUSBMode(void * phyBase)193 static usb_hsdcd_status_t USB_HSDCDSetPHYtoUSBMode(void *phyBase)
194 {
195     USBPHY_Type *usbPhyBase = (USBPHY_Type *)phyBase;
196 
197     if (NULL == usbPhyBase)
198     {
199         return kStatus_hsdcd_Error;
200     }
201     /*de-initialize phy for dcd detect*/
202     usbPhyBase->PWD &= ~(USBPHY_PWD_TXPWDFS_MASK);
203     usbPhyBase->ANACTRL |= USBPHY_ANACTRL_DEV_PULLDOWN_MASK;
204     usbPhyBase->PLL_SIC |= USBPHY_PLL_SIC_REFBIAS_PWD_MASK;
205     usbPhyBase->PLL_SIC &= ~(USBPHY_PLL_SIC_REFBIAS_PWD_SEL_MASK);
206     return kStatus_hsdcd_Success;
207 }
208 #endif
USB_HSDCD_Control(usb_hsdcd_handle handle,usb_hsdcd_control_t type,void * param)209 usb_hsdcd_status_t USB_HSDCD_Control(usb_hsdcd_handle handle, usb_hsdcd_control_t type, void *param)
210 {
211     usb_hsdcd_state_struct_t *dcdHSState;
212     dcdHSState                  = (usb_hsdcd_state_struct_t *)handle;
213     usb_hsdcd_status_t dcdError = kStatus_hsdcd_Success;
214     if (NULL == handle)
215     {
216         return kStatus_hsdcd_Error;
217     }
218     switch (type)
219     {
220         case kUSB_DeviceHSDcdRun:
221             if (0U == dcdHSState->dcdDisable)
222             {
223 #if (defined(FSL_FEATURE_USBPHY_HAS_DCD_ANALOG) && (FSL_FEATURE_USBPHY_HAS_DCD_ANALOG > 0U)) && \
224     ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U))
225                 dcdError = USB_HSDCDSetPHYtoDCDMode(dcdHSState->phyBase);
226 #endif
227                 dcdHSState->dcdRegisterBase->CONTROL |= USBHSDCD_CONTROL_START_MASK;
228             }
229             break;
230         case kUSB_DeviceHSDcdStop:
231             if (0U == dcdHSState->dcdDisable)
232             {
233 #if (defined(FSL_FEATURE_USBPHY_HAS_DCD_ANALOG) && (FSL_FEATURE_USBPHY_HAS_DCD_ANALOG > 0U)) && \
234     ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U))
235                 dcdError = USB_HSDCDSetPHYtoUSBMode(dcdHSState->phyBase);
236 #endif
237                 dcdHSState->dcdRegisterBase->CONTROL |= USBHSDCD_CONTROL_SR_MASK;
238             }
239             break;
240         case kUSB_DeviceHSDcdEnable:
241             dcdHSState->dcdDisable = 0U;
242             break;
243         case kUSB_DeviceHSDcdDisable:
244             dcdHSState->dcdDisable = 1U;
245             break;
246         case kUSB_HostHSDcdSetType:
247             if ((*((uint8_t *)param)) == (uint8_t)kUSB_DcdCDP)
248             {
249                 dcdHSState->dcdRegisterBase->SIGNAL_OVERRIDE =
250                     ((dcdHSState->dcdRegisterBase->SIGNAL_OVERRIDE &
251                       (~(USBHSDCD_SIGNAL_OVERRIDE_PS_MASK << USBHSDCD_SIGNAL_OVERRIDE_PS_SHIFT))) |
252                      (USBHSDCD_SIGNAL_OVERRIDE_PS(3u)));
253             }
254             else
255             {
256                 dcdHSState->dcdRegisterBase->SIGNAL_OVERRIDE =
257                     (dcdHSState->dcdRegisterBase->SIGNAL_OVERRIDE &
258                      (~(USBHSDCD_SIGNAL_OVERRIDE_PS_MASK << USBHSDCD_SIGNAL_OVERRIDE_PS_SHIFT)));
259             }
260             break;
261         default:
262             /*no action*/
263             break;
264     }
265     return dcdError;
266 }
USB_HSDcdIsrFunction(usb_hsdcd_handle handle)267 void USB_HSDcdIsrFunction(usb_hsdcd_handle handle)
268 {
269     uint32_t status;
270     uint32_t chargerType;
271     usb_hsdcd_state_struct_t *dcdHSState;
272     dcdHSState = (usb_hsdcd_state_struct_t *)handle;
273     usb_device_charger_detect_type_t event;
274     if (NULL == handle)
275     {
276         return;
277     }
278 
279     event  = kUSB_DcdError;
280     status = dcdHSState->dcdRegisterBase->STATUS;
281 
282     if (0U != (status & USBHSDCD_STATUS_ERR_MASK))
283     {
284         if (0U != (status & USBHSDCD_STATUS_TO_MASK))
285         {
286             event = kUSB_DcdTimeOut;
287         }
288         else
289         {
290             event = kUSB_DcdError;
291         }
292     }
293     else
294     {
295         switch (status & USBHSDCD_STATUS_SEQ_STAT_MASK)
296         {
297             case USBHSDCD_STATUS_SEQ_STAT(kUSB_DcdChargingPortDetectionCompleted):
298                 chargerType = status & USBHSDCD_STATUS_SEQ_RES_MASK;
299                 if (chargerType == USBHSDCD_STATUS_SEQ_RES(kUSB_DcdDetectionStandardHost))
300                 {
301                     event = kUSB_DcdSDP;
302                 }
303                 else if (chargerType == USBHSDCD_STATUS_SEQ_RES(kUSB_DcdDetectionChargingPort))
304                 {
305                     event = kUSB_DcdError;
306                 }
307                 else
308                 {
309                     /*no action*/
310                 }
311                 break;
312             case USBHSDCD_STATUS_SEQ_STAT(kUSB_DcdChargerTypeDetectionCompleted):
313                 chargerType = status & USBHSDCD_STATUS_SEQ_RES_MASK;
314                 if (chargerType == USBHSDCD_STATUS_SEQ_RES(kUSB_DcdDetectionChargingPort))
315                 {
316                     event = kUSB_DcdCDP;
317                 }
318                 else if (chargerType == USBHSDCD_STATUS_SEQ_RES(kUSB_DcdDetectionDedicatedCharger))
319                 {
320                     event = kUSB_DcdDCP;
321                 }
322                 else
323                 {
324                     /*no action*/
325                 }
326                 break;
327             default:
328                 /*no action*/
329                 break;
330         }
331     }
332 
333     dcdHSState->detectResult = (uint8_t)event;
334     dcdHSState->dcdRegisterBase->CONTROL |= USBHSDCD_CONTROL_IACK_MASK;
335     dcdHSState->dcdRegisterBase->CONTROL |= USBHSDCD_CONTROL_SR_MASK;
336     (void)dcdHSState->dcdCallback(dcdHSState->dcdCallbackParam, event, (void *)&dcdHSState->detectResult);
337     (void)USB_HSDCD_Control(dcdHSState, kUSB_DeviceHSDcdStop, NULL);
338 }
339