summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomas Melin <tomas.melin@vaisala.com>2026-01-22 16:53:47 +0300
committerAlexandre Belloni <alexandre.belloni@bootlin.com>2026-01-29 18:44:37 +0300
commit0f9989443faec6ae8b8418ddf39f080c75a23c0d (patch)
tree29f6debde3ef522a73a4ac7d37d8fb312f254a59
parent83b9e5eb043710190f6461729fa2e05320a6594d (diff)
downloadlinux-0f9989443faec6ae8b8418ddf39f080c75a23c0d.tar.xz
rtc: zynqmp: rework read_offset
read_offset() was using static frequency for determining the tick offset. It was also using remainder from do_div() operation as tick_mult value which caused the offset to be incorrect. At the same time, rework function to improve readability. It is worth noting, that due to rounding errors, the offset readback will differ slightly for positive and negative calibration values. Reviewed-by: Harini T <harini.t@amd.com> Tested-by: Harini T <harini.t@amd.com> Signed-off-by: Tomas Melin <tomas.melin@vaisala.com> Acked-by: Michal Simek <michal.simek@amd.com> Link: https://patch.msgid.link/20260122-zynqmp-rtc-updates-v4-3-d4edb966b499@vaisala.com Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
-rw-r--r--drivers/rtc/rtc-zynqmp.c27
1 files changed, 17 insertions, 10 deletions
diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
index caacce3725e2..c82f4d490fc7 100644
--- a/drivers/rtc/rtc-zynqmp.c
+++ b/drivers/rtc/rtc-zynqmp.c
@@ -43,7 +43,7 @@
#define RTC_MSEC 1000
#define RTC_FR_MASK 0xF0000
#define RTC_FR_MAX_TICKS 16
-#define RTC_PPB 1000000000LL
+#define RTC_PPB 1000000000
#define RTC_MIN_OFFSET -32768000
#define RTC_MAX_OFFSET 32767000
@@ -178,21 +178,28 @@ static void xlnx_init_rtc(struct xlnx_rtc_dev *xrtcdev)
static int xlnx_rtc_read_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;
+ unsigned int calibval, fract_data, fract_part;
+ int freq = xrtcdev->freq;
+ int max_tick, tick_mult;
long offset_val;
+ /* Tick to offset multiplier */
+ tick_mult = DIV_ROUND_CLOSEST(RTC_PPB, freq);
+
calibval = readl(xrtcdev->reg_base + RTC_CALIB_RD);
/* Offset with seconds ticks */
- offset_val = calibval & RTC_TICK_MASK;
- offset_val = offset_val - RTC_CALIB_DEF;
- offset_val = offset_val * tick_mult;
+ max_tick = calibval & RTC_TICK_MASK;
+ offset_val = max_tick - freq;
+ /* Convert to ppb */
+ offset_val *= tick_mult;
/* Offset with fractional ticks */
- if (calibval & RTC_FR_EN)
- offset_val += ((calibval & RTC_FR_MASK) >> RTC_FR_DATSHIFT)
- * (tick_mult / RTC_FR_MAX_TICKS);
+ if (calibval & RTC_FR_EN) {
+ fract_data = (calibval & RTC_FR_MASK) >> RTC_FR_DATSHIFT;
+ fract_part = DIV_ROUND_UP(tick_mult, RTC_FR_MAX_TICKS);
+ offset_val += (fract_part * fract_data);
+ }
+
*offset = offset_val;
return 0;