Commit bc3bee02 authored by Russell King's avatar Russell King Committed by Alexandre Belloni

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: default avatarRussell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: default avatarAlexandre Belloni <alexandre.belloni@free-electrons.com>
parent f94ffbc2
......@@ -35,6 +35,9 @@
#define REG_MONTHS 0x08
#define REG_YEARS 0x09
#define REG_OFFSET 0x0e
#define REG_OFFSET_MODE BIT(7)
struct pcf8523 {
struct rtc_device *rtc;
};
......@@ -272,10 +275,47 @@ static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd,
#define pcf8523_rtc_ioctl NULL
#endif
static int pcf8523_rtc_read_offset(struct device *dev, long *offset)
{
struct i2c_client *client = to_i2c_client(dev);
int err;
u8 value;
s8 val;
err = pcf8523_read(client, REG_OFFSET, &value);
if (err < 0)
return err;
/* sign extend the 7-bit offset value */
val = value << 1;
*offset = (value & REG_OFFSET_MODE ? 4069 : 4340) * (val >> 1);
return 0;
}
static int pcf8523_rtc_set_offset(struct device *dev, long offset)
{
struct i2c_client *client = to_i2c_client(dev);
long reg_m0, reg_m1;
u8 value;
reg_m0 = clamp(DIV_ROUND_CLOSEST(offset, 4340), -64L, 63L);
reg_m1 = clamp(DIV_ROUND_CLOSEST(offset, 4069), -64L, 63L);
if (abs(reg_m0 * 4340 - offset) < abs(reg_m1 * 4069 - offset))
value = reg_m0 & 0x7f;
else
value = (reg_m1 & 0x7f) | REG_OFFSET_MODE;
return pcf8523_write(client, REG_OFFSET, value);
}
static const struct rtc_class_ops pcf8523_rtc_ops = {
.read_time = pcf8523_rtc_read_time,
.set_time = pcf8523_rtc_set_time,
.ioctl = pcf8523_rtc_ioctl,
.read_offset = pcf8523_rtc_read_offset,
.set_offset = pcf8523_rtc_set_offset,
};
static int pcf8523_probe(struct i2c_client *client,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment