/** ****************************************************************************** * @file usb_core.c * @author MCD Application Team * @version V2.1.0 * @date 19-March-2012 * @brief USB-OTG Core Layer ****************************************************************************** * @attention * *

© COPYRIGHT 2012 STMicroelectronics

* * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.st.com/software_license_agreement_liberty_v2 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "usb_core.h" #include "usb_bsp.h" /** @addtogroup USB_OTG_DRIVER * @{ */ /** @defgroup USB_CORE * @brief This file includes the USB-OTG Core Layer * @{ */ /** @defgroup USB_CORE_Private_Defines * @{ */ /** * @} */ /** @defgroup USB_CORE_Private_TypesDefinitions * @{ */ /** * @} */ /** @defgroup USB_CORE_Private_Macros * @{ */ /** * @} */ /** @defgroup USB_CORE_Private_Variables * @{ */ /** * @} */ /** @defgroup USB_CORE_Private_FunctionPrototypes * @{ */ /** * @} */ /** @defgroup USB_CORE_Private_Functions * @{ */ /** * @brief USB_OTG_EnableCommonInt * Initializes the commmon interrupts, used in both device and modes * @param pdev : Selected device * @retval None */ static void USB_OTG_EnableCommonInt(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_GINTMSK_TypeDef int_mask; int_mask.d32 = 0; /* Clear any pending USB_OTG Interrupts */ #ifndef USE_OTG_MODE USB_OTG_WRITE_REG32( &pdev->regs.GREGS->GOTGINT, 0xFFFFFFFF); #endif /* Clear any pending interrupts */ USB_OTG_WRITE_REG32( &pdev->regs.GREGS->GINTSTS, 0xBFFFFFFF); /* Enable the interrupts in the INTMSK */ int_mask.b.wkupintr = 1; int_mask.b.usbsuspend = 1; #ifdef USE_OTG_MODE int_mask.b.otgintr = 1; int_mask.b.sessreqintr = 1; int_mask.b.conidstschng = 1; #endif USB_OTG_WRITE_REG32( &pdev->regs.GREGS->GINTMSK, int_mask.d32); } /** * @brief USB_OTG_CoreReset : Soft reset of the core * @param pdev : Selected device * @retval USB_OTG_STS : status */ static USB_OTG_STS USB_OTG_CoreReset(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_STS status = USB_OTG_OK; __IO USB_OTG_GRSTCTL_TypeDef greset; uint32_t count = 0; greset.d32 = 0; /* Wait for AHB master IDLE state. */ do { USB_OTG_BSP_uDelay(3); greset.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GRSTCTL); if (++count > 200000) { return USB_OTG_OK; } } while (greset.b.ahbidle == 0); /* Core Soft Reset */ count = 0; greset.b.csftrst = 1; USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GRSTCTL, greset.d32 ); do { greset.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GRSTCTL); if (++count > 200000) { break; } } while (greset.b.csftrst == 1); /* Wait for 3 PHY Clocks*/ USB_OTG_BSP_uDelay(3); return status; } /** * @brief USB_OTG_WritePacket : Writes a packet into the Tx FIFO associated * with the EP * @param pdev : Selected device * @param src : source pointer * @param ch_ep_num : end point number * @param bytes : No. of bytes * @retval USB_OTG_STS : status */ USB_OTG_STS USB_OTG_WritePacket(USB_OTG_CORE_HANDLE *pdev, uint8_t *src, uint8_t ch_ep_num, uint16_t len) { USB_OTG_STS status = USB_OTG_OK; if (pdev->cfg.dma_enable == 0) { uint32_t count32b= 0 , i= 0; __IO uint32_t *fifo; count32b = (len + 3) / 4; fifo = pdev->regs.DFIFO[ch_ep_num]; for (i = 0; i < count32b; i++, src+=4) { USB_OTG_WRITE_REG32( fifo, *((__packed uint32_t *)src) ); } } return status; } /** * @brief USB_OTG_ReadPacket : Reads a packet from the Rx FIFO * @param pdev : Selected device * @param dest : Destination Pointer * @param bytes : No. of bytes * @retval None */ void *USB_OTG_ReadPacket(USB_OTG_CORE_HANDLE *pdev, uint8_t *dest, uint16_t len) { uint32_t i=0; uint32_t count32b = (len + 3) / 4; __IO uint32_t *fifo = pdev->regs.DFIFO[0]; for ( i = 0; i < count32b; i++, dest += 4 ) { *(__packed uint32_t *)dest = USB_OTG_READ_REG32(fifo); } return ((void *)dest); } /** * @brief USB_OTG_SelectCore * Initialize core registers address. * @param pdev : Selected device * @param coreID : USB OTG Core ID * @retval USB_OTG_STS : status */ USB_OTG_STS USB_OTG_SelectCore(USB_OTG_CORE_HANDLE *pdev, USB_OTG_CORE_ID_TypeDef coreID) { uint32_t i , baseAddress = 0; USB_OTG_STS status = USB_OTG_OK; pdev->cfg.dma_enable = 0; /* at startup the core is in FS mode */ pdev->cfg.speed = USB_OTG_SPEED_FULL; pdev->cfg.mps = USB_OTG_FS_MAX_PACKET_SIZE ; /* initialize device cfg following its address */ if (coreID == USB_OTG_FS_CORE_ID) { baseAddress = USB_OTG_FS_BASE_ADDR; pdev->cfg.coreID = USB_OTG_FS_CORE_ID; pdev->cfg.host_channels = 8 ; pdev->cfg.dev_endpoints = 4 ; pdev->cfg.TotalFifoSize = 320; /* in 32-bits */ pdev->cfg.phy_itface = USB_OTG_EMBEDDED_PHY; #ifdef USB_OTG_FS_SOF_OUTPUT_ENABLED pdev->cfg.Sof_output = 1; #endif #ifdef USB_OTG_FS_LOW_PWR_MGMT_SUPPORT pdev->cfg.low_power = 1; #endif } else if (coreID == USB_OTG_HS_CORE_ID) { baseAddress = USB_OTG_HS_BASE_ADDR; pdev->cfg.coreID = USB_OTG_HS_CORE_ID; pdev->cfg.host_channels = 12 ; pdev->cfg.dev_endpoints = 6 ; pdev->cfg.TotalFifoSize = 1280;/* in 32-bits */ #ifdef USB_OTG_ULPI_PHY_ENABLED pdev->cfg.phy_itface = USB_OTG_ULPI_PHY; #else #ifdef USB_OTG_EMBEDDED_PHY_ENABLED pdev->cfg.phy_itface = USB_OTG_EMBEDDED_PHY; #endif #endif #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED pdev->cfg.dma_enable = 1; #endif #ifdef USB_OTG_HS_SOF_OUTPUT_ENABLED pdev->cfg.Sof_output = 1; #endif #ifdef USB_OTG_HS_LOW_PWR_MGMT_SUPPORT pdev->cfg.low_power = 1; #endif } pdev->regs.GREGS = (USB_OTG_GREGS *)(baseAddress + \ USB_OTG_CORE_GLOBAL_REGS_OFFSET); pdev->regs.DREGS = (USB_OTG_DREGS *) (baseAddress + \ USB_OTG_DEV_GLOBAL_REG_OFFSET); for (i = 0; i < pdev->cfg.dev_endpoints; i++) { pdev->regs.INEP_REGS[i] = (USB_OTG_INEPREGS *) \ (baseAddress + USB_OTG_DEV_IN_EP_REG_OFFSET + \ (i * USB_OTG_EP_REG_OFFSET)); pdev->regs.OUTEP_REGS[i] = (USB_OTG_OUTEPREGS *) \ (baseAddress + USB_OTG_DEV_OUT_EP_REG_OFFSET + \ (i * USB_OTG_EP_REG_OFFSET)); } pdev->regs.HREGS = (USB_OTG_HREGS *)(baseAddress + \ USB_OTG_HOST_GLOBAL_REG_OFFSET); pdev->regs.HPRT0 = (uint32_t *)(baseAddress + USB_OTG_HOST_PORT_REGS_OFFSET); for (i = 0; i < pdev->cfg.host_channels; i++) { pdev->regs.HC_REGS[i] = (USB_OTG_HC_REGS *)(baseAddress + \ USB_OTG_HOST_CHAN_REGS_OFFSET + \ (i * USB_OTG_CHAN_REGS_OFFSET)); } for (i = 0; i < pdev->cfg.host_channels; i++) { pdev->regs.DFIFO[i] = (uint32_t *)(baseAddress + USB_OTG_DATA_FIFO_OFFSET +\ (i * USB_OTG_DATA_FIFO_SIZE)); } pdev->regs.PCGCCTL = (uint32_t *)(baseAddress + USB_OTG_PCGCCTL_OFFSET); return status; } /** * @brief USB_OTG_CoreInit * Initializes the USB_OTG controller registers and prepares the core * device mode or host mode operation. * @param pdev : Selected device * @retval USB_OTG_STS : status */ USB_OTG_STS USB_OTG_CoreInit(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_GUSBCFG_TypeDef usbcfg; USB_OTG_GCCFG_TypeDef gccfg; USB_OTG_GAHBCFG_TypeDef ahbcfg; usbcfg.d32 = 0; gccfg.d32 = 0; ahbcfg.d32 = 0; if (pdev->cfg.phy_itface == USB_OTG_ULPI_PHY) { gccfg.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GCCFG); gccfg.b.pwdn = 0; if (pdev->cfg.Sof_output) { gccfg.b.sofouten = 1; } USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GCCFG, gccfg.d32); /* Init The ULPI Interface */ usbcfg.d32 = 0; usbcfg.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GUSBCFG); usbcfg.b.physel = 0; /* HS Interface */ #ifdef USB_OTG_INTERNAL_VBUS_ENABLED usbcfg.b.ulpi_ext_vbus_drv = 0; /* Use internal VBUS */ #else #ifdef USB_OTG_EXTERNAL_VBUS_ENABLED usbcfg.b.ulpi_ext_vbus_drv = 1; /* Use external VBUS */ #endif #endif usbcfg.b.term_sel_dl_pulse = 0; /* Data line pulsing using utmi_txvalid */ usbcfg.b.ulpi_fsls = 0; usbcfg.b.ulpi_clk_sus_m = 0; USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GUSBCFG, usbcfg.d32); /* Reset after a PHY select */ USB_OTG_CoreReset(pdev); if(pdev->cfg.dma_enable == 1) { ahbcfg.b.hburstlen = 5; /* 64 x 32-bits*/ ahbcfg.b.dmaenable = 1; USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GAHBCFG, ahbcfg.d32); } } else /* FS interface (embedded Phy) */ { usbcfg.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GUSBCFG);; usbcfg.b.physel = 1; /* FS Interface */ USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GUSBCFG, usbcfg.d32); /* Reset after a PHY select and set Host mode */ USB_OTG_CoreReset(pdev); /* Deactivate the power down*/ gccfg.d32 = 0; gccfg.b.pwdn = 1; gccfg.b.vbussensingA = 1 ; gccfg.b.vbussensingB = 1 ; #ifndef VBUS_SENSING_ENABLED gccfg.b.disablevbussensing = 1; #endif if(pdev->cfg.Sof_output) { gccfg.b.sofouten = 1; } USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GCCFG, gccfg.d32); USB_OTG_BSP_mDelay(20); } /* case the HS core is working in FS mode */ if(pdev->cfg.dma_enable == 1) { ahbcfg.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GAHBCFG); ahbcfg.b.hburstlen = 5; /* 64 x 32-bits*/ ahbcfg.b.dmaenable = 1; USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GAHBCFG, ahbcfg.d32); } /* initialize OTG features */ #ifdef USE_OTG_MODE usbcfg.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GUSBCFG); usbcfg.b.hnpcap = 1; usbcfg.b.srpcap = 1; USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GUSBCFG, usbcfg.d32); USB_OTG_EnableCommonInt(pdev); #endif return status; } /** * @brief USB_OTG_EnableGlobalInt * Enables the controller's Global Int in the AHB Config reg * @param pdev : Selected device * @retval USB_OTG_STS : status */ USB_OTG_STS USB_OTG_EnableGlobalInt(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_GAHBCFG_TypeDef ahbcfg; ahbcfg.d32 = 0; ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GAHBCFG, 0, ahbcfg.d32); return status; } /** * @brief USB_OTG_DisableGlobalInt * Enables the controller's Global Int in the AHB Config reg * @param pdev : Selected device * @retval USB_OTG_STS : status */ USB_OTG_STS USB_OTG_DisableGlobalInt(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_GAHBCFG_TypeDef ahbcfg; ahbcfg.d32 = 0; ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GAHBCFG, ahbcfg.d32, 0); return status; } /** * @brief USB_OTG_FlushTxFifo : Flush a Tx FIFO * @param pdev : Selected device * @param num : FO num * @retval USB_OTG_STS : status */ USB_OTG_STS USB_OTG_FlushTxFifo (USB_OTG_CORE_HANDLE *pdev , uint32_t num ) { USB_OTG_STS status = USB_OTG_OK; __IO USB_OTG_GRSTCTL_TypeDef greset; uint32_t count = 0; greset.d32 = 0; greset.b.txfflsh = 1; greset.b.txfnum = num; USB_OTG_WRITE_REG32( &pdev->regs.GREGS->GRSTCTL, greset.d32 ); do { greset.d32 = USB_OTG_READ_REG32( &pdev->regs.GREGS->GRSTCTL); if (++count > 200000) { break; } } while (greset.b.txfflsh == 1); /* Wait for 3 PHY Clocks*/ USB_OTG_BSP_uDelay(3); return status; } /** * @brief USB_OTG_FlushRxFifo : Flush a Rx FIFO * @param pdev : Selected device * @retval USB_OTG_STS : status */ USB_OTG_STS USB_OTG_FlushRxFifo( USB_OTG_CORE_HANDLE *pdev ) { USB_OTG_STS status = USB_OTG_OK; __IO USB_OTG_GRSTCTL_TypeDef greset; uint32_t count = 0; greset.d32 = 0; greset.b.rxfflsh = 1; USB_OTG_WRITE_REG32( &pdev->regs.GREGS->GRSTCTL, greset.d32 ); do { greset.d32 = USB_OTG_READ_REG32( &pdev->regs.GREGS->GRSTCTL); if (++count > 200000) { break; } } while (greset.b.rxfflsh == 1); /* Wait for 3 PHY Clocks*/ USB_OTG_BSP_uDelay(3); return status; } /** * @brief USB_OTG_SetCurrentMode : Set ID line * @param pdev : Selected device * @param mode : (Host/device) * @retval USB_OTG_STS : status */ USB_OTG_STS USB_OTG_SetCurrentMode(USB_OTG_CORE_HANDLE *pdev , uint8_t mode) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_GUSBCFG_TypeDef usbcfg; usbcfg.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GUSBCFG); usbcfg.b.force_host = 0; usbcfg.b.force_dev = 0; if ( mode == HOST_MODE) { usbcfg.b.force_host = 1; } else if ( mode == DEVICE_MODE) { usbcfg.b.force_dev = 1; } USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GUSBCFG, usbcfg.d32); USB_OTG_BSP_mDelay(50); return status; } /** * @brief USB_OTG_GetMode : Get current mode * @param pdev : Selected device * @retval current mode */ uint32_t USB_OTG_GetMode(USB_OTG_CORE_HANDLE *pdev) { return (USB_OTG_READ_REG32(&pdev->regs.GREGS->GINTSTS ) & 0x1); } /** * @brief USB_OTG_IsDeviceMode : Check if it is device mode * @param pdev : Selected device * @retval num_in_ep */ uint8_t USB_OTG_IsDeviceMode(USB_OTG_CORE_HANDLE *pdev) { return (USB_OTG_GetMode(pdev) != HOST_MODE); } /** * @brief USB_OTG_IsHostMode : Check if it is host mode * @param pdev : Selected device * @retval num_in_ep */ uint8_t USB_OTG_IsHostMode(USB_OTG_CORE_HANDLE *pdev) { return (USB_OTG_GetMode(pdev) == HOST_MODE); } /** * @brief USB_OTG_ReadCoreItr : returns the Core Interrupt register * @param pdev : Selected device * @retval Status */ uint32_t USB_OTG_ReadCoreItr(USB_OTG_CORE_HANDLE *pdev) { uint32_t v = 0; v = USB_OTG_READ_REG32(&pdev->regs.GREGS->GINTSTS); v &= USB_OTG_READ_REG32(&pdev->regs.GREGS->GINTMSK); return v; } /** * @brief USB_OTG_ReadOtgItr : returns the USB_OTG Interrupt register * @param pdev : Selected device * @retval Status */ uint32_t USB_OTG_ReadOtgItr (USB_OTG_CORE_HANDLE *pdev) { return (USB_OTG_READ_REG32 (&pdev->regs.GREGS->GOTGINT)); } #ifdef USE_HOST_MODE /** * @brief USB_OTG_CoreInitHost : Initializes USB_OTG controller for host mode * @param pdev : Selected device * @retval status */ USB_OTG_STS USB_OTG_CoreInitHost(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_FSIZ_TypeDef nptxfifosize; USB_OTG_FSIZ_TypeDef ptxfifosize; USB_OTG_HCFG_TypeDef hcfg; #ifdef USE_OTG_MODE USB_OTG_OTGCTL_TypeDef gotgctl; #endif uint32_t i = 0; nptxfifosize.d32 = 0; ptxfifosize.d32 = 0; #ifdef USE_OTG_MODE gotgctl.d32 = 0; #endif hcfg.d32 = 0; /* configure charge pump IO */ USB_OTG_BSP_ConfigVBUS(pdev); /* Restart the Phy Clock */ USB_OTG_WRITE_REG32(pdev->regs.PCGCCTL, 0); /* Initialize Host Configuration Register */ if (pdev->cfg.phy_itface == USB_OTG_ULPI_PHY) { USB_OTG_InitFSLSPClkSel(pdev , HCFG_30_60_MHZ); } else { USB_OTG_InitFSLSPClkSel(pdev , HCFG_48_MHZ); } USB_OTG_ResetPort(pdev); hcfg.d32 = USB_OTG_READ_REG32(&pdev->regs.HREGS->HCFG); hcfg.b.fslssupp = 0; USB_OTG_WRITE_REG32(&pdev->regs.HREGS->HCFG, hcfg.d32); /* Configure data FIFO sizes */ /* Rx FIFO */ #ifdef USB_OTG_FS_CORE if(pdev->cfg.coreID == USB_OTG_FS_CORE_ID) { /* set Rx FIFO size */ USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GRXFSIZ, RX_FIFO_FS_SIZE); nptxfifosize.b.startaddr = RX_FIFO_FS_SIZE; nptxfifosize.b.depth = TXH_NP_FS_FIFOSIZ; USB_OTG_WRITE_REG32(&pdev->regs.GREGS->DIEPTXF0_HNPTXFSIZ, nptxfifosize.d32); ptxfifosize.b.startaddr = RX_FIFO_FS_SIZE + TXH_NP_FS_FIFOSIZ; ptxfifosize.b.depth = TXH_P_FS_FIFOSIZ; USB_OTG_WRITE_REG32(&pdev->regs.GREGS->HPTXFSIZ, ptxfifosize.d32); } #endif #ifdef USB_OTG_HS_CORE if (pdev->cfg.coreID == USB_OTG_HS_CORE_ID) { /* set Rx FIFO size */ USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GRXFSIZ, RX_FIFO_HS_SIZE); nptxfifosize.b.startaddr = RX_FIFO_HS_SIZE; nptxfifosize.b.depth = TXH_NP_HS_FIFOSIZ; USB_OTG_WRITE_REG32(&pdev->regs.GREGS->DIEPTXF0_HNPTXFSIZ, nptxfifosize.d32); ptxfifosize.b.startaddr = RX_FIFO_HS_SIZE + TXH_NP_HS_FIFOSIZ; ptxfifosize.b.depth = TXH_P_HS_FIFOSIZ; USB_OTG_WRITE_REG32(&pdev->regs.GREGS->HPTXFSIZ, ptxfifosize.d32); } #endif #ifdef USE_OTG_MODE /* Clear Host Set HNP Enable in the USB_OTG Control Register */ gotgctl.b.hstsethnpen = 1; USB_OTG_MODIFY_REG32( &pdev->regs.GREGS->GOTGCTL, gotgctl.d32, 0); #endif /* Make sure the FIFOs are flushed. */ USB_OTG_FlushTxFifo(pdev, 0x10 ); /* all Tx FIFOs */ USB_OTG_FlushRxFifo(pdev); /* Clear all pending HC Interrupts */ for (i = 0; i < pdev->cfg.host_channels; i++) { USB_OTG_WRITE_REG32( &pdev->regs.HC_REGS[i]->HCINT, 0xFFFFFFFF ); USB_OTG_WRITE_REG32( &pdev->regs.HC_REGS[i]->HCINTMSK, 0 ); } #ifndef USE_OTG_MODE USB_OTG_DriveVbus(pdev, 1); #endif USB_OTG_EnableHostInt(pdev); return status; } /** * @brief USB_OTG_IsEvenFrame * This function returns the frame number for sof packet * @param pdev : Selected device * @retval Frame number */ uint8_t USB_OTG_IsEvenFrame (USB_OTG_CORE_HANDLE *pdev) { return !(USB_OTG_READ_REG32(&pdev->regs.HREGS->HFNUM) & 0x1); } /** * @brief USB_OTG_DriveVbus : set/reset vbus * @param pdev : Selected device * @param state : VBUS state * @retval None */ void USB_OTG_DriveVbus (USB_OTG_CORE_HANDLE *pdev, uint8_t state) { USB_OTG_HPRT0_TypeDef hprt0; hprt0.d32 = 0; /* enable disable the external charge pump */ USB_OTG_BSP_DriveVBUS(pdev, state); /* Turn on the Host port power. */ hprt0.d32 = USB_OTG_ReadHPRT0(pdev); if ((hprt0.b.prtpwr == 0 ) && (state == 1 )) { hprt0.b.prtpwr = 1; USB_OTG_WRITE_REG32(pdev->regs.HPRT0, hprt0.d32); } if ((hprt0.b.prtpwr == 1 ) && (state == 0 )) { hprt0.b.prtpwr = 0; USB_OTG_WRITE_REG32(pdev->regs.HPRT0, hprt0.d32); } USB_OTG_BSP_mDelay(200); } /** * @brief USB_OTG_EnableHostInt: Enables the Host mode interrupts * @param pdev : Selected device * @retval USB_OTG_STS : status */ USB_OTG_STS USB_OTG_EnableHostInt(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_GINTMSK_TypeDef intmsk; intmsk.d32 = 0; /* Disable all interrupts. */ USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GINTMSK, 0); /* Clear any pending interrupts. */ USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GINTSTS, 0xFFFFFFFF); /* Enable the common interrupts */ USB_OTG_EnableCommonInt(pdev); if (pdev->cfg.dma_enable == 0) { intmsk.b.rxstsqlvl = 1; } intmsk.b.portintr = 1; intmsk.b.hcintr = 1; intmsk.b.disconnect = 1; intmsk.b.sofintr = 1; intmsk.b.incomplisoout = 1; USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GINTMSK, intmsk.d32, intmsk.d32); return status; } /** * @brief USB_OTG_InitFSLSPClkSel : Initializes the FSLSPClkSel field of the * HCFG register on the PHY type * @param pdev : Selected device * @param freq : clock frequency * @retval None */ void USB_OTG_InitFSLSPClkSel(USB_OTG_CORE_HANDLE *pdev , uint8_t freq) { USB_OTG_HCFG_TypeDef hcfg; hcfg.d32 = USB_OTG_READ_REG32(&pdev->regs.HREGS->HCFG); hcfg.b.fslspclksel = freq; USB_OTG_WRITE_REG32(&pdev->regs.HREGS->HCFG, hcfg.d32); } /** * @brief USB_OTG_ReadHPRT0 : Reads HPRT0 to modify later * @param pdev : Selected device * @retval HPRT0 value */ uint32_t USB_OTG_ReadHPRT0(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_HPRT0_TypeDef hprt0; hprt0.d32 = USB_OTG_READ_REG32(pdev->regs.HPRT0); hprt0.b.prtena = 0; hprt0.b.prtconndet = 0; hprt0.b.prtenchng = 0; hprt0.b.prtovrcurrchng = 0; return hprt0.d32; } /** * @brief USB_OTG_ReadHostAllChannels_intr : Register PCD Callbacks * @param pdev : Selected device * @retval Status */ uint32_t USB_OTG_ReadHostAllChannels_intr (USB_OTG_CORE_HANDLE *pdev) { return (USB_OTG_READ_REG32 (&pdev->regs.HREGS->HAINT)); } /** * @brief USB_OTG_ResetPort : Reset Host Port * @param pdev : Selected device * @retval status * @note : (1)The application must wait at least 10 ms (+ 10 ms security) * before clearing the reset bit. */ uint32_t USB_OTG_ResetPort(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_HPRT0_TypeDef hprt0; hprt0.d32 = USB_OTG_ReadHPRT0(pdev); hprt0.b.prtrst = 1; USB_OTG_WRITE_REG32(pdev->regs.HPRT0, hprt0.d32); USB_OTG_BSP_mDelay (10); /* See Note #1 */ hprt0.b.prtrst = 0; USB_OTG_WRITE_REG32(pdev->regs.HPRT0, hprt0.d32); USB_OTG_BSP_mDelay (20); return 1; } /** * @brief USB_OTG_HC_Init : Prepares a host channel for transferring packets * @param pdev : Selected device * @param hc_num : channel number * @retval USB_OTG_STS : status */ USB_OTG_STS USB_OTG_HC_Init(USB_OTG_CORE_HANDLE *pdev , uint8_t hc_num) { USB_OTG_STS status = USB_OTG_OK; uint32_t intr_enable = 0; USB_OTG_HCINTMSK_TypeDef hcintmsk; USB_OTG_GINTMSK_TypeDef gintmsk; USB_OTG_HCCHAR_TypeDef hcchar; USB_OTG_HCINTn_TypeDef hcint; gintmsk.d32 = 0; hcintmsk.d32 = 0; hcchar.d32 = 0; /* Clear old interrupt conditions for this host channel. */ hcint.d32 = 0xFFFFFFFF; USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCINT, hcint.d32); /* Enable channel interrupts required for this transfer. */ hcintmsk.d32 = 0; if (pdev->cfg.dma_enable == 1) { hcintmsk.b.ahberr = 1; } switch (pdev->host.hc[hc_num].ep_type) { case EP_TYPE_CTRL: case EP_TYPE_BULK: hcintmsk.b.xfercompl = 1; hcintmsk.b.stall = 1; hcintmsk.b.xacterr = 1; hcintmsk.b.datatglerr = 1; hcintmsk.b.nak = 1; if (pdev->host.hc[hc_num].ep_is_in) { hcintmsk.b.bblerr = 1; } else { hcintmsk.b.nyet = 1; if (pdev->host.hc[hc_num].do_ping) { hcintmsk.b.ack = 1; } } break; case EP_TYPE_INTR: hcintmsk.b.xfercompl = 1; hcintmsk.b.nak = 1; hcintmsk.b.stall = 1; hcintmsk.b.xacterr = 1; hcintmsk.b.datatglerr = 1; hcintmsk.b.frmovrun = 1; if (pdev->host.hc[hc_num].ep_is_in) { hcintmsk.b.bblerr = 1; } break; case EP_TYPE_ISOC: hcintmsk.b.xfercompl = 1; hcintmsk.b.frmovrun = 1; hcintmsk.b.ack = 1; if (pdev->host.hc[hc_num].ep_is_in) { hcintmsk.b.xacterr = 1; hcintmsk.b.bblerr = 1; } break; } USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCINTMSK, hcintmsk.d32); /* Enable the top level host channel interrupt. */ intr_enable = (1 << hc_num); USB_OTG_MODIFY_REG32(&pdev->regs.HREGS->HAINTMSK, 0, intr_enable); /* Make sure host channel interrupts are enabled. */ gintmsk.b.hcintr = 1; USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GINTMSK, 0, gintmsk.d32); /* Program the HCCHAR register */ hcchar.d32 = 0; hcchar.b.devaddr = pdev->host.hc[hc_num].dev_addr; hcchar.b.epnum = pdev->host.hc[hc_num].ep_num; hcchar.b.epdir = pdev->host.hc[hc_num].ep_is_in; hcchar.b.lspddev = (pdev->host.hc[hc_num].speed == HPRT0_PRTSPD_LOW_SPEED); hcchar.b.eptype = pdev->host.hc[hc_num].ep_type; hcchar.b.mps = pdev->host.hc[hc_num].max_packet; if (pdev->host.hc[hc_num].ep_type == HCCHAR_INTR) { hcchar.b.oddfrm = 1; } USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCCHAR, hcchar.d32); return status; } /** * @brief USB_OTG_HC_StartXfer : Start transfer * @param pdev : Selected device * @param hc_num : channel number * @retval USB_OTG_STS : status */ USB_OTG_STS USB_OTG_HC_StartXfer(USB_OTG_CORE_HANDLE *pdev , uint8_t hc_num) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_HCCHAR_TypeDef hcchar; USB_OTG_HCTSIZn_TypeDef hctsiz; USB_OTG_HNPTXSTS_TypeDef hnptxsts; USB_OTG_HPTXSTS_TypeDef hptxsts; USB_OTG_GINTMSK_TypeDef intmsk; uint16_t len_words = 0; uint16_t num_packets; uint16_t max_hc_pkt_count; max_hc_pkt_count = 256; hctsiz.d32 = 0; hcchar.d32 = 0; intmsk.d32 = 0; /* Compute the expected number of packets associated to the transfer */ if (pdev->host.hc[hc_num].xfer_len > 0) { num_packets = (pdev->host.hc[hc_num].xfer_len + \ pdev->host.hc[hc_num].max_packet - 1) / pdev->host.hc[hc_num].max_packet; if (num_packets > max_hc_pkt_count) { num_packets = max_hc_pkt_count; pdev->host.hc[hc_num].xfer_len = num_packets * \ pdev->host.hc[hc_num].max_packet; } } else { num_packets = 1; } if (pdev->host.hc[hc_num].ep_is_in) { pdev->host.hc[hc_num].xfer_len = num_packets * \ pdev->host.hc[hc_num].max_packet; } /* Initialize the HCTSIZn register */ hctsiz.b.xfersize = pdev->host.hc[hc_num].xfer_len; hctsiz.b.pktcnt = num_packets; hctsiz.b.pid = pdev->host.hc[hc_num].data_pid; USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCTSIZ, hctsiz.d32); if (pdev->cfg.dma_enable == 1) { USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCDMA, (unsigned int)pdev->host.hc[hc_num].xfer_buff); } hcchar.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[hc_num]->HCCHAR); hcchar.b.oddfrm = USB_OTG_IsEvenFrame(pdev); /* Set host channel enable */ hcchar.b.chen = 1; hcchar.b.chdis = 0; USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCCHAR, hcchar.d32); if (pdev->cfg.dma_enable == 0) /* Slave mode */ { if((pdev->host.hc[hc_num].ep_is_in == 0) && (pdev->host.hc[hc_num].xfer_len > 0)) { switch(pdev->host.hc[hc_num].ep_type) { /* Non periodic transfer */ case EP_TYPE_CTRL: case EP_TYPE_BULK: hnptxsts.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->HNPTXSTS); len_words = (pdev->host.hc[hc_num].xfer_len + 3) / 4; /* check if there is enough space in FIFO space */ if(len_words > hnptxsts.b.nptxfspcavail) { /* need to process data in nptxfempty interrupt */ intmsk.b.nptxfempty = 1; USB_OTG_MODIFY_REG32( &pdev->regs.GREGS->GINTMSK, 0, intmsk.d32); } break; /* Periodic transfer */ case EP_TYPE_INTR: case EP_TYPE_ISOC: hptxsts.d32 = USB_OTG_READ_REG32(&pdev->regs.HREGS->HPTXSTS); len_words = (pdev->host.hc[hc_num].xfer_len + 3) / 4; /* check if there is enough space in FIFO space */ if(len_words > hptxsts.b.ptxfspcavail) /* split the transfer */ { /* need to process data in ptxfempty interrupt */ intmsk.b.ptxfempty = 1; USB_OTG_MODIFY_REG32( &pdev->regs.GREGS->GINTMSK, 0, intmsk.d32); } break; default: break; } /* Write packet into the Tx FIFO. */ USB_OTG_WritePacket(pdev, pdev->host.hc[hc_num].xfer_buff , hc_num, pdev->host.hc[hc_num].xfer_len); } } return status; } /** * @brief USB_OTG_HC_Halt : Halt channel * @param pdev : Selected device * @param hc_num : channel number * @retval USB_OTG_STS : status */ USB_OTG_STS USB_OTG_HC_Halt(USB_OTG_CORE_HANDLE *pdev , uint8_t hc_num) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_HNPTXSTS_TypeDef nptxsts; USB_OTG_HPTXSTS_TypeDef hptxsts; USB_OTG_HCCHAR_TypeDef hcchar; nptxsts.d32 = 0; hptxsts.d32 = 0; hcchar.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[hc_num]->HCCHAR); hcchar.b.chen = 1; hcchar.b.chdis = 1; /* Check for space in the request queue to issue the halt. */ if (hcchar.b.eptype == HCCHAR_CTRL || hcchar.b.eptype == HCCHAR_BULK) { nptxsts.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->HNPTXSTS); if (nptxsts.b.nptxqspcavail == 0) { hcchar.b.chen = 0; } } else { hptxsts.d32 = USB_OTG_READ_REG32(&pdev->regs.HREGS->HPTXSTS); if (hptxsts.b.ptxqspcavail == 0) { hcchar.b.chen = 0; } } USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCCHAR, hcchar.d32); return status; } /** * @brief Issue a ping token * @param None * @retval : None */ USB_OTG_STS USB_OTG_HC_DoPing(USB_OTG_CORE_HANDLE *pdev , uint8_t hc_num) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_HCCHAR_TypeDef hcchar; USB_OTG_HCTSIZn_TypeDef hctsiz; hctsiz.d32 = 0; hctsiz.b.dopng = 1; hctsiz.b.pktcnt = 1; USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCTSIZ, hctsiz.d32); hcchar.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[hc_num]->HCCHAR); hcchar.b.chen = 1; hcchar.b.chdis = 0; USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCCHAR, hcchar.d32); return status; } /** * @brief Stop the device and clean up fifo's * @param None * @retval : None */ void USB_OTG_StopHost(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_HCCHAR_TypeDef hcchar; uint32_t i; USB_OTG_WRITE_REG32(&pdev->regs.HREGS->HAINTMSK , 0); USB_OTG_WRITE_REG32(&pdev->regs.HREGS->HAINT, 0xFFFFFFFF); /* Flush out any leftover queued requests. */ for (i = 0; i < pdev->cfg.host_channels; i++) { hcchar.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[i]->HCCHAR); hcchar.b.chen = 0; hcchar.b.chdis = 1; hcchar.b.epdir = 0; USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[i]->HCCHAR, hcchar.d32); } /* Flush the FIFO */ USB_OTG_FlushRxFifo(pdev); USB_OTG_FlushTxFifo(pdev , 0x10 ); } #endif #ifdef USE_DEVICE_MODE /* PCD Core Layer */ /** * @brief USB_OTG_InitDevSpeed :Initializes the DevSpd field of DCFG register * depending the PHY type and the enumeration speed of the device. * @param pdev : Selected device * @retval : None */ void USB_OTG_InitDevSpeed(USB_OTG_CORE_HANDLE *pdev , uint8_t speed) { USB_OTG_DCFG_TypeDef dcfg; dcfg.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DCFG); dcfg.b.devspd = speed; USB_OTG_WRITE_REG32(&pdev->regs.DREGS->DCFG, dcfg.d32); } /** * @brief USB_OTG_CoreInitDev : Initializes the USB_OTG controller registers * for device mode * @param pdev : Selected device * @retval USB_OTG_STS : status */ USB_OTG_STS USB_OTG_CoreInitDev (USB_OTG_CORE_HANDLE *pdev) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_DEPCTL_TypeDef depctl; uint32_t i; USB_OTG_DCFG_TypeDef dcfg; USB_OTG_FSIZ_TypeDef nptxfifosize; USB_OTG_FSIZ_TypeDef txfifosize; USB_OTG_DIEPMSK_TypeDef msk; USB_OTG_DTHRCTL_TypeDef dthrctl; depctl.d32 = 0; dcfg.d32 = 0; nptxfifosize.d32 = 0; txfifosize.d32 = 0; msk.d32 = 0; /* Restart the Phy Clock */ USB_OTG_WRITE_REG32(pdev->regs.PCGCCTL, 0); /* Device configuration register */ dcfg.d32 = USB_OTG_READ_REG32( &pdev->regs.DREGS->DCFG); dcfg.b.perfrint = DCFG_FRAME_INTERVAL_80; USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DCFG, dcfg.d32 ); #ifdef USB_OTG_FS_CORE if(pdev->cfg.coreID == USB_OTG_FS_CORE_ID ) { /* Set Full speed phy */ USB_OTG_InitDevSpeed (pdev , USB_OTG_SPEED_PARAM_FULL); /* set Rx FIFO size */ USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GRXFSIZ, RX_FIFO_FS_SIZE); /* EP0 TX*/ nptxfifosize.b.depth = TX0_FIFO_FS_SIZE; nptxfifosize.b.startaddr = RX_FIFO_FS_SIZE; USB_OTG_WRITE_REG32( &pdev->regs.GREGS->DIEPTXF0_HNPTXFSIZ, nptxfifosize.d32 ); /* EP1 TX*/ txfifosize.b.startaddr = nptxfifosize.b.startaddr + nptxfifosize.b.depth; txfifosize.b.depth = TX1_FIFO_FS_SIZE; USB_OTG_WRITE_REG32( &pdev->regs.GREGS->DIEPTXF[0], txfifosize.d32 ); /* EP2 TX*/ txfifosize.b.startaddr += txfifosize.b.depth; txfifosize.b.depth = TX2_FIFO_FS_SIZE; USB_OTG_WRITE_REG32( &pdev->regs.GREGS->DIEPTXF[1], txfifosize.d32 ); /* EP3 TX*/ txfifosize.b.startaddr += txfifosize.b.depth; txfifosize.b.depth = TX3_FIFO_FS_SIZE; USB_OTG_WRITE_REG32( &pdev->regs.GREGS->DIEPTXF[2], txfifosize.d32 ); } #endif #ifdef USB_OTG_HS_CORE if(pdev->cfg.coreID == USB_OTG_HS_CORE_ID ) { /* Set High speed phy */ if(pdev->cfg.phy_itface == USB_OTG_ULPI_PHY) { USB_OTG_InitDevSpeed (pdev , USB_OTG_SPEED_PARAM_HIGH); } else /* set High speed phy in Full speed mode */ { USB_OTG_InitDevSpeed (pdev , USB_OTG_SPEED_PARAM_HIGH_IN_FULL); } /* set Rx FIFO size */ USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GRXFSIZ, RX_FIFO_HS_SIZE); /* EP0 TX*/ nptxfifosize.b.depth = TX0_FIFO_HS_SIZE; nptxfifosize.b.startaddr = RX_FIFO_HS_SIZE; USB_OTG_WRITE_REG32( &pdev->regs.GREGS->DIEPTXF0_HNPTXFSIZ, nptxfifosize.d32 ); /* EP1 TX*/ txfifosize.b.startaddr = nptxfifosize.b.startaddr + nptxfifosize.b.depth; txfifosize.b.depth = TX1_FIFO_HS_SIZE; USB_OTG_WRITE_REG32( &pdev->regs.GREGS->DIEPTXF[0], txfifosize.d32 ); /* EP2 TX*/ txfifosize.b.startaddr += txfifosize.b.depth; txfifosize.b.depth = TX2_FIFO_HS_SIZE; USB_OTG_WRITE_REG32( &pdev->regs.GREGS->DIEPTXF[1], txfifosize.d32 ); /* EP3 TX*/ txfifosize.b.startaddr += txfifosize.b.depth; txfifosize.b.depth = TX3_FIFO_HS_SIZE; USB_OTG_WRITE_REG32( &pdev->regs.GREGS->DIEPTXF[2], txfifosize.d32 ); /* EP4 TX*/ txfifosize.b.startaddr += txfifosize.b.depth; txfifosize.b.depth = TX4_FIFO_HS_SIZE; USB_OTG_WRITE_REG32( &pdev->regs.GREGS->DIEPTXF[3], txfifosize.d32 ); /* EP5 TX*/ txfifosize.b.startaddr += txfifosize.b.depth; txfifosize.b.depth = TX5_FIFO_HS_SIZE; USB_OTG_WRITE_REG32( &pdev->regs.GREGS->DIEPTXF[4], txfifosize.d32 ); } #endif /* Flush the FIFOs */ USB_OTG_FlushTxFifo(pdev , 0x10); /* all Tx FIFOs */ USB_OTG_FlushRxFifo(pdev); /* Clear all pending Device Interrupts */ USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DIEPMSK, 0 ); USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DOEPMSK, 0 ); USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DAINT, 0xFFFFFFFF ); USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DAINTMSK, 0 ); for (i = 0; i < pdev->cfg.dev_endpoints; i++) { depctl.d32 = USB_OTG_READ_REG32(&pdev->regs.INEP_REGS[i]->DIEPCTL); if (depctl.b.epena) { depctl.d32 = 0; depctl.b.epdis = 1; depctl.b.snak = 1; } else { depctl.d32 = 0; } USB_OTG_WRITE_REG32( &pdev->regs.INEP_REGS[i]->DIEPCTL, depctl.d32); USB_OTG_WRITE_REG32( &pdev->regs.INEP_REGS[i]->DIEPTSIZ, 0); USB_OTG_WRITE_REG32( &pdev->regs.INEP_REGS[i]->DIEPINT, 0xFF); } for (i = 0; i < pdev->cfg.dev_endpoints; i++) { USB_OTG_DEPCTL_TypeDef depctl; depctl.d32 = USB_OTG_READ_REG32(&pdev->regs.OUTEP_REGS[i]->DOEPCTL); if (depctl.b.epena) { depctl.d32 = 0; depctl.b.epdis = 1; depctl.b.snak = 1; } else { depctl.d32 = 0; } USB_OTG_WRITE_REG32( &pdev->regs.OUTEP_REGS[i]->DOEPCTL, depctl.d32); USB_OTG_WRITE_REG32( &pdev->regs.OUTEP_REGS[i]->DOEPTSIZ, 0); USB_OTG_WRITE_REG32( &pdev->regs.OUTEP_REGS[i]->DOEPINT, 0xFF); } msk.d32 = 0; msk.b.txfifoundrn = 1; USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPMSK, msk.d32, msk.d32); if (pdev->cfg.dma_enable == 1) { dthrctl.d32 = 0; dthrctl.b.non_iso_thr_en = 1; dthrctl.b.iso_thr_en = 1; dthrctl.b.tx_thr_len = 64; dthrctl.b.rx_thr_en = 1; dthrctl.b.rx_thr_len = 64; USB_OTG_WRITE_REG32(&pdev->regs.DREGS->DTHRCTL, dthrctl.d32); } USB_OTG_EnableDevInt(pdev); return status; } /** * @brief USB_OTG_EnableDevInt : Enables the Device mode interrupts * @param pdev : Selected device * @retval USB_OTG_STS : status */ USB_OTG_STS USB_OTG_EnableDevInt(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_GINTMSK_TypeDef intmsk; intmsk.d32 = 0; /* Disable all interrupts. */ USB_OTG_WRITE_REG32( &pdev->regs.GREGS->GINTMSK, 0); /* Clear any pending interrupts */ USB_OTG_WRITE_REG32( &pdev->regs.GREGS->GINTSTS, 0xBFFFFFFF); /* Enable the common interrupts */ USB_OTG_EnableCommonInt(pdev); if (pdev->cfg.dma_enable == 0) { intmsk.b.rxstsqlvl = 1; } /* Enable interrupts matching to the Device mode ONLY */ intmsk.b.usbsuspend = 1; intmsk.b.usbreset = 1; intmsk.b.enumdone = 1; intmsk.b.inepintr = 1; intmsk.b.outepintr = 1; intmsk.b.sofintr = 1; intmsk.b.incomplisoin = 1; intmsk.b.incomplisoout = 1; #ifdef VBUS_SENSING_ENABLED intmsk.b.sessreqintr = 1; intmsk.b.otgintr = 1; #endif USB_OTG_MODIFY_REG32( &pdev->regs.GREGS->GINTMSK, intmsk.d32, intmsk.d32); return status; } /** * @brief USB_OTG_GetDeviceSpeed * Get the device speed from the device status register * @param None * @retval status */ enum USB_OTG_SPEED USB_OTG_GetDeviceSpeed (USB_OTG_CORE_HANDLE *pdev) { USB_OTG_DSTS_TypeDef dsts; enum USB_OTG_SPEED speed = USB_SPEED_UNKNOWN; dsts.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DSTS); switch (dsts.b.enumspd) { case DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ: speed = USB_SPEED_HIGH; break; case DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ: case DSTS_ENUMSPD_FS_PHY_48MHZ: speed = USB_SPEED_FULL; break; case DSTS_ENUMSPD_LS_PHY_6MHZ: speed = USB_SPEED_LOW; break; } return speed; } /** * @brief enables EP0 OUT to receive SETUP packets and configures EP0 * for transmitting packets * @param None * @retval USB_OTG_STS : status */ USB_OTG_STS USB_OTG_EP0Activate(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_DSTS_TypeDef dsts; USB_OTG_DEPCTL_TypeDef diepctl; USB_OTG_DCTL_TypeDef dctl; dctl.d32 = 0; /* Read the Device Status and Endpoint 0 Control registers */ dsts.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DSTS); diepctl.d32 = USB_OTG_READ_REG32(&pdev->regs.INEP_REGS[0]->DIEPCTL); /* Set the MPS of the IN EP based on the enumeration speed */ switch (dsts.b.enumspd) { case DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ: case DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ: case DSTS_ENUMSPD_FS_PHY_48MHZ: diepctl.b.mps = DEP0CTL_MPS_64; break; case DSTS_ENUMSPD_LS_PHY_6MHZ: diepctl.b.mps = DEP0CTL_MPS_8; break; } USB_OTG_WRITE_REG32(&pdev->regs.INEP_REGS[0]->DIEPCTL, diepctl.d32); dctl.b.cgnpinnak = 1; USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DCTL, dctl.d32, dctl.d32); return status; } /** * @brief USB_OTG_EPActivate : Activates an EP * @param pdev : Selected device * @retval USB_OTG_STS : status */ USB_OTG_STS USB_OTG_EPActivate(USB_OTG_CORE_HANDLE *pdev , USB_OTG_EP *ep) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_DEPCTL_TypeDef depctl; USB_OTG_DAINT_TypeDef daintmsk; __IO uint32_t *addr; depctl.d32 = 0; daintmsk.d32 = 0; /* Read DEPCTLn register */ if (ep->is_in == 1) { addr = &pdev->regs.INEP_REGS[ep->num]->DIEPCTL; daintmsk.ep.in = 1 << ep->num; } else { addr = &pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL; daintmsk.ep.out = 1 << ep->num; } /* If the EP is already active don't change the EP Control * register. */ depctl.d32 = USB_OTG_READ_REG32(addr); if (!depctl.b.usbactep) { depctl.b.mps = ep->maxpacket; depctl.b.eptype = ep->type; depctl.b.txfnum = ep->tx_fifo_num; depctl.b.setd0pid = 1; depctl.b.usbactep = 1; USB_OTG_WRITE_REG32(addr, depctl.d32); } /* Enable the Interrupt for this EP */ #ifdef USB_OTG_HS_DEDICATED_EP1_ENABLED if((ep->num == 1)&&(pdev->cfg.coreID == USB_OTG_HS_CORE_ID)) { USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DEACHMSK, 0, daintmsk.d32); } else #endif USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DAINTMSK, 0, daintmsk.d32); return status; } /** * @brief USB_OTG_EPDeactivate : Deactivates an EP * @param pdev : Selected device * @retval USB_OTG_STS : status */ USB_OTG_STS USB_OTG_EPDeactivate(USB_OTG_CORE_HANDLE *pdev , USB_OTG_EP *ep) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_DEPCTL_TypeDef depctl; USB_OTG_DAINT_TypeDef daintmsk; __IO uint32_t *addr; depctl.d32 = 0; daintmsk.d32 = 0; /* Read DEPCTLn register */ if (ep->is_in == 1) { addr = &pdev->regs.INEP_REGS[ep->num]->DIEPCTL; daintmsk.ep.in = 1 << ep->num; } else { addr = &pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL; daintmsk.ep.out = 1 << ep->num; } depctl.b.usbactep = 0; USB_OTG_WRITE_REG32(addr, depctl.d32); /* Disable the Interrupt for this EP */ #ifdef USB_OTG_HS_DEDICATED_EP1_ENABLED if((ep->num == 1)&&(pdev->cfg.coreID == USB_OTG_HS_CORE_ID)) { USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DEACHMSK, daintmsk.d32, 0); } else #endif USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DAINTMSK, daintmsk.d32, 0); return status; } /** * @brief USB_OTG_EPStartXfer : Handle the setup for data xfer for an EP and * starts the xfer * @param pdev : Selected device * @retval USB_OTG_STS : status */ USB_OTG_STS USB_OTG_EPStartXfer(USB_OTG_CORE_HANDLE *pdev , USB_OTG_EP *ep) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_DEPCTL_TypeDef depctl; USB_OTG_DEPXFRSIZ_TypeDef deptsiz; USB_OTG_DSTS_TypeDef dsts; uint32_t fifoemptymsk = 0; depctl.d32 = 0; deptsiz.d32 = 0; /* IN endpoint */ if (ep->is_in == 1) { depctl.d32 = USB_OTG_READ_REG32(&(pdev->regs.INEP_REGS[ep->num]->DIEPCTL)); deptsiz.d32 = USB_OTG_READ_REG32(&(pdev->regs.INEP_REGS[ep->num]->DIEPTSIZ)); /* Zero Length Packet? */ if (ep->xfer_len == 0) { deptsiz.b.xfersize = 0; deptsiz.b.pktcnt = 1; } else { /* Program the transfer size and packet count * as follows: xfersize = N * maxpacket + * short_packet pktcnt = N + (short_packet * exist ? 1 : 0) */ deptsiz.b.xfersize = ep->xfer_len; deptsiz.b.pktcnt = (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket; if (ep->type == EP_TYPE_ISOC) { deptsiz.b.mc = 1; } } USB_OTG_WRITE_REG32(&pdev->regs.INEP_REGS[ep->num]->DIEPTSIZ, deptsiz.d32); if (pdev->cfg.dma_enable == 1) { USB_OTG_WRITE_REG32(&pdev->regs.INEP_REGS[ep->num]->DIEPDMA, ep->dma_addr); } else { if (ep->type != EP_TYPE_ISOC) { /* Enable the Tx FIFO Empty Interrupt for this EP */ if (ep->xfer_len > 0) { fifoemptymsk = 1 << ep->num; USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, 0, fifoemptymsk); } } } if (ep->type == EP_TYPE_ISOC) { dsts.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DSTS); if (((dsts.b.soffn)&0x1) == 0) { depctl.b.setd1pid = 1; } else { depctl.b.setd0pid = 1; } } /* EP enable, IN data in FIFO */ depctl.b.cnak = 1; depctl.b.epena = 1; USB_OTG_WRITE_REG32(&pdev->regs.INEP_REGS[ep->num]->DIEPCTL, depctl.d32); if (ep->type == EP_TYPE_ISOC) { USB_OTG_WritePacket(pdev, ep->xfer_buff, ep->num, ep->xfer_len); } } else { /* OUT endpoint */ depctl.d32 = USB_OTG_READ_REG32(&(pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL)); deptsiz.d32 = USB_OTG_READ_REG32(&(pdev->regs.OUTEP_REGS[ep->num]->DOEPTSIZ)); /* Program the transfer size and packet count as follows: * pktcnt = N * xfersize = N * maxpacket */ if (ep->xfer_len == 0) { deptsiz.b.xfersize = ep->maxpacket; deptsiz.b.pktcnt = 1; } else { deptsiz.b.pktcnt = (ep->xfer_len + (ep->maxpacket - 1)) / ep->maxpacket; deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket; } USB_OTG_WRITE_REG32(&pdev->regs.OUTEP_REGS[ep->num]->DOEPTSIZ, deptsiz.d32); if (pdev->cfg.dma_enable == 1) { USB_OTG_WRITE_REG32(&pdev->regs.OUTEP_REGS[ep->num]->DOEPDMA, ep->dma_addr); } if (ep->type == EP_TYPE_ISOC) { if (ep->even_odd_frame) { depctl.b.setd1pid = 1; } else { depctl.b.setd0pid = 1; } } /* EP enable */ depctl.b.cnak = 1; depctl.b.epena = 1; USB_OTG_WRITE_REG32(&pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL, depctl.d32); } return status; } /** * @brief USB_OTG_EP0StartXfer : Handle the setup for a data xfer for EP0 and * starts the xfer * @param pdev : Selected device * @retval USB_OTG_STS : status */ USB_OTG_STS USB_OTG_EP0StartXfer(USB_OTG_CORE_HANDLE *pdev , USB_OTG_EP *ep) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_DEPCTL_TypeDef depctl; USB_OTG_DEP0XFRSIZ_TypeDef deptsiz; USB_OTG_INEPREGS *in_regs; uint32_t fifoemptymsk = 0; depctl.d32 = 0; deptsiz.d32 = 0; /* IN endpoint */ if (ep->is_in == 1) { in_regs = pdev->regs.INEP_REGS[0]; depctl.d32 = USB_OTG_READ_REG32(&in_regs->DIEPCTL); deptsiz.d32 = USB_OTG_READ_REG32(&in_regs->DIEPTSIZ); /* Zero Length Packet? */ if (ep->xfer_len == 0) { deptsiz.b.xfersize = 0; deptsiz.b.pktcnt = 1; } else { if (ep->xfer_len > ep->maxpacket) { ep->xfer_len = ep->maxpacket; deptsiz.b.xfersize = ep->maxpacket; } else { deptsiz.b.xfersize = ep->xfer_len; } deptsiz.b.pktcnt = 1; } USB_OTG_WRITE_REG32(&in_regs->DIEPTSIZ, deptsiz.d32); if (pdev->cfg.dma_enable == 1) { USB_OTG_WRITE_REG32(&pdev->regs.INEP_REGS[ep->num]->DIEPDMA, ep->dma_addr); } /* EP enable, IN data in FIFO */ depctl.b.cnak = 1; depctl.b.epena = 1; USB_OTG_WRITE_REG32(&in_regs->DIEPCTL, depctl.d32); if (pdev->cfg.dma_enable == 0) { /* Enable the Tx FIFO Empty Interrupt for this EP */ if (ep->xfer_len > 0) { { fifoemptymsk |= 1 << ep->num; USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, 0, fifoemptymsk); } } } } else { /* OUT endpoint */ depctl.d32 = USB_OTG_READ_REG32(&pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL); deptsiz.d32 = USB_OTG_READ_REG32(&pdev->regs.OUTEP_REGS[ep->num]->DOEPTSIZ); /* Program the transfer size and packet count as follows: * xfersize = N * (maxpacket + 4 - (maxpacket % 4)) * pktcnt = N */ if (ep->xfer_len == 0) { deptsiz.b.xfersize = ep->maxpacket; deptsiz.b.pktcnt = 1; } else { ep->xfer_len = ep->maxpacket; deptsiz.b.xfersize = ep->maxpacket; deptsiz.b.pktcnt = 1; } USB_OTG_WRITE_REG32(&pdev->regs.OUTEP_REGS[ep->num]->DOEPTSIZ, deptsiz.d32); if (pdev->cfg.dma_enable == 1) { USB_OTG_WRITE_REG32(&pdev->regs.OUTEP_REGS[ep->num]->DOEPDMA, ep->dma_addr); } /* EP enable */ depctl.b.cnak = 1; depctl.b.epena = 1; USB_OTG_WRITE_REG32 (&(pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL), depctl.d32); } return status; } /** * @brief USB_OTG_EPSetStall : Set the EP STALL * @param pdev : Selected device * @retval USB_OTG_STS : status */ USB_OTG_STS USB_OTG_EPSetStall(USB_OTG_CORE_HANDLE *pdev , USB_OTG_EP *ep) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_DEPCTL_TypeDef depctl; __IO uint32_t *depctl_addr; depctl.d32 = 0; if (ep->is_in == 1) { depctl_addr = &(pdev->regs.INEP_REGS[ep->num]->DIEPCTL); depctl.d32 = USB_OTG_READ_REG32(depctl_addr); /* set the disable and stall bits */ if (depctl.b.epena) { depctl.b.epdis = 1; } depctl.b.stall = 1; USB_OTG_WRITE_REG32(depctl_addr, depctl.d32); } else { depctl_addr = &(pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL); depctl.d32 = USB_OTG_READ_REG32(depctl_addr); /* set the stall bit */ depctl.b.stall = 1; USB_OTG_WRITE_REG32(depctl_addr, depctl.d32); } return status; } /** * @brief Clear the EP STALL * @param pdev : Selected device * @retval USB_OTG_STS : status */ USB_OTG_STS USB_OTG_EPClearStall(USB_OTG_CORE_HANDLE *pdev , USB_OTG_EP *ep) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_DEPCTL_TypeDef depctl; __IO uint32_t *depctl_addr; depctl.d32 = 0; if (ep->is_in == 1) { depctl_addr = &(pdev->regs.INEP_REGS[ep->num]->DIEPCTL); } else { depctl_addr = &(pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL); } depctl.d32 = USB_OTG_READ_REG32(depctl_addr); /* clear the stall bits */ depctl.b.stall = 0; if (ep->type == EP_TYPE_INTR || ep->type == EP_TYPE_BULK) { depctl.b.setd0pid = 1; /* DATA0 */ } USB_OTG_WRITE_REG32(depctl_addr, depctl.d32); return status; } /** * @brief USB_OTG_ReadDevAllOutEp_itr : returns OUT endpoint interrupt bits * @param pdev : Selected device * @retval OUT endpoint interrupt bits */ uint32_t USB_OTG_ReadDevAllOutEp_itr(USB_OTG_CORE_HANDLE *pdev) { uint32_t v; v = USB_OTG_READ_REG32(&pdev->regs.DREGS->DAINT); v &= USB_OTG_READ_REG32(&pdev->regs.DREGS->DAINTMSK); return ((v & 0xffff0000) >> 16); } /** * @brief USB_OTG_ReadDevOutEP_itr : returns Device OUT EP Interrupt register * @param pdev : Selected device * @param ep : end point number * @retval Device OUT EP Interrupt register */ uint32_t USB_OTG_ReadDevOutEP_itr(USB_OTG_CORE_HANDLE *pdev , uint8_t epnum) { uint32_t v; v = USB_OTG_READ_REG32(&pdev->regs.OUTEP_REGS[epnum]->DOEPINT); v &= USB_OTG_READ_REG32(&pdev->regs.DREGS->DOEPMSK); return v; } /** * @brief USB_OTG_ReadDevAllInEPItr : Get int status register * @param pdev : Selected device * @retval int status register */ uint32_t USB_OTG_ReadDevAllInEPItr(USB_OTG_CORE_HANDLE *pdev) { uint32_t v; v = USB_OTG_READ_REG32(&pdev->regs.DREGS->DAINT); v &= USB_OTG_READ_REG32(&pdev->regs.DREGS->DAINTMSK); return (v & 0xffff); } /** * @brief configures EPO to receive SETUP packets * @param None * @retval : None */ void USB_OTG_EP0_OutStart(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_DEP0XFRSIZ_TypeDef doeptsize0; doeptsize0.d32 = 0; doeptsize0.b.supcnt = 3; doeptsize0.b.pktcnt = 1; doeptsize0.b.xfersize = 8 * 3; USB_OTG_WRITE_REG32( &pdev->regs.OUTEP_REGS[0]->DOEPTSIZ, doeptsize0.d32 ); if (pdev->cfg.dma_enable == 1) { USB_OTG_DEPCTL_TypeDef doepctl; doepctl.d32 = 0; USB_OTG_WRITE_REG32( &pdev->regs.OUTEP_REGS[0]->DOEPDMA, (uint32_t)&pdev->dev.setup_packet); /* EP enable */ doepctl.d32 = USB_OTG_READ_REG32(&pdev->regs.OUTEP_REGS[0]->DOEPCTL); doepctl.b.epena = 1; doepctl.d32 = 0x80008000; USB_OTG_WRITE_REG32( &pdev->regs.OUTEP_REGS[0]->DOEPCTL, doepctl.d32); } } /** * @brief USB_OTG_RemoteWakeup : active remote wakeup signalling * @param None * @retval : None */ void USB_OTG_ActiveRemoteWakeup(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_DCTL_TypeDef dctl; USB_OTG_DSTS_TypeDef dsts; USB_OTG_PCGCCTL_TypeDef power; if (pdev->dev.DevRemoteWakeup) { dsts.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DSTS); if(dsts.b.suspsts == 1) { if(pdev->cfg.low_power) { /* un-gate USB Core clock */ power.d32 = USB_OTG_READ_REG32(&pdev->regs.PCGCCTL); power.b.gatehclk = 0; power.b.stoppclk = 0; USB_OTG_WRITE_REG32(pdev->regs.PCGCCTL, power.d32); } /* active Remote wakeup signaling */ dctl.d32 = 0; dctl.b.rmtwkupsig = 1; USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DCTL, 0, dctl.d32); USB_OTG_BSP_mDelay(5); USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DCTL, dctl.d32, 0 ); } } } /** * @brief USB_OTG_UngateClock : active USB Core clock * @param None * @retval : None */ void USB_OTG_UngateClock(USB_OTG_CORE_HANDLE *pdev) { if(pdev->cfg.low_power) { USB_OTG_DSTS_TypeDef dsts; USB_OTG_PCGCCTL_TypeDef power; dsts.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DSTS); if(dsts.b.suspsts == 1) { /* un-gate USB Core clock */ power.d32 = USB_OTG_READ_REG32(&pdev->regs.PCGCCTL); power.b.gatehclk = 0; power.b.stoppclk = 0; USB_OTG_WRITE_REG32(pdev->regs.PCGCCTL, power.d32); } } } /** * @brief Stop the device and clean up fifo's * @param None * @retval : None */ void USB_OTG_StopDevice(USB_OTG_CORE_HANDLE *pdev) { uint32_t i; pdev->dev.device_status = 1; for (i = 0; i < pdev->cfg.dev_endpoints ; i++) { USB_OTG_WRITE_REG32( &pdev->regs.INEP_REGS[i]->DIEPINT, 0xFF); USB_OTG_WRITE_REG32( &pdev->regs.OUTEP_REGS[i]->DOEPINT, 0xFF); } USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DIEPMSK, 0 ); USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DOEPMSK, 0 ); USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DAINTMSK, 0 ); USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DAINT, 0xFFFFFFFF ); /* Flush the FIFO */ USB_OTG_FlushRxFifo(pdev); USB_OTG_FlushTxFifo(pdev , 0x10 ); } /** * @brief returns the EP Status * @param pdev : Selected device * ep : endpoint structure * @retval : EP status */ uint32_t USB_OTG_GetEPStatus(USB_OTG_CORE_HANDLE *pdev ,USB_OTG_EP *ep) { USB_OTG_DEPCTL_TypeDef depctl; __IO uint32_t *depctl_addr; uint32_t Status = 0; depctl.d32 = 0; if (ep->is_in == 1) { depctl_addr = &(pdev->regs.INEP_REGS[ep->num]->DIEPCTL); depctl.d32 = USB_OTG_READ_REG32(depctl_addr); if (depctl.b.stall == 1) Status = USB_OTG_EP_TX_STALL; else if (depctl.b.naksts == 1) Status = USB_OTG_EP_TX_NAK; else Status = USB_OTG_EP_TX_VALID; } else { depctl_addr = &(pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL); depctl.d32 = USB_OTG_READ_REG32(depctl_addr); if (depctl.b.stall == 1) Status = USB_OTG_EP_RX_STALL; else if (depctl.b.naksts == 1) Status = USB_OTG_EP_RX_NAK; else Status = USB_OTG_EP_RX_VALID; } /* Return the current status */ return Status; } /** * @brief Set the EP Status * @param pdev : Selected device * Status : new Status * ep : EP structure * @retval : None */ void USB_OTG_SetEPStatus (USB_OTG_CORE_HANDLE *pdev , USB_OTG_EP *ep , uint32_t Status) { USB_OTG_DEPCTL_TypeDef depctl; __IO uint32_t *depctl_addr; depctl.d32 = 0; /* Process for IN endpoint */ if (ep->is_in == 1) { depctl_addr = &(pdev->regs.INEP_REGS[ep->num]->DIEPCTL); depctl.d32 = USB_OTG_READ_REG32(depctl_addr); if (Status == USB_OTG_EP_TX_STALL) { USB_OTG_EPSetStall(pdev, ep); return; } else if (Status == USB_OTG_EP_TX_NAK) depctl.b.snak = 1; else if (Status == USB_OTG_EP_TX_VALID) { if (depctl.b.stall == 1) { ep->even_odd_frame = 0; USB_OTG_EPClearStall(pdev, ep); return; } depctl.b.cnak = 1; depctl.b.usbactep = 1; depctl.b.epena = 1; } else if (Status == USB_OTG_EP_TX_DIS) depctl.b.usbactep = 0; } else /* Process for OUT endpoint */ { depctl_addr = &(pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL); depctl.d32 = USB_OTG_READ_REG32(depctl_addr); if (Status == USB_OTG_EP_RX_STALL) { depctl.b.stall = 1; } else if (Status == USB_OTG_EP_RX_NAK) depctl.b.snak = 1; else if (Status == USB_OTG_EP_RX_VALID) { if (depctl.b.stall == 1) { ep->even_odd_frame = 0; USB_OTG_EPClearStall(pdev, ep); return; } depctl.b.cnak = 1; depctl.b.usbactep = 1; depctl.b.epena = 1; } else if (Status == USB_OTG_EP_RX_DIS) { depctl.b.usbactep = 0; } } USB_OTG_WRITE_REG32(depctl_addr, depctl.d32); } #endif /** * @} */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/