Commit 24879257 authored by Christophe Guibout's avatar Christophe Guibout Committed by Alexandre Belloni

rtc: stm32: improve rtc precision

The rtc is used to update the stgen counter on wake up from
low power modes, so it needs to be as much accurate as possible.

The maximization of asynchronous divider leads to a 4ms rtc
precision clock.
By decreasing pred_a to 0, it will have pred_s=32767 (when
need_accuracy is true), so stgen clock becomes more accurate
with 30us precision.
Nevertheless this will leads to an increase of power consumption.
Signed-off-by: default avatarChristophe Guibout <christophe.guibout@foss.st.com>
Signed-off-by: default avatarValentin Caron <valentin.caron@foss.st.com>
Link: https://lore.kernel.org/r/20230705174357.353616-4-valentin.caron@foss.st.comSigned-off-by: default avatarAlexandre Belloni <alexandre.belloni@bootlin.com>
parent 1c18b8ec
......@@ -114,6 +114,7 @@ struct stm32_rtc_data {
void (*clear_events)(struct stm32_rtc *rtc, unsigned int flags);
bool has_pclk;
bool need_dbp;
bool need_accuracy;
};
struct stm32_rtc {
......@@ -545,6 +546,7 @@ static void stm32_rtc_clear_events(struct stm32_rtc *rtc,
static const struct stm32_rtc_data stm32_rtc_data = {
.has_pclk = false,
.need_dbp = true,
.need_accuracy = false,
.regs = {
.tr = 0x00,
.dr = 0x04,
......@@ -566,6 +568,7 @@ static const struct stm32_rtc_data stm32_rtc_data = {
static const struct stm32_rtc_data stm32h7_rtc_data = {
.has_pclk = true,
.need_dbp = true,
.need_accuracy = false,
.regs = {
.tr = 0x00,
.dr = 0x04,
......@@ -596,6 +599,7 @@ static void stm32mp1_rtc_clear_events(struct stm32_rtc *rtc,
static const struct stm32_rtc_data stm32mp1_data = {
.has_pclk = true,
.need_dbp = false,
.need_accuracy = true,
.regs = {
.tr = 0x00,
.dr = 0x04,
......@@ -636,11 +640,25 @@ static int stm32_rtc_init(struct platform_device *pdev,
pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT;
pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT;
for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) {
pred_s = (rate / (pred_a + 1)) - 1;
if (rate > (pred_a_max + 1) * (pred_s_max + 1)) {
dev_err(&pdev->dev, "rtc_ck rate is too high: %dHz\n", rate);
return -EINVAL;
}
if (rtc->data->need_accuracy) {
for (pred_a = 0; pred_a <= pred_a_max; pred_a++) {
pred_s = (rate / (pred_a + 1)) - 1;
if (((pred_s + 1) * (pred_a + 1)) == rate)
break;
if (pred_s <= pred_s_max && ((pred_s + 1) * (pred_a + 1)) == rate)
break;
}
} else {
for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) {
pred_s = (rate / (pred_a + 1)) - 1;
if (((pred_s + 1) * (pred_a + 1)) == rate)
break;
}
}
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment