[RESEND v4 4/5] rtc: pcf85363: add oscillator offset calibration support
Lakshay Piplani <[email protected]>
| Newsgroups | org.kernel.vger.linux-rtc,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel,org.kernel.vger.linux-watchdog |
|---|---|
| Message-ID | <[email protected]> |
Expose the oscillator offset register of PCF85263/PCF85363 through the rtc_class_ops read_offset and set_offset callbacks, allowing userspace to apply frequency correction for drift compensation. The correction mode defaults to normal mode (OFFM = 0), where each step introduces an offset of approximately 2.170 ppm and corrections occur every 4 hours. Signed-off-by: Lakshay Piplani <[email protected]> --- V3 -> V4: - No changes in v4. V2 -> V3: - Split into separate patches as suggested: - Battery switch-over detection. - Timestamp recording for TS pin and battery switch-over events. - Offset calibration. - Watchdog timer (to be reviewed by watchdog maintainers). - Dropped Alarm2 support - Switched to rtc_add_group() for sysfs attributes V1 -> V2: - Watchdog related changes due to removal of vendor specific properties from device tree * remove vendor DT knobs (enable/timeout/stepsize/repeat) * use watchdog_init_timeout (with 10s default) * derive clock_sel from final timeout * default, repeat=true (repeat mode) - Fixed uninitalised warning on 'ret' (reported by kernel test robot) - Use dev_dbg instead of dev_info for debug related print messages - Minor cleanup and comments. drivers/rtc/rtc-pcf85363.c | 46 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/drivers/rtc/rtc-pcf85363.c b/drivers/rtc/rtc-pcf85363.c index e10e58f69012..665bbbb169b0 100644 --- a/drivers/rtc/rtc-pcf85363.c +++ b/drivers/rtc/rtc-pcf85363.c @@ -123,6 +123,11 @@ #define TSR2_SHIFT 2 #define TSR3_SHIFT 6 +#define OFFSET_SIGN_BIT 7 +#define OFFSET_MINIMUM -128 +#define OFFSET_MAXIMUM 127 +#define OFFSET_MASK 0xFF + struct pcf85363 { struct rtc_device *rtc; struct regmap *regmap; @@ -359,6 +364,45 @@ static irqreturn_t pcf85363_rtc_handle_irq(int irq, void *dev_id) return handled ? IRQ_HANDLED : IRQ_NONE; } +/* + * Read the current RTC offset from the CTRL_OFFSET + * register. This value is an 8-bit signed 2's complement + * value that corrects osciallator drift. + */ +static int pcf85363_read_offset(struct device *dev, long *offset) +{ + struct pcf85363 *pcf85363 = dev_get_drvdata(dev); + unsigned int val; + int ret; + + ret = regmap_read(pcf85363->regmap, CTRL_OFFSET, &val); + + if (ret) + return ret; + + *offset = sign_extend32(val & OFFSET_MASK, OFFSET_SIGN_BIT); + + return 0; +} + +/* + * Write an oscillator offset correction value to + * the CTRL_OFFSET register. The valid range is + * -128 to 127 (8-bit signed), typically used to fine + * tune accuracy. + */ +static int pcf85363_set_offset(struct device *dev, long offset) +{ + struct pcf85363 *pcf85363 = dev_get_drvdata(dev); + + if (offset < OFFSET_MINIMUM || offset > OFFSET_MAXIMUM) { + dev_warn(dev, "Offset out of range: %ld\n", offset); + return -ERANGE; + } + + return regmap_write(pcf85363->regmap, CTRL_OFFSET, offset & OFFSET_MASK); +} + static int pcf85363_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { @@ -396,6 +440,8 @@ static const struct rtc_class_ops rtc_ops = { .read_alarm = pcf85363_rtc_read_alarm, .set_alarm = pcf85363_rtc_set_alarm, .alarm_irq_enable = pcf85363_rtc_alarm_irq_enable, + .read_offset = pcf85363_read_offset, + .set_offset = pcf85363_set_offset, }; static int pcf85363_nvram_read(void *priv, unsigned int offset, void *val, -- 2.25.1