From 014912daae9e558f90780e92abef6bf009bf8161 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Wed, 13 Apr 2022 16:51:44 +0200 Subject: [PATCH] stm32/ulpi: Add USB3320 ULPI low-power functions. This driver allows switching USB3320 ULPI to low-power mode. It is ported/ adapted from ST code, stm32f7xx_lp_modes.c, which is BSD-3 licensed code. --- ports/stm32/Makefile | 1 + ports/stm32/ulpi.c | 194 +++++++++++++++++++++++++++++++++++++++++++ ports/stm32/ulpi.h | 32 +++++++ 3 files changed, 227 insertions(+) create mode 100644 ports/stm32/ulpi.c create mode 100644 ports/stm32/ulpi.h diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 85b25c77e2..34d5866747 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -279,6 +279,7 @@ SRC_C += \ pyb_spi.c \ qspi.c \ uart.c \ + ulpi.c \ can.c \ fdcan.c \ pyb_can.c \ diff --git a/ports/stm32/ulpi.c b/ports/stm32/ulpi.c new file mode 100644 index 0000000000..a118ca57f2 --- /dev/null +++ b/ports/stm32/ulpi.c @@ -0,0 +1,194 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Copyright (c) 2016 STMicroelectronics. All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + * USB3320 ULPI functions ported from stm32f7xx_lp_modes.c + * + * Source file: https://github.com/STMicroelectronics/STM32CubeF7/blob/v1.15.0/Projects/STM32746G-Discovery/Examples/PWR/PWR_CurrentConsumption/Src/stm32f7xx_lp_modes.c + */ + +#include +#include "py/mphal.h" +#include "pin_static_af.h" +#include "ulpi.h" + +#if MICROPY_HW_USB_HS_ULPI3320 + +#include STM32_HAL_H + +#define USBULPI_PHYCR ((uint32_t)(0x40040000 + 0x034)) +#define USBULPI_D07 ((uint32_t)0x000000FF) +#define USBULPI_New ((uint32_t)0x02000000) +#define USBULPI_RW ((uint32_t)0x00400000) +#define USBULPI_S_BUSY ((uint32_t)0x04000000) +#define USBULPI_S_DONE ((uint32_t)0x08000000) +#define USBULPI_TIMEOUT_COUNT (100) + +#define USB_OTG_READ_REG32(reg) (*(__IO uint32_t *)(reg)) +#define USB_OTG_WRITE_REG32(reg,value) (*(__IO uint32_t *)(reg) = (value)) + +/** + * @brief Read CR value + * @param Addr the Address of the ULPI Register + * @retval Returns value of PHY CR register + */ +static uint32_t USB_ULPI_Read(uint32_t Addr) { + uint32_t val = 0; + uint32_t timeout = USBULPI_TIMEOUT_COUNT; + + USB_OTG_WRITE_REG32(USBULPI_PHYCR, USBULPI_New | (Addr << 16)); + val = USB_OTG_READ_REG32(USBULPI_PHYCR); + while (((val & USBULPI_S_DONE) == 0) && (timeout--)) { + val = USB_OTG_READ_REG32(USBULPI_PHYCR); + } + val = USB_OTG_READ_REG32(USBULPI_PHYCR); + return val & 0x000000ff; +} + +/** + * @brief Write CR value + * @param Addr the Address of the ULPI Register + * @param Data Data to write + * @retval Returns value of PHY CR register + */ +static uint32_t USB_ULPI_Write(uint32_t Addr, uint32_t Data) { + uint32_t val; + uint32_t timeout = USBULPI_TIMEOUT_COUNT; + + USB_OTG_WRITE_REG32(USBULPI_PHYCR, USBULPI_New | USBULPI_RW | (Addr << 16) | (Data & 0x000000ff)); + val = USB_OTG_READ_REG32(USBULPI_PHYCR); + while (((val & USBULPI_S_DONE) == 0) && (timeout--)) { + val = USB_OTG_READ_REG32(USBULPI_PHYCR); + } + + val = USB_OTG_READ_REG32(USBULPI_PHYCR); + return 0; +} + +/** + * @brief This function configures the USB PHY to enter the low power mode + * @param None + * @retval None + */ +int ulpi_enter_low_power(void) { + uint32_t regval = 0; + + // Disable ULPI_CLK by accessing ULPI_PHY + // Read Vendor ID : (Low, High) 0x24,0x04 for USB3300 + regval = USB_ULPI_Read(0x00); + if (regval != 0x24) { + return MP_EIO; + } + + regval = USB_ULPI_Read(0x01); + if (regval != 0x04) { + return MP_EIO; + } + + // Read Product ID + regval = USB_ULPI_Read(0x02); + if (regval != 0x07) { + return MP_EIO; + } + + regval = USB_ULPI_Read(0x03); + if (regval != 0x00) { + return MP_EIO; + } + + // Write to scratch register the pattern 0x55 + USB_ULPI_Write(0x16, 0x55); + // Read to scratch Register and check-it again the written Pattern + regval = USB_ULPI_Read(0x16); + if (regval != 0x55) { + return MP_EIO; + } + + // Write to scratch register the pattern 0xAA + USB_ULPI_Write(0x16, 0xAA); + // Read to scratch Register and check-it again the written Pattern + regval = USB_ULPI_Read(0x16); + if (regval != 0xAA) { + return MP_EIO; + } + + // Read InterfaceControl reg + regval = USB_ULPI_Read(0x07); + + // Write InterfaceControl reg,to disable PullUp on stp, + // to avoid USB_PHY wake up when MCU entering standby + USB_ULPI_Write(0x07, regval | 0x80); + + // Read InterfaceControl reg + regval = USB_ULPI_Read(0x07); + if (regval != 0x80) { + return MP_EIO; + } + + // Read FunctionControl reg + regval = USB_ULPI_Read(0x04); + + // Reg 0x40 has a different value if USB is disconnected + if (regval != 0x40 && regval != 0x45) { + return MP_EIO; + } + + // Write FunctionControl reg,to put PHY into LowPower mode + USB_ULPI_Write(0x04, regval & (~0x40)); + + // Read FunctionControl reg again + regval = USB_ULPI_Read(0x04); + if (regval != 0x00) { + return MP_EIO; + } + + // Wait for the transceiver clock to stop. + HAL_Delay(10); + + return 0; +} + +/** + * @brief This function wakeup the USB PHY from the Low power mode + * @param None + * @retval None + */ +int ulpi_leave_low_power(void) { + // Configure STP as an output pin + mp_hal_pin_config(MICROPY_HW_USB_HS_ULPI_STP, MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0); + mp_hal_pin_config_speed(MICROPY_HW_USB_HS_ULPI_STP, MP_HAL_PIN_SPEED_VERY_HIGH); + + // Configure DIR as an input pin + mp_hal_pin_config(MICROPY_HW_USB_HS_ULPI_DIR, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0); + mp_hal_pin_config_speed(MICROPY_HW_USB_HS_ULPI_DIR, MP_HAL_PIN_SPEED_VERY_HIGH); + + // Set STP pin high + mp_hal_pin_high(MICROPY_HW_USB_HS_ULPI_STP); + + // Wait for DIR to go low + for (uint32_t i = 0; i < 500; i++, HAL_Delay(1)) { + if (mp_hal_pin_read(MICROPY_HW_USB_HS_ULPI_DIR) == 0) { + break; + } + } + + // Save DIR pin state before switching to alternate function + int dir_state = mp_hal_pin_read(MICROPY_HW_USB_HS_ULPI_DIR); + + // Revert STP/DIR to their alternate functions + mp_hal_pin_config(MICROPY_HW_USB_HS_ULPI_STP, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, GPIO_AF10_OTG_HS); + mp_hal_pin_config_speed(MICROPY_HW_USB_HS_ULPI_STP, MP_HAL_PIN_SPEED_VERY_HIGH); + + mp_hal_pin_config(MICROPY_HW_USB_HS_ULPI_DIR, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, GPIO_AF10_OTG_HS); + mp_hal_pin_config_speed(MICROPY_HW_USB_HS_ULPI_DIR, MP_HAL_PIN_SPEED_VERY_HIGH); + + return (dir_state == 0) ? 0 : -1; +} + +#endif // MICROPY_HW_USB_HS_ULPI3320 diff --git a/ports/stm32/ulpi.h b/ports/stm32/ulpi.h new file mode 100644 index 0000000000..1464110e77 --- /dev/null +++ b/ports/stm32/ulpi.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_ULPI_H +#define MICROPY_INCLUDED_STM32_ULPI_H + +int ulpi_enter_low_power(void); +int ulpi_leave_low_power(void); + +#endif // MICROPY_INCLUDED_STM32_ULPI_H