usb_core.c
2162 lines
| 57.6 KiB
| text/x-c
|
CLexer
r71 | /** | |||
****************************************************************************** | ||||
* @file usb_core.c | ||||
* @author MCD Application Team | ||||
* @version V2.1.0 | ||||
* @date 19-March-2012 | ||||
* @brief USB-OTG Core Layer | ||||
****************************************************************************** | ||||
* @attention | ||||
* | ||||
* <h2><center>© COPYRIGHT 2012 STMicroelectronics</center></h2> | ||||
* | ||||
* 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****/ | ||||