|
@@ -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,
|