Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Tomas Melin and committed by
Alexandre Belloni
0f998944 83b9e5eb

+17 -10
+17 -10
drivers/rtc/rtc-zynqmp.c
··· 43 43 #define RTC_MSEC 1000 44 44 #define RTC_FR_MASK 0xF0000 45 45 #define RTC_FR_MAX_TICKS 16 46 - #define RTC_PPB 1000000000LL 46 + #define RTC_PPB 1000000000 47 47 #define RTC_MIN_OFFSET -32768000 48 48 #define RTC_MAX_OFFSET 32767000 49 49 ··· 178 178 static int xlnx_rtc_read_offset(struct device *dev, long *offset) 179 179 { 180 180 struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev); 181 - unsigned long long rtc_ppb = RTC_PPB; 182 - unsigned int tick_mult = do_div(rtc_ppb, xrtcdev->freq); 183 - unsigned int calibval; 181 + unsigned int calibval, fract_data, fract_part; 182 + int freq = xrtcdev->freq; 183 + int max_tick, tick_mult; 184 184 long offset_val; 185 + 186 + /* Tick to offset multiplier */ 187 + tick_mult = DIV_ROUND_CLOSEST(RTC_PPB, freq); 185 188 186 189 calibval = readl(xrtcdev->reg_base + RTC_CALIB_RD); 187 190 /* Offset with seconds ticks */ 188 - offset_val = calibval & RTC_TICK_MASK; 189 - offset_val = offset_val - RTC_CALIB_DEF; 190 - offset_val = offset_val * tick_mult; 191 + max_tick = calibval & RTC_TICK_MASK; 192 + offset_val = max_tick - freq; 193 + /* Convert to ppb */ 194 + offset_val *= tick_mult; 191 195 192 196 /* Offset with fractional ticks */ 193 - if (calibval & RTC_FR_EN) 194 - offset_val += ((calibval & RTC_FR_MASK) >> RTC_FR_DATSHIFT) 195 - * (tick_mult / RTC_FR_MAX_TICKS); 197 + if (calibval & RTC_FR_EN) { 198 + fract_data = (calibval & RTC_FR_MASK) >> RTC_FR_DATSHIFT; 199 + fract_part = DIV_ROUND_UP(tick_mult, RTC_FR_MAX_TICKS); 200 + offset_val += (fract_part * fract_data); 201 + } 202 + 196 203 *offset = offset_val; 197 204 198 205 return 0;