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@vaisala.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