mirror of
https://gitee.com/Vancouver2017/luban-lite-t3e-pro.git
synced 2025-12-14 18:38:55 +00:00
507 lines
11 KiB
C
507 lines
11 KiB
C
|
|
/*
|
||
|
|
* Copyright (c) 2023, Artinchip Technology Co., Ltd
|
||
|
|
*
|
||
|
|
* SPDX-License-Identifier: Apache-2.0
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include "aic_core.h"
|
||
|
|
#include "aic_hal.h"
|
||
|
|
#include "usb_otg.h"
|
||
|
|
#include "usbd_core.h"
|
||
|
|
#include "usbh_core.h"
|
||
|
|
#if defined(KERNEL_RTTHREAD)
|
||
|
|
#include <rtdevice.h>
|
||
|
|
#include <rtthread.h>
|
||
|
|
#endif
|
||
|
|
|
||
|
|
struct usb_otg g_usb_otg;
|
||
|
|
|
||
|
|
static int usb_otg_get_id(void);
|
||
|
|
static void usb_otg_sw_mode(unsigned int mode);
|
||
|
|
|
||
|
|
static void usb_otg_irq(void *args)
|
||
|
|
{
|
||
|
|
struct usb_otg *d = &g_usb_otg;
|
||
|
|
|
||
|
|
usb_osal_sem_give(d->waitsem);
|
||
|
|
}
|
||
|
|
|
||
|
|
#if defined(KERNEL_RTTHREAD)
|
||
|
|
static void usbh_otg_thread(void *argument)
|
||
|
|
{
|
||
|
|
struct usb_otg *d = &g_usb_otg;
|
||
|
|
int mode = 0;
|
||
|
|
int ret = 0;
|
||
|
|
|
||
|
|
while (1) {
|
||
|
|
ret = usb_osal_sem_take(d->waitsem, USB_OSAL_WAITING_FOREVER);
|
||
|
|
if (ret < 0) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
mode = usb_otg_get_id();
|
||
|
|
if (mode < 0) {
|
||
|
|
USB_LOG_ERR("get mode err.\n");
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
usb_otg_sw_mode(mode);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#elif defined(KERNEL_BAREMETAL)
|
||
|
|
void usbh_otg_thread_poll(void *argument)
|
||
|
|
{
|
||
|
|
struct usb_otg *d = &g_usb_otg;
|
||
|
|
int mode = 0;
|
||
|
|
int ret = 0;
|
||
|
|
|
||
|
|
ret = usb_osal_sem_take(d->waitsem, 0);
|
||
|
|
if (ret < 0) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
mode = usb_otg_get_id();
|
||
|
|
if (mode < 0) {
|
||
|
|
USB_LOG_ERR("get mode err.\n");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
usb_otg_sw_mode(mode);
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
static int usb_otg_id_detect_en(void)
|
||
|
|
{
|
||
|
|
struct usb_otg *d = &g_usb_otg;
|
||
|
|
int pin = d->id_gpio;
|
||
|
|
|
||
|
|
if (pin < 0) {
|
||
|
|
USB_LOG_ERR("get id gpio err.\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
d->waitsem = usb_osal_sem_create(0);
|
||
|
|
#if defined(KERNEL_RTTHREAD)
|
||
|
|
d->otg_thread = usb_osal_thread_create("usbh_enum", CONFIG_USBHOST_PSC_STACKSIZE, CONFIG_USBHOST_PSC_PRIO + 1, usbh_otg_thread, NULL);
|
||
|
|
if (d->otg_thread == NULL) {
|
||
|
|
USB_LOG_ERR("Failed to create hub thread\r\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
rt_pin_attach_irq(pin, PIN_IRQ_MODE_RISING_FALLING, usb_otg_irq, RT_NULL);
|
||
|
|
rt_pin_irq_enable(pin, 1);
|
||
|
|
#elif defined(KERNEL_BAREMETAL)
|
||
|
|
unsigned int g, p;
|
||
|
|
g = GPIO_GROUP(pin);
|
||
|
|
p = GPIO_GROUP_PIN(pin);
|
||
|
|
aicos_request_irq(AIC_GPIO_TO_IRQ(pin), (irq_handler_t)usb_otg_irq, 0, "pin", NULL);
|
||
|
|
hal_gpio_set_irq_mode(g, p, PIN_IRQ_MODE_EDGE_BOTH);
|
||
|
|
hal_gpio_enable_irq(g, p);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void usb_otg_id_detect_dis(void)
|
||
|
|
{
|
||
|
|
struct usb_otg *d = &g_usb_otg;
|
||
|
|
int pin = d->id_gpio;
|
||
|
|
|
||
|
|
if (pin < 0) {
|
||
|
|
USB_LOG_ERR("get id gpio err.\n");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
#if defined(KERNEL_RTTHREAD)
|
||
|
|
rt_pin_irq_enable(pin, 0);
|
||
|
|
rt_pin_detach_irq(pin);
|
||
|
|
usb_osal_thread_delete(d->otg_thread);
|
||
|
|
#elif defined(KERNEL_BAREMETAL)
|
||
|
|
unsigned int g, p;
|
||
|
|
g = GPIO_GROUP(pin);
|
||
|
|
p = GPIO_GROUP_PIN(pin);
|
||
|
|
aicos_irq_disable(AIC_GPIO_TO_IRQ(pin));
|
||
|
|
hal_gpio_disable_irq(g, p);
|
||
|
|
#endif
|
||
|
|
usb_osal_sem_delete(d->waitsem);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void usb_otg_set_vbus(unsigned char on)
|
||
|
|
{
|
||
|
|
#ifdef LPKG_CHERRYUSB_VBUSEN_GPIO
|
||
|
|
struct usb_otg *d = &g_usb_otg;
|
||
|
|
int pin = d->vbus_en_gpio;
|
||
|
|
unsigned int g, p;
|
||
|
|
|
||
|
|
if (pin < 0) {
|
||
|
|
USB_LOG_ERR("get vbus-en gpio err.\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
g = GPIO_GROUP(pin);
|
||
|
|
p = GPIO_GROUP_PIN(pin);
|
||
|
|
|
||
|
|
if (on ^ d->vbus_en_gpio_polarity)
|
||
|
|
hal_gpio_set_value(g, p, 0);
|
||
|
|
else
|
||
|
|
hal_gpio_set_value(g, p, 1);
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
static void usb_otg_set_dpsw_host(unsigned char on)
|
||
|
|
{
|
||
|
|
#ifdef LPKG_CHERRYUSB_DPSW_GPIO
|
||
|
|
struct usb_otg *d = &g_usb_otg;
|
||
|
|
int pin = d->dp_sw_gpio;
|
||
|
|
unsigned int g, p;
|
||
|
|
|
||
|
|
if (pin < 0) {
|
||
|
|
USB_LOG_ERR("get dp-sw gpio err.\n");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
g = GPIO_GROUP(pin);
|
||
|
|
p = GPIO_GROUP_PIN(pin);
|
||
|
|
|
||
|
|
if (on ^ d->dp_sw_gpio_polarity)
|
||
|
|
hal_gpio_set_value(g, p, 0);
|
||
|
|
else
|
||
|
|
hal_gpio_set_value(g, p, 1);
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
static int usb_otg_get_id(void)
|
||
|
|
{
|
||
|
|
struct usb_otg *d = &g_usb_otg;
|
||
|
|
int pin = d->id_gpio;
|
||
|
|
unsigned int g, p, val;
|
||
|
|
|
||
|
|
if (pin < 0) {
|
||
|
|
USB_LOG_ERR("get dp-sw gpio err.\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
g = GPIO_GROUP(pin);
|
||
|
|
p = GPIO_GROUP_PIN(pin);
|
||
|
|
|
||
|
|
hal_gpio_get_value(g, p, &val);
|
||
|
|
|
||
|
|
if (val ^ d->id_gpio_polarity)
|
||
|
|
return OTG_MODE_DEVICE;
|
||
|
|
else
|
||
|
|
return OTG_MODE_HOST;
|
||
|
|
}
|
||
|
|
|
||
|
|
int usb_otg_register_host(int index, struct usbh_bus *host)
|
||
|
|
{
|
||
|
|
struct usb_otg *d = &g_usb_otg;
|
||
|
|
|
||
|
|
if (index >= MAX_USB_HOST_BUS) {
|
||
|
|
USB_LOG_ERR("get id gpio err.\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
d->host[index] = host;
|
||
|
|
|
||
|
|
if (d->mode != OTG_MODE_HOST)
|
||
|
|
return 1;
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int usb_otg_register_device(void *device)
|
||
|
|
{
|
||
|
|
static unsigned char init = 0;
|
||
|
|
struct usb_otg *d = &g_usb_otg;
|
||
|
|
|
||
|
|
if (init)
|
||
|
|
return 0;
|
||
|
|
else
|
||
|
|
init = 1;
|
||
|
|
|
||
|
|
if (d->auto_flg)
|
||
|
|
usb_otg_id_detect_en();
|
||
|
|
|
||
|
|
d->device = device;
|
||
|
|
|
||
|
|
if (d->mode != OTG_MODE_DEVICE)
|
||
|
|
return 1;
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void usb_otg_start_host(unsigned char on)
|
||
|
|
{
|
||
|
|
struct usb_otg *d = &g_usb_otg;
|
||
|
|
int i = 0;
|
||
|
|
|
||
|
|
for (i=0; i< MAX_USB_HOST_BUS; i++) {
|
||
|
|
if ((d->host[i] == NULL)/* || (on == d->host_on[i])*/)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
if (on)
|
||
|
|
usbh_initialize(d->host[i]);
|
||
|
|
else
|
||
|
|
usbh_deinitialize(d->host[i]);
|
||
|
|
|
||
|
|
d->host_on[i] = on;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static void usb_otg_start_device(unsigned char on)
|
||
|
|
{
|
||
|
|
struct usb_otg *d = &g_usb_otg;
|
||
|
|
|
||
|
|
/*if (d->device_on == on)
|
||
|
|
return;*/
|
||
|
|
|
||
|
|
if (on)
|
||
|
|
usbd_initialize();
|
||
|
|
else
|
||
|
|
usbd_deinitialize();
|
||
|
|
|
||
|
|
d->device_on = on;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void usb_otg_sw_gpio(unsigned int mode)
|
||
|
|
{
|
||
|
|
struct usb_otg *d = &g_usb_otg;
|
||
|
|
|
||
|
|
if (OTG_MODE_HOST == mode) {
|
||
|
|
usb_otg_set_vbus(1);
|
||
|
|
usb_otg_set_dpsw_host(1);
|
||
|
|
} else {
|
||
|
|
usb_otg_set_vbus(0);
|
||
|
|
usb_otg_set_dpsw_host(0);
|
||
|
|
}
|
||
|
|
|
||
|
|
d->mode = mode;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void usb_otg_sw_mode(unsigned int mode)
|
||
|
|
{
|
||
|
|
struct usb_otg *d = &g_usb_otg;
|
||
|
|
|
||
|
|
if (mode == d->mode)
|
||
|
|
return;
|
||
|
|
|
||
|
|
if (d->auto_flg)
|
||
|
|
printf("Usb otg auto mode ");
|
||
|
|
else
|
||
|
|
printf("Usb otg manual mode ");
|
||
|
|
|
||
|
|
if (OTG_MODE_HOST == mode) {
|
||
|
|
usb_otg_start_device(0);
|
||
|
|
usb_otg_sw_gpio(mode);
|
||
|
|
usb_otg_start_host(1);
|
||
|
|
printf("(switch usb0 to host).\n");
|
||
|
|
} else {
|
||
|
|
usb_otg_start_host(0);
|
||
|
|
usb_otg_sw_gpio(mode);
|
||
|
|
usb_otg_start_device(1);
|
||
|
|
printf("(switch usb0 to device).\n");
|
||
|
|
}
|
||
|
|
|
||
|
|
d->mode = mode;
|
||
|
|
}
|
||
|
|
|
||
|
|
void usb_otg_set_mode(unsigned int auto_flg, unsigned int mode)
|
||
|
|
{
|
||
|
|
struct usb_otg *d = &g_usb_otg;
|
||
|
|
int id_mode = 0;
|
||
|
|
|
||
|
|
if ((auto_flg == d->auto_flg) && (mode == d->mode))
|
||
|
|
return;
|
||
|
|
|
||
|
|
if (auto_flg != d->auto_flg) {
|
||
|
|
if (auto_flg) {
|
||
|
|
if (d->id_gpio < 0) {
|
||
|
|
USB_LOG_ERR("Auto mode get id gpio err.\n");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
id_mode = usb_otg_get_id();
|
||
|
|
usb_otg_sw_mode(id_mode);
|
||
|
|
usb_otg_id_detect_en();
|
||
|
|
} else {
|
||
|
|
usb_otg_id_detect_dis();
|
||
|
|
usb_otg_sw_mode(mode);
|
||
|
|
}
|
||
|
|
d->auto_flg = !!auto_flg;
|
||
|
|
} else {
|
||
|
|
if ((!auto_flg) && (mode != d->mode)) {
|
||
|
|
usb_otg_sw_mode(mode);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int usb_otg_get_mode(unsigned int *auto_flg, unsigned int *mode)
|
||
|
|
{
|
||
|
|
*auto_flg = g_usb_otg.auto_flg;
|
||
|
|
*mode = g_usb_otg.mode;
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int usb_otg_config_init(void)
|
||
|
|
{
|
||
|
|
struct usb_otg *d = &g_usb_otg;
|
||
|
|
int pin;
|
||
|
|
unsigned int g, p;
|
||
|
|
|
||
|
|
/* (1) Get id gpio */
|
||
|
|
d->id_gpio = -1;
|
||
|
|
#ifdef LPKG_CHERRYUSB_ID_GPIO
|
||
|
|
pin = hal_gpio_name2pin(LPKG_CHERRYUSB_ID_GPIO_NAME);
|
||
|
|
if (pin < 0) {
|
||
|
|
USB_LOG_ERR("get id gpio err.\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
d->id_gpio = pin;
|
||
|
|
g = GPIO_GROUP(pin);
|
||
|
|
p = GPIO_GROUP_PIN(pin);
|
||
|
|
hal_gpio_set_func(g, p, 1);
|
||
|
|
hal_gpio_set_bias_pull(g, p, PIN_PULL_UP);
|
||
|
|
hal_gpio_set_debounce(g, p, 0xFFF);
|
||
|
|
hal_gpio_direction_input(g, p);
|
||
|
|
hal_gpio_set_irq_mode(g, p, PIN_IRQ_MODE_EDGE_BOTH);
|
||
|
|
#ifdef LPKG_CHERRYUSB_ID_GPIO_ACT_LOW
|
||
|
|
d->id_gpio_polarity = 0;
|
||
|
|
#else
|
||
|
|
d->id_gpio_polarity = 1;
|
||
|
|
#endif
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/* (2) Get vbus-en gpio */
|
||
|
|
d->vbus_en_gpio = -1;
|
||
|
|
#ifdef LPKG_CHERRYUSB_VBUSEN_GPIO
|
||
|
|
pin = hal_gpio_name2pin(LPKG_CHERRYUSB_VBUSEN_GPIO_NAME);
|
||
|
|
if (pin < 0) {
|
||
|
|
USB_LOG_ERR("get vbus-en gpio err.\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
d->vbus_en_gpio = pin;
|
||
|
|
g = GPIO_GROUP(pin);
|
||
|
|
p = GPIO_GROUP_PIN(pin);
|
||
|
|
hal_gpio_set_func(g, p, 1);
|
||
|
|
hal_gpio_set_drive_strength(g, p, 3);
|
||
|
|
hal_gpio_direction_output(g, p);
|
||
|
|
#ifdef LPKG_CHERRYUSB_VBUSEN_GPIO_ACT_LOW
|
||
|
|
d->vbus_en_gpio_polarity = 0;
|
||
|
|
#else
|
||
|
|
d->vbus_en_gpio_polarity = 1;
|
||
|
|
#endif
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/* (3) Get dp-sw gpio */
|
||
|
|
d->dp_sw_gpio = -1;
|
||
|
|
#ifdef LPKG_CHERRYUSB_DPSW_GPIO
|
||
|
|
pin = hal_gpio_name2pin(LPKG_CHERRYUSB_DPSW_GPIO_NAME);
|
||
|
|
if (pin < 0) {
|
||
|
|
USB_LOG_ERR("get dp-sw gpio err.\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
d->dp_sw_gpio = pin;
|
||
|
|
g = GPIO_GROUP(pin);
|
||
|
|
p = GPIO_GROUP_PIN(pin);
|
||
|
|
hal_gpio_set_func(g, p, 1);
|
||
|
|
hal_gpio_set_drive_strength(g, p, 3);
|
||
|
|
hal_gpio_direction_output(g, p);
|
||
|
|
#ifdef LPKG_CHERRYUSB_DPSW_GPIO_ACT_LOW
|
||
|
|
d->dp_sw_gpio_polarity = 0;
|
||
|
|
#else
|
||
|
|
d->dp_sw_gpio_polarity = 1;
|
||
|
|
#endif
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/* (4) Get otg auto/manual mode */
|
||
|
|
#ifdef LPKG_CHERRYUSB_OTG_AUTO
|
||
|
|
d->auto_flg = 1;
|
||
|
|
if (d->id_gpio < 0) {
|
||
|
|
USB_LOG_ERR("get id gpio err.\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
d->mode = usb_otg_get_id();
|
||
|
|
usb_otg_sw_gpio(d->mode);
|
||
|
|
//usb_otg_id_detect_en();
|
||
|
|
#else
|
||
|
|
d->auto_flg = 0;
|
||
|
|
#ifdef LPKG_CHERRYUSB_OTG_DEF_HOST
|
||
|
|
d->mode = OTG_MODE_HOST;
|
||
|
|
#else
|
||
|
|
d->mode = OTG_MODE_DEVICE;
|
||
|
|
#endif
|
||
|
|
usb_otg_sw_gpio(d->mode);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int usb_otg_init(void)
|
||
|
|
{
|
||
|
|
int ret = EOK;
|
||
|
|
|
||
|
|
memset(&g_usb_otg, 0, sizeof(struct usb_otg));
|
||
|
|
usb_otg_config_init();
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void cmd_set_otg_mode_usage(void)
|
||
|
|
{
|
||
|
|
printf("Usage: set_otg_mode [auto/host/device]\n");
|
||
|
|
printf("Example: set_otg_mode device\n");
|
||
|
|
}
|
||
|
|
|
||
|
|
static int cmd_set_otg_mode(int argc, char **argv)
|
||
|
|
{
|
||
|
|
if (argc != 2) {
|
||
|
|
cmd_set_otg_mode_usage();
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
if (strcmp(argv[1], "auto") == 0) {
|
||
|
|
usb_otg_set_mode(1, 0);
|
||
|
|
} else if (strcmp(argv[1], "host") == 0) {
|
||
|
|
usb_otg_set_mode(0, OTG_MODE_HOST);
|
||
|
|
} else if (strcmp(argv[1], "device") == 0) {
|
||
|
|
usb_otg_set_mode(0, OTG_MODE_DEVICE);
|
||
|
|
} else {
|
||
|
|
cmd_set_otg_mode_usage();
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int cmd_get_otg_mode(int argc, char **argv)
|
||
|
|
{
|
||
|
|
unsigned int auto_flg, mode;
|
||
|
|
|
||
|
|
usb_otg_get_mode(&auto_flg, &mode);
|
||
|
|
|
||
|
|
if (auto_flg)
|
||
|
|
printf("Usb otg auto mode ");
|
||
|
|
else
|
||
|
|
printf("Usb otg manual mode ");
|
||
|
|
|
||
|
|
if (mode == OTG_MODE_HOST)
|
||
|
|
printf("(usb0 = host).\n");
|
||
|
|
else
|
||
|
|
printf("(usb0 = device).\n");
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
#if defined(RT_USING_FINSH)
|
||
|
|
MSH_CMD_EXPORT_ALIAS(cmd_set_otg_mode, set_otg_mode, Set usb otg mode);
|
||
|
|
MSH_CMD_EXPORT_ALIAS(cmd_get_otg_mode, get_otg_mode, Get usb otg mode);
|
||
|
|
#elif defined(AIC_CONSOLE_BARE_DRV)
|
||
|
|
#include <console.h>
|
||
|
|
CONSOLE_CMD(set_otg_mode, cmd_set_otg_mode, "Set usb otg mode");
|
||
|
|
CONSOLE_CMD(get_otg_mode, cmd_get_otg_mode, "Get usb otg mode");
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#if defined(KERNEL_RTTHREAD)
|
||
|
|
INIT_BOARD_EXPORT(usb_otg_init);
|
||
|
|
#endif
|
||
|
|
|