Skip to content

Commit 03623b4

Browse files
baxenoalexandrebelloni
authored andcommitted
rtc: pcf2127: add tamper detection support
Add support for integrated tamper detection function in both PCF2127 and PCF2129 chips. This patch implements the feature by adding an additional timestamp0 file to sysfs device path. This file contains seconds since epoch, if an event occurred, or is empty, if none occurred. Interface should match ISL1208 and RV3028 RTC drivers. Signed-off-by: Bruno Thomsen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexandre Belloni <[email protected]>
1 parent 0e735ea commit 03623b4

File tree

1 file changed

+160
-0
lines changed

1 file changed

+160
-0
lines changed

drivers/rtc/rtc-pcf2127.c

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,18 @@
2525

2626
/* Control register 1 */
2727
#define PCF2127_REG_CTRL1 0x00
28+
#define PCF2127_BIT_CTRL1_TSF1 BIT(4)
2829
/* Control register 2 */
2930
#define PCF2127_REG_CTRL2 0x01
31+
#define PCF2127_BIT_CTRL2_TSIE BIT(2)
32+
#define PCF2127_BIT_CTRL2_TSF2 BIT(5)
3033
/* Control register 3 */
3134
#define PCF2127_REG_CTRL3 0x02
35+
#define PCF2127_BIT_CTRL3_BLIE BIT(0)
36+
#define PCF2127_BIT_CTRL3_BIE BIT(1)
3237
#define PCF2127_BIT_CTRL3_BLF BIT(2)
38+
#define PCF2127_BIT_CTRL3_BF BIT(3)
39+
#define PCF2127_BIT_CTRL3_BTSE BIT(4)
3340
/* Time and date registers */
3441
#define PCF2127_REG_SC 0x03
3542
#define PCF2127_BIT_SC_OSF BIT(7)
@@ -46,6 +53,16 @@
4653
#define PCF2127_BIT_WD_CTL_CD0 BIT(6)
4754
#define PCF2127_BIT_WD_CTL_CD1 BIT(7)
4855
#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
4966
/*
5067
* RAM registers
5168
* PCF2127 has 512 bytes general-purpose static RAM (SRAM) that is
@@ -305,6 +322,97 @@ static const struct watchdog_ops pcf2127_watchdog_ops = {
305322
.set_timeout = pcf2127_wdt_set_timeout,
306323
};
307324

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+
308416
static int pcf2127_probe(struct device *dev, struct regmap *regmap,
309417
const char *name, bool has_nvmem)
310418
{
@@ -371,6 +479,58 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
371479
if (ret)
372480
return ret;
373481

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+
374534
return rtc_register_device(pcf2127->rtc);
375535
}
376536

0 commit comments

Comments
 (0)