text: /**
    *********************************************************************************
    *
    * @file    ald_usb.c
    * @brief   USB module driver.
    *
    * @version V1.0
    * @date    25 Dec 2019
    * @author  AE Team
    * @note
    *
    * Copyright (C) Shanghai Eastsoft Microelectronics Co. Ltd. All rights reserved.
    *
    * SPDX-License-Identifier: Apache-2.0
    *
    * Licensed under the Apache License, Version 2.0 (the License); you may
    * not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    * www.apache.org/licenses/LICENSE-2.0
    *
    * 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.
    *
    *********************************************************************************
    */
  
  #include "ald_usb.h"
  #include "ald_syscfg.h"
  
  /** @addtogroup ES32FXXX_ALD
    * @{
    */
  
  /** @defgroup USB USB
    * @brief USB module driver
    * @{
    */
  #ifdef ALD_USB
  /**
    * @defgroup USB_Public_Functions USB Public Function
    * @{
    */
  /** @defgroup USB_Public_Functions_Group1 Base functions
    * @brief Base functions
    * @{
    */
  
  /**
    * @brief  Gets the number of current frame.
    * @retval Number of the frame.
    */
  uint32_t ald_usb_frame_number_get(void)
  {
  	return USB0->FRAME;
  }
  
  /**
    * @brief  Request the session.
    * @param  start: true/false.
    * @retval None
    */
  void ald_usb_otg_session_request(bool start)
  {
  	if (start)
  		USB0->DEVCTL |= USB_DEVCTL_SESSION;
  	else
  		USB0->DEVCTL &= ~(USB_DEVCTL_SESSION);
  }
  
  /**
    * @brief  Gets the mode.
    * @retval Mode
    */
  uint32_t ald_usb_mode_get(void)
  {
  	return USB0->DEVCTL & (USB_DEVCTL_DEV | USB_DEVCTL_HOST
  			 | USB_DEVCTL_SESSION | USB_DEVCTL_VBUS_M);
  }
  
  /**
    * @brief  Enable/Disable the high mode.
    * @param  enable: ENABLE/DISABLE.
    * @retval None
    */
  void ald_usb_high_speed_enable(bool enable)
  {
  	if (enable)
  		USB0->POWER |= USB_POWER_HS_EN;
  	else
  		USB0->POWER &= ~(USB_POWER_HS_EN);
  }
  
  /**
    * @brief  Gets the speed of the device.
    * @retval Type of the speed.
    */
  uint32_t ald_usb_device_speed_get(void)
  {
  	if (USB0->POWER & USB_POWER_HS_EN)
  		return USB_HIGH_SPEED;
  
  	return USB_FULL_SPEED;
  }
  
  /**
    * @brief  Gets the number of the endpoint.
    * @retval Number of the endpoint.
    */
  uint32_t ald_usb_num_ep_get( void)
  {
  	return NUM_USB_EP;
  }
  
  /**
    * @brief  Reset USB Control.
    * @retval None
    */
  void ald_usb_control_reset(void)
  {
  	ald_rmu_reset_periperal(RMU_PERH_USB);
  }
  
  /**
    * @brief  Output USB clock via PA15, 60MHz/256=234.375KHz.
    * @retval None
    */
  void ald_usb_clock_output(void)
  {
  	SYSCFG_UNLOCK();
  	SYSCFG->TESTKEY = 0x5A962814;
  	SYSCFG->TESTKEY = 0xE7CB69A5;
  	SYSCFG->USBTEST = 0x43;
  
  	return;
  }
  
  /**
    * @brief  Starts eye diagram for high-speed host.
    * @param  buf: Buffer for eye diagram.
    * @param  len: Length of the buffer.
    * @retval Status, 0 means success, other values means failure.
    */
  int ald_usb_eye_diagram_start(uint8_t *buf, uint16_t len)
  {
  	if (len < 53)
  		return -1;
  
  	ald_usb_ep_data_put(0, buf, 53);
  	USB0->TEST = 0x08 | 0x90;
  	ald_delay_ms(20);
  	USB0->CSR0L = USB_CSRL0_TXRDY;
  
  	return 0;
  }
  /**
    * @}
    */
  
  /** @defgroup USB_Public_Functions_Group2 Device functions
    * @brief Device functions
    * @{
    */
  
  /**
    * @brief  Gets the address.
    * @retval Address.
    */
  uint8_t ald_usb_dev_get_addr(void)
  {
  	return USB0->FADDR;
  }
  
  /**
    * @brief  Sets the address.
    * @param  addr: The address which will be set.
    * @retval None
    */
  void ald_usb_dev_set_addr(uint8_t addr)
  {
  	USB0->FADDR = addr;
  }
  
  /**
    * @brief  Enable connection.
    * @retval None
    */
  void ald_usb_dev_connect(void)
  {
  	USB0->POWER |= USB_POWER_SOFTCONN;
  }
  
  /**
    * @brief  Disable connection.
    * @retval None
    */
  void ald_usb_dev_disconnect(void)
  {
  	USB0->POWER &= ~(USB_POWER_SOFTCONN);
  }
  
  /**
    * @brief  Configure the endpoint in device mode.
    * @param  ep_idx: Index of the endpoint
    * @param  p_max: Size of the maximum package.
    * @param  flags: Flags of the endpoint.
    * @retval None
    */
  void ald_usb_dev_ep_config(uint32_t ep_idx, uint32_t p_max, uint32_t flags)
  {
  	uint32_t tmp = 0;
  
  	if (flags & USB_EP_DEV_IN) {
  		USB0->CSR[ep_idx - 1].TXxMAXP = p_max;
  		if (flags & USB_EP_AUTO_SET)
  			tmp |= USB_TXCSRH1_AUTOSET;
  		if ((flags & USB_EP_MODE_MASK) == USB_EP_MODE_ISOC)
  			tmp |= USB_TXCSRH1_ISO;
  
  		USB0->CSR[ep_idx - 1].TXxCSRH = (uint8_t)tmp;
  		USB0->CSR[ep_idx - 1].TXxCSRL = USB_TXCSRL1_CLRDT;
  	}
  	else {
  		USB0->CSR[ep_idx - 1].RXxMAXP = p_max;
  		if (flags & USB_EP_AUTO_CLEAR)
  			tmp = USB_RXCSRH1_AUTOCL;
  		if (flags & USB_EP_DIS_NYET)
  			tmp |= USB_RXCSRH1_DISNYET;
  
  		if ((flags & USB_EP_MODE_MASK) == USB_EP_MODE_ISOC)
  			tmp |= USB_RXCSRH1_ISO;
  
  		USB0->CSR[ep_idx - 1].RXxCSRH = (uint8_t)tmp;
  		USB0->CSR[ep_idx - 1].RXxCSRL = USB_RXCSRL1_CLRDT;
  	}
  }
  
  /**
    * @brief  Gets the parameters of the endpoint.
    * @param  ep_idx: Index of the endpoint
    * @param  p_max: Size of the maximum package.
    * @param  flags: Flags of the endpoint.
    * @retval None
    */
  void ald_usb_dev_ep_get_config(uint32_t ep_idx, uint32_t *p_max, uint32_t *flags)
  {
  	uint32_t tmp;
  
  	if (*flags & USB_EP_DEV_IN) {
  		*flags = USB_EP_DEV_IN;
  		*p_max = (uint32_t)USB0->CSR[ep_idx - 1].TXxMAXP;
  		tmp    = (uint32_t)USB0->CSR[ep_idx - 1].TXxCSRH;
  
  		if (tmp & USB_TXCSRH1_AUTOSET)
  			*flags |= USB_EP_AUTO_SET;
  		if (tmp & USB_TXCSRH1_ISO)
  			*flags |= USB_EP_MODE_ISOC;
  		else
  			*flags |= USB_EP_MODE_BULK;
  	}
  	else {
  		*flags = USB_EP_DEV_OUT;
  		*p_max = (uint32_t)USB0->CSR[ep_idx - 1].RXxMAXP;
  		tmp    = (uint32_t)USB0->CSR[ep_idx - 1].RXxCSRH;
  
  		if (tmp & USB_RXCSRH1_AUTOCL)
  			*flags |= USB_EP_AUTO_CLEAR;
  		if (tmp & USB_RXCSRH1_ISO)
  			*flags |= USB_EP_MODE_ISOC;
  		else
  			*flags |= USB_EP_MODE_BULK;
  	}
  }
  
  /**
    * @brief  Acknowledge the data from the host.
    * @param  ep_idx: Index of the endpoint
    * @param  last: true/false
    * @retval None
    */
  void ald_usb_dev_ep_data_ack(uint32_t ep_idx, bool last)
  {
  	if (ep_idx == USB_EP_0)
  		USB0->CSR0L = USB_CSRL0_RXRDYC | (last ? USB_CSRL0_DATAEND : 0);
  	else
  		USB0->CSR[ep_idx - 1].RXxCSRL &= ~(USB_RXCSRL1_RXRDY);
  }
  
  /**
    * @brief  Stall the endpoint.
    * @param  ep_idx: Index of the endpoint
    * @param  flags: Flags.
    * @retval None
    */
  void ald_usb_dev_ep_stall(uint32_t ep_idx, uint32_t flags)
  {
  	if (ep_idx == USB_EP_0)
  		USB0->CSR0L |= (USB_CSRL0_STALL | USB_CSRL0_RXRDYC);
  	else if (flags == USB_EP_DEV_IN)
  		USB0->CSR[ep_idx - 1].TXxCSRL |= USB_TXCSRL1_STALL;
  	else
  		USB0->CSR[ep_idx - 1].RXxCSRL |= USB_RXCSRL1_STALL;
  }
  
  /**
    * @brief  Cancel the stall status.
    * @param  ep_idx: Index of the endpoint
    * @param  flags: Flags.
    * @retval None
    */
  void ald_usb_dev_ep_stall_clear(uint32_t ep_idx, uint32_t flags)
  {
  	if (ep_idx == USB_EP_0)
  		USB0->CSR0L &= ~USB_CSRL0_STALLED;
  	else if (flags == USB_EP_DEV_IN) {
  		USB0->CSR[ep_idx - 1].TXxCSRL &= ~(USB_TXCSRL1_STALL | USB_TXCSRL1_STALLED);
  		USB0->CSR[ep_idx - 1].TXxCSRL |= USB_TXCSRL1_CLRDT;
  	}
  	else {
  		USB0->CSR[ep_idx - 1].RXxCSRL &= ~(USB_RXCSRL1_STALL | USB_RXCSRL1_STALLED);
  		USB0->CSR[ep_idx - 1].RXxCSRL |= USB_RXCSRL1_CLRDT;
  	}
  }
  
  /**
    * @brief  Clear the status of the endpoint.
    * @param  ep_idx: Index of the endpoint
    * @param  flags: Flags.
    * @retval None
    */
  void ald_usb_dev_ep_status_clear(uint32_t ep_idx, uint32_t flags)
  {
  	if (ep_idx == USB_EP_0) {
  		if (flags & USB_DEV_EP0_OUT_PKTRDY)
  			USB0->CSR0L |= USB_CSRL0_RXRDYC;
  		if (flags & USB_DEV_EP0_SETUP_END)
  			USB0->CSR0L |= USB_CSRL0_SETENDC;
  		if (flags & USB_DEV_EP0_SENT_STALL)
  			USB0->CSR0L &= ~(USB_DEV_EP0_SENT_STALL);
  	}
  	else {
  		USB0->CSR[ep_idx - 1].TXxCSRL &= ~(flags & (USB_DEV_TX_SENT_STALL | USB_DEV_TX_UNDERRUN));
  		USB0->CSR[ep_idx - 1].RXxCSRL &= ~((flags & (USB_DEV_RX_SENT_STALL | USB_DEV_RX_DATA_ERROR
  						 | USB_DEV_RX_OVERRUN)) >> USB_RX_EPSTATUS_SHIFT);
  	}
  }
  /**
    * @}
    */
  
  /** @defgroup USB_Public_Functions_Group3 Host functions
    * @brief Host functions
    * @{
    */
  /**
    * @brief  Gets the device's address.
    * @param  ep_idx: Index of the endpoint
    * @param  flags: Flags.
    * @retval Address
    */
  uint32_t ald_usb_host_addr_get(uint32_t ep_idx, uint32_t flags)
  {
  	if (flags & USB_EP_HOST_OUT)
  		return USB0->ADDR[ep_idx].TXxFUNCADDR;
  	else
  		return USB0->ADDR[ep_idx].RXxFUNCADDR;
  }
  
  /**
    * @brief  Sets the device's address.
    * @param  ep_idx: Index of the endpoint.
    * @param  addr: The device's address.
    * @param  flags: Flags.
    * @retval None
    */
  void ald_usb_host_addr_set(uint32_t ep_idx, uint32_t addr, uint32_t flags)
  {
  	if (flags & USB_EP_HOST_OUT)
  		USB0->ADDR[ep_idx].TXxFUNCADDR = addr;
  	else
  		USB0->ADDR[ep_idx].RXxFUNCADDR = addr;
  }
  
  /**
    * @brief  Configure the endpoint in host mode.
    * @param  ep_idx: Index of the endpoint.
    * @param  p_max: Size of the maximum package.
    * @param  nak_val: Value of the nack.
    * @param  t_ep: Target endpoint.
    * @param  flags: Flags.
    * @retval None
    */
  void ald_usb_host_ep_config(uint32_t ep_idx, uint32_t p_max, uint32_t nak_val, uint32_t t_ep, uint32_t flags)
  {
  	uint32_t tmp;
  
  	if (ep_idx == USB_EP_0) {
  		USB0->NACK = nak_val;
  
  		if (flags & USB_EP_SPEED_HIGH)
  			USB0->TYPE0 = USB_TYPE0_SPEED_HIGH;
  		else if (flags & USB_EP_SPEED_FULL)
  			USB0->TYPE0 = USB_TYPE0_SPEED_FULL;
  		else
  			USB0->TYPE0 = USB_TYPE0_SPEED_LOW;
  	}
  	else {
  		tmp = t_ep;
  
  		if (flags & USB_EP_SPEED_HIGH)
  			tmp |= USB_TXTYPE1_SPEED_HIGH;
  		else if (flags & USB_EP_SPEED_FULL)
  			tmp |= USB_TXTYPE1_SPEED_FULL;
  		else
  			tmp |= USB_TXTYPE1_SPEED_LOW;
  
  		switch (flags & USB_EP_MODE_MASK) {
  		case USB_EP_MODE_BULK:
  			tmp |= USB_TXTYPE1_PROTO_BULK;
  			break;
  
  		case USB_EP_MODE_ISOC:
  			tmp |= USB_TXTYPE1_PROTO_ISOC;
  			break;
  
  		case USB_EP_MODE_INT:
  			tmp |= USB_TXTYPE1_PROTO_INT;
  			break;
  
  		case USB_EP_MODE_CTRL:
  			tmp |= USB_TXTYPE1_PROTO_CTRL;
  			break;
  		}
  
  		if (flags & USB_EP_HOST_OUT) {
  			USB0->CSR[ep_idx - 1].TXxTYPE     = tmp;
  			USB0->CSR[ep_idx - 1].TXxINTERVAL = nak_val;
  			USB0->CSR[ep_idx - 1].TXxMAXP     = p_max;
  
  			tmp = 0;
  			if (flags & USB_EP_AUTO_SET)
  				tmp |= USB_TXCSRH1_AUTOSET;
  			USB0->CSR[ep_idx - 1].TXxCSRH = (uint8_t)tmp;
  		}
  		else {
  			USB0->CSR[ep_idx - 1].RXxTYPE     = tmp;
  			USB0->CSR[ep_idx - 1].RXxINTERVAL = nak_val;
  			USB0->CSR[ep_idx - 1].RXxMAXP     = p_max;
  
  			tmp = 0;
  			if (flags & USB_EP_AUTO_CLEAR)
  				tmp |= USB_RXCSRH1_AUTOCL;
  			if (flags & USB_EP_AUTO_REQUEST)
  				tmp |= USB_RXCSRH1_AUTORQ;
  
  			USB0->CSR[ep_idx - 1].RXxCSRH = (uint8_t)tmp;
  		}
  	}
  }
  
  /**
    * @brief  Acknowledge the data in host mode.
    * @param  ep_idx: Index of the endpoint.
    * @retval None
    */
  void ald_usb_host_ep_data_ack(uint32_t ep_idx)
  {
  	if (ep_idx == USB_EP_0)
  		USB0->CSR0L &= ~(USB_CSRL0_RXRDY);
  	else
  		USB0->CSR[ep_idx - 1].RXxCSRL &= ~(USB_RXCSRL1_RXRDY);
  }
  
  /**
    * @brief  Toggle the data in host mode.
    * @param  ep_idx: Index of the endpoint.
    * @param  toggle: true/false.
    * @param  flags: Flags.
    * @retval None
    */
  void ald_usb_host_ep_data_toggle(uint32_t ep_idx, bool toggle, uint32_t flags)
  {
  	uint32_t tmp = 0;
  
  	if (toggle) {
  		if (ep_idx == USB_EP_0)
  			tmp = USB_CSRH0_DT;
  		else if (flags == USB_EP_HOST_IN)
  			tmp = USB_RXCSRH1_DT;
  		else
  			tmp = USB_TXCSRH1_DT;
  	}
  
  	if (ep_idx == USB_EP_0) {
  		USB0->CSR0H = (uint8_t)((USB0->CSR0H  & ~(USB_CSRH0_DTWE | USB_CSRH0_DT)) |
  						(tmp | USB_CSRH0_DTWE));
  	}
  	else if (flags == USB_EP_HOST_IN) {
  		USB0->CSR[ep_idx - 1].RXxCSRH = (uint8_t)((USB0->CSR[ep_idx - 1].RXxCSRH &
  							~(USB_RXCSRH1_DTWE | USB_RXCSRH1_DT)) |
  							(tmp | USB_RXCSRH1_DTWE));
  	}
  	else {
  		USB0->CSR[ep_idx - 1].TXxCSRH = (uint8_t)((USB0->CSR[ep_idx - 1].TXxCSRH &
  							~(USB_TXCSRH1_DTWE | USB_TXCSRH1_DT)) |
  							(tmp | USB_TXCSRH1_DTWE));
  	}
  }
  
  /**
    * @brief  Clear the status of endpoint in host mode.
    * @param  ep_idx: Index of the endpoint.
    * @param  flags: Flags.
    * @retval None
    */
  void ald_usb_host_ep_status_clear(uint32_t ep_idx, uint32_t flags)
  {
  	if (ep_idx == USB_EP_0) {
  		USB0->CSR0L &= ~flags;
  	}
  	else {
  		USB0->CSR[ep_idx - 1].TXxCSRL &= ~flags;
  		USB0->CSR[ep_idx - 1].RXxCSRL &= ~flags;
  	}
  }
  
  /**
    * @brief  Gets the HUB's address.
    * @param  ep_idx: Index of the endpoint.
    * @param  flags: Flags.
    * @retval Address
    */
  uint32_t ald_usb_host_hub_addr_get(uint32_t ep_idx, uint32_t flags)
  {
  	if (flags & USB_EP_HOST_OUT)
  		return USB0->ADDR[ep_idx].TXxHUBADDR;
  	else
  		return USB0->ADDR[ep_idx].RXxHUBADDR;
  }
  
  /**
    * @brief  Sets the HUB's address.
    * @param  ep_idx: Index of the endpoint.
    * @param  addr: HUB's address which will be set.
    * @param  flags: Flags.
    * @retval Address
    */
  void ald_usb_host_hub_addr_set(uint32_t ep_idx, uint32_t addr, uint32_t flags)
  {
  	if (flags & USB_EP_HOST_OUT)
  		USB0->ADDR[ep_idx].TXxHUBADDR = addr;
  	else
  		USB0->ADDR[ep_idx].RXxHUBADDR = addr;
  
  	if (ep_idx == USB_EP_0) {
  		if (flags & USB_EP_SPEED_FULL)
  			USB0->TYPE0 |= USB_TYPE0_SPEED_FULL;
  		else if (flags & USB_EP_SPEED_HIGH)
  			USB0->TYPE0 |= USB_TYPE0_SPEED_HIGH;
  		else
  			USB0->TYPE0 |= USB_TYPE0_SPEED_LOW;
  	}
  }
  
  /**
    * @brief  Disable power.
    * @retval None
    */
  void ald_usb_host_pwr_disable(void)
  {
  	return;
  }
  
  /**
    * @brief  Enable power.
    * @retval None
    */
  void ald_usb_host_pwr_enable(void)
  {
  	return;
  }
  
  /**
    * @brief  Configure power in host mode.
    * @param  flags: Flags
    * @retval None
    */
  void ald_usb_host_pwr_config(uint32_t flags)
  {
  	return;
  }
  
  /**
    * @brief  Disable the fault parameters of the power.
    * @retval None
    */
  void ald_usb_host_pwr_fault_disable(void)
  {
  	return;
  }
  
  /**
    * @brief  Enable the fault parameters of the power.
    * @retval None
    */
  void ald_usb_host_pwr_fault_enable(void)
  {
  	return;
  }
  
  /**
    * @brief  Request data IN(from device to host)
    * @param  ep_idx: Index of the endpoint.
    * @retval None
    */
  void ald_usb_host_request_in(uint32_t ep_idx)
  {
  	if (ep_idx == USB_EP_0)
  		USB0->CSR0L = USB_RXCSRL1_REQPKT;
  	else
  		USB0->CSR[ep_idx - 1].RXxCSRL = USB_RXCSRL1_REQPKT;
  }
  
  /**
    * @brief  Clear the status of request IN.
    * @param  ep_idx: Index of the endpoint.
    * @retval None
    */
  void ald_usb_host_request_in_clear(uint32_t ep_idx)
  {
  	if (ep_idx == USB_EP_0)
  		USB0->CSR0L &= ~(USB_RXCSRL1_REQPKT);
  	else
  		USB0->CSR[ep_idx - 1].RXxCSRL &= ~(USB_RXCSRL1_REQPKT);
  }
  
  /**
    * @brief  Request data IN at endpoint 0.
    * @retval None
    */
  void ald_usb_host_request_status(void)
  {
  	USB0->CSR0L = USB_CSRL0_REQPKT | USB_CSRL0_STATUS;
  }
  
  /**
    * @brief  Reset the USB's bus.
    * @param  start: true/false.
    * @retval None
    */
  void ald_usb_host_reset(bool start)
  {
  	if (start)
  		USB0->POWER |= USB_POWER_RESET;
  	else
  		USB0->POWER &= ~(USB_POWER_RESET);
  }
  
  /**
    * @brief  Resume the devices.
    * @param  start: true/false.
    * @retval None
    */
  void ald_usb_host_resume(bool start)
  {
  	if (start)
  		USB0->POWER |= USB_POWER_RESUME;
  	else
  		USB0->POWER &= ~(USB_POWER_RESUME);
  }
  
  /**
    * @brief  Suspend the devices.
    * @retval None
    */
  void ald_usb_host_suspend(void)
  {
  	USB0->POWER |= USB_POWER_SUSPEND;
  }
  
  /**
    * @brief  Gets the device's speed.
    * @retval Type of the speed.
    */
  uint32_t ald_usb_host_speed_get(void)
  {
  	if (USB0->POWER & USB_POWER_HS_M)
  		return USB_HIGH_SPEED;
  
  	if (USB0->DEVCTL & USB_DEVCTL_FSDEV)
  		return USB_FULL_SPEED;
  
  	if (USB0->DEVCTL & USB_DEVCTL_LSDEV)
  		return USB_LOW_SPEED;
  
  	return USB_UNDEF_SPEED;
  }
  
  /**
    * @brief  Sets the endpoint speed.
    * @param  ep_idx: Index of the endpoint.
    * @param  flags: Type of the speed.
    * @retval None
    */
  void ald_usb_host_ep_speed_set(uint32_t ep_idx, uint32_t flags)
  {
  	uint32_t tmp;
  
  	if (flags & USB_EP_SPEED_HIGH)
  		tmp = USB_TYPE0_SPEED_HIGH;
  	else if (flags & USB_EP_SPEED_FULL)
  		tmp = USB_TYPE0_SPEED_FULL;
  	else
  		tmp = USB_TYPE0_SPEED_LOW;
  
  	if (ep_idx == USB_EP_0)
  		USB0->TYPE0 |= tmp;
  	else if (flags & USB_EP_HOST_OUT)
  		USB0->CSR[ep_idx - 1].TXxTYPE |= tmp;
  	else
  		USB0->CSR[ep_idx - 1].RXxTYPE |= tmp;
  }
  
  /**
    * @brief  Ping the endpoint.
    * @param  ep_idx: Index of the endpoint.
    * @param  enable: ENABLE/DISABLE.
    * @retval None
    */
  void ald_usb_host_ep_ping(uint32_t ep_idx, bool enable)
  {
  	if (enable)
  		USB0->CSR0H &= ~(USB_CSRH0_DISPING);
  	else
  		USB0->CSR0H |= USB_CSRH0_DISPING;
  }
  /**
    * @}
    */
  
  /** @defgroup USB_Public_Functions_Group4 Endpoint functions
    * @brief Endpoint functions
    * @{
    */
  /**
    * @brief  Gets the size of the available data.
    * @param  ep_idx: Index of the endpoint
    * @retval Size in bytes.
    */
  uint32_t ald_usb_ep_data_avail(uint32_t ep_idx)
  {
  	if (ep_idx == USB_EP_0) {
  		if ((USB0->CSR0L & USB_CSRL0_RXRDY) == 0)
  			return 0;
  
  		return USB0->COUNT0;
  	}
  	else {
  		if ((USB0->CSR[ep_idx - 1].RXxCSRL & USB_CSRL0_RXRDY) == 0)
  			return 0;
  
  		return USB0->CSR[ep_idx - 1].RXxCOUNT;
  	}
  }
  
  /**
    * @brief  Gets the data from FIFO.
    * @param  ep_idx: Index of the endpoint
    * @param  data: Pointer to the buffer.
    * @param  size: Size of the data.
    * @retval Status.
    */
  int32_t ald_usb_ep_data_get(uint32_t ep_idx, uint8_t *data, uint32_t *size)
  {
  	uint32_t i;
  
  	if (ep_idx == USB_EP_0) {
  		if ((USB0->CSR0L & USB_CSRL0_RXRDY) == 0) {
  			*size = 0;
  			return -1;
  		}
  		i = USB0->COUNT0;
  	}
  	else {
  		if ((USB0->CSR[ep_idx - 1].RXxCSRL & USB_CSRL0_RXRDY) == 0) {
  			*size = 0;
  			return -1;
  		}
  		i = USB0->CSR[ep_idx - 1].RXxCOUNT;
  	}
  
  	i     = (i < *size) ? i : *size;
  	*size = i;
  
  	for (; i > 0; i--)
  		*data++ = USB0->FIFO[ep_idx].Byte[0];
  
  	return 0;
  }
  
  /**
    * @brief  Puts data to the FIFO.
    * @param  ep_idx: Index of the endpoint
    * @param  data: Pointer to the data.
    * @param  size: Size of the data.
    * @retval Status.
    */
  int32_t ald_usb_ep_data_put(uint32_t ep_idx, uint8_t *data, uint32_t size)
  {
  	if (ep_idx == USB_EP_0) {
  		if (USB0->CSR0L & USB_CSRL0_TXRDY)
  			return -1;
  	}
  	else {
  		if (USB0->CSR[ep_idx - 1].TXxCSRL & USB_TXCSRL1_TXRDY)
  			return -1;
  	}
  
  	for (; size > 0; size--)
  		USB0->FIFO[ep_idx].Byte[0] = *data++;
  
  	return 0;
  }
  
  /**
    * @brief  Send data.
    * @param  ep_idx: Index of the endpoint
    * @param  tx_type: Type.
    * @retval Status.
    */
  int32_t ald_usb_ep_data_send(uint32_t ep_idx, uint32_t tx_type)
  {
  	uint32_t tmp;
  
  	if (ep_idx == USB_EP_0) {
  		if (USB0->CSR0L & USB_CSRL0_TXRDY)
  			return -1;
  
  		tmp = tx_type & 0xff;
  		USB0->CSR0L = tmp;
  	}
  	else {
  		if (USB0->CSR[ep_idx - 1].TXxCSRL & USB_TXCSRL1_TXRDY)
  			return -1;
  
  		tmp = (tx_type >> 8) & 0xff;
  		USB0->CSR[ep_idx - 1].TXxCSRL = tmp;
  	}
  
  	return 0;
  }
  
  /**
    * @brief  Clear the status of the toggle.
    * @param  ep_idx: Index of the endpoint
    * @param  flags: Flags.
    * @retval None
    */
  void ald_usb_ep_data_toggle_clear(uint32_t ep_idx, uint32_t flags)
  {
  	if (flags & (USB_EP_HOST_OUT | USB_EP_DEV_IN))
  		USB0->CSR[ep_idx - 1].TXxCSRL |= USB_TXCSRL1_CLRDT;
  	else
  		USB0->CSR[ep_idx - 1].RXxCSRL |= USB_RXCSRL1_CLRDT;
  }
  
  /**
    * @brief  Sets the size of request data IN
    * @param  ep_idx: Index of the endpoint
    * @param  count: Size of request data IN.
    * @retval None
    */
  void ald_usb_ep_req_packet_count(uint32_t ep_idx, uint32_t count)
  {
  	USB0->EP_RQPKTCOUNT[ep_idx - 1] = count;
  }
  
  /**
    * @brief  Gets the status of the endpoint.
    * @param  ep_idx: Index of the endpoint
    * @retval Status.
    */
  uint32_t ald_usb_ep_status(uint32_t ep_idx)
  {
  	uint32_t status;
  
  	if (ep_idx == USB_EP_0) {
  		status  = USB0->CSR0L;
  		status |= (USB0->CSR0H) << USB_RX_EPSTATUS_SHIFT;
  	}
  	else {
  		status  = USB0->CSR[ep_idx - 1].TXxCSRL;
  		status |= USB0->CSR[ep_idx - 1].TXxCSRH << 8;
  		status |= USB0->CSR[ep_idx - 1].RXxCSRL << 16;
  		status |= USB0->CSR[ep_idx - 1].RXxCSRH << 24;
  	}
  
  	return status;
  }
  
  /**
    * @brief  Configure the endpoint in DMA mode.
    * @param  ep_idx: Index of the endpoint
    * @param  flag: Flags.
    * @param  en: ENABLE/DISABLE.
    * @retval None
    */
  void ald_usb_ep_dma_config(uint32_t ep_idx, uint32_t flag, type_func_t en)
  {
  	if (ep_idx == USB_EP_0)
  		return;
  
  	if (en) {
  		switch (flag) {
  		case USB_DMA_EP_CFG_TX:
  			USB0->CSR[ep_idx - 1].TXxCSRH |= USB_DMA_EP_TX_MSK;
  			break;
  		case USB_DMA_EP_CFG_RX_DEV:
  			USB0->CSR[ep_idx - 1].RXxCSRH |= USB_DMA_EP_RX_DEV_MSK;
  			break;
  		case USB_DMA_EP_CFG_RX_HOST:
  			USB0->CSR[ep_idx - 1].RXxCSRH |= USB_DMA_EP_RX_HOST_MSK;
  			break;
  		default:
  			break;
  		}
  	}
  	else {
  		switch (flag) {
  		case USB_DMA_EP_CFG_TX:
  			USB0->CSR[ep_idx - 1].TXxCSRH &= ~(USB_DMA_EP_TX_MSK);
  			break;
  		case USB_DMA_EP_CFG_RX_DEV:
  			USB0->CSR[ep_idx - 1].RXxCSRH &= ~(USB_DMA_EP_RX_DEV_MSK);
  			break;
  		case USB_DMA_EP_CFG_RX_HOST:
  			USB0->CSR[ep_idx - 1].RXxCSRH &= ~(USB_DMA_EP_RX_HOST_MSK);
  			break;
  		default:
  			break;
  		}
  	}
  
  	return;
  }
  /**
    * @}
    */
  
  /** @defgroup USB_Public_Functions_Group5 FIFO functions
    * @brief FIFO functions
    * @{
    */
  /**
    * @brief  Gets the address of the FIFO.
    * @param  ep_idx: Index of the endpoint
    * @retval Address
    */
  uint32_t ald_usb_fifo_addr_get(uint32_t ep_idx)
  {
  	return (uint32_t)&USB0->FIFO[ep_idx].Word;
  }
  
  /**
    * @brief  Gets the parameters of the FIFO.
    * @param  ep_idx: Index of the endpoint
    * @param  addr: Address.
    * @param  size: Size of FIFO.
    * @param  flags: Flags.
    * @retval None
    */
  void ald_usb_fifo_config_get(uint32_t ep_idx, uint32_t *addr, uint32_t *size, uint32_t flags)
  {
  	uint32_t tmp = USB0->INDEX;
  
  	USB0->INDEX = ep_idx;
  
  	if (flags & (USB_EP_HOST_OUT | USB_EP_DEV_IN)) {
  		*addr = (USB0->TXFIFOADD << 3);
  		*size = (USB0->TXFIFOSIZE & 0xF);
  	}
  	else {
  		*addr = (USB0->RXFIFOADD << 3);
  		*size = (USB0->RXFIFOSIZE & 0xF);
  	}
  
  	USB0->INDEX = tmp;
  	return;
  }
  
  /**
    * @brief  Sets the parameters of the FIFO.
    * @param  ep_idx: Index of the endpoint
    * @param  addr: Address.
    * @param  size: Size of FIFO.
    * @param  flags: Flags.
    * @retval None
    */
  void ald_usb_fifo_config_set(uint32_t ep_idx, uint32_t addr, uint32_t size, uint32_t flags)
  {
  	uint32_t tmp = USB0->INDEX;
  
  	USB0->INDEX = ep_idx;
  
  	if (flags & (USB_EP_HOST_OUT | USB_EP_DEV_IN)) {
  		USB0->TXFIFOADD  = (addr >> 3);
  		USB0->TXFIFOSIZE = (size & 0xF);
  	}
  	else {
  		USB0->RXFIFOADD  = (addr >> 3);
  		USB0->RXFIFOSIZE = (size & 0xF);
  	}
  
  	USB0->INDEX = tmp;
  	return;
  }
  
  /**
    * @brief  Flush the FIFO
    * @param  ep_idx: Index of the endpoint
    * @param  flags: Flags.
    * @retval None
    */
  void ald_usb_fifo_flush(uint32_t ep_idx, uint32_t flags)
  {
  	if (ep_idx == USB_EP_0) {
  		if ((USB0->CSR0L & (USB_CSRL0_RXRDY | USB_CSRL0_TXRDY)) != 0)
  			USB0->CSR0H |= USB_CSRH0_FLUSH;
  	}
  	else {
  		if (flags & (USB_EP_HOST_OUT | USB_EP_DEV_IN)) {
  			if (USB0->CSR[ep_idx - 1].TXxCSRL & USB_TXCSRL1_TXRDY)
  				USB0->CSR[ep_idx - 1].TXxCSRL |= USB_TXCSRL1_FLUSH;
  		}
  		else {
  			if (USB0->CSR[ep_idx - 1].RXxCSRL & USB_RXCSRL1_RXRDY)
  				USB0->CSR[ep_idx - 1].RXxCSRL |= USB_RXCSRL1_FLUSH;
  		}
  	}
  }
  /**
    * @}
    */
  
  /** @defgroup USB_Public_Functions_Group6 Interrupt functions
    * @brief Interrupt functions
    * @{
    */
  /**
    * @brief  Disable interrupt.
    * @param  flags: Type of the interrupt.
    * @retval None
    */
  void ald_usb_int_disable(uint32_t flags)
  {
  	if (flags & USB_INTCTRL_STATUS)
  		USB0->USBIE &= ~(flags & USB_INTCTRL_STATUS);
  }
  
  /**
    * @brief  Enable interrupt.
    * @param  flags: Type of the interrupt.
    * @retval None
    */
  void ald_usb_int_enable(uint32_t flags)
  {
  	if (flags & USB_INTCTRL_STATUS)
  		USB0->USBIE |= flags ;
  }
  
  /**
    * @brief  Gets the status of the interrupt.
    * @retval Status.
    */
  uint32_t ald_usb_int_status_get(void)
  {
  	return USB0->USBIS;
  }
  
  /**
    * @brief  Disable interrupt of the endpoint.
    * @param  flags: Type of the interrupt.
    * @retval None
    */
  void ald_usb_int_disable_ep(uint32_t flags)
  {
  	USB0->TXIE &= ~(flags & (USB_INTEP_HOST_OUT | USB_INTEP_DEV_IN | USB_INTEP_0));
  	USB0->RXIE &= ~((flags & (USB_INTEP_HOST_IN | USB_INTEP_DEV_OUT)) >> USB_INTEP_RX_SHIFT);
  }
  
  /**
    * @brief  Enable interrupt of the endpoint.
    * @param  flags: Type of the interrupt.
    * @retval None
    */
  void ald_usb_int_enable_ep(uint32_t flags)
  {
  
  	USB0->TXIE |= flags & (USB_INTEP_HOST_OUT | USB_INTEP_DEV_IN | USB_INTEP_0);
  	USB0->RXIE |= ((flags & (USB_INTEP_HOST_IN | USB_INTEP_DEV_OUT)) >> USB_INTEP_RX_SHIFT);
  }
  
  /**
    * @brief  Gets the ststus of the endpoint interrupt.
    * @retval Status.
    */
  uint32_t ald_usb_int_status_ep_get(void)
  {
  	uint32_t status;
  
  	status = USB0->TXIS;
  	status |= (USB0->RXIS << USB_INTEP_RX_SHIFT);
  
  	return status;
  }
  
  /**
    * @brief  Register USB's interrupt.
    * @retval None
    */
  void ald_usb_int_register(void)
  {
  	ald_mcu_irq_config(USB_INT_IRQn, 2, 2, ENABLE);
  
  }
  
  /**
    * @brief  Unregister USB's interrupt.
    * @retval None
    */
  void ald_usb_int_unregister(void)
  {
  	ald_mcu_irq_config(USB_INT_IRQn, 2, 2, DISABLE);
  }
  
  /**
    * @brief  Get USB's interrupt number.
    * @retval None
    */
  uint32_t ald_usb_int_num_get(void)
  {
  	return USB_INT_IRQn;
  }
  /**
    * @}
    */
  
  /** @defgroup USB_Public_Functions_Group7 DMA functions
    * @brief DMA functions
    * @{
    */
  /**
    * @brief  Configure DMA's channel.
    * @param  ch: Channel.
    * @param  addr: Address.
    * @param  count: Size of the data to be moved.
    * @param  ctrl: Parameters of the DMA's controler
    * @retval None
    */
  void ald_usb_dma_channel_config(uint8_t ch, uint32_t addr, uint32_t count, uint32_t ctrl)
  {
  	USB0->DMA_CH[ch].DMA_ADDR  = addr;
  	USB0->DMA_CH[ch].DMA_COUNT = count;
  	USB0->DMA_CH[ch].DMA_CNTL  = ctrl;
  	return;
  }
  
  /**
    * @brief  Start multiple receive.
    * @param  ep_idx: Index of the endpoint
    * @retval None
    */
  void ald_usb_dma_mult_recv_start(uint32_t ep_idx)
  {
  	USB0->CSR[ep_idx - 1].RXxCSRH &= ~(USB_RXCSRH1_DMAMOD);
  	return;
  }
  
  
  /**
    * @brief  Start DMA's machine.
    * @param  ch: Channel.
    * @retval None
    */
  void ald_usb_dma_channel_start(uint8_t ch)
  {
  	USB0->DMA_CH[ch].DMA_CNTL |= 0x1;
  	return;
  }
  
  /**
    * @brief  Stop DMA's machine.
    * @param  ch: Channel.
    * @retval None
    */
  void ald_usb_dma_channel_stop(uint8_t ch)
  {
  	USB0->DMA_CH[ch].DMA_CNTL &= (uint32_t)(~0x1);
  	return;
  }
  
  /**
    * @brief  Gets flags of the interrupt.
    * @retval Flags of the interrupt.
    */
  uint32_t ald_usb_dma_get_interrupt_flag(void)
  {
  	return USB0->DMA_INTR;
  }
  
  /**
    * @brief  Gets the status of the error.
    * @param  ch: Channel.
    * @retval Status.
    */
  uint32_t ald_usb_dma_get_channel_error(uint8_t ch)
  {
  	if (USB0->DMA_CH[ch].DMA_CNTL & USB_DMA_CH_ERR_MSK)
  		return 1;
  
  	return 0;
  }
  
  /**
    * @brief  Clear the status of the error.
    * @param  ch: Channel.
    * @retval None
    */
  void ald_usb_dma_clear_channel_error(uint8_t ch)
  {
  	USB0->DMA_CH[ch].DMA_CNTL &= ~(USB_DMA_CH_ERR_MSK);
  }
  /**
    * @}
    */
  
  /** @defgroup USB_Public_Functions_Group8 LPM functions
    * @brief LPM functions
    * @{
    */
  /**
    * @brief  Transmit a LPM transaction in host mode.
    * @param  addr: Address.
    * @param  ep_idx: Index of the endpoint.
    * @retval None
    */
  void ald_usb_host_lpm_send(uint32_t addr, uint32_t ep_idx)
  {
  	uint32_t tmp;
  
  	USB0->LPM_FADDR = addr;
  
  	tmp = USB0->LPM_ATTR & ~(USB_LPMATTR_ENDPT_M);
  	tmp |= ep_idx << USB_LPMATTR_ENDPT_S;
  
  	USB0->LPM_ATTR = tmp;
  	USB0->LPM_CNTRL |= USB_LPMCNTRL_LPMXMT;
  }
  
  /**
    * @brief  Configure the LPM parameters in host mode.
    * @param  resume_time: Resume time.
    * @param  config: Parameters
    * @retval None
    */
  void ald_usb_host_lpm_config(uint32_t resume_time, uint32_t config)
  {
  	uint32_t tmp;
  
  	tmp  = USB0->LPM_ATTR;
  	tmp &= ~(USB_LPMATTR_HIRD_M);
  	tmp |= ((((resume_time - 50) / 75) & 0xF) << USB_LPMATTR_HIRD_S);
  	tmp |= config;
  	USB0->LPM_ATTR = tmp;
  }
  
  /**
    * @brief  Gets status of remote wakeup.
    * @retval Status.
    */
  uint32_t ald_usb_lpm_remote_wake_is_enable(void)
  {
  	if (USB0->LPM_ATTR & USB_LPMATTR_RMTWAK)
  		return 1;
  
  	return 0;
  }
  
  /**
    * @brief  Initiate a RESUME from the L1 state in host mode.
    * @retval None
    */
  void ald_usb_host_lpm_resume(void)
  {
  	USB0->LPM_CNTRL |= USB_LPMCNTRL_LPMRES;
  }
  
  /**
    * @brief  Enable remote wakeup in device mode.
    * @retval None
    */
  void ald_usb_dev_lpm_remote_wake(void)
  {
  	USB0->LPM_CNTRL |= USB_LPMCNTRL_LPMRES;
  }
  
  /**
    * @brief  Enable remote wakeup in device mode.
    * @retval None
    */
  void ald_usb_dev_lpm_config(uint32_t config)
  {
  	USB0->LPM_CNTRL = config;
  }
  
  /**
    * @brief  Enable LPM in device mode.
    * @retval None
    */
  void ald_usb_dev_lpm_enable(void)
  {
  	USB0->LPM_CNTRL |= (USB_LPMCNTRL_LPMXMT | USB_LPMCNTRL_ENABLE);
  }
  
  /**
    * @brief  Disable LPM in device mode.
    * @retval None
    */
  void ald_usb_dev_lpm_disable(void)
  {
  	USB0->LPM_CNTRL &= ~(USB_LPMCNTRL_LPMXMT);
  }
  
  /**
    * @brief  Gets the link status
    * @retval Status
    */
  uint32_t ald_usb_lpm_link_status_get(void)
  {
  	return (USB0->LPM_ATTR & USB_LPMATTR_LS_M);
  }
  
  /**
    * @brief  Gets the index of the endpoint.
    * @retval Index of the endpoint.
    */
  uint32_t ald_usb_lpm_ep_get(void)
  {
  	uint32_t tmp;
  
  	tmp  = USB0->LPM_ATTR;
  	tmp &= USB_LPMATTR_ENDPT_M;
  	tmp  = tmp >> USB_LPMATTR_ENDPT_S;
  
  	return tmp;
  }
  
  /**
    * @brief  Gets the status of the interrupt.
    * @retval Status.
    */
  uint32_t ald_usb_lpm_int_status_get(void)
  {
  	return USB0->LPM_INTR;
  }
  
  /**
    * @brief  Disable the LPM interrupt.
    * @retval None
    */
  void ald_usb_lpm_int_disable(uint32_t ints)
  {
  	USB0->LPM_INTREN &= ~ints;
  }
  
  /**
    * @brief  Enable the LPM interrupt.
    * @retval None
    */
  void ald_usb_lpm_int_enable(uint32_t ints)
  {
  	USB0->LPM_INTREN |= ints;
  }
  /**
    * @}
    */
  
  /**
    * @}
    */
  #endif
  /**
    * @}
    */
  
  /**
    * @}
    */
  