diff --git a/boards/arm/b_u585i_iot02a/Kconfig.defconfig b/boards/arm/b_u585i_iot02a/Kconfig.defconfig index fd6fa58108c15..b3a8482d9bdeb 100644 --- a/boards/arm/b_u585i_iot02a/Kconfig.defconfig +++ b/boards/arm/b_u585i_iot02a/Kconfig.defconfig @@ -12,4 +12,9 @@ config SPI_STM32_INTERRUPT default y depends on SPI +choice STM32_LPTIM_CLOCK + default STM32_LPTIM_CLOCK_LSE + depends on STM32_LPTIM_TIMER +endchoice + endif # BOARD_B_U585I_IOT02A diff --git a/boards/arm/b_u585i_iot02a/arduino_r3_connector.dtsi b/boards/arm/b_u585i_iot02a/arduino_r3_connector.dtsi index 438187906d695..4bf599c616c9f 100644 --- a/boards/arm/b_u585i_iot02a/arduino_r3_connector.dtsi +++ b/boards/arm/b_u585i_iot02a/arduino_r3_connector.dtsi @@ -36,3 +36,4 @@ }; arduino_spi: &spi1 {}; +arduino_i2c: &i2c1 {}; diff --git a/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi b/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi index 09e8411896309..dfe376ea04240 100644 --- a/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi +++ b/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi @@ -28,6 +28,27 @@ gpios = <&gpioc 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; }; }; + + power-states { + stop0: state0 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <1>; + min-residency-us = <100>; + }; + stop1: state1 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <2>; + min-residency-us = <500>; + }; + stop2: state2 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <3>; + min-residency-us = <900>; + }; + }; }; &clk_lse { diff --git a/boards/arm/b_u585i_iot02a/b_u585i_iot02a.dts b/boards/arm/b_u585i_iot02a/b_u585i_iot02a.dts index 2ef68c6c36af2..b1ac2a10d3ce1 100644 --- a/boards/arm/b_u585i_iot02a/b_u585i_iot02a.dts +++ b/boards/arm/b_u585i_iot02a/b_u585i_iot02a.dts @@ -25,6 +25,14 @@ }; }; +&cpu0 { + cpu-power-states = <&stop0 &stop1 &stop2>; +}; + +&lptim1 { + status = "okay"; +}; + &usart1 { pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>; current-speed = <115200>; @@ -36,3 +44,21 @@ &spi1_miso_pe14 &spi1_mosi_pe15>; status = "okay"; }; + +&i2c1 { + pinctrl-0 = <&i2c1_scl_pb8 &i2c1_sda_pb9>; + status = "okay"; + clock-frequency = ; +}; + +&i2c2 { + pinctrl-0 = <&i2c2_scl_ph4 &i2c2_sda_ph5>; + status = "okay"; + clock-frequency = ; + + hts221@5f { + compatible = "st,hts221"; + reg = <0x5f>; + label = "HTS221"; + }; +}; diff --git a/boards/arm/b_u585i_iot02a/b_u585i_iot02a.yaml b/boards/arm/b_u585i_iot02a/b_u585i_iot02a.yaml index a6e4b2b3733ce..5158aacd737a3 100644 --- a/boards/arm/b_u585i_iot02a/b_u585i_iot02a.yaml +++ b/boards/arm/b_u585i_iot02a/b_u585i_iot02a.yaml @@ -9,5 +9,7 @@ toolchain: ram: 786 flash: 2048 supported: + - arduino_i2c - arduino_spi + - hts221 - spi diff --git a/boards/arm/b_u585i_iot02a/doc/index.rst b/boards/arm/b_u585i_iot02a/doc/index.rst index 830e81baa2201..de3450836c985 100644 --- a/boards/arm/b_u585i_iot02a/doc/index.rst +++ b/boards/arm/b_u585i_iot02a/doc/index.rst @@ -175,10 +175,11 @@ The Zephyr b_u585i_iot02a board configuration supports the following hardware fe +-----------+------------+-------------------------------------+ | GPIO | on-chip | gpio | +-----------+------------+-------------------------------------+ +| I2C | on-chip | i2c | ++-----------+------------+-------------------------------------+ | SPI | on-chip | spi | +-----------+------------+-------------------------------------+ - The default configuration can be found in the defconfig file: ``boards/arm/b_u585i_iot02a/b_u585i_iot02a_defconfig`` @@ -200,6 +201,8 @@ Default Zephyr Peripheral Mapping: - LD2 : PH6 - user button : PC13 - SPI1 NSS/SCK/MISO/MOSI : PE12/P13/P14/P15 (Arduino SPI) +- I2C_1 SDA/SDL : PB9/PB8 (Arduino I2C) +- I2C_2 SDA/SDL : PH5/PH4 System Clock ------------ diff --git a/drivers/clock_control/clock_stm32_ll_u5.c b/drivers/clock_control/clock_stm32_ll_u5.c index e396e016bacae..4edbb170cece9 100644 --- a/drivers/clock_control/clock_stm32_ll_u5.c +++ b/drivers/clock_control/clock_stm32_ll_u5.c @@ -324,6 +324,10 @@ void config_src_sysclk_pll(LL_UTILS_ClkInitTypeDef s_ClkInitStruct) STM32_PLL_N_MULTIPLIER, STM32_PLL_R_DIVISOR); + LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); + while (LL_PWR_IsActiveFlag_VOS() == 0) { + } + if (CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC >= 55) { /* * Set EPOD prescaler based on PLL1 input freq (MSI/PLLM) diff --git a/drivers/timer/stm32_lptim_timer.c b/drivers/timer/stm32_lptim_timer.c index af4b113cff805..485499fa819b5 100644 --- a/drivers/timer/stm32_lptim_timer.c +++ b/drivers/timer/stm32_lptim_timer.c @@ -83,8 +83,13 @@ int sys_clock_driver_init(const struct device *dev) ARG_UNUSED(dev); /* enable LPTIM clock source */ +#if defined(LL_APB1_GRP1_PERIPH_LPTIM1) LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_LPTIM1); LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_LPTIM1); +#elif defined(LL_APB3_GRP1_PERIPH_LPTIM1) + LL_APB3_GRP1_EnableClock(LL_APB3_GRP1_PERIPH_LPTIM1); + LL_SRDAMR_GRP1_EnableAutonomousClock(LL_SRDAMR_GRP1_PERIPH_LPTIM1AMEN); +#endif #if defined(CONFIG_STM32_LPTIM_CLOCK_LSI) /* enable LSI clock */ @@ -137,28 +142,51 @@ int sys_clock_driver_init(const struct device *dev) LL_LPTIM_SetClockSource(LPTIM1, LL_LPTIM_CLK_SOURCE_INTERNAL); /* configure the LPTIM1 prescaler with 1 */ LL_LPTIM_SetPrescaler(LPTIM1, LL_LPTIM_PRESCALER_DIV1); +#ifdef CONFIG_SOC_SERIES_STM32U5X + LL_LPTIM_OC_SetPolarity(LPTIM1, LL_LPTIM_CHANNEL_CH1, + LL_LPTIM_OUTPUT_POLARITY_REGULAR); +#else LL_LPTIM_SetPolarity(LPTIM1, LL_LPTIM_OUTPUT_POLARITY_REGULAR); +#endif LL_LPTIM_SetUpdateMode(LPTIM1, LL_LPTIM_UPDATE_MODE_IMMEDIATE); LL_LPTIM_SetCounterMode(LPTIM1, LL_LPTIM_COUNTER_MODE_INTERNAL); LL_LPTIM_DisableTimeout(LPTIM1); /* counting start is initiated by software */ LL_LPTIM_TrigSw(LPTIM1); +#ifdef CONFIG_SOC_SERIES_STM32U5X + /* Enable the LPTIM1 before proceeding with configuration */ + LL_LPTIM_Enable(LPTIM1); + + LL_LPTIM_DisableIT_CC1(LPTIM1); + while (LL_LPTIM_IsActiveFlag_DIEROK(LPTIM1) == 0) { + } + LL_LPTIM_ClearFlag_DIEROK(LPTIM1); + LL_LPTIM_ClearFLAG_CC1(LPTIM1); +#else /* LPTIM1 interrupt set-up before enabling */ /* no Compare match Interrupt */ LL_LPTIM_DisableIT_CMPM(LPTIM1); LL_LPTIM_ClearFLAG_CMPM(LPTIM1); +#endif /* Autoreload match Interrupt */ LL_LPTIM_EnableIT_ARRM(LPTIM1); +#ifdef CONFIG_SOC_SERIES_STM32U5X + while (LL_LPTIM_IsActiveFlag_DIEROK(LPTIM1) == 0) { + } + LL_LPTIM_ClearFlag_DIEROK(LPTIM1); +#endif LL_LPTIM_ClearFLAG_ARRM(LPTIM1); /* ARROK bit validates the write operation to ARR register */ LL_LPTIM_ClearFlag_ARROK(LPTIM1); accumulated_lptim_cnt = 0; +#ifndef CONFIG_SOC_SERIES_STM32U5X /* Enable the LPTIM1 counter */ LL_LPTIM_Enable(LPTIM1); +#endif /* Set the Autoreload value once the timer is enabled */ if (IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { @@ -175,7 +203,12 @@ int sys_clock_driver_init(const struct device *dev) #ifdef CONFIG_DEBUG /* stop LPTIM1 during DEBUG */ +#if defined(LL_DBGMCU_APB1_GRP1_LPTIM1_STOP) LL_DBGMCU_APB1_GRP1_FreezePeriph(LL_DBGMCU_APB1_GRP1_LPTIM1_STOP); +#elif defined(LL_DBGMCU_APB3_GRP1_LPTIM1_STOP) + LL_DBGMCU_APB3_GRP1_FreezePeriph(LL_DBGMCU_APB3_GRP1_LPTIM1_STOP); +#endif + #endif return 0; } @@ -210,14 +243,24 @@ void sys_clock_set_timeout(int32_t ticks, bool idle) if (ticks == K_TICKS_FOREVER) { /* disable LPTIM clock to avoid counting */ +#if defined(LL_APB1_GRP1_PERIPH_LPTIM1) LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_LPTIM1); +#elif defined(LL_APB3_GRP1_PERIPH_LPTIM1) + LL_APB3_GRP1_DisableClock(LL_APB3_GRP1_PERIPH_LPTIM1); +#endif return; } /* if LPTIM clock was previously stopped, it must now be restored */ +#if defined(LL_APB1_GRP1_PERIPH_LPTIM1) if (!LL_APB1_GRP1_IsEnabledClock(LL_APB1_GRP1_PERIPH_LPTIM1)) { LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_LPTIM1); } +#elif defined(LL_APB3_GRP1_PERIPH_LPTIM1) + if (!LL_APB3_GRP1_IsEnabledClock(LL_APB3_GRP1_PERIPH_LPTIM1)) { + LL_APB3_GRP1_EnableClock(LL_APB3_GRP1_PERIPH_LPTIM1); + } +#endif /* passing ticks==1 means "announce the next tick", * ticks value of zero (or even negative) is legal and diff --git a/dts/arm/st/u5/stm32u5.dtsi b/dts/arm/st/u5/stm32u5.dtsi index 55dc27f1da041..a8216bc76d1a3 100644 --- a/dts/arm/st/u5/stm32u5.dtsi +++ b/dts/arm/st/u5/stm32u5.dtsi @@ -8,6 +8,7 @@ #include #include #include +#include #include / { @@ -280,6 +281,44 @@ status = "disabled"; label = "SPI_3"; }; + + i2c1: i2c@40005400 { + compatible = "st,stm32-i2c-v2"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40005400 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00200000>; + interrupts = <55 0>, <56 0>; + interrupt-names = "event", "error"; + status = "disabled"; + label= "I2C_1"; + }; + + i2c2: i2c@40005800 { + compatible = "st,stm32-i2c-v2"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40005800 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00400000>; + interrupts = <57 0>, <58 0>; + interrupt-names = "event", "error"; + status = "disabled"; + label= "I2C_2"; + }; + + lptim1: timers@46004400 { + compatible = "st,stm32-lptim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x46004400 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00000800>; + interrupts = <67 1>; + interrupt-names = "wakeup"; + status = "disabled"; + label = "LPTIM_1"; + }; }; }; diff --git a/soc/arm/st_stm32/stm32u5/CMakeLists.txt b/soc/arm/st_stm32/stm32u5/CMakeLists.txt index ac3ba70ace6e7..59be7817eab82 100644 --- a/soc/arm/st_stm32/stm32u5/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32u5/CMakeLists.txt @@ -4,3 +4,7 @@ zephyr_include_directories(${ZEPHYR_BASE}/drivers) zephyr_sources( soc.c ) + +zephyr_sources_ifdef(CONFIG_PM + power.c + ) diff --git a/soc/arm/st_stm32/stm32u5/Kconfig.defconfig.series b/soc/arm/st_stm32/stm32u5/Kconfig.defconfig.series index b2be2f03e439a..8504d22820095 100644 --- a/soc/arm/st_stm32/stm32u5/Kconfig.defconfig.series +++ b/soc/arm/st_stm32/stm32u5/Kconfig.defconfig.series @@ -10,4 +10,7 @@ source "soc/arm/st_stm32/stm32u5/Kconfig.defconfig.stm32u5*" config SOC_SERIES default "stm32u5" +config STM32_LPTIM_TIMER + default y if PM + endif # SOC_SERIES_STM32U5X diff --git a/soc/arm/st_stm32/stm32u5/power.c b/soc/arm/st_stm32/stm32u5/power.c new file mode 100644 index 0000000000000..d38f166132c6a --- /dev/null +++ b/soc/arm/st_stm32/stm32u5/power.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2021 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); + +/* select MSI as wake-up system clock if configured, HSI otherwise */ +#if STM32_SYSCLK_SRC_MSI +#define RCC_STOP_WAKEUPCLOCK_SELECTED LL_RCC_STOP_WAKEUPCLOCK_MSI +#else +#define RCC_STOP_WAKEUPCLOCK_SELECTED LL_RCC_STOP_WAKEUPCLOCK_HSI +#endif + +void set_mode_stop(uint8_t substate_id) +{ + /* ensure the proper wake-up system clock */ + LL_RCC_SetClkAfterWakeFromStop(RCC_STOP_WAKEUPCLOCK_SELECTED); + + switch (substate_id) { + case 1: /* enter STOP0 mode */ + LL_PWR_SetPowerMode(LL_PWR_STOP0_MODE); + break; + case 2: /* enter STOP1 mode */ + LL_PWR_SetPowerMode(LL_PWR_STOP1_MODE); + break; + case 3: /* enter STOP2 mode */ + LL_PWR_SetPowerMode(LL_PWR_STOP2_MODE); + break; + default: + LOG_DBG("Unsupported power state substate-id %u", substate_id); + break; + } +} + +void set_mode_standby(uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + /* Select standby mode */ + LL_PWR_SetPowerMode(LL_PWR_STANDBY_MODE); +} + +void set_mode_shutdown(uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + /* Select shutdown mode */ + LL_PWR_SetPowerMode(LL_PWR_SHUTDOWN_MODE); +} + +/* Invoke Low Power/System Off specific Tasks */ +__weak void pm_power_state_set(struct pm_state_info info) +{ + + switch (info.state) { + case PM_STATE_SUSPEND_TO_IDLE: + set_mode_stop(info.substate_id); + break; + case PM_STATE_STANDBY: + /* To be tested */ + set_mode_standby(info.substate_id); + break; + case PM_STATE_SOFT_OFF: + set_mode_shutdown(info.substate_id); + break; + /* Following states are not supported */ + case PM_STATE_RUNTIME_IDLE: + __fallthrough; + case PM_STATE_ACTIVE: + __fallthrough; + case PM_STATE_SUSPEND_TO_RAM: + __fallthrough; + case PM_STATE_SUSPEND_TO_DISK: + LOG_DBG("Unsupported power state %u", info.state); + return; + } + + /* Set SLEEPDEEP bit of Cortex System Control Register */ + LL_LPM_EnableDeepSleep(); + + /* Select mode entry : WFE or WFI and enter the CPU selected mode */ + k_cpu_idle(); +} + +/* Handle SOC specific activity after Low Power Mode Exit */ +__weak void pm_power_state_exit_post_ops(struct pm_state_info info) +{ + switch (info.state) { + case PM_STATE_SUSPEND_TO_IDLE: + if (info.substate_id <= 3) { + LL_LPM_DisableSleepOnExit(); + LL_LPM_EnableSleep(); + } else { + LOG_DBG("Unsupported power substate-id %u", + info.substate_id); + } + case PM_STATE_STANDBY: + /* To be tested */ + LL_LPM_EnableSleep(); + case PM_STATE_SOFT_OFF: + /* We should not get there */ + __fallthrough; + case PM_STATE_ACTIVE: + __fallthrough; + case PM_STATE_SUSPEND_TO_RAM: + __fallthrough; + case PM_STATE_SUSPEND_TO_DISK: + __fallthrough; + default: + LOG_DBG("Unsupported power state %u", info.state); + break; + } + /* need to restore the clock */ + stm32_clock_control_init(NULL); + + /* + * System is now in active mode. + * Reenable interrupts which were disabled + * when OS started idling code. + */ + irq_unlock(0); +} + +/* Initialize STM32 Power */ +static int stm32_power_init(const struct device *dev) +{ + ARG_UNUSED(dev); + + /* enable Power clock */ + LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_PWR); + +#ifdef CONFIG_DEBUG + /* Enable the Debug Module during all and any Low power mode */ + LL_DBGMCU_EnableDBGStopMode(); +#endif /* CONFIG_DEBUG */ + + return 0; +} + +SYS_INIT(stm32_power_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/arm/st_stm32/stm32u5/soc.c b/soc/arm/st_stm32/stm32u5/soc.c index dcce2b4fcb321..a81800dc9c01e 100644 --- a/soc/arm/st_stm32/stm32u5/soc.c +++ b/soc/arm/st_stm32/stm32u5/soc.c @@ -59,8 +59,6 @@ static int stm32u5_init(const struct device *arg) /* Disable USB Type-C dead battery pull-down behavior */ LL_PWR_DisableUCPDDeadBattery(); - LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); - return 0; }