diff options
-rw-r--r-- | drivers/rtc/rtc-pcf2127.c | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 8d6eda455d81..3ec87d320766 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c | |||
@@ -25,11 +25,18 @@ | |||
25 | 25 | ||
26 | /* Control register 1 */ | 26 | /* Control register 1 */ |
27 | #define PCF2127_REG_CTRL1 0x00 | 27 | #define PCF2127_REG_CTRL1 0x00 |
28 | #define PCF2127_BIT_CTRL1_TSF1 BIT(4) | ||
28 | /* Control register 2 */ | 29 | /* Control register 2 */ |
29 | #define PCF2127_REG_CTRL2 0x01 | 30 | #define PCF2127_REG_CTRL2 0x01 |
31 | #define PCF2127_BIT_CTRL2_TSIE BIT(2) | ||
32 | #define PCF2127_BIT_CTRL2_TSF2 BIT(5) | ||
30 | /* Control register 3 */ | 33 | /* Control register 3 */ |
31 | #define PCF2127_REG_CTRL3 0x02 | 34 | #define PCF2127_REG_CTRL3 0x02 |
35 | #define PCF2127_BIT_CTRL3_BLIE BIT(0) | ||
36 | #define PCF2127_BIT_CTRL3_BIE BIT(1) | ||
32 | #define PCF2127_BIT_CTRL3_BLF BIT(2) | 37 | #define PCF2127_BIT_CTRL3_BLF BIT(2) |
38 | #define PCF2127_BIT_CTRL3_BF BIT(3) | ||
39 | #define PCF2127_BIT_CTRL3_BTSE BIT(4) | ||
33 | /* Time and date registers */ | 40 | /* Time and date registers */ |
34 | #define PCF2127_REG_SC 0x03 | 41 | #define PCF2127_REG_SC 0x03 |
35 | #define PCF2127_BIT_SC_OSF BIT(7) | 42 | #define PCF2127_BIT_SC_OSF BIT(7) |
@@ -46,6 +53,16 @@ | |||
46 | #define PCF2127_BIT_WD_CTL_CD0 BIT(6) | 53 | #define PCF2127_BIT_WD_CTL_CD0 BIT(6) |
47 | #define PCF2127_BIT_WD_CTL_CD1 BIT(7) | 54 | #define PCF2127_BIT_WD_CTL_CD1 BIT(7) |
48 | #define PCF2127_REG_WD_VAL 0x11 | 55 | #define PCF2127_REG_WD_VAL 0x11 |
56 | /* Tamper timestamp registers */ | ||
57 | #define PCF2127_REG_TS_CTRL 0x12 | ||
58 | #define PCF2127_BIT_TS_CTRL_TSOFF BIT(6) | ||
59 | #define PCF2127_BIT_TS_CTRL_TSM BIT(7) | ||
60 | #define PCF2127_REG_TS_SC 0x13 | ||
61 | #define PCF2127_REG_TS_MN 0x14 | ||
62 | #define PCF2127_REG_TS_HR 0x15 | ||
63 | #define PCF2127_REG_TS_DM 0x16 | ||
64 | #define PCF2127_REG_TS_MO 0x17 | ||
65 | #define PCF2127_REG_TS_YR 0x18 | ||
49 | /* | 66 | /* |
50 | * RAM registers | 67 | * RAM registers |
51 | * PCF2127 has 512 bytes general-purpose static RAM (SRAM) that is | 68 | * PCF2127 has 512 bytes general-purpose static RAM (SRAM) that is |
@@ -305,6 +322,97 @@ static const struct watchdog_ops pcf2127_watchdog_ops = { | |||
305 | .set_timeout = pcf2127_wdt_set_timeout, | 322 | .set_timeout = pcf2127_wdt_set_timeout, |
306 | }; | 323 | }; |
307 | 324 | ||
325 | /* sysfs interface */ | ||
326 | |||
327 | static ssize_t timestamp0_store(struct device *dev, | ||
328 | struct device_attribute *attr, | ||
329 | const char *buf, size_t count) | ||
330 | { | ||
331 | struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent); | ||
332 | int ret; | ||
333 | |||
334 | ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1, | ||
335 | PCF2127_BIT_CTRL1_TSF1, 0); | ||
336 | if (ret) { | ||
337 | dev_err(dev, "%s: update ctrl1 ret=%d\n", __func__, ret); | ||
338 | return ret; | ||
339 | } | ||
340 | |||
341 | ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2, | ||
342 | PCF2127_BIT_CTRL2_TSF2, 0); | ||
343 | if (ret) { | ||
344 | dev_err(dev, "%s: update ctrl2 ret=%d\n", __func__, ret); | ||
345 | return ret; | ||
346 | } | ||
347 | |||
348 | ret = pcf2127_wdt_active_ping(&pcf2127->wdd); | ||
349 | if (ret) | ||
350 | return ret; | ||
351 | |||
352 | return count; | ||
353 | }; | ||
354 | |||
355 | static ssize_t timestamp0_show(struct device *dev, | ||
356 | struct device_attribute *attr, char *buf) | ||
357 | { | ||
358 | struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent); | ||
359 | struct rtc_time tm; | ||
360 | int ret; | ||
361 | unsigned char data[25]; | ||
362 | |||
363 | ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL1, data, | ||
364 | sizeof(data)); | ||
365 | if (ret) { | ||
366 | dev_err(dev, "%s: read error ret=%d\n", __func__, ret); | ||
367 | return ret; | ||
368 | } | ||
369 | |||
370 | dev_dbg(dev, | ||
371 | "%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, ts_sc=%02x, " | ||
372 | "ts_mn=%02x, ts_hr=%02x, ts_dm=%02x, ts_mo=%02x, ts_yr=%02x\n", | ||
373 | __func__, data[PCF2127_REG_CTRL1], data[PCF2127_REG_CTRL2], | ||
374 | data[PCF2127_REG_CTRL3], data[PCF2127_REG_TS_SC], | ||
375 | data[PCF2127_REG_TS_MN], data[PCF2127_REG_TS_HR], | ||
376 | data[PCF2127_REG_TS_DM], data[PCF2127_REG_TS_MO], | ||
377 | data[PCF2127_REG_TS_YR]); | ||
378 | |||
379 | ret = pcf2127_wdt_active_ping(&pcf2127->wdd); | ||
380 | if (ret) | ||
381 | return ret; | ||
382 | |||
383 | if (!(data[PCF2127_REG_CTRL1] & PCF2127_BIT_CTRL1_TSF1) && | ||
384 | !(data[PCF2127_REG_CTRL2] & PCF2127_BIT_CTRL2_TSF2)) | ||
385 | return 0; | ||
386 | |||
387 | tm.tm_sec = bcd2bin(data[PCF2127_REG_TS_SC] & 0x7F); | ||
388 | tm.tm_min = bcd2bin(data[PCF2127_REG_TS_MN] & 0x7F); | ||
389 | tm.tm_hour = bcd2bin(data[PCF2127_REG_TS_HR] & 0x3F); | ||
390 | tm.tm_mday = bcd2bin(data[PCF2127_REG_TS_DM] & 0x3F); | ||
391 | /* TS_MO register (month) value range: 1-12 */ | ||
392 | tm.tm_mon = bcd2bin(data[PCF2127_REG_TS_MO] & 0x1F) - 1; | ||
393 | tm.tm_year = bcd2bin(data[PCF2127_REG_TS_YR]); | ||
394 | if (tm.tm_year < 70) | ||
395 | tm.tm_year += 100; /* assume we are in 1970...2069 */ | ||
396 | |||
397 | ret = rtc_valid_tm(&tm); | ||
398 | if (ret) | ||
399 | return ret; | ||
400 | |||
401 | return sprintf(buf, "%llu\n", | ||
402 | (unsigned long long)rtc_tm_to_time64(&tm)); | ||
403 | }; | ||
404 | |||
405 | static DEVICE_ATTR_RW(timestamp0); | ||
406 | |||
407 | static struct attribute *pcf2127_attrs[] = { | ||
408 | &dev_attr_timestamp0.attr, | ||
409 | NULL | ||
410 | }; | ||
411 | |||
412 | static const struct attribute_group pcf2127_attr_group = { | ||
413 | .attrs = pcf2127_attrs, | ||
414 | }; | ||
415 | |||
308 | static int pcf2127_probe(struct device *dev, struct regmap *regmap, | 416 | static int pcf2127_probe(struct device *dev, struct regmap *regmap, |
309 | const char *name, bool has_nvmem) | 417 | const char *name, bool has_nvmem) |
310 | { | 418 | { |
@@ -371,6 +479,58 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, | |||
371 | if (ret) | 479 | if (ret) |
372 | return ret; | 480 | return ret; |
373 | 481 | ||
482 | /* | ||
483 | * Disable battery low/switch-over timestamp and interrupts. | ||
484 | * Clear battery interrupt flags which can block new trigger events. | ||
485 | * Note: This is the default chip behaviour but added to ensure | ||
486 | * correct tamper timestamp and interrupt function. | ||
487 | */ | ||
488 | ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL3, | ||
489 | PCF2127_BIT_CTRL3_BTSE | | ||
490 | PCF2127_BIT_CTRL3_BF | | ||
491 | PCF2127_BIT_CTRL3_BIE | | ||
492 | PCF2127_BIT_CTRL3_BLIE, 0); | ||
493 | if (ret) { | ||
494 | dev_err(dev, "%s: interrupt config (ctrl3) failed\n", | ||
495 | __func__); | ||
496 | return ret; | ||
497 | } | ||
498 | |||
499 | /* | ||
500 | * Enable timestamp function and store timestamp of first trigger | ||
501 | * event until TSF1 and TFS2 interrupt flags are cleared. | ||
502 | */ | ||
503 | ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_TS_CTRL, | ||
504 | PCF2127_BIT_TS_CTRL_TSOFF | | ||
505 | PCF2127_BIT_TS_CTRL_TSM, | ||
506 | PCF2127_BIT_TS_CTRL_TSM); | ||
507 | if (ret) { | ||
508 | dev_err(dev, "%s: tamper detection config (ts_ctrl) failed\n", | ||
509 | __func__); | ||
510 | return ret; | ||
511 | } | ||
512 | |||
513 | /* | ||
514 | * Enable interrupt generation when TSF1 or TSF2 timestamp flags | ||
515 | * are set. Interrupt signal is an open-drain output and can be | ||
516 | * left floating if unused. | ||
517 | */ | ||
518 | ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2, | ||
519 | PCF2127_BIT_CTRL2_TSIE, | ||
520 | PCF2127_BIT_CTRL2_TSIE); | ||
521 | if (ret) { | ||
522 | dev_err(dev, "%s: tamper detection config (ctrl2) failed\n", | ||
523 | __func__); | ||
524 | return ret; | ||
525 | } | ||
526 | |||
527 | ret = rtc_add_group(pcf2127->rtc, &pcf2127_attr_group); | ||
528 | if (ret) { | ||
529 | dev_err(dev, "%s: tamper sysfs registering failed\n", | ||
530 | __func__); | ||
531 | return ret; | ||
532 | } | ||
533 | |||
374 | return rtc_register_device(pcf2127->rtc); | 534 | return rtc_register_device(pcf2127->rtc); |
375 | } | 535 | } |
376 | 536 | ||