drivers: timer: stm32 lptim can divide its input clock freq

This PR will divide the LPTIM clock freq to increase the max timeout.
Only one LPTIM instance is considered for PM timer.
The input freq becomes a fraction of the internal PCLK
source (mainly LSE clock). As the tick per sec does not change,
the minimum lptim counter must always be >0.

Signed-off-by: Francois Ramu <francois.ramu@st.com>
This commit is contained in:
Francois Ramu 2022-06-21 15:42:56 +02:00 committed by Marti Bolivar
commit 39fab29c10

View file

@ -50,18 +50,24 @@ static const struct device *const clk_ctrl = DEVICE_DT_GET(STM32_CLOCK_CONTROL_N
* Assumptions and limitations:
*
* - system clock based on an LPTIM instance, clocked by LSI or LSE
* - prescaler is set to 1 (LL_LPTIM_PRESCALER_DIV1 in the related register)
* - prescaler is set to a 2^value from 1 (division of the LPTIM source clock by 1)
* to 128 (division of the LPTIM source clock by 128)
* - using LPTIM AutoReload capability to trig the IRQ (timeout irq)
* - when timeout irq occurs the counter is already reset
* - the maximum timeout duration is reached with the lptim_time_base value
* - with prescaler of 1, the max timeout (lptim_time_base) is 2seconds
* - with prescaler of 1, the max timeout (LPTIM_TIMEBASE) is 2 seconds:
* 0xFFFF / (LSE freq (32768Hz) / 1)
* - with prescaler of 128, the max timeout (LPTIM_TIMEBASE) is 256 seconds:
* 0xFFFF / (LSE freq (32768Hz) / 128)
*/
static uint32_t lptim_clock_freq = 32000;
static int32_t lptim_time_base;
/* The prescaler given by the DTS and to apply to the lptim clock */
#define LPTIM_CLOCK_RATIO DT_PROP(DT_DRV_INST(0), st_prescaler)
/* minimum nb of clock cycles to have to set autoreload register correctly */
/* Minimum nb of clock cycles to have to set autoreload register correctly */
#define LPTIM_GUARD_VALUE 2
/* A 32bit value cannot exceed 0xFFFFFFFF/LPTIM_TIMEBASE counting cycles.
@ -317,6 +323,7 @@ void stm32_lptim_wait_ready(void)
static int sys_clock_driver_init(void)
{
uint32_t count_per_tick;
int err;
@ -386,6 +393,9 @@ static int sys_clock_driver_init(void)
* Time base = (2s * freq) - 1
*/
/* Actual lptim clock freq when the clock source is reduced by the prescaler */
lptim_clock_freq = lptim_clock_freq / LPTIM_CLOCK_RATIO;
/* Clear the event flag and possible pending interrupt */
IRQ_CONNECT(DT_INST_IRQN(0),
DT_INST_IRQ(0, priority),
@ -399,8 +409,8 @@ static int sys_clock_driver_init(void)
/* configure the LPTIM counter */
LL_LPTIM_SetClockSource(LPTIM, LL_LPTIM_CLK_SOURCE_INTERNAL);
/* configure the LPTIM prescaler with 1 */
LL_LPTIM_SetPrescaler(LPTIM, LL_LPTIM_PRESCALER_DIV1);
/* the LPTIM clock freq is affected by the prescaler */
LL_LPTIM_SetPrescaler(LPTIM, (__CLZ(__RBIT(LPTIM_CLOCK_RATIO)) << LPTIM_CFGR_PRESC_Pos));
#ifdef CONFIG_SOC_SERIES_STM32U5X
LL_LPTIM_OC_SetPolarity(LPTIM, LL_LPTIM_CHANNEL_CH1,
LL_LPTIM_OUTPUT_POLARITY_REGULAR);
@ -454,8 +464,10 @@ static int sys_clock_driver_init(void)
/* LPTIM is triggered on a LPTIM_TIMEBASE period */
lptim_set_autoreload(lptim_time_base);
} else {
/* nb of LPTIM counter unit per kernel tick (depends on lptim clock prescaler) */
count_per_tick = (lptim_clock_freq / CONFIG_SYS_CLOCK_TICKS_PER_SEC);
/* LPTIM is triggered on a Tick period */
lptim_set_autoreload((lptim_clock_freq / CONFIG_SYS_CLOCK_TICKS_PER_SEC) - 1);
lptim_set_autoreload(count_per_tick - 1);
}
/* Start the LPTIM counter in continuous mode */