drivers: usb_dc_stm32: Add support for all STM32 families

Add support for all STM32 families

Signed-off-by: Yannis Damigos <giannis.damigos@gmail.com>
Signed-off-by: qianfan Zhao <qianfanguijin@163.com>
This commit is contained in:
Yannis Damigos 2017-10-27 20:21:12 +03:00 committed by Kumar Gala
commit 921bfeb05a
4 changed files with 116 additions and 26 deletions

View file

@ -65,4 +65,11 @@ config I2C_STM32
endif endif
if USB
config USB_DC_STM32
def_bool y
endif # USB
endif # SOC_FAMILY_STM32 endif # SOC_FAMILY_STM32

View file

@ -27,9 +27,6 @@ endif # GPIO_STM32
if USB if USB
config USB_DC_STM32
def_bool y
if USB_CDC_ACM if USB_CDC_ACM
config CDC_ACM_INT_EP_ADDR config CDC_ACM_INT_EP_ADDR

View file

@ -29,15 +29,16 @@ config USB_DW_IRQ_PRI
config USB_DC_STM32 config USB_DC_STM32
bool bool
prompt "USB device controller driver for STM32 devices" prompt "USB device controller driver for STM32 devices"
depends on SOC_SERIES_STM32F4X depends on SOC_FAMILY_STM32
select USB_DEVICE_DRIVER select USB_DEVICE_DRIVER
select USE_STM32_LL_USB select USE_STM32_LL_USB if !SOC_SERIES_STM32F0X && !SOC_SERIES_STM32F3X && !SOC_SERIES_STM32L0X
select USE_STM32_HAL_PCD select USE_STM32_HAL_PCD
select USE_STM32_HAL_PCD_EX select USE_STM32_HAL_PCD_EX
select HAS_DTS_USB select HAS_DTS_USB
default n default n
help help
STM32 family USB device controller Driver. Enable USB support on the STM32 F0, F1, F3, F4 and L4 family of
processors.
config USB_DC_SAM0 config USB_DC_SAM0
bool bool

View file

@ -2,6 +2,7 @@
/* /*
* Copyright (c) 2017 Christer Weinigel. * Copyright (c) 2017 Christer Weinigel.
* Copyright (c) 2017, I-SENSE group of ICCS
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -53,6 +54,18 @@
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_USB_DRIVER_LEVEL #define SYS_LOG_LEVEL CONFIG_SYS_LOG_USB_DRIVER_LEVEL
#include <logging/sys_log.h> #include <logging/sys_log.h>
/*
* USB LL API provides the EP_TYPE_* defines. STM32Cube does
* not provide USB LL API for STM32F0 and STM32F3 families.
* Map EP_TYPE_* defines to PCD_EP_TYPE_* defines
*/
#if defined(CONFIG_SOC_SERIES_STM32F3X) || defined(CONFIG_SOC_SERIES_STM32F0X)
#define EP_TYPE_CTRL PCD_EP_TYPE_CTRL
#define EP_TYPE_ISOC PCD_EP_TYPE_ISOC
#define EP_TYPE_BULK PCD_EP_TYPE_BULK
#define EP_TYPE_INTR PCD_EP_TYPE_INTR
#endif
/* Total in ep number = bidirectional ep number + in ep number */ /* Total in ep number = bidirectional ep number + in ep number */
#define NUM_IN_EP (CONFIG_USB_NUM_BIDIR_ENDPOINTS + \ #define NUM_IN_EP (CONFIG_USB_NUM_BIDIR_ENDPOINTS + \
CONFIG_USB_NUM_IN_ENDPOINTS) CONFIG_USB_NUM_IN_ENDPOINTS)
@ -67,6 +80,32 @@
*/ */
#define NUM_BIDIR_EP NUM_OUT_EP #define NUM_BIDIR_EP NUM_OUT_EP
/*
* USB and USB_OTG_FS are defined in STM32Cube HAL and allows to distinguish
* between two kind of USB DC. STM32 F0, F3, and L0 series support USB device
* controller. STM32 F4 and F7 series support USB_OTG_FS device controller.
* STM32 F1 and L4 series support either USB or USB_OTG_FS device controller.
*
* WARNING: Don't mix USB defined in STM32Cube HAL and CONFIG_USB from Zephyr
* Kconfig system.
*/
#ifdef USB
#define EP0_MPS 64U
#define EP_MPS 64U
/*
* USB BTABLE is stored in the PMA. The size of BTABLE is 4 bytes
* per endpoint.
*
*/
#define USB_BTABLE_SIZE (8 * NUM_BIDIR_EP)
#else /* USB_OTG_FS */
#define EP0_MPS USB_OTG_MAX_EP0_SIZE
#define EP_MPS USB_OTG_FS_MAX_PACKET_SIZE
/* We need one RX FIFO and n TX-IN FIFOs */ /* We need one RX FIFO and n TX-IN FIFOs */
#define FIFO_NUM (1 + NUM_IN_EP) #define FIFO_NUM (1 + NUM_IN_EP)
@ -76,6 +115,8 @@
/* Allocate FIFO memory evenly between the FIFOs */ /* Allocate FIFO memory evenly between the FIFOs */
#define FIFO_EP_WORDS (FIFO_WORDS / FIFO_NUM) #define FIFO_EP_WORDS (FIFO_WORDS / FIFO_NUM)
#endif /* USB */
/* Size of a USB SETUP packet */ /* Size of a USB SETUP packet */
#define SETUP_SIZE 8 #define SETUP_SIZE 8
@ -105,7 +146,11 @@ struct usb_dc_stm32_state {
usb_dc_status_callback status_cb; /* Status callback */ usb_dc_status_callback status_cb; /* Status callback */
struct usb_dc_stm32_ep_state out_ep_state[NUM_OUT_EP]; struct usb_dc_stm32_ep_state out_ep_state[NUM_OUT_EP];
struct usb_dc_stm32_ep_state in_ep_state[NUM_IN_EP]; struct usb_dc_stm32_ep_state in_ep_state[NUM_IN_EP];
u8_t ep_buf[NUM_OUT_EP][USB_OTG_FS_MAX_PACKET_SIZE]; u8_t ep_buf[NUM_OUT_EP][EP_MPS];
#ifdef USB
u32_t pma_offset;
#endif /* USB */
}; };
static struct usb_dc_stm32_state usb_dc_stm32_state; static struct usb_dc_stm32_state usb_dc_stm32_state;
@ -138,8 +183,21 @@ static int usb_dc_stm32_clock_enable(void)
{ {
struct device *clk = device_get_binding(STM32_CLOCK_CONTROL_NAME); struct device *clk = device_get_binding(STM32_CLOCK_CONTROL_NAME);
struct stm32_pclken pclken = { struct stm32_pclken pclken = {
#ifdef USB
.bus = STM32_CLOCK_BUS_APB1,
.enr = LL_APB1_GRP1_PERIPH_USB,
#else /* USB_OTG_FS */
#ifdef CONFIG_SOC_SERIES_STM32F1X
.bus = STM32_CLOCK_BUS_AHB1,
.enr = LL_AHB1_GRP1_PERIPH_OTGFS,
#else
.bus = STM32_CLOCK_BUS_AHB2, .bus = STM32_CLOCK_BUS_AHB2,
.enr = LL_AHB2_GRP1_PERIPH_OTGFS, .enr = LL_AHB2_GRP1_PERIPH_OTGFS,
#endif /* CONFIG_SOC_SERIES_STM32F1X */
#endif /* USB */
}; };
clock_control_on(clk, (clock_control_subsys_t *)&pclken); clock_control_on(clk, (clock_control_subsys_t *)&pclken);
@ -152,15 +210,27 @@ static int usb_dc_stm32_init(void)
HAL_StatusTypeDef status; HAL_StatusTypeDef status;
unsigned int i; unsigned int i;
/* We only support OTG FS for now */ #ifdef USB
usb_dc_stm32_state.pcd.Instance = USB;
usb_dc_stm32_state.pcd.Init.speed = PCD_SPEED_FULL;
usb_dc_stm32_state.pcd.Init.dev_endpoints = NUM_BIDIR_EP;
usb_dc_stm32_state.pcd.Init.phy_itface = PCD_PHY_EMBEDDED;
usb_dc_stm32_state.pcd.Init.ep0_mps = PCD_EP0MPS_64;
usb_dc_stm32_state.pcd.Init.low_power_enable = 0;
#else /* USB_OTG_FS */
usb_dc_stm32_state.pcd.Instance = USB_OTG_FS; usb_dc_stm32_state.pcd.Instance = USB_OTG_FS;
usb_dc_stm32_state.pcd.Init.dev_endpoints = NUM_BIDIR_EP; usb_dc_stm32_state.pcd.Init.dev_endpoints = NUM_BIDIR_EP;
usb_dc_stm32_state.pcd.Init.speed = USB_OTG_SPEED_FULL; usb_dc_stm32_state.pcd.Init.speed = USB_OTG_SPEED_FULL;
usb_dc_stm32_state.pcd.Init.phy_itface = PCD_PHY_EMBEDDED; usb_dc_stm32_state.pcd.Init.phy_itface = PCD_PHY_EMBEDDED;
usb_dc_stm32_state.pcd.Init.ep0_mps = USB_OTG_MAX_EP0_SIZE; usb_dc_stm32_state.pcd.Init.ep0_mps = USB_OTG_MAX_EP0_SIZE;
usb_dc_stm32_state.pcd.Init.dma_enable = DISABLE;
usb_dc_stm32_state.pcd.Init.vbus_sensing_enable = DISABLE; usb_dc_stm32_state.pcd.Init.vbus_sensing_enable = DISABLE;
#ifndef CONFIG_SOC_SERIES_STM32F1X
usb_dc_stm32_state.pcd.Init.dma_enable = DISABLE;
#endif
#endif /* USB */
SYS_LOG_DBG("HAL_PCD_Init"); SYS_LOG_DBG("HAL_PCD_Init");
status = HAL_PCD_Init(&usb_dc_stm32_state.pcd); status = HAL_PCD_Init(&usb_dc_stm32_state.pcd);
if (status != HAL_OK) { if (status != HAL_OK) {
@ -175,11 +245,19 @@ static int usb_dc_stm32_init(void)
return -EIO; return -EIO;
} }
usb_dc_stm32_state.out_ep_state[EP0_IDX].ep_mps = USB_OTG_MAX_EP0_SIZE; usb_dc_stm32_state.out_ep_state[EP0_IDX].ep_mps = EP0_MPS;
usb_dc_stm32_state.out_ep_state[EP0_IDX].ep_type = EP_TYPE_CTRL; usb_dc_stm32_state.out_ep_state[EP0_IDX].ep_type = EP_TYPE_CTRL;
usb_dc_stm32_state.in_ep_state[EP0_IDX].ep_mps = USB_OTG_MAX_EP0_SIZE; usb_dc_stm32_state.in_ep_state[EP0_IDX].ep_mps = EP0_MPS;
usb_dc_stm32_state.in_ep_state[EP0_IDX].ep_type = EP_TYPE_CTRL; usb_dc_stm32_state.in_ep_state[EP0_IDX].ep_type = EP_TYPE_CTRL;
#ifdef USB
/* Start PMA configuration for the endpoints after the BTABLE. */
usb_dc_stm32_state.pma_offset = USB_BTABLE_SIZE;
for (i = 0; i < NUM_IN_EP; i++) {
k_sem_init(&usb_dc_stm32_state.in_ep_state[i].write_sem, 1, 1);
}
#else /* USB_OTG_FS */
/* TODO: make this dynamic (depending usage) */ /* TODO: make this dynamic (depending usage) */
HAL_PCDEx_SetRxFiFo(&usb_dc_stm32_state.pcd, FIFO_EP_WORDS); HAL_PCDEx_SetRxFiFo(&usb_dc_stm32_state.pcd, FIFO_EP_WORDS);
for (i = 0; i < NUM_IN_EP; i++) { for (i = 0; i < NUM_IN_EP; i++) {
@ -187,11 +265,11 @@ static int usb_dc_stm32_init(void)
FIFO_EP_WORDS); FIFO_EP_WORDS);
k_sem_init(&usb_dc_stm32_state.in_ep_state[i].write_sem, 1, 1); k_sem_init(&usb_dc_stm32_state.in_ep_state[i].write_sem, 1, 1);
} }
#endif /* USB */
IRQ_CONNECT(CONFIG_USB_IRQ, CONFIG_USB_IRQ_PRI, IRQ_CONNECT(CONFIG_USB_IRQ, CONFIG_USB_IRQ_PRI,
usb_dc_stm32_isr, 0, 0); usb_dc_stm32_isr, 0, 0);
irq_enable(CONFIG_USB_IRQ); irq_enable(CONFIG_USB_IRQ);
return 0; return 0;
} }
@ -268,8 +346,8 @@ int usb_dc_ep_start_read(u8_t ep, u8_t *data, u32_t max_data_len)
return -EINVAL; return -EINVAL;
} }
if (max_data_len > USB_OTG_FS_MAX_PACKET_SIZE) { if (max_data_len > EP_MPS) {
max_data_len = USB_OTG_FS_MAX_PACKET_SIZE; max_data_len = EP_MPS;
} }
status = HAL_PCD_EP_Receive(&usb_dc_stm32_state.pcd, ep, status = HAL_PCD_EP_Receive(&usb_dc_stm32_state.pcd, ep,
@ -308,6 +386,15 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data * const ep_cfg)
return -EINVAL; return -EINVAL;
} }
#ifdef USB
if (CONFIG_USB_RAM_SIZE <=
(usb_dc_stm32_state.pma_offset + ep_cfg->ep_mps)) {
return -EINVAL;
}
HAL_PCDEx_PMAConfig(&usb_dc_stm32_state.pcd, ep, PCD_SNG_BUF,
usb_dc_stm32_state.pma_offset);
usb_dc_stm32_state.pma_offset += ep_cfg->ep_mps;
#endif
ep_state->ep_mps = ep_cfg->ep_mps; ep_state->ep_mps = ep_cfg->ep_mps;
switch (ep_cfg->ep_type) { switch (ep_cfg->ep_type) {
@ -396,7 +483,6 @@ int usb_dc_ep_enable(const u8_t ep)
{ {
struct usb_dc_stm32_ep_state *ep_state = usb_dc_stm32_get_ep_state(ep); struct usb_dc_stm32_ep_state *ep_state = usb_dc_stm32_get_ep_state(ep);
HAL_StatusTypeDef status; HAL_StatusTypeDef status;
int ret;
SYS_LOG_DBG("ep 0x%02x", ep); SYS_LOG_DBG("ep 0x%02x", ep);
@ -415,15 +501,10 @@ int usb_dc_ep_enable(const u8_t ep)
return -EIO; return -EIO;
} }
ret = usb_dc_ep_clear_stall(ep);
if (ret) {
return ret;
}
if (EP_IS_OUT(ep) && ep != EP0_OUT) { if (EP_IS_OUT(ep) && ep != EP0_OUT) {
return usb_dc_ep_start_read(ep, return usb_dc_ep_start_read(ep,
usb_dc_stm32_state.ep_buf[EP_IDX(ep)], usb_dc_stm32_state.ep_buf[EP_IDX(ep)],
USB_OTG_FS_MAX_PACKET_SIZE); EP_MPS);
} }
return 0; return 0;
@ -471,7 +552,7 @@ int usb_dc_ep_write(const u8_t ep, const u8_t *const data,
} }
if (!k_is_in_isr()) { if (!k_is_in_isr()) {
irq_disable(STM32F4_IRQ_OTG_FS); irq_disable(CONFIG_USB_IRQ);
} }
status = HAL_PCD_EP_Transmit(&usb_dc_stm32_state.pcd, ep, status = HAL_PCD_EP_Transmit(&usb_dc_stm32_state.pcd, ep,
@ -483,7 +564,7 @@ int usb_dc_ep_write(const u8_t ep, const u8_t *const data,
ret = -EIO; ret = -EIO;
} }
if (!ret && ep == EP0_IN) { if (!ret && ep == EP0_IN && data_len > 0) {
/* Wait for an empty package as from the host. /* Wait for an empty package as from the host.
* This also flushes the TX FIFO to the host. * This also flushes the TX FIFO to the host.
*/ */
@ -491,7 +572,7 @@ int usb_dc_ep_write(const u8_t ep, const u8_t *const data,
} }
if (!k_is_in_isr()) { if (!k_is_in_isr()) {
irq_enable(STM32F4_IRQ_OTG_FS); irq_enable(CONFIG_USB_IRQ);
} }
if (ret_bytes) { if (ret_bytes) {
@ -550,7 +631,7 @@ int usb_dc_ep_read_continue(u8_t ep)
*/ */
if (ep != EP0_OUT && !ep_state->read_count) { if (ep != EP0_OUT && !ep_state->read_count) {
usb_dc_ep_start_read(ep, usb_dc_stm32_state.ep_buf[EP_IDX(ep)], usb_dc_ep_start_read(ep, usb_dc_stm32_state.ep_buf[EP_IDX(ep)],
USB_OTG_FS_MAX_PACKET_SIZE); EP_MPS);
} }
return 0; return 0;
@ -584,6 +665,10 @@ void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd)
{ {
SYS_LOG_DBG(""); SYS_LOG_DBG("");
HAL_PCD_EP_Open(&usb_dc_stm32_state.pcd, EP0_IN, EP0_MPS, EP_TYPE_CTRL);
HAL_PCD_EP_Open(&usb_dc_stm32_state.pcd, EP0_OUT, EP0_MPS,
EP_TYPE_CTRL);
if (usb_dc_stm32_state.status_cb) { if (usb_dc_stm32_state.status_cb) {
usb_dc_stm32_state.status_cb(USB_DC_RESET, NULL); usb_dc_stm32_state.status_cb(USB_DC_RESET, NULL);
} }