kopia lustrzana https://github.com/espressif/esp-idf
usb: Add usb_phy driver to support operations on USB PHY
rodzic
7fc071e133
commit
1fcd639224
|
@ -61,6 +61,7 @@ if(NOT BOOTLOADER_BUILD)
|
|||
"systimer_hal.c"
|
||||
"touch_sensor_hal.c"
|
||||
"usb_hal.c"
|
||||
"usb_phy_hal.c"
|
||||
"xt_wdt_hal.c"
|
||||
"esp32s2/adc_hal.c"
|
||||
"esp32s2/brownout_hal.c"
|
||||
|
@ -83,6 +84,7 @@ if(NOT BOOTLOADER_BUILD)
|
|||
"systimer_hal.c"
|
||||
"touch_sensor_hal.c"
|
||||
"usb_hal.c"
|
||||
"usb_phy_hal.c"
|
||||
"xt_wdt_hal.c"
|
||||
"esp32s3/brownout_hal.c"
|
||||
"esp32s3/hmac_hal.c"
|
||||
|
|
|
@ -2,7 +2,7 @@ COMPONENT_SRCDIRS := . esp32
|
|||
COMPONENT_ADD_INCLUDEDIRS := esp32/include include platform_port/include
|
||||
COMPONENT_ADD_LDFRAGMENTS += linker.lf
|
||||
|
||||
COMPONENT_OBJEXCLUDE += ./spi_slave_hd_hal.o ./spi_flash_hal_gpspi.o ./spi_slave_hd_hal.o ./ds_hal.o ./gdma_hal.o ./lcd_hal.o ./systimer_hal.o ./usb_hal.o ./usbh_hal.o ./xt_wdt_hal.o
|
||||
COMPONENT_OBJEXCLUDE += ./spi_slave_hd_hal.o ./spi_flash_hal_gpspi.o ./spi_slave_hd_hal.o ./ds_hal.o ./gdma_hal.o ./lcd_hal.o ./systimer_hal.o ./usb_hal.o ./usbh_hal.o ./usb_phy_hal.o ./xt_wdt_hal.o
|
||||
|
||||
ifndef CONFIG_ETH_USE_ESP32_EMAC
|
||||
COMPONENT_OBJEXCLUDE += ./emac_hal.o
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "soc/soc.h"
|
||||
#include "soc/system_reg.h"
|
||||
#include "soc/usb_wrap_struct.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Configures the internal PHY for USB_OTG
|
||||
*
|
||||
* @param hw Start address of the USB Wrap registers
|
||||
*/
|
||||
static inline void usb_phy_ll_int_otg_enable(usb_wrap_dev_t *hw)
|
||||
{
|
||||
//Enable internal PHY
|
||||
hw->otg_conf.pad_enable = 1;
|
||||
hw->otg_conf.phy_sel = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures the external PHY for USB_OTG
|
||||
*
|
||||
* @param hw Start address of the USB Wrap registers
|
||||
*/
|
||||
static inline void usb_phy_ll_ext_otg_enable(usb_wrap_dev_t *hw)
|
||||
{
|
||||
//Enable external PHY
|
||||
hw->otg_conf.phy_sel = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures port loads for the internal PHY
|
||||
*
|
||||
* @param hw Start address of the USB Wrap registers
|
||||
* @param dp_pu D+ pullup load
|
||||
* @param dp_pd D+ pulldown load
|
||||
* @param dm_pu D- pullup load
|
||||
* @param dm_pd D- pulldown load
|
||||
*/
|
||||
static inline void usb_phy_ll_int_load_conf(usb_wrap_dev_t *hw, bool dp_pu, bool dp_pd, bool dm_pu, bool dm_pd)
|
||||
{
|
||||
usb_wrap_otg_conf_reg_t conf = hw->otg_conf;
|
||||
conf.pad_pull_override = 1;
|
||||
conf.dp_pullup = dp_pu;
|
||||
conf.dp_pulldown = dp_pd;
|
||||
conf.dm_pullup = dm_pu;
|
||||
conf.dm_pulldown = dm_pd;
|
||||
hw->otg_conf = conf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the internal PHY's test mode
|
||||
*
|
||||
* @param hw Start address of the USB Wrap registers
|
||||
* @param en Whether to enable the internal PHY's test mode
|
||||
*/
|
||||
static inline void usb_phy_ll_int_enable_test_mode(usb_wrap_dev_t *hw, bool en)
|
||||
{
|
||||
if (en) {
|
||||
// Clear USB_WRAP_TEST_CONF_REG
|
||||
hw->test_conf.val = 0;
|
||||
// Set USB test pad oen
|
||||
hw->test_conf.test_usb_wrap_oe = 1;
|
||||
// Enable USB test mode
|
||||
hw->test_conf.test_enable = 1;
|
||||
} else {
|
||||
hw->test_conf.test_enable = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "soc/soc.h"
|
||||
#include "soc/system_reg.h"
|
||||
#include "soc/usb_wrap_struct.h"
|
||||
#include "soc/rtc_cntl_struct.h"
|
||||
#include "soc/usb_serial_jtag_struct.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Configures the internal PHY for USB_OTG
|
||||
*
|
||||
* @param hw Start address of the USB Wrap registers
|
||||
*/
|
||||
static inline void usb_phy_ll_int_otg_enable(usb_wrap_dev_t *hw)
|
||||
{
|
||||
hw->otg_conf.pad_enable = 1;
|
||||
// USB_OTG use internal PHY
|
||||
hw->otg_conf.phy_sel = 0;
|
||||
// phy_sel is controlled by the following register value
|
||||
RTCCNTL.usb_conf.sw_hw_usb_phy_sel = 1;
|
||||
// phy_sel=sw_usb_phy_sel=1, USB_OTG is connected with internal PHY
|
||||
RTCCNTL.usb_conf.sw_usb_phy_sel = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures the external PHY for USB_OTG
|
||||
*
|
||||
* @param hw Start address of the USB Wrap registers
|
||||
*/
|
||||
static inline void usb_phy_ll_ext_otg_enable(usb_wrap_dev_t *hw)
|
||||
{
|
||||
// USB_OTG use external PHY
|
||||
hw->otg_conf.phy_sel = 1;
|
||||
// phy_sel is controlled by the following register value
|
||||
RTCCNTL.usb_conf.sw_hw_usb_phy_sel = 1;
|
||||
// phy_sel=sw_usb_phy_sel=0, USB_OTG is connected with external PHY through GPIO Matrix
|
||||
RTCCNTL.usb_conf.sw_usb_phy_sel = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures the internal PHY for USB_Serial_JTAG
|
||||
*
|
||||
* @param hw Start address of the USB Serial_JTAG registers
|
||||
*/
|
||||
static inline void usb_phy_ll_int_jtag_enable(usb_serial_jtag_dev_t *hw)
|
||||
{
|
||||
// USB_Serial_JTAG use internal PHY
|
||||
hw->conf0.phy_sel = 0;
|
||||
// Disable software control USB D+ D- pullup pulldown (Device FS: dp_pullup = 1)
|
||||
hw->conf0.pad_pull_override = 0;
|
||||
// Enable USB pad function
|
||||
hw->conf0.usb_pad_enable = 1;
|
||||
// phy_sel is controlled by the following register value
|
||||
RTCCNTL.usb_conf.sw_hw_usb_phy_sel = 1;
|
||||
// phy_sel=sw_usb_phy_sel=0, USB_Serial_JTAG is connected with internal PHY
|
||||
RTCCNTL.usb_conf.sw_usb_phy_sel = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures the external PHY for USB_Serial_JTAG
|
||||
*
|
||||
* @param hw Start address of the USB Serial_JTAG registers
|
||||
*/
|
||||
static inline void usb_phy_ll_ext_jtag_enable(usb_serial_jtag_dev_t *hw)
|
||||
{
|
||||
// USB_Serial_JTAG use external PHY
|
||||
hw->conf0.phy_sel = 1;
|
||||
// phy_sel is controlled by the following register value
|
||||
RTCCNTL.usb_conf.sw_hw_usb_phy_sel = 1;
|
||||
// phy_sel=sw_usb_phy_sel=1, USB_Serial_JTAG is connected with external PHY
|
||||
RTCCNTL.usb_conf.sw_usb_phy_sel = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures port loads for the internal PHY
|
||||
*
|
||||
* @param hw Start address of the USB Wrap registers
|
||||
* @param dp_pu D+ pullup load
|
||||
* @param dp_pd D+ pulldown load
|
||||
* @param dm_pu D- pullup load
|
||||
* @param dm_pd D- pulldown load
|
||||
*/
|
||||
static inline void usb_phy_ll_int_load_conf(usb_wrap_dev_t *hw, bool dp_pu, bool dp_pd, bool dm_pu, bool dm_pd)
|
||||
{
|
||||
usb_wrap_otg_conf_reg_t conf = hw->otg_conf;
|
||||
conf.pad_pull_override = 1;
|
||||
conf.dp_pullup = dp_pu;
|
||||
conf.dp_pulldown = dp_pd;
|
||||
conf.dm_pullup = dm_pu;
|
||||
conf.dm_pulldown = dm_pd;
|
||||
hw->otg_conf = conf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the internal PHY's test mode
|
||||
*
|
||||
* @param hw Start address of the USB Wrap registers
|
||||
* @param en Whether to enable the internal PHY's test mode
|
||||
*/
|
||||
static inline void usb_phy_ll_int_enable_test_mode(usb_wrap_dev_t *hw, bool en)
|
||||
{
|
||||
if (en) {
|
||||
// Clear USB_WRAP_TEST_CONF_REG
|
||||
hw->test_conf.val = 0;
|
||||
// Set USB test pad oen
|
||||
hw->test_conf.test_usb_wrap_oe = 1;
|
||||
// Enable USB test mode
|
||||
hw->test_conf.test_enable = 1;
|
||||
} else {
|
||||
hw->test_conf.test_enable = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "usb_types_private.h"
|
||||
#include "usb_phy_types.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/usb_wrap_struct.h"
|
||||
#if SOC_USB_SERIAL_JTAG_SUPPORTED
|
||||
#include "soc/usb_serial_jtag_struct.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Context that should be maintained by both the driver and the HAL
|
||||
*/
|
||||
typedef struct {
|
||||
usb_wrap_dev_t *wrap_dev; /**< Pointer to base address of USB Wrapper registers */
|
||||
#if SOC_USB_SERIAL_JTAG_SUPPORTED
|
||||
usb_serial_jtag_dev_t *jtag_dev; /**< Pointer to base address of USB Serial JTAG registers */
|
||||
#endif
|
||||
} usb_phy_hal_context_t;
|
||||
|
||||
/**
|
||||
* @brief Init the USB PHY hal. This function should be called first before other hal layer function is called
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
void usb_phy_hal_init(usb_phy_hal_context_t *hal);
|
||||
|
||||
/**
|
||||
* @brief Configure internal/external PHY for USB_OTG
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param phy_target USB PHY target
|
||||
*/
|
||||
void usb_phy_hal_otg_conf(usb_phy_hal_context_t *hal, usb_phy_target_t phy_target);
|
||||
|
||||
#if SOC_USB_SERIAL_JTAG_SUPPORTED
|
||||
/**
|
||||
* @brief Configure internal/external PHY for USB_Serial_JTAG
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param phy_target USB PHY target
|
||||
*/
|
||||
void usb_phy_hal_jtag_conf(usb_phy_hal_context_t *hal, usb_phy_target_t phy_target);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Configure pullup/pulldown loads for the D+/D- as a host
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
void usb_phy_hal_int_load_conf_host(usb_phy_hal_context_t *hal);
|
||||
|
||||
/**
|
||||
* @brief Configure pullup/pulldown loads for the D+/D- as a device
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param speed USB speed
|
||||
*/
|
||||
void usb_phy_hal_int_load_conf_dev(usb_phy_hal_context_t *hal, usb_priv_speed_t speed);
|
||||
|
||||
/**
|
||||
* @brief Enable/Disable test mode for internal PHY to mimick host-device disconnection
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param disconn Whether to disconnect
|
||||
*/
|
||||
void usb_phy_hal_int_mimick_disconn(usb_phy_hal_context_t *hal, bool disconn);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
Note: This header file contains USB2.0 related types and macros that can be used by code specific to the DWC_OTG
|
||||
controller (i.e., the HW specific layers of the USB host stack). Thus, this header is only meant to be used below (and
|
||||
including) the HAL layer. For types and macros that are HW implementation agnostic (i.e., HCD layer and above), add them
|
||||
to the "usb/usb_types_ch9.h" header instead.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief USB PHY target
|
||||
*/
|
||||
typedef enum {
|
||||
USB_PHY_TARGET_INT, /**< USB target is internal PHY */
|
||||
USB_PHY_TARGET_EXT, /**< USB target is external PHY */
|
||||
USB_PHY_TARGET_MAX,
|
||||
} usb_phy_target_t;
|
||||
|
||||
/**
|
||||
* @brief USB PHY source
|
||||
*/
|
||||
typedef enum {
|
||||
USB_PHY_CTRL_OTG, /**< PHY controller is USB OTG */
|
||||
#if SOC_USB_SERIAL_JTAG_SUPPORTED
|
||||
USB_PHY_CTRL_SERIAL_JTAG, /**< PHY controller is USB Serial JTAG */
|
||||
#endif
|
||||
USB_PHY_CTRL_MAX,
|
||||
} usb_phy_controller_t;
|
||||
|
||||
/**
|
||||
* @brief USB OTG mode
|
||||
*/
|
||||
typedef enum {
|
||||
USB_PHY_MODE_DEFAULT, /**< USB OTG default mode */
|
||||
USB_OTG_MODE_HOST, /**< USB OTG host mode */
|
||||
USB_OTG_MODE_DEVICE, /**< USB OTG device mode */
|
||||
USB_OTG_MODE_MAX,
|
||||
} usb_otg_mode_t;
|
||||
|
||||
/**
|
||||
* @brief USB speed
|
||||
*/
|
||||
typedef enum {
|
||||
USB_PHY_SPEED_UNDEFINED,
|
||||
USB_PHY_SPEED_LOW, /**< USB Low Speed (1.5 Mbit/s) */
|
||||
USB_PHY_SPEED_FULL, /**< USB Full Speed (12 Mbit/s) */
|
||||
USB_PHY_SPEED_MAX,
|
||||
} usb_phy_speed_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "hal/usb_phy_ll.h"
|
||||
#include "hal/usb_phy_hal.h"
|
||||
|
||||
void usb_phy_hal_init(usb_phy_hal_context_t *hal)
|
||||
{
|
||||
hal->wrap_dev = &USB_WRAP;
|
||||
#if SOC_USB_SERIAL_JTAG_SUPPORTED
|
||||
hal->jtag_dev = &USB_SERIAL_JTAG;
|
||||
#endif
|
||||
}
|
||||
|
||||
void usb_phy_hal_otg_conf(usb_phy_hal_context_t *hal, usb_phy_target_t phy_target)
|
||||
{
|
||||
if (phy_target == USB_PHY_TARGET_EXT) {
|
||||
usb_phy_ll_ext_otg_enable(hal->wrap_dev);
|
||||
} else if (phy_target == USB_PHY_TARGET_INT) {
|
||||
usb_phy_ll_int_otg_enable(hal->wrap_dev);
|
||||
}
|
||||
}
|
||||
|
||||
#if SOC_USB_SERIAL_JTAG_SUPPORTED
|
||||
void usb_phy_hal_jtag_conf(usb_phy_hal_context_t *hal, usb_phy_target_t phy_target)
|
||||
{
|
||||
if (phy_target == USB_PHY_TARGET_EXT) {
|
||||
usb_phy_ll_ext_jtag_enable(hal->jtag_dev);
|
||||
} else if (phy_target == USB_PHY_TARGET_INT) {
|
||||
usb_phy_ll_int_jtag_enable(hal->jtag_dev);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void usb_phy_hal_int_load_conf_host(usb_phy_hal_context_t *hal)
|
||||
{
|
||||
// HOST - upstream: dp_pd = 1, dm_pd = 1
|
||||
usb_phy_ll_int_load_conf(hal->wrap_dev, false, true, false, true);
|
||||
}
|
||||
|
||||
void usb_phy_hal_int_load_conf_dev(usb_phy_hal_context_t *hal, usb_priv_speed_t speed)
|
||||
{
|
||||
// DEVICE - downstream
|
||||
if (speed == USB_PRIV_SPEED_LOW) {
|
||||
// LS: dm_pu = 1
|
||||
usb_phy_ll_int_load_conf(hal->wrap_dev, false, false, true, false);
|
||||
} else {
|
||||
// FS: dp_pu = 1
|
||||
usb_phy_ll_int_load_conf(hal->wrap_dev, true, false, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
void usb_phy_hal_int_mimick_disconn(usb_phy_hal_context_t *hal, bool disconn)
|
||||
{
|
||||
/*
|
||||
We mimick a disconnect by enabling the internal PHY's test mode, then forcing the output_enable to HIGH. This will:
|
||||
A HIGH output_enable will cause the received VP and VM to be zero, thus mimicking a disconnection.
|
||||
*/
|
||||
usb_phy_ll_int_enable_test_mode(hal->wrap_dev, disconn);
|
||||
}
|
|
@ -16,7 +16,8 @@ set(srcs
|
|||
"timer_periph.c"
|
||||
"touch_sensor_periph.c"
|
||||
"uart_periph.c"
|
||||
"usb_periph.c")
|
||||
"usb_periph.c"
|
||||
"usb_phy_periph.c")
|
||||
|
||||
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}")
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/usb_phy_periph.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
|
||||
/*
|
||||
Bunch of constants for USB peripheral: GPIO signals
|
||||
*/
|
||||
const usb_phy_signal_conn_t usb_phy_periph_signal = {
|
||||
.extphy_vp_in = USB_EXTPHY_VP_IDX,
|
||||
.extphy_vm_in = USB_EXTPHY_VM_IDX,
|
||||
.extphy_rcv_in = USB_EXTPHY_RCV_IDX,
|
||||
.extphy_oen_out = USB_EXTPHY_OEN_IDX,
|
||||
.extphy_vpo_out = USB_EXTPHY_VPO_IDX,
|
||||
.extphy_vmo_out = USB_EXTPHY_VMO_IDX,
|
||||
.extphy_suspend_in = USB_EXTPHY_SUSPND_IDX,
|
||||
.extphy_speed_in = USB_EXTPHY_SPEED_IDX,
|
||||
.module = PERIPH_USB_MODULE
|
||||
};
|
|
@ -19,7 +19,8 @@ set(srcs
|
|||
"timer_periph.c"
|
||||
"touch_sensor_periph.c"
|
||||
"uart_periph.c"
|
||||
"usb_periph.c")
|
||||
"usb_periph.c"
|
||||
"usb_phy_periph.c")
|
||||
|
||||
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}")
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define SOC_CACHE_SUPPORT_WRAP 1
|
||||
#define SOC_ULP_SUPPORTED 1
|
||||
#define SOC_USB_OTG_SUPPORTED 1
|
||||
#define SOC_USB_SERIAL_JTAG_SUPPORTED 1
|
||||
#define SOC_RTC_SLOW_MEM_SUPPORTED 1
|
||||
#define SOC_CCOMP_TIMER_SUPPORTED 1
|
||||
#define SOC_DIG_SIGN_SUPPORTED 1
|
||||
|
|
|
@ -154,7 +154,7 @@ typedef union {
|
|||
* USB D- rx value in test.
|
||||
*/
|
||||
uint32_t test_rx_dm:1;
|
||||
uint32_t reserved7: 25;
|
||||
uint32_t reserved7:25;
|
||||
};
|
||||
uint32_t val;
|
||||
} usb_wrap_test_conf_reg_t;
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/usb_phy_periph.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
|
||||
/*
|
||||
Bunch of constants for USB peripheral: GPIO signals
|
||||
*/
|
||||
const usb_phy_signal_conn_t usb_phy_periph_signal = {
|
||||
.extphy_vp_in = USB_EXTPHY_VP_IDX,
|
||||
.extphy_vm_in = USB_EXTPHY_VM_IDX,
|
||||
.extphy_rcv_in = USB_EXTPHY_RCV_IDX,
|
||||
.extphy_oen_out = USB_EXTPHY_OEN_IDX,
|
||||
.extphy_vpo_out = USB_EXTPHY_VPO_IDX,
|
||||
.extphy_vmo_out = USB_EXTPHY_VMO_IDX,
|
||||
.extphy_suspend_in = USB_EXTPHY_SUSPND_IDX,
|
||||
.extphy_speed_in = USB_EXTPHY_SPEED_IDX,
|
||||
.module = PERIPH_USB_MODULE
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/periph_defs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
Stores a bunch of USB-peripheral data.
|
||||
*/
|
||||
typedef struct {
|
||||
const uint8_t extphy_vp_in;
|
||||
const uint8_t extphy_vm_in;
|
||||
const uint8_t extphy_rcv_in;
|
||||
const uint8_t extphy_oen_out;
|
||||
const uint8_t extphy_vpo_out;
|
||||
const uint8_t extphy_vmo_out;
|
||||
const uint8_t extphy_suspend_in;
|
||||
const uint8_t extphy_speed_in;
|
||||
const periph_module_t module;
|
||||
} usb_phy_signal_conn_t;
|
||||
|
||||
extern const usb_phy_signal_conn_t usb_phy_periph_signal;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -73,7 +73,7 @@ endif() # CONFIG_TINYUSB
|
|||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS ${includes_public}
|
||||
PRIV_INCLUDE_DIRS ${includes_private}
|
||||
PRIV_REQUIRES "vfs"
|
||||
PRIV_REQUIRES "vfs" "usb"
|
||||
)
|
||||
|
||||
if(CONFIG_TINYUSB)
|
||||
|
|
|
@ -9,7 +9,8 @@ if(CONFIG_USB_OTG_SUPPORTED)
|
|||
"usb_helpers.c"
|
||||
"usb_host.c"
|
||||
"usb_private.c"
|
||||
"usbh.c")
|
||||
"usbh.c"
|
||||
"usb_phy.c")
|
||||
list(APPEND include "include")
|
||||
list(APPEND priv_include "private_include")
|
||||
list(APPEND priv_require "hal" "driver")
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/usb_phy_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief USB PHY status
|
||||
*/
|
||||
typedef enum {
|
||||
USB_PHY_STATUS_FREE, /**< PHY is not being used */
|
||||
USB_PHY_STATUS_IN_USE, /**< PHY is in use */
|
||||
} usb_phy_status_t;
|
||||
|
||||
/**
|
||||
* @brief USB PHY available actions
|
||||
*/
|
||||
typedef enum {
|
||||
USB_PHY_ACTION_HOST_ALLOW_CONN, /**< Enable physical connection when operating as an OTG Host */
|
||||
USB_PHY_ACTION_HOST_FORCE_DISCONN, /**< Disable physical connection when operating as an OTG Host */
|
||||
USB_PHY_ACTION_MAX,
|
||||
} usb_phy_action_t;
|
||||
|
||||
/**
|
||||
* @brief USB external PHY iopins configure struct
|
||||
*/
|
||||
typedef struct {
|
||||
int vp_io_num; /**< GPIO pin to USB_EXTPHY_VP_IDX */
|
||||
int vm_io_num; /**< GPIO pin to USB_EXTPHY_VM_IDX */
|
||||
int rcv_io_num; /**< GPIO pin to USB_EXTPHY_RCV_IDX */
|
||||
int oen_io_num; /**< GPIO pin to USB_EXTPHY_OEN_IDX */
|
||||
int vpo_io_num; /**< GPIO pin to USB_EXTPHY_VPO_IDX */
|
||||
int vmo_io_num; /**< GPIO pin to USB_EXTPHY_VMO_IDX */
|
||||
} usb_phy_gpio_conf_t;
|
||||
|
||||
/**
|
||||
* @brief USB PHY configure struct
|
||||
*
|
||||
* At minimum the PHY controller and PHY target must be initialized.
|
||||
*/
|
||||
typedef struct {
|
||||
usb_phy_controller_t controller; /**< USB PHY controller */
|
||||
usb_phy_target_t target; /**< USB PHY target INT/EXT */
|
||||
usb_otg_mode_t otg_mode; /**< USB OTG mode */
|
||||
usb_phy_speed_t otg_speed; /**< USB OTG speed */
|
||||
usb_phy_gpio_conf_t *gpio_conf; /**< USB external PHY iopins configure */
|
||||
} usb_phy_config_t;
|
||||
|
||||
typedef struct phy_context_t *usb_phy_handle_t; /**< USB PHY context handle */
|
||||
|
||||
/**
|
||||
* @brief Initialize a new USB PHY
|
||||
* Configure at least PHY source.
|
||||
*
|
||||
* @param[in] config USB PHY configurtion struct
|
||||
* @param[out] handle_ret USB PHY context handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL USB PHY init error.
|
||||
* - ESP_ERR_INVALID_STATE USB PHY not installed.
|
||||
* - ESP_ERR_NO_MEM USB_OTG installation failed due to no mem.
|
||||
*/
|
||||
esp_err_t usb_new_phy(const usb_phy_config_t *config, usb_phy_handle_t *handle_ret);
|
||||
|
||||
/**
|
||||
* @brief Configure OTG mode for a USB PHY
|
||||
*
|
||||
* @param handle Pointer of USB PHY context handle
|
||||
* @param mode USB OTG mode
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error.
|
||||
* - ESP_FAIL OTG set mode fail.
|
||||
*/
|
||||
esp_err_t usb_phy_otg_set_mode(usb_phy_handle_t handle, usb_otg_mode_t mode);
|
||||
|
||||
/**
|
||||
* @brief Configure USB speed for a USB PHY that is operating as an OTG Device
|
||||
*
|
||||
* @param handle Pointer of USB PHY context handle
|
||||
* @param mode USB speed
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error.
|
||||
* - ESP_FAIL OTG set speed fail.
|
||||
*/
|
||||
esp_err_t usb_phy_otg_dev_set_speed(usb_phy_handle_t handle, usb_phy_speed_t speed);
|
||||
|
||||
/**
|
||||
* @brief Take a action for a USB PHY
|
||||
*
|
||||
* @param handle Pointer of USB PHY context handle
|
||||
* @param action USB PHY action
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error.
|
||||
* - ESP_FAIL Action cannot be performed.
|
||||
*/
|
||||
esp_err_t usb_phy_action(usb_phy_handle_t handle, usb_phy_action_t action);
|
||||
|
||||
/**
|
||||
* @brief Delete a USB PHY
|
||||
*
|
||||
* @param handle Pointer of USB PHY context handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error.
|
||||
*/
|
||||
esp_err_t usb_del_phy(usb_phy_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Get status of a USB PHY
|
||||
*
|
||||
* @param[in] target The specific PHY target to check
|
||||
* @param[out] status Status of the PHY
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error.
|
||||
* - ESP_ERR_INVALID_STATE USB PHY not installed.
|
||||
*/
|
||||
esp_err_t usb_phy_get_phy_status(usb_phy_target_t target, usb_phy_status_t *status);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,328 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <esp_types.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "esp_private/usb_phy.h"
|
||||
#include "soc/usb_phy_periph.h"
|
||||
#include "hal/usb_phy_hal.h"
|
||||
#include "hal/usb_phy_ll.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "hal/gpio_ll.h"
|
||||
#include "soc/usb_pins.h"
|
||||
|
||||
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 */
|
||||
usb_phy_gpio_conf_t *iopins; /**< external PHY I/O pins */
|
||||
usb_phy_hal_context_t hal_context; /**< USB_PHY hal context */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
phy_context_t *internal_phy; /**< internal PHY context */
|
||||
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;
|
||||
|
||||
/**
|
||||
* @brief A pin descriptor for initialize external PHY I/O pins
|
||||
*/
|
||||
typedef struct {
|
||||
int pin; /**< GPIO pin num */
|
||||
const int func; /**< GPIO matrix signal */
|
||||
const bool is_output; /**< input/output signal */
|
||||
} usb_iopin_dsc_t;
|
||||
|
||||
static phy_ctrl_obj_t *p_phy_ctrl_obj = NULL;
|
||||
static portMUX_TYPE phy_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
static esp_err_t phy_external_iopins_configure(usb_phy_gpio_conf_t *gpio_conf)
|
||||
{
|
||||
const usb_iopin_dsc_t usb_periph_iopins[] = {
|
||||
{gpio_conf->vp_io_num, usb_phy_periph_signal.extphy_vp_in, 0},
|
||||
{gpio_conf->vm_io_num, usb_phy_periph_signal.extphy_vm_in, 0},
|
||||
{gpio_conf->rcv_io_num, usb_phy_periph_signal.extphy_rcv_in, 0},
|
||||
{gpio_conf->oen_io_num, usb_phy_periph_signal.extphy_oen_out, 1},
|
||||
{gpio_conf->vpo_io_num, usb_phy_periph_signal.extphy_vpo_out, 1},
|
||||
{gpio_conf->vmo_io_num, usb_phy_periph_signal.extphy_vmo_out, 1},
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(usb_periph_iopins)/sizeof(usb_iopin_dsc_t); i++) {
|
||||
const usb_iopin_dsc_t iopin = usb_periph_iopins[i];
|
||||
if (iopin.pin != -1) {
|
||||
ESP_RETURN_ON_FALSE((iopin.is_output && GPIO_IS_VALID_OUTPUT_GPIO(iopin.pin)) ||
|
||||
(!iopin.is_output && GPIO_IS_VALID_GPIO(iopin.pin)),
|
||||
ESP_ERR_INVALID_ARG, USBPHY_TAG, "io_num argument is invalid");
|
||||
esp_rom_gpio_pad_select_gpio(iopin.pin);
|
||||
if (iopin.is_output) {
|
||||
esp_rom_gpio_connect_out_signal(iopin.pin, iopin.func, false, false);
|
||||
} else {
|
||||
esp_rom_gpio_connect_in_signal(iopin.pin, iopin.func, false);
|
||||
gpio_ll_input_enable(&GPIO, iopin.pin);
|
||||
}
|
||||
esp_rom_gpio_pad_unhold(iopin.pin);
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
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;
|
||||
if (mode == USB_OTG_MODE_HOST) {
|
||||
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_OTG_IDDIG_IN_IDX, false); //connected connector is A side
|
||||
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_SRP_BVALID_IN_IDX, false);
|
||||
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_VBUSVALID_IN_IDX, false); //receiving a valid Vbus from host
|
||||
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_AVALID_IN_IDX, false); //HIGH to force USB host mode
|
||||
if (handle->target == USB_PHY_TARGET_INT) {
|
||||
usb_phy_hal_int_load_conf_host(&(handle->hal_context));
|
||||
}
|
||||
} else if (mode == USB_OTG_MODE_DEVICE) {
|
||||
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_IDDIG_IN_IDX, false); //connected connector is mini-B side
|
||||
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_SRP_BVALID_IN_IDX, false); //HIGH to force USB device mode
|
||||
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_VBUSVALID_IN_IDX, false); //receiving a valid Vbus from device
|
||||
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_OTG_AVALID_IN_IDX, false);
|
||||
}
|
||||
|
||||
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");
|
||||
ESP_RETURN_ON_FALSE((handle->target == USB_PHY_TARGET_INT && handle->otg_mode == USB_OTG_MODE_DEVICE), ESP_FAIL,
|
||||
USBPHY_TAG, "set speed not supported");
|
||||
|
||||
handle->otg_speed = speed;
|
||||
usb_priv_speed_t hal_speed = 0;
|
||||
if (speed == USB_PHY_SPEED_LOW) {
|
||||
hal_speed = USB_PRIV_SPEED_LOW;
|
||||
} else if (speed == USB_PHY_SPEED_FULL) {
|
||||
hal_speed = USB_PRIV_SPEED_FULL;
|
||||
}
|
||||
usb_phy_hal_int_load_conf_dev(&(handle->hal_context), hal_speed);
|
||||
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");
|
||||
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;
|
||||
switch (action) {
|
||||
case USB_PHY_ACTION_HOST_ALLOW_CONN:
|
||||
if (handle->target == USB_PHY_TARGET_INT) {
|
||||
usb_phy_hal_int_mimick_disconn(&(handle->hal_context), false);
|
||||
} else {
|
||||
if (!handle->iopins) {
|
||||
ret = ESP_FAIL;
|
||||
ESP_LOGE(USBPHY_TAG, "no I/O pins provided for connection");
|
||||
break;
|
||||
}
|
||||
/*
|
||||
Allow for connections on the external PHY by connecting the VP and VM signals to the external PHY.
|
||||
*/
|
||||
esp_rom_gpio_connect_in_signal(handle->iopins->vp_io_num, USB_EXTPHY_VP_IDX, false);
|
||||
esp_rom_gpio_connect_in_signal(handle->iopins->vm_io_num, USB_EXTPHY_VM_IDX, false);
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_PHY_ACTION_HOST_FORCE_DISCONN:
|
||||
if (handle->target == USB_PHY_TARGET_INT) {
|
||||
usb_phy_hal_int_mimick_disconn(&(handle->hal_context), true);
|
||||
} else {
|
||||
/*
|
||||
Disable connections on the external PHY by connecting the VP and VM signals to the constant LOW signal.
|
||||
*/
|
||||
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_EXTPHY_VP_IDX, false);
|
||||
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_EXTPHY_VM_IDX, false);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t usb_phy_install(void)
|
||||
{
|
||||
portENTER_CRITICAL(&phy_spinlock);
|
||||
if (p_phy_ctrl_obj) {
|
||||
// p_phy_ctrl_obj already installed, return immediately
|
||||
portEXIT_CRITICAL(&phy_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
portEXIT_CRITICAL(&phy_spinlock);
|
||||
|
||||
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");
|
||||
|
||||
portENTER_CRITICAL(&phy_spinlock);
|
||||
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
|
||||
portEXIT_CRITICAL(&phy_spinlock);
|
||||
goto cleanup;
|
||||
}
|
||||
portEXIT_CRITICAL(&phy_spinlock);
|
||||
periph_module_enable(usb_phy_periph_signal.module);
|
||||
periph_module_reset(usb_phy_periph_signal.module);
|
||||
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)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(config, ESP_ERR_INVALID_ARG, USBPHY_TAG, "config argument is invalid");
|
||||
ESP_RETURN_ON_FALSE(config->target < USB_PHY_TARGET_MAX, ESP_ERR_INVALID_ARG, USBPHY_TAG, "specified PHY argument is invalid");
|
||||
ESP_RETURN_ON_FALSE(config->controller < USB_PHY_CTRL_MAX, ESP_ERR_INVALID_ARG, USBPHY_TAG, "specified source argument is invalid");
|
||||
|
||||
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");
|
||||
|
||||
portENTER_CRITICAL(&phy_spinlock);
|
||||
usb_phy_get_phy_status(config->target, &phy_context->status);
|
||||
if (phy_context->status == USB_PHY_STATUS_FREE) {
|
||||
new_phy = true;
|
||||
p_phy_ctrl_obj->ref_count++;
|
||||
if (config->target == USB_PHY_TARGET_EXT) {
|
||||
p_phy_ctrl_obj->external_phy = phy_context;
|
||||
} else {
|
||||
p_phy_ctrl_obj->internal_phy = phy_context;
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL(&phy_spinlock);
|
||||
ESP_GOTO_ON_FALSE(new_phy, ESP_ERR_INVALID_STATE, cleanup, USBPHY_TAG, "selected PHY is in use");
|
||||
|
||||
phy_context->target = config->target;
|
||||
phy_context->controller = config->controller;
|
||||
phy_context->status = USB_PHY_STATUS_IN_USE;
|
||||
|
||||
usb_phy_hal_init(&(phy_context->hal_context));
|
||||
if (config->controller == USB_PHY_CTRL_OTG) {
|
||||
usb_phy_hal_otg_conf(&(phy_context->hal_context), config->target == USB_PHY_TARGET_EXT);
|
||||
}
|
||||
#if SOC_USB_SERIAL_JTAG_SUPPORTED
|
||||
else if (config->controller == USB_PHY_CTRL_SERIAL_JTAG) {
|
||||
usb_phy_hal_jtag_conf(&(phy_context->hal_context), config->target == USB_PHY_TARGET_EXT);
|
||||
phy_context->otg_mode = USB_OTG_MODE_DEVICE;
|
||||
phy_context->otg_speed = USB_PHY_SPEED_FULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (config->target == USB_PHY_TARGET_INT) {
|
||||
gpio_set_drive_capability(USBPHY_DM_NUM, GPIO_DRIVE_CAP_3);
|
||||
gpio_set_drive_capability(USBPHY_DP_NUM, GPIO_DRIVE_CAP_3);
|
||||
}
|
||||
|
||||
*handle_ret = (usb_phy_handle_t) phy_context;
|
||||
if (config->gpio_conf && config->target == USB_PHY_TARGET_EXT) {
|
||||
phy_context->iopins = (usb_phy_gpio_conf_t *) calloc(1, sizeof(usb_phy_gpio_conf_t));
|
||||
ESP_GOTO_ON_FALSE(phy_context->iopins, ESP_ERR_NO_MEM, cleanup, USBPHY_TAG, "no mem for storing I/O pins");
|
||||
memcpy(phy_context->iopins, config->gpio_conf, sizeof(usb_phy_gpio_conf_t));
|
||||
ESP_ERROR_CHECK(phy_external_iopins_configure(phy_context->iopins));
|
||||
}
|
||||
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));
|
||||
}
|
||||
return ESP_OK;
|
||||
|
||||
cleanup:
|
||||
free(phy_context->iopins);
|
||||
free(phy_context);
|
||||
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;
|
||||
portENTER_CRITICAL(&phy_spinlock);
|
||||
if (p_phy_ctrl_obj->ref_count == 0) {
|
||||
p_phy_ctrl_obj_free = p_phy_ctrl_obj;
|
||||
p_phy_ctrl_obj = NULL;
|
||||
// Disable USB peripheral
|
||||
periph_module_disable(usb_phy_periph_signal.module);
|
||||
}
|
||||
portEXIT_CRITICAL(&phy_spinlock);
|
||||
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");
|
||||
|
||||
portENTER_CRITICAL(&phy_spinlock);
|
||||
p_phy_ctrl_obj->ref_count--;
|
||||
if (handle->target == USB_PHY_TARGET_EXT) {
|
||||
p_phy_ctrl_obj->external_phy = NULL;
|
||||
} else {
|
||||
// Clear pullup and pulldown loads on D+ / D-
|
||||
usb_phy_ll_int_load_conf(handle->hal_context.wrap_dev, false, false, false, false);
|
||||
p_phy_ctrl_obj->internal_phy = NULL;
|
||||
}
|
||||
portEXIT_CRITICAL(&phy_spinlock);
|
||||
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;
|
||||
} else if (target == USB_PHY_TARGET_INT && p_phy_ctrl_obj->internal_phy) {
|
||||
*status = p_phy_ctrl_obj->internal_phy->status;
|
||||
} else {
|
||||
*status = USB_PHY_STATUS_FREE;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
Ładowanie…
Reference in New Issue