summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristophe Guibout <christophe.guibout@foss.st.com>2023-07-05 19:43:53 +0200
committerAlexandre Belloni <alexandre.belloni@bootlin.com>2023-07-27 23:03:34 +0200
commit2487925731b75961cf4b7d1d0d28d204b63787b9 (patch)
tree8c86417a2ba2830644aadaa04331ddcc8493f698
parent1c18b8ec52396af6a6e20cd3450dc9bff0781ab8 (diff)
downloadlinux-2487925731b75961cf4b7d1d0d28d204b63787b9.tar.gz
linux-2487925731b75961cf4b7d1d0d28d204b63787b9.tar.bz2
linux-2487925731b75961cf4b7d1d0d28d204b63787b9.zip
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: Christophe Guibout <christophe.guibout@foss.st.com> Signed-off-by: Valentin Caron <valentin.caron@foss.st.com> Link: https://lore.kernel.org/r/20230705174357.353616-4-valentin.caron@foss.st.com Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
-rw-r--r--drivers/rtc/rtc-stm32.c26
1 files changed, 22 insertions, 4 deletions
diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c
index bd7a59a07537..cad88668bcfb 100644
--- a/drivers/rtc/rtc-stm32.c
+++ b/drivers/rtc/rtc-stm32.c
@@ -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;
+ }
}
/*