1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

cpu/sam0/usbdev: generalize pm_layered interaction

periph_cpu.h should define the required pm modes.
Additionally, some CPUs require a certain pm mode in USB IDLE mode.
This commit is contained in:
Jue 2022-10-29 13:50:52 +02:00
parent 220be1da7e
commit 5866262122
2 changed files with 34 additions and 17 deletions

View File

@ -1,5 +1,6 @@
/*
* Copyright (C) 2019 Koen Zandberg
* 2022 SSV Software Systems GmbH
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -13,6 +14,7 @@
* @brief Low level USB interface functions for the sam0 class devices
*
* @author Koen Zandberg <koen@bergzand.net>
* @author Juergen Fitschen <me@jue.yt>
* @}
*/
@ -279,20 +281,6 @@ static usbdev_ep_t *_usbdev_new_ep(usbdev_t *dev, usb_ep_type_t type,
return res;
}
static void _block_pm(void)
{
#if defined(CPU_COMMON_SAMD21)
pm_block(SAMD21_PM_IDLE_1);
#endif
}
static void _unblock_pm(void)
{
#if defined(CPU_COMMON_SAMD21)
pm_unblock(SAMD21_PM_IDLE_1);
#endif
}
static void _setup(sam0_common_usb_t *usbdev,
const sam0_common_usb_config_t *config)
{
@ -319,6 +307,18 @@ static void _usbdev_init(usbdev_t *dev)
/* Only one usb device on this board */
sam0_common_usb_t *usbdev = (sam0_common_usb_t *)dev;
/* clear previously set pm blockers */
if (usbdev->config->device->CTRLA.bit.ENABLE) {
#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_USB_IDLE_PM_BLOCK)
pm_unblock(SAM0_USB_IDLE_PM_BLOCK);
#endif
if (!usbdev->suspended) {
#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_USB_ACTIVE_PM_BLOCK)
pm_unblock(SAM0_USB_ACTIVE_PM_BLOCK);
#endif
}
}
/* Set GPIO */
gpio_init(usbdev->config->dp, GPIO_IN);
gpio_init(usbdev->config->dm, GPIO_IN);
@ -347,7 +347,13 @@ static void _usbdev_init(usbdev_t *dev)
usbdev->config->device->CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_FS;
_enable_irq(usbdev);
_block_pm();
#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_USB_IDLE_PM_BLOCK)
pm_block(SAM0_USB_IDLE_PM_BLOCK);
#endif
#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_USB_ACTIVE_PM_BLOCK)
pm_block(SAM0_USB_ACTIVE_PM_BLOCK);
#endif
usbdev->usbdev.cb(&usbdev->usbdev, USBDEV_EVENT_HOST_CONNECT);
/* Interrupt configuration */
#ifdef CPU_COMMON_SAMD5X
@ -542,8 +548,10 @@ static void _usbdev_esr(usbdev_t *dev)
USB_DEVICE_INTFLAG_SUSPEND;
usbdev->suspended = true;
usbdev->usbdev.cb(&usbdev->usbdev, USBDEV_EVENT_SUSPEND);
#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_USB_ACTIVE_PM_BLOCK)
/* Low power modes are available while suspended */
_unblock_pm();
pm_unblock(SAM0_USB_ACTIVE_PM_BLOCK);
#endif
}
else if (usbdev->config->device->INTFLAG.bit.WAKEUP &&
usbdev->suspended) {
@ -551,8 +559,10 @@ static void _usbdev_esr(usbdev_t *dev)
USB_DEVICE_INTFLAG_SUSPEND;
usbdev->suspended = false;
usbdev->usbdev.cb(&usbdev->usbdev, USBDEV_EVENT_RESUME);
#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_USB_ACTIVE_PM_BLOCK)
/* Device wakeup detected, blocking low power modes */
_block_pm();
pm_block(SAM0_USB_ACTIVE_PM_BLOCK);
#endif
}
else {
DEBUG("sam_usb: Unhandled interrupt\n");

View File

@ -53,6 +53,13 @@ extern "C" {
#define SAMD21_PM_IDLE_0 (3U) /**< Idle 0 (stops CPU) */
/** @} */
/**
* @name USB configuration
* @{
*/
#define SAM0_USB_ACTIVE_PM_BLOCK SAMD21_PM_IDLE_1 /**< Stay in Idle 0 mode */
/** @} */
/**
* @name SAMD21 GCLK definitions
* @{