diff options
author | Joshua Clayton <stillcompiling@gmail.com> | 2016-02-05 15:41:13 -0500 |
---|---|---|
committer | Alexandre Belloni <alexandre.belloni@free-electrons.com> | 2016-03-14 12:08:16 -0400 |
commit | bae2f647025549fd2a24f02e9587481a50c0066b (patch) | |
tree | 5e614db01c4a0a8eb9e892f22facd52893ff9e29 | |
parent | 5495a4159f7413f0367e8c9727ba9facd40ade7f (diff) |
rtc: pcf2123: implement read_offset and set_offset
pcf2123 has an offset register, which can be used to make minor
adjustments to the clock rate to compensate for temperature or
a crystal that is not exactly right.
Signed-off-by: Joshua Clayton <stillcompiling@gmail.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
-rw-r--r-- | drivers/rtc/rtc-pcf2123.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index d9a44ad1239b..da27738b1242 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c | |||
@@ -100,6 +100,7 @@ | |||
100 | /* PCF2123_REG_OFFSET BITS */ | 100 | /* PCF2123_REG_OFFSET BITS */ |
101 | #define OFFSET_SIGN_BIT BIT(6) /* 2's complement sign bit */ | 101 | #define OFFSET_SIGN_BIT BIT(6) /* 2's complement sign bit */ |
102 | #define OFFSET_COARSE BIT(7) /* Coarse mode offset */ | 102 | #define OFFSET_COARSE BIT(7) /* Coarse mode offset */ |
103 | #define OFFSET_STEP (2170) /* Offset step in parts per billion */ | ||
103 | 104 | ||
104 | /* READ/WRITE ADDRESS BITS */ | 105 | /* READ/WRITE ADDRESS BITS */ |
105 | #define PCF2123_WRITE BIT(4) | 106 | #define PCF2123_WRITE BIT(4) |
@@ -206,6 +207,59 @@ static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr, | |||
206 | return count; | 207 | return count; |
207 | } | 208 | } |
208 | 209 | ||
210 | static int pcf2123_read_offset(struct device *dev, long *offset) | ||
211 | { | ||
212 | int ret; | ||
213 | s8 reg; | ||
214 | |||
215 | ret = pcf2123_read(dev, PCF2123_REG_OFFSET, ®, 1); | ||
216 | if (ret < 0) | ||
217 | return ret; | ||
218 | |||
219 | if (reg & OFFSET_COARSE) | ||
220 | reg <<= 1; /* multiply by 2 and sign extend */ | ||
221 | else | ||
222 | reg |= (reg & OFFSET_SIGN_BIT) << 1; /* sign extend only */ | ||
223 | |||
224 | *offset = ((long)reg) * OFFSET_STEP; | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | /* | ||
230 | * The offset register is a 7 bit signed value with a coarse bit in bit 7. | ||
231 | * The main difference between the two is normal offset adjusts the first | ||
232 | * second of n minutes every other hour, with 61, 62 and 63 being shoved | ||
233 | * into the 60th minute. | ||
234 | * The coarse adjustment does the same, but every hour. | ||
235 | * the two overlap, with every even normal offset value corresponding | ||
236 | * to a coarse offset. Based on this algorithm, it seems that despite the | ||
237 | * name, coarse offset is a better fit for overlapping values. | ||
238 | */ | ||
239 | static int pcf2123_set_offset(struct device *dev, long offset) | ||
240 | { | ||
241 | s8 reg; | ||
242 | |||
243 | if (offset > OFFSET_STEP * 127) | ||
244 | reg = 127; | ||
245 | else if (offset < OFFSET_STEP * -128) | ||
246 | reg = -128; | ||
247 | else | ||
248 | reg = (s8)((offset + (OFFSET_STEP >> 1)) / OFFSET_STEP); | ||
249 | |||
250 | /* choose fine offset only for odd values in the normal range */ | ||
251 | if (reg & 1 && reg <= 63 && reg >= -64) { | ||
252 | /* Normal offset. Clear the coarse bit */ | ||
253 | reg &= ~OFFSET_COARSE; | ||
254 | } else { | ||
255 | /* Coarse offset. Divide by 2 and set the coarse bit */ | ||
256 | reg >>= 1; | ||
257 | reg |= OFFSET_COARSE; | ||
258 | } | ||
259 | |||
260 | return pcf2123_write_reg(dev, PCF2123_REG_OFFSET, reg); | ||
261 | } | ||
262 | |||
209 | static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm) | 263 | static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm) |
210 | { | 264 | { |
211 | u8 rxbuf[7]; | 265 | u8 rxbuf[7]; |
@@ -314,6 +368,9 @@ static int pcf2123_reset(struct device *dev) | |||
314 | static const struct rtc_class_ops pcf2123_rtc_ops = { | 368 | static const struct rtc_class_ops pcf2123_rtc_ops = { |
315 | .read_time = pcf2123_rtc_read_time, | 369 | .read_time = pcf2123_rtc_read_time, |
316 | .set_time = pcf2123_rtc_set_time, | 370 | .set_time = pcf2123_rtc_set_time, |
371 | .read_offset = pcf2123_read_offset, | ||
372 | .set_offset = pcf2123_set_offset, | ||
373 | |||
317 | }; | 374 | }; |
318 | 375 | ||
319 | static int pcf2123_probe(struct spi_device *spi) | 376 | static int pcf2123_probe(struct spi_device *spi) |