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

rtc: pcf8523: add support for trimming the RTC oscillator

Add support for reading and writing the RTC offset register, converting
it to the corresponding parts-per-billion value.

When setting the drift, the PCF8523 has two modes: one applies the
adjustment every two hours, the other applies the adjustment every
minute. We select between these two modes according to which ever
gives the closest PPB value to the one requested.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>

authored by

Russell King and committed by
Alexandre Belloni
bc3bee02 f94ffbc2

+40
+40
drivers/rtc/rtc-pcf8523.c
··· 35 35 #define REG_MONTHS 0x08 36 36 #define REG_YEARS 0x09 37 37 38 + #define REG_OFFSET 0x0e 39 + #define REG_OFFSET_MODE BIT(7) 40 + 38 41 struct pcf8523 { 39 42 struct rtc_device *rtc; 40 43 }; ··· 275 272 #define pcf8523_rtc_ioctl NULL 276 273 #endif 277 274 275 + static int pcf8523_rtc_read_offset(struct device *dev, long *offset) 276 + { 277 + struct i2c_client *client = to_i2c_client(dev); 278 + int err; 279 + u8 value; 280 + s8 val; 281 + 282 + err = pcf8523_read(client, REG_OFFSET, &value); 283 + if (err < 0) 284 + return err; 285 + 286 + /* sign extend the 7-bit offset value */ 287 + val = value << 1; 288 + *offset = (value & REG_OFFSET_MODE ? 4069 : 4340) * (val >> 1); 289 + 290 + return 0; 291 + } 292 + 293 + static int pcf8523_rtc_set_offset(struct device *dev, long offset) 294 + { 295 + struct i2c_client *client = to_i2c_client(dev); 296 + long reg_m0, reg_m1; 297 + u8 value; 298 + 299 + reg_m0 = clamp(DIV_ROUND_CLOSEST(offset, 4340), -64L, 63L); 300 + reg_m1 = clamp(DIV_ROUND_CLOSEST(offset, 4069), -64L, 63L); 301 + 302 + if (abs(reg_m0 * 4340 - offset) < abs(reg_m1 * 4069 - offset)) 303 + value = reg_m0 & 0x7f; 304 + else 305 + value = (reg_m1 & 0x7f) | REG_OFFSET_MODE; 306 + 307 + return pcf8523_write(client, REG_OFFSET, value); 308 + } 309 + 278 310 static const struct rtc_class_ops pcf8523_rtc_ops = { 279 311 .read_time = pcf8523_rtc_read_time, 280 312 .set_time = pcf8523_rtc_set_time, 281 313 .ioctl = pcf8523_rtc_ioctl, 314 + .read_offset = pcf8523_rtc_read_offset, 315 + .set_offset = pcf8523_rtc_set_offset, 282 316 }; 283 317 284 318 static int pcf8523_probe(struct i2c_client *client,