Commit 0f998944 authored by Tomas Melin's avatar Tomas Melin Committed by Alexandre Belloni
Browse files

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: default avatarHarini T <harini.t@amd.com>
Tested-by: default avatarHarini T <harini.t@amd.com>
Signed-off-by: default avatarTomas Melin <tomas.melin@vaisala.com>
Acked-by: default avatarMichal Simek <michal.simek@amd.com>
Link: https://patch.msgid.link/20260122-zynqmp-rtc-updates-v4-3-d4edb966b499@vaisala.com


Signed-off-by: default avatarAlexandre Belloni <alexandre.belloni@bootlin.com>
parent 83b9e5eb
Loading
Loading
Loading
Loading
+17 −10
Original line number Diff line number Diff line
@@ -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;