[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-Id: <20251201-zynqmp-rtc-updates-v1-3-33875c1e385b@vaisala.com>
Date: Mon, 01 Dec 2025 12:50:28 +0000
From: Tomas Melin <tomas.melin@...sala.com>
To: Alexandre Belloni <alexandre.belloni@...tlin.com>,
Michal Simek <michal.simek@....com>
Cc: linux-rtc@...r.kernel.org, linux-arm-kernel@...ts.infradead.org,
linux-kernel@...r.kernel.org, Tomas Melin <tomas.melin@...sala.com>
Subject: [PATCH 3/4] rtc: zynqmp: rework set_offset
set_offset was using remainder of do_div as tick_mult which resulted in
wrong offset. Calibration value also assumed builtin calibration default.
Update fract_offset to correctly calculate the value for
negative offset and replace the for loop with division.
Signed-off-by: Tomas Melin <tomas.melin@...sala.com>
---
drivers/rtc/rtc-zynqmp.c | 29 +++++++++++------------------
1 file changed, 11 insertions(+), 18 deletions(-)
diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
index 7af5f6f99538f961a53ff56bfc656c907611b900..3bc8831ba2c4c4c701a49506b67ae6174f3ade3d 100644
--- a/drivers/rtc/rtc-zynqmp.c
+++ b/drivers/rtc/rtc-zynqmp.c
@@ -208,13 +208,13 @@ static int xlnx_rtc_read_offset(struct device *dev, long *offset)
static int xlnx_rtc_set_offset(struct device *dev, long offset)
{
struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
- unsigned long long rtc_ppb = RTC_PPB;
- unsigned int tick_mult = do_div(rtc_ppb, xrtcdev->freq);
+ unsigned int calibval, tick_mult, fract_part;
unsigned char fract_tick = 0;
- unsigned int calibval;
- short int max_tick;
- int fract_offset;
+ int freq = xrtcdev->freq;
+ int max_tick, fract_offset;
+ /* ticks to reach RTC_PPB */
+ tick_mult = DIV_ROUND_CLOSEST(RTC_PPB, xrtcdev->freq);
if (offset < RTC_MIN_OFFSET || offset > RTC_MAX_OFFSET)
return -ERANGE;
@@ -223,29 +223,22 @@ static int xlnx_rtc_set_offset(struct device *dev, long offset)
/* Number fractional ticks for given offset */
if (fract_offset) {
+ /* round up here so we stay below a full tick */
+ fract_part = DIV_ROUND_UP(tick_mult, RTC_FR_MAX_TICKS);
if (fract_offset < 0) {
- fract_offset = fract_offset + tick_mult;
+ fract_offset += (fract_part * RTC_FR_MAX_TICKS);
max_tick--;
}
- if (fract_offset > (tick_mult / RTC_FR_MAX_TICKS)) {
- for (fract_tick = 1; fract_tick < 16; fract_tick++) {
- if (fract_offset <=
- (fract_tick *
- (tick_mult / RTC_FR_MAX_TICKS)))
- break;
- }
- }
+ fract_tick = fract_offset / fract_part;
}
/* Zynqmp RTC uses second and fractional tick
* counters for compensation
*/
- calibval = max_tick + RTC_CALIB_DEF;
+ calibval = max_tick + freq;
if (fract_tick)
- calibval |= RTC_FR_EN;
-
- calibval |= (fract_tick << RTC_FR_DATSHIFT);
+ calibval |= (RTC_FR_EN | (fract_tick << RTC_FR_DATSHIFT));
writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
--
2.47.3
Powered by blists - more mailing lists