summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTomas Melin <tomas.melin@vaisala.com>2026-01-22 13:53:48 +0000
committerAlexandre Belloni <alexandre.belloni@bootlin.com>2026-01-29 16:44:37 +0100
commit9f5af70268d679e710a65e5e1b4259789a848309 (patch)
tree6b3556761fb1e5baf6186e9da5a514d9c8f79f90 /drivers
parent0f9989443faec6ae8b8418ddf39f080c75a23c0d (diff)
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. Tested-by: Harini T <harini.t@amd.com> Signed-off-by: Tomas Melin <tomas.melin@vaisala.com> Reviewed-by: Harini T <harini.t@amd.com> Acked-by: Michal Simek <michal.simek@amd.com> Link: https://patch.msgid.link/20260122-zynqmp-rtc-updates-v4-4-d4edb966b499@vaisala.com Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/rtc/rtc-zynqmp.c33
1 files changed, 13 insertions, 20 deletions
diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
index c82f4d490fc7..f0f5dc63e254 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 char fract_tick = 0;
+ int max_tick, tick_mult, fract_offset, fract_part;
+ int freq = xrtcdev->freq;
unsigned int calibval;
- short int max_tick;
- int fract_offset;
+ int fract_data = 0;
+ /* Tick to offset multiplier */
+ tick_mult = DIV_ROUND_CLOSEST(RTC_PPB, 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) {
- if (fract_offset < 0) {
- fract_offset = fract_offset + tick_mult;
+ fract_part = DIV_ROUND_UP(tick_mult, RTC_FR_MAX_TICKS);
+ fract_data = fract_offset / fract_part;
+ /* Subtract one from max_tick while adding fract_offset */
+ if (fract_offset < 0 && fract_data) {
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_data += RTC_FR_MAX_TICKS;
}
}
/* Zynqmp RTC uses second and fractional tick
* counters for compensation
*/
- calibval = max_tick + RTC_CALIB_DEF;
-
- if (fract_tick)
- calibval |= RTC_FR_EN;
+ calibval = max_tick + freq;
- calibval |= (fract_tick << RTC_FR_DATSHIFT);
+ if (fract_data)
+ calibval |= (RTC_FR_EN | (fract_data << RTC_FR_DATSHIFT));
writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR));