drivers: usb_dc_rpi_pico: Implemented vbus detection handling

As per USB 2.0 specification 7.1.5.1: The voltage source on the pull-up
resistor must be derived from or controlled by the power supplied on the
USB cable such that when VBUS is removed, the pull-up resistor does not
supply current on the data line to which it is attached.

Signed-off-by: Lukas Gehreke <lk.gehreke@gmail.com>
This commit is contained in:
Lukas Gehreke 2024-09-09 12:05:30 +02:00 committed by Anas Nashif
commit 4c0317fa47
3 changed files with 92 additions and 7 deletions

View file

@ -18,6 +18,7 @@
#include <zephyr/logging/log.h>
#include <zephyr/irq.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/pinctrl.h>
LOG_MODULE_REGISTER(udc_rpi, CONFIG_USB_DRIVER_LOG_LEVEL);
@ -50,6 +51,16 @@ struct udc_rpi_ep_state {
uint8_t next_pid;
};
#define USB_RPI_PICO_PINCTRL_DT_INST_DEFINE(n) \
COND_CODE_1(DT_INST_PINCTRL_HAS_NAME(n, default), (PINCTRL_DT_INST_DEFINE(n)), ())
#define USB_RPI_PICO_PINCTRL_DT_INST_DEV_CONFIG_GET(n) \
COND_CODE_1(DT_INST_PINCTRL_HAS_NAME(n, default), \
((void *)PINCTRL_DT_INST_DEV_CONFIG_GET(n)), (NULL))
USB_RPI_PICO_PINCTRL_DT_INST_DEFINE(0);
const struct pinctrl_dev_config *pcfg = USB_RPI_PICO_PINCTRL_DT_INST_DEV_CONFIG_GET(0);
#define USBD_THREAD_STACK_SIZE 1024
K_THREAD_STACK_DEFINE(thread_stack, USBD_THREAD_STACK_SIZE);
@ -333,9 +344,33 @@ static void udc_rpi_isr(const void *arg)
USB_DC_CONNECTED :
USB_DC_DISCONNECTED;
/* VBUS detection does not always detect the detach.
* Check on disconnect if VBUS is still attached
*/
if (pcfg != NULL && msg.type == USB_DC_DISCONNECTED &&
(usb_hw->sie_status & USB_SIE_STATUS_VBUS_DETECTED_BITS) == 0) {
LOG_DBG("Disconnected. Disabling pull-up");
hw_clear_alias(usb_hw)->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
}
k_msgq_put(&usb_dc_msgq, &msg, K_NO_WAIT);
}
if (status & USB_INTS_VBUS_DETECT_BITS) {
handled |= USB_INTS_VBUS_DETECT_BITS;
hw_clear_alias(usb_hw)->sie_status = USB_SIE_STATUS_VBUS_DETECTED_BITS;
if (pcfg != NULL) {
if (usb_hw->sie_status & USB_SIE_STATUS_VBUS_DETECTED_BITS) {
LOG_DBG("VBUS attached. Enabling pull-up");
hw_set_alias(usb_hw)->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
} else {
LOG_DBG("VBUS detached. Disabling pull-up");
hw_clear_alias(usb_hw)->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
}
}
}
if (status & USB_INTS_BUS_RESET_BITS) {
LOG_WRN("BUS RESET");
handled |= USB_INTS_BUS_RESET_BITS;
@ -426,6 +461,17 @@ static void udc_rpi_init_endpoint(const uint8_t i)
static int udc_rpi_init(void)
{
int ret;
/* Apply the pinctrl */
if (pcfg != NULL) {
ret = pinctrl_apply_state(pcfg, PINCTRL_STATE_DEFAULT);
if (ret != 0) {
LOG_ERR("Failed to apply pincfg: %d", ret);
return ret;
}
}
/* Reset usb controller */
reset_block(RESETS_RESET_USBCTRL_BITS);
unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
@ -437,8 +483,11 @@ static int udc_rpi_init(void)
/* Mux the controller to the onboard usb phy */
usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;
/* Force VBUS detect so the device thinks it is plugged into a host */
usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
if (pcfg == NULL) {
/* Force VBUS detect so the device thinks it is plugged into a host */
usb_hw->pwr =
USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
}
/* Enable the USB controller in device mode. */
usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS;
@ -455,7 +504,7 @@ static int udc_rpi_init(void)
USB_INTS_ERROR_BIT_STUFF_BITS | USB_INTS_ERROR_CRC_BITS |
USB_INTS_ERROR_DATA_SEQ_BITS | USB_INTS_ERROR_RX_OVERFLOW_BITS |
USB_INTS_ERROR_RX_TIMEOUT_BITS | USB_INTS_DEV_SUSPEND_BITS |
USB_INTR_DEV_RESUME_FROM_HOST_BITS;
USB_INTR_DEV_RESUME_FROM_HOST_BITS | USB_INTE_VBUS_DETECT_BITS;
/* Set up endpoints (endpoint control registers)
* described by device configuration
@ -465,8 +514,15 @@ static int udc_rpi_init(void)
udc_rpi_init_endpoint(i);
}
/* Present full speed device by enabling pull up on DP */
hw_set_alias(usb_hw)->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
/* Self powered devices must enable the pull up only if vbus is detected.
* If the pull-up is not enabled here, this will be handled by the USB_INTS_VBUS_DETECT
* interrupt.
*/
if (usb_hw->sie_status & USB_SIE_STATUS_VBUS_DETECTED_BITS) {
LOG_DBG("Enabling pull-up");
/* Present full speed device by enabling pull up on DP */
hw_set_alias(usb_hw)->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
}
return 0;
}

View file

@ -1,11 +1,29 @@
# Copyright (c) 2021, Pete Johanson
# SPDX-License-Identifier: Apache-2.0
description: RaspberryPi Pico USB Device Controller
description: |
RaspberryPi Pico USB Device Controller.
Example of enabling the controller with vbus detection:
&pinctrl {
usb_default: usb_default {
group1 {
pinmux = <USB_VBUS_DET_P1>;
input-enable;
};
};
};
zephyr_udc0: &usbd {
status = "okay";
pinctrl-0 = <&usb_default>;
pinctrl-names = "default";
};
compatible: "raspberrypi,pico-usbd"
include: [usb-ep.yaml, reset-device.yaml]
include: [usb-ep.yaml, reset-device.yaml, pinctrl-device.yaml]
properties:
reg:

View file

@ -231,4 +231,15 @@
#define GPOUT2_P24 RP2040_PINMUX(24, RP2_PINCTRL_GPIO_FUNC_GPCK)
#define GPOUT3_P25 RP2040_PINMUX(25, RP2_PINCTRL_GPIO_FUNC_GPCK)
#define USB_VBUS_DET_P1 RP2040_PINMUX(1, RP2_PINCTRL_GPIO_FUNC_USB)
#define USB_VBUS_DET_P4 RP2040_PINMUX(4, RP2_PINCTRL_GPIO_FUNC_USB)
#define USB_VBUS_DET_P7 RP2040_PINMUX(7, RP2_PINCTRL_GPIO_FUNC_USB)
#define USB_VBUS_DET_P10 RP2040_PINMUX(10, RP2_PINCTRL_GPIO_FUNC_USB)
#define USB_VBUS_DET_P13 RP2040_PINMUX(13, RP2_PINCTRL_GPIO_FUNC_USB)
#define USB_VBUS_DET_P16 RP2040_PINMUX(16, RP2_PINCTRL_GPIO_FUNC_USB)
#define USB_VBUS_DET_P19 RP2040_PINMUX(19, RP2_PINCTRL_GPIO_FUNC_USB)
#define USB_VBUS_DET_P22 RP2040_PINMUX(22, RP2_PINCTRL_GPIO_FUNC_USB)
#define USB_VBUS_DET_P25 RP2040_PINMUX(25, RP2_PINCTRL_GPIO_FUNC_USB)
#define USB_VBUS_DET_P28 RP2040_PINMUX(28, RP2_PINCTRL_GPIO_FUNC_USB)
#endif /* __RP2040_PINCTRL_H__ */