2021-08-19 20:28:28 +08:00
/*
2025-01-03 18:51:08 +01:00
* SPDX - FileCopyrightText : 2015 - 2025 Espressif Systems ( Shanghai ) CO LTD
2021-08-19 20:28:28 +08:00
*
* SPDX - License - Identifier : Apache - 2.0
*/
# include <esp_types.h>
# include <string.h>
2025-01-08 13:00:02 +01:00
# include "sdkconfig.h"
2021-08-19 20:28:28 +08:00
# include "esp_log.h"
# include "esp_check.h"
2021-10-25 17:13:46 +08:00
# include "esp_private/periph_ctrl.h"
2021-08-19 20:28:28 +08:00
# include "esp_private/usb_phy.h"
2024-10-07 13:51:09 +02:00
# include "esp_private/critical_section.h"
2024-01-16 16:43:42 +08:00
# include "soc/usb_dwc_periph.h"
2024-03-14 21:20:33 +08:00
# include "hal/usb_wrap_hal.h"
2025-01-08 13:00:02 +01:00
# include "hal/usb_utmi_hal.h"
2021-08-19 20:28:28 +08:00
# include "esp_rom_gpio.h"
# include "driver/gpio.h"
2023-10-27 18:23:50 +08:00
# include "soc/soc_caps.h"
2021-08-19 20:28:28 +08:00
2023-10-27 18:23:50 +08:00
# if !SOC_RCC_IS_INDEPENDENT
2024-11-22 11:18:46 +01:00
# define USB_PHY_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
2023-10-27 18:23:50 +08:00
# else
2024-11-22 11:18:46 +01:00
# define USB_PHY_RCC_ATOMIC()
2023-10-27 18:23:50 +08:00
# endif
2021-08-19 20:28:28 +08:00
static const char * USBPHY_TAG = " usb_phy " ;
# define USBPHY_NOT_INIT_ERR_STR "USB_PHY is not initialized"
typedef struct phy_context_t phy_context_t ;
struct phy_context_t {
usb_phy_target_t target ; /**< PHY target */
usb_phy_controller_t controller ; /**< PHY controller */
usb_phy_status_t status ; /**< PHY status */
usb_otg_mode_t otg_mode ; /**< USB OTG mode */
usb_phy_speed_t otg_speed ; /**< USB speed */
2022-10-06 09:04:53 +02:00
usb_phy_ext_io_conf_t * iopins ; /**< external PHY I/O pins */
2024-04-02 21:10:35 +08:00
usb_wrap_hal_context_t wrap_hal ; /**< USB WRAP HAL context */
2021-08-19 20:28:28 +08:00
} ;
typedef struct {
2025-01-08 13:00:02 +01:00
phy_context_t * fsls_phy ; /**< internal FSLS PHY context */
phy_context_t * utmi_phy ; /**< internal UTMI PHY context */
2021-08-19 20:28:28 +08:00
phy_context_t * external_phy ; /**< external PHY context */
uint32_t ref_count ; /**< reference count used to protect p_phy_ctrl_obj */
} phy_ctrl_obj_t ;
static phy_ctrl_obj_t * p_phy_ctrl_obj = NULL ;
2025-01-08 13:00:02 +01:00
// Mapping of OTG1.1 peripheral in usb_dwc_info struct
# if CONFIG_IDF_TARGET_ESP32P4
static const int otg11_index = 1 ;
# else
static const int otg11_index = 0 ;
# endif
2024-10-07 13:51:09 +02:00
DEFINE_CRIT_SECTION_LOCK_STATIC ( phy_spinlock ) ;
# define PHY_ENTER_CRITICAL() esp_os_enter_critical(&phy_spinlock)
# define PHY_EXIT_CRITICAL() esp_os_exit_critical(&phy_spinlock)
2021-08-19 20:28:28 +08:00
2024-12-18 17:04:22 +01:00
static esp_err_t phy_configure_pin_input ( int gpio_pin , int signal_idx )
2021-08-19 20:28:28 +08:00
{
2024-12-18 17:04:22 +01:00
if ( gpio_pin ! = GPIO_NUM_NC ) {
ESP_RETURN_ON_FALSE ( GPIO_IS_VALID_GPIO ( gpio_pin ) ,
ESP_ERR_INVALID_ARG , USBPHY_TAG , " io_num argument is invalid " ) ;
esp_rom_gpio_pad_select_gpio ( gpio_pin ) ;
esp_rom_gpio_connect_in_signal ( gpio_pin , signal_idx , false ) ;
gpio_input_enable ( gpio_pin ) ;
esp_rom_gpio_pad_unhold ( gpio_pin ) ;
}
return ESP_OK ;
}
static esp_err_t phy_configure_pin_output ( int gpio_pin , int signal_idx )
{
if ( gpio_pin ! = GPIO_NUM_NC ) {
ESP_RETURN_ON_FALSE ( GPIO_IS_VALID_OUTPUT_GPIO ( gpio_pin ) ,
ESP_ERR_INVALID_ARG , USBPHY_TAG , " io_num argument is invalid " ) ;
esp_rom_gpio_pad_select_gpio ( gpio_pin ) ;
esp_rom_gpio_connect_out_signal ( gpio_pin , signal_idx , false , false ) ;
esp_rom_gpio_pad_unhold ( gpio_pin ) ;
2021-08-19 20:28:28 +08:00
}
return ESP_OK ;
}
2025-01-03 18:51:08 +01:00
static esp_err_t phy_external_iopins_configure ( const usb_phy_ext_io_conf_t * ext_io_conf , const usb_fsls_serial_signal_conn_t * fsls_sig )
2022-10-06 09:04:53 +02:00
{
2025-01-03 18:51:08 +01:00
ESP_RETURN_ON_FALSE ( ext_io_conf & & fsls_sig , ESP_ERR_INVALID_ARG , USBPHY_TAG , " argument is invalid " ) ;
2024-12-18 17:04:22 +01:00
esp_err_t ret = ESP_OK ;
// Inputs
ret | = phy_configure_pin_input ( ext_io_conf - > vp_io_num , fsls_sig - > rx_dp ) ;
ret | = phy_configure_pin_input ( ext_io_conf - > vm_io_num , fsls_sig - > rx_dm ) ;
ret | = phy_configure_pin_input ( ext_io_conf - > rcv_io_num , fsls_sig - > rx_rcv ) ;
2022-10-06 09:04:53 +02:00
2024-12-18 17:04:22 +01:00
// Outputs
ret | = phy_configure_pin_output ( ext_io_conf - > suspend_n_io_num , fsls_sig - > suspend_n ) ;
ret | = phy_configure_pin_output ( ext_io_conf - > oen_io_num , fsls_sig - > tx_enable_n ) ;
ret | = phy_configure_pin_output ( ext_io_conf - > vpo_io_num , fsls_sig - > tx_dp ) ;
ret | = phy_configure_pin_output ( ext_io_conf - > vmo_io_num , fsls_sig - > tx_dm ) ;
ret | = phy_configure_pin_output ( ext_io_conf - > fs_edge_sel_io_num , fsls_sig - > fs_edge_sel ) ;
return ret ;
2022-10-06 09:04:53 +02:00
}
2025-01-03 18:51:08 +01:00
static esp_err_t phy_otg_iopins_configure ( const usb_phy_otg_io_conf_t * otg_io_conf , const usb_otg_signal_conn_t * otg_sig )
2022-10-06 09:04:53 +02:00
{
2025-01-03 18:51:08 +01:00
ESP_RETURN_ON_FALSE ( otg_io_conf & & otg_sig , ESP_ERR_INVALID_ARG , USBPHY_TAG , " argument is invalid " ) ;
2024-12-18 17:04:22 +01:00
esp_err_t ret = ESP_OK ;
// Inputs
ret | = phy_configure_pin_input ( otg_io_conf - > iddig_io_num , otg_sig - > iddig ) ;
ret | = phy_configure_pin_input ( otg_io_conf - > avalid_io_num , otg_sig - > avalid ) ;
ret | = phy_configure_pin_input ( otg_io_conf - > vbusvalid_io_num , otg_sig - > vbusvalid ) ;
ret | = phy_configure_pin_input ( otg_io_conf - > bvalid_io_num , otg_sig - > bvalid ) ;
ret | = phy_configure_pin_input ( otg_io_conf - > sessend_io_num , otg_sig - > sessend ) ;
// Outputs
ret | = phy_configure_pin_output ( otg_io_conf - > idpullup_io_num , otg_sig - > idpullup ) ;
ret | = phy_configure_pin_output ( otg_io_conf - > dppulldown_io_num , otg_sig - > dppulldown ) ;
ret | = phy_configure_pin_output ( otg_io_conf - > dmpulldown_io_num , otg_sig - > dmpulldown ) ;
ret | = phy_configure_pin_output ( otg_io_conf - > drvvbus_io_num , otg_sig - > drvvbus ) ;
ret | = phy_configure_pin_output ( otg_io_conf - > chrgvbus_io_num , otg_sig - > chrgvbus ) ;
ret | = phy_configure_pin_output ( otg_io_conf - > dischrgvbus_io_num , otg_sig - > dischrgvbus ) ;
return ret ;
2022-10-06 09:04:53 +02:00
}
2021-08-19 20:28:28 +08:00
esp_err_t usb_phy_otg_set_mode ( usb_phy_handle_t handle , usb_otg_mode_t mode )
{
ESP_RETURN_ON_FALSE ( handle , ESP_ERR_INVALID_ARG , USBPHY_TAG , " handle argument is invalid " ) ;
ESP_RETURN_ON_FALSE ( mode < USB_OTG_MODE_MAX , ESP_ERR_INVALID_ARG , USBPHY_TAG , " mode argument is invalid " ) ;
ESP_RETURN_ON_FALSE ( handle - > controller = = USB_PHY_CTRL_OTG , ESP_FAIL , USBPHY_TAG , " phy source is not USB_OTG " ) ;
handle - > otg_mode = mode ;
2025-01-08 13:00:02 +01:00
// On targets with multiple internal PHYs (FSLS and UTMI)
// we support only fixed PHY to USB-DWC mapping:
// USB-DWC2.0 <-> UTMI PHY
// USB-DWC1.1 <-> FSLS PHY
if ( handle - > target = = USB_PHY_TARGET_UTMI ) {
return ESP_OK ; // No need to configure anything for UTMI PHY
}
const usb_otg_signal_conn_t * otg_sig = usb_dwc_info . controllers [ otg11_index ] . otg_signals ;
2025-01-03 18:51:08 +01:00
assert ( otg_sig ) ;
2021-08-19 20:28:28 +08:00
if ( mode = = USB_OTG_MODE_HOST ) {
2025-01-03 18:51:08 +01:00
esp_rom_gpio_connect_in_signal ( GPIO_MATRIX_CONST_ZERO_INPUT , otg_sig - > iddig , false ) ; // connected connector is A side
esp_rom_gpio_connect_in_signal ( GPIO_MATRIX_CONST_ZERO_INPUT , otg_sig - > bvalid , false ) ;
esp_rom_gpio_connect_in_signal ( GPIO_MATRIX_CONST_ONE_INPUT , otg_sig - > vbusvalid , false ) ; // receiving a valid Vbus from host
2025-01-08 13:00:02 +01:00
esp_rom_gpio_connect_in_signal ( GPIO_MATRIX_CONST_ONE_INPUT , otg_sig - > avalid , false ) ; // HIGH to force USB host mode
2021-08-19 20:28:28 +08:00
if ( handle - > target = = USB_PHY_TARGET_INT ) {
2024-04-02 21:10:35 +08:00
// Configure pull resistors for host
usb_wrap_pull_override_vals_t vals = {
. dp_pu = false ,
. dm_pu = false ,
. dp_pd = true ,
. dm_pd = true ,
} ;
usb_wrap_hal_phy_enable_pull_override ( & handle - > wrap_hal , & vals ) ;
2021-08-19 20:28:28 +08:00
}
} else if ( mode = = USB_OTG_MODE_DEVICE ) {
2025-01-03 18:51:08 +01:00
esp_rom_gpio_connect_in_signal ( GPIO_MATRIX_CONST_ONE_INPUT , otg_sig - > iddig , false ) ; // connected connector is mini-B side
esp_rom_gpio_connect_in_signal ( GPIO_MATRIX_CONST_ONE_INPUT , otg_sig - > bvalid , false ) ; // HIGH to force USB device mode
esp_rom_gpio_connect_in_signal ( GPIO_MATRIX_CONST_ONE_INPUT , otg_sig - > vbusvalid , false ) ; // receiving a valid Vbus from device
esp_rom_gpio_connect_in_signal ( GPIO_MATRIX_CONST_ZERO_INPUT , otg_sig - > avalid , false ) ;
2021-08-19 20:28:28 +08:00
}
return ESP_OK ;
}
esp_err_t usb_phy_otg_dev_set_speed ( usb_phy_handle_t handle , usb_phy_speed_t speed )
{
ESP_RETURN_ON_FALSE ( handle , ESP_ERR_INVALID_ARG , USBPHY_TAG , " handle argument is invalid " ) ;
ESP_RETURN_ON_FALSE ( speed < USB_PHY_SPEED_MAX , ESP_ERR_INVALID_ARG , USBPHY_TAG , " speed argument is invalid " ) ;
ESP_RETURN_ON_FALSE ( handle - > controller = = USB_PHY_CTRL_OTG , ESP_FAIL , USBPHY_TAG , " phy source is not USB_OTG " ) ;
2025-01-08 13:00:02 +01:00
ESP_RETURN_ON_FALSE ( ( handle - > target ! = USB_PHY_TARGET_EXT & & handle - > otg_mode = = USB_OTG_MODE_DEVICE ) , ESP_FAIL ,
2021-08-19 20:28:28 +08:00
USBPHY_TAG , " set speed not supported " ) ;
2025-01-08 13:00:02 +01:00
ESP_RETURN_ON_FALSE ( ( handle - > target = = USB_PHY_TARGET_UTMI ) = = ( speed = = USB_PHY_SPEED_HIGH ) , ESP_ERR_NOT_SUPPORTED , USBPHY_TAG , " UTMI can be HighSpeed only " ) ; // This is our software limitation
2021-08-19 20:28:28 +08:00
handle - > otg_speed = speed ;
2025-01-08 13:00:02 +01:00
if ( handle - > target = = USB_PHY_TARGET_UTMI ) {
return ESP_OK ; // No need to configure anything for UTMI PHY
}
2024-04-02 21:10:35 +08:00
// Configure pull resistors for device
usb_wrap_pull_override_vals_t vals = {
. dp_pd = false ,
. dm_pd = false ,
} ;
if ( speed = = USB_PHY_SPEED_LOW ) {
vals . dp_pu = false ;
vals . dm_pu = true ;
} else {
vals . dp_pu = true ;
vals . dm_pu = false ;
}
usb_wrap_hal_phy_enable_pull_override ( & handle - > wrap_hal , & vals ) ;
2021-08-19 20:28:28 +08:00
return ESP_OK ;
}
esp_err_t usb_phy_action ( usb_phy_handle_t handle , usb_phy_action_t action )
{
ESP_RETURN_ON_FALSE ( handle , ESP_ERR_INVALID_ARG , USBPHY_TAG , " handle argument is invalid " ) ;
2025-01-08 13:00:02 +01:00
ESP_RETURN_ON_FALSE ( handle - > target ! = USB_PHY_TARGET_UTMI , ESP_ERR_NOT_SUPPORTED , USBPHY_TAG , " Operation not supported on UTMI PHY " ) ;
2021-08-19 20:28:28 +08:00
ESP_RETURN_ON_FALSE ( action < USB_PHY_ACTION_MAX , ESP_ERR_INVALID_ARG , USBPHY_TAG , " action argument is invalid " ) ;
ESP_RETURN_ON_FALSE ( ( action = = USB_PHY_ACTION_HOST_ALLOW_CONN & & handle - > controller = = USB_PHY_CTRL_OTG ) | |
( action = = USB_PHY_ACTION_HOST_FORCE_DISCONN & & handle - > controller = = USB_PHY_CTRL_OTG ) ,
ESP_ERR_INVALID_ARG , USBPHY_TAG , " wrong target for the action " ) ;
esp_err_t ret = ESP_OK ;
2025-01-08 13:00:02 +01:00
const usb_fsls_serial_signal_conn_t * fsls_sig = usb_dwc_info . controllers [ otg11_index ] . fsls_signals ;
2025-01-03 18:51:08 +01:00
assert ( fsls_sig ) ;
2021-08-19 20:28:28 +08:00
switch ( action ) {
2023-05-09 00:53:27 +08:00
case USB_PHY_ACTION_HOST_ALLOW_CONN :
if ( handle - > target = = USB_PHY_TARGET_INT ) {
2024-04-02 21:10:35 +08:00
usb_wrap_hal_phy_enable_test_mode ( & handle - > wrap_hal , false ) ;
2023-05-09 00:53:27 +08:00
} else {
if ( ! handle - > iopins ) {
ret = ESP_FAIL ;
ESP_LOGE ( USBPHY_TAG , " no I/O pins provided for connection " ) ;
break ;
2021-08-19 20:28:28 +08:00
}
2023-05-09 00:53:27 +08:00
/*
Allow for connections on the external PHY by connecting the VP and VM signals to the external PHY .
*/
2025-01-03 18:51:08 +01:00
esp_rom_gpio_connect_in_signal ( handle - > iopins - > vp_io_num , fsls_sig - > rx_dp , false ) ;
esp_rom_gpio_connect_in_signal ( handle - > iopins - > vm_io_num , fsls_sig - > rx_dm , false ) ;
2023-05-09 00:53:27 +08:00
}
break ;
2021-08-19 20:28:28 +08:00
2023-05-09 00:53:27 +08:00
case USB_PHY_ACTION_HOST_FORCE_DISCONN :
if ( handle - > target = = USB_PHY_TARGET_INT ) {
2024-04-02 21:10:35 +08:00
/*
We mimic a disconnect by enabling the internal PHY ' s test mode ,
then forcing the output_enable to HIGH . This will cause the received
VP and VM to be zero , thus mimicking a disconnection .
*/
const usb_wrap_test_mode_vals_t vals = {
. tx_enable_n = true ,
. tx_dp = false ,
. tx_dm = false ,
. rx_dp = false ,
. rx_dm = false ,
. rx_rcv = false ,
} ;
usb_wrap_hal_phy_test_mode_set_signals ( & handle - > wrap_hal , & vals ) ;
usb_wrap_hal_phy_enable_test_mode ( & handle - > wrap_hal , true ) ;
2023-05-09 00:53:27 +08:00
} else {
/*
Disable connections on the external PHY by connecting the VP and VM signals to the constant LOW signal .
*/
2025-01-03 18:51:08 +01:00
esp_rom_gpio_connect_in_signal ( GPIO_MATRIX_CONST_ZERO_INPUT , fsls_sig - > rx_dp , false ) ;
esp_rom_gpio_connect_in_signal ( GPIO_MATRIX_CONST_ZERO_INPUT , fsls_sig - > rx_dm , false ) ;
2023-05-09 00:53:27 +08:00
}
break ;
2021-08-19 20:28:28 +08:00
2023-05-09 00:53:27 +08:00
default :
break ;
2021-08-19 20:28:28 +08:00
}
return ret ;
}
static esp_err_t usb_phy_install ( void )
{
2024-10-07 13:51:09 +02:00
PHY_ENTER_CRITICAL ( ) ;
2021-08-19 20:28:28 +08:00
if ( p_phy_ctrl_obj ) {
// p_phy_ctrl_obj already installed, return immediately
2024-10-07 13:51:09 +02:00
PHY_EXIT_CRITICAL ( ) ;
2021-08-19 20:28:28 +08:00
return ESP_OK ;
}
2024-10-07 13:51:09 +02:00
PHY_EXIT_CRITICAL ( ) ;
2021-08-19 20:28:28 +08:00
esp_err_t ret = ESP_OK ;
phy_ctrl_obj_t * phy_ctrl_obj = ( phy_ctrl_obj_t * ) calloc ( 1 , sizeof ( phy_ctrl_obj_t ) ) ;
ESP_GOTO_ON_FALSE ( phy_ctrl_obj , ESP_ERR_NO_MEM , cleanup , USBPHY_TAG , " no mem for USB_PHY driver " ) ;
2024-10-07 13:51:09 +02:00
PHY_ENTER_CRITICAL ( ) ;
2021-08-19 20:28:28 +08:00
if ( ! p_phy_ctrl_obj ) {
p_phy_ctrl_obj = phy_ctrl_obj ;
p_phy_ctrl_obj - > ref_count = 0 ;
} else {
// p_phy_ctrl_obj already installed, need to free resource
2024-10-07 13:51:09 +02:00
PHY_EXIT_CRITICAL ( ) ;
2021-08-19 20:28:28 +08:00
goto cleanup ;
}
2024-10-07 13:51:09 +02:00
PHY_EXIT_CRITICAL ( ) ;
2021-08-19 20:28:28 +08:00
return ESP_OK ;
cleanup :
free ( phy_ctrl_obj ) ;
return ret ;
}
esp_err_t usb_new_phy ( const usb_phy_config_t * config , usb_phy_handle_t * handle_ret )
{
2025-01-08 13:00:02 +01:00
usb_phy_target_t phy_target = config - > target ;
// Backward compatibility code:
// Initial P4 device support was for USB-DWC HS and UTMI PHY.
// To maintain backward compatibility on ESP32-P4 in USB Device mode, we select UTMI PHY
// In case otg_speed is UNDEFINED or HIGH
# if CONFIG_IDF_TARGET_ESP32P4
if ( config - > otg_mode = = USB_OTG_MODE_DEVICE & &
( config - > otg_speed = = USB_PHY_SPEED_UNDEFINED | | config - > otg_speed = = USB_PHY_SPEED_HIGH ) ) {
if ( phy_target ! = USB_PHY_TARGET_UTMI ) {
ESP_LOGW ( USBPHY_TAG , " Using UTMI PHY instead of requested %s PHY " , ( phy_target = = USB_PHY_TARGET_INT ) ? " internal " : " external " ) ;
phy_target = USB_PHY_TARGET_UTMI ;
}
}
# endif
2021-08-19 20:28:28 +08:00
ESP_RETURN_ON_FALSE ( config , ESP_ERR_INVALID_ARG , USBPHY_TAG , " config argument is invalid " ) ;
2025-01-08 13:00:02 +01:00
ESP_RETURN_ON_FALSE ( phy_target < USB_PHY_TARGET_MAX , ESP_ERR_INVALID_ARG , USBPHY_TAG , " specified PHY argument is invalid " ) ;
2021-08-19 20:28:28 +08:00
ESP_RETURN_ON_FALSE ( config - > controller < USB_PHY_CTRL_MAX , ESP_ERR_INVALID_ARG , USBPHY_TAG , " specified source argument is invalid " ) ;
2025-01-08 13:00:02 +01:00
ESP_RETURN_ON_FALSE ( phy_target ! = USB_PHY_TARGET_EXT | | config - > ext_io_conf , ESP_ERR_INVALID_ARG , USBPHY_TAG , " ext_io_conf must be provided for ext PHY " ) ;
2025-01-03 18:51:08 +01:00
# if !USB_WRAP_LL_EXT_PHY_SUPPORTED
2025-01-08 13:00:02 +01:00
ESP_RETURN_ON_FALSE ( phy_target ! = USB_PHY_TARGET_EXT , ESP_ERR_NOT_SUPPORTED , USBPHY_TAG , " Ext PHY not supported on this target " ) ;
2025-01-03 18:51:08 +01:00
# endif
# if !SOC_USB_UTMI_PHY_NUM
2025-01-08 13:00:02 +01:00
ESP_RETURN_ON_FALSE ( phy_target ! = USB_PHY_TARGET_UTMI , ESP_ERR_NOT_SUPPORTED , USBPHY_TAG , " UTMI PHY not supported on this target " ) ;
2025-01-03 18:51:08 +01:00
# endif
2021-08-19 20:28:28 +08:00
ESP_RETURN_ON_ERROR ( usb_phy_install ( ) , USBPHY_TAG , " usb_phy driver installation failed " ) ;
esp_err_t ret = ESP_OK ;
bool new_phy = false ;
phy_context_t * phy_context = ( phy_context_t * ) calloc ( 1 , sizeof ( phy_context_t ) ) ;
ESP_GOTO_ON_FALSE ( phy_context , ESP_ERR_NO_MEM , cleanup , USBPHY_TAG , " no mem for phy context " ) ;
2024-10-07 13:51:09 +02:00
PHY_ENTER_CRITICAL ( ) ;
2025-01-08 13:00:02 +01:00
usb_phy_get_phy_status ( phy_target , & phy_context - > status ) ;
2021-08-19 20:28:28 +08:00
if ( phy_context - > status = = USB_PHY_STATUS_FREE ) {
new_phy = true ;
p_phy_ctrl_obj - > ref_count + + ;
2025-01-08 13:00:02 +01:00
if ( phy_target = = USB_PHY_TARGET_EXT ) {
2021-08-19 20:28:28 +08:00
p_phy_ctrl_obj - > external_phy = phy_context ;
2025-01-08 13:00:02 +01:00
} else if ( phy_target = = USB_PHY_TARGET_INT ) {
p_phy_ctrl_obj - > fsls_phy = phy_context ;
} else { // USB_PHY_TARGET_UTMI
p_phy_ctrl_obj - > utmi_phy = phy_context ;
2021-08-19 20:28:28 +08:00
}
}
2024-10-07 13:51:09 +02:00
PHY_EXIT_CRITICAL ( ) ;
2021-08-19 20:28:28 +08:00
ESP_GOTO_ON_FALSE ( new_phy , ESP_ERR_INVALID_STATE , cleanup , USBPHY_TAG , " selected PHY is in use " ) ;
2025-01-08 13:00:02 +01:00
phy_context - > target = phy_target ;
2021-08-19 20:28:28 +08:00
phy_context - > controller = config - > controller ;
phy_context - > status = USB_PHY_STATUS_IN_USE ;
2025-01-08 13:00:02 +01:00
if ( phy_target ! = USB_PHY_TARGET_UTMI ) {
USB_PHY_RCC_ATOMIC ( ) {
usb_wrap_hal_init ( & phy_context - > wrap_hal ) ;
}
} else {
# if (SOC_USB_UTMI_PHY_NUM > 0)
usb_utmi_hal_context_t utmi_hal_context ; // Unused for now
USB_PHY_RCC_ATOMIC ( ) {
usb_utmi_hal_init ( & utmi_hal_context ) ;
}
# endif
2024-11-22 11:18:46 +01:00
}
2021-08-19 20:28:28 +08:00
if ( config - > controller = = USB_PHY_CTRL_OTG ) {
2024-04-02 19:55:44 +08:00
# if USB_WRAP_LL_EXT_PHY_SUPPORTED
2025-01-08 13:00:02 +01:00
usb_wrap_hal_phy_set_external ( & phy_context - > wrap_hal , ( phy_target = = USB_PHY_TARGET_EXT ) ) ;
2024-04-02 19:55:44 +08:00
# endif
2021-08-19 20:28:28 +08:00
}
2025-01-08 13:00:02 +01:00
// For FSLS PHY that shares pads with GPIO peripheral, we must set drive capability to 3 (40mA)
if ( phy_target = = USB_PHY_TARGET_INT ) {
2025-01-20 21:08:43 +01:00
assert ( usb_dwc_info . controllers [ otg11_index ] . internal_phy_io ) ;
gpio_set_drive_capability ( usb_dwc_info . controllers [ otg11_index ] . internal_phy_io - > dm , GPIO_DRIVE_CAP_3 ) ;
gpio_set_drive_capability ( usb_dwc_info . controllers [ otg11_index ] . internal_phy_io - > dp , GPIO_DRIVE_CAP_3 ) ;
2021-08-19 20:28:28 +08:00
}
* handle_ret = ( usb_phy_handle_t ) phy_context ;
2025-01-08 13:00:02 +01:00
if ( phy_target = = USB_PHY_TARGET_EXT ) {
2022-10-06 09:04:53 +02:00
phy_context - > iopins = ( usb_phy_ext_io_conf_t * ) calloc ( 1 , sizeof ( usb_phy_ext_io_conf_t ) ) ;
2021-08-19 20:28:28 +08:00
ESP_GOTO_ON_FALSE ( phy_context - > iopins , ESP_ERR_NO_MEM , cleanup , USBPHY_TAG , " no mem for storing I/O pins " ) ;
2022-10-06 09:04:53 +02:00
memcpy ( phy_context - > iopins , config - > ext_io_conf , sizeof ( usb_phy_ext_io_conf_t ) ) ;
2025-01-08 13:00:02 +01:00
const usb_fsls_serial_signal_conn_t * fsls_sig = usb_dwc_info . controllers [ otg11_index ] . fsls_signals ;
2025-01-03 18:51:08 +01:00
ESP_ERROR_CHECK ( phy_external_iopins_configure ( phy_context - > iopins , fsls_sig ) ) ;
2021-08-19 20:28:28 +08:00
}
if ( config - > otg_mode ! = USB_PHY_MODE_DEFAULT ) {
ESP_ERROR_CHECK ( usb_phy_otg_set_mode ( * handle_ret , config - > otg_mode ) ) ;
}
if ( config - > otg_speed ! = USB_PHY_SPEED_UNDEFINED ) {
ESP_ERROR_CHECK ( usb_phy_otg_dev_set_speed ( * handle_ret , config - > otg_speed ) ) ;
}
2022-10-06 09:04:53 +02:00
if ( config - > otg_io_conf & & ( phy_context - > controller = = USB_PHY_CTRL_OTG ) ) {
2025-01-08 13:00:02 +01:00
const usb_otg_signal_conn_t * otg_sig = usb_dwc_info . controllers [ otg11_index ] . otg_signals ;
2025-01-03 18:51:08 +01:00
ESP_ERROR_CHECK ( phy_otg_iopins_configure ( config - > otg_io_conf , otg_sig ) ) ;
2022-10-06 09:04:53 +02:00
}
2021-08-19 20:28:28 +08:00
return ESP_OK ;
cleanup :
2024-06-18 00:17:15 +07:00
if ( phy_context ) {
free ( phy_context - > iopins ) ;
free ( phy_context ) ;
}
2021-08-19 20:28:28 +08:00
if ( p_phy_ctrl_obj - > ref_count = = 0 ) {
free ( p_phy_ctrl_obj ) ;
p_phy_ctrl_obj = NULL ;
}
return ret ;
}
static void phy_uninstall ( void )
{
phy_ctrl_obj_t * p_phy_ctrl_obj_free = NULL ;
2024-10-07 13:51:09 +02:00
PHY_ENTER_CRITICAL ( ) ;
2021-08-19 20:28:28 +08:00
if ( p_phy_ctrl_obj - > ref_count = = 0 ) {
p_phy_ctrl_obj_free = p_phy_ctrl_obj ;
p_phy_ctrl_obj = NULL ;
2024-11-22 11:18:46 +01:00
USB_PHY_RCC_ATOMIC ( ) {
2023-10-27 18:23:50 +08:00
// Disable USB peripheral without reset the module
2024-11-22 11:18:46 +01:00
usb_wrap_hal_disable ( ) ;
2025-01-08 13:00:02 +01:00
# if (SOC_USB_UTMI_PHY_NUM > 0)
usb_utmi_hal_disable ( ) ;
# endif
2023-10-27 18:23:50 +08:00
}
2021-08-19 20:28:28 +08:00
}
2024-10-07 13:51:09 +02:00
PHY_EXIT_CRITICAL ( ) ;
2021-08-19 20:28:28 +08:00
free ( p_phy_ctrl_obj_free ) ;
}
esp_err_t usb_del_phy ( usb_phy_handle_t handle )
{
ESP_RETURN_ON_FALSE ( handle , ESP_ERR_INVALID_ARG , USBPHY_TAG , " handle argument is invalid " ) ;
2024-10-07 13:51:09 +02:00
PHY_ENTER_CRITICAL ( ) ;
2021-08-19 20:28:28 +08:00
p_phy_ctrl_obj - > ref_count - - ;
if ( handle - > target = = USB_PHY_TARGET_EXT ) {
p_phy_ctrl_obj - > external_phy = NULL ;
2025-01-08 13:00:02 +01:00
} else if ( handle - > target = = USB_PHY_TARGET_INT ) {
2023-10-27 18:23:50 +08:00
// Clear pullup and pulldown loads on D+ / D-, and disable the pads
2024-04-02 21:10:35 +08:00
usb_wrap_hal_phy_disable_pull_override ( & handle - > wrap_hal ) ;
2025-01-08 13:00:02 +01:00
p_phy_ctrl_obj - > fsls_phy = NULL ;
} else { // USB_PHY_TARGET_UTMI
p_phy_ctrl_obj - > utmi_phy = NULL ;
2021-08-19 20:28:28 +08:00
}
2024-10-07 13:51:09 +02:00
PHY_EXIT_CRITICAL ( ) ;
2021-08-19 20:28:28 +08:00
free ( handle - > iopins ) ;
free ( handle ) ;
phy_uninstall ( ) ;
return ESP_OK ;
}
esp_err_t usb_phy_get_phy_status ( usb_phy_target_t target , usb_phy_status_t * status )
{
ESP_RETURN_ON_FALSE ( target < USB_PHY_TARGET_MAX , ESP_ERR_INVALID_ARG , USBPHY_TAG , " argument is invalid " ) ;
ESP_RETURN_ON_FALSE ( p_phy_ctrl_obj , ESP_ERR_INVALID_STATE , USBPHY_TAG , USBPHY_NOT_INIT_ERR_STR ) ;
if ( target = = USB_PHY_TARGET_EXT & & p_phy_ctrl_obj - > external_phy ) {
* status = p_phy_ctrl_obj - > external_phy - > status ;
2025-01-08 13:00:02 +01:00
} else if ( target = = USB_PHY_TARGET_INT & & p_phy_ctrl_obj - > fsls_phy ) {
* status = p_phy_ctrl_obj - > fsls_phy - > status ;
} else if ( target = = USB_PHY_TARGET_UTMI & & p_phy_ctrl_obj - > utmi_phy ) {
* status = p_phy_ctrl_obj - > utmi_phy - > status ;
2021-08-19 20:28:28 +08:00
} else {
* status = USB_PHY_STATUS_FREE ;
}
return ESP_OK ;
}