Skip to content

Commit 2f86198

Browse files
Mian Yousaf Kaukabalexandrebelloni
Mian Yousaf Kaukab
authored andcommitted
rtc: pcf2127: handle timestamp interrupts
commit 03623b4 ("rtc: pcf2127: add tamper detection support") added support for timestamp interrupts. However they are not being handled in the irq handler. If a timestamp interrupt occurs it results in kernel disabling the interrupt and displaying the call trace: [ 121.145580] irq 78: nobody cared (try booting with the "irqpoll" option) ... [ 121.238087] [<00000000c4d69393>] irq_default_primary_handler threaded [<000000000a90d25b>] pcf2127_rtc_irq [rtc_pcf2127] [ 121.248971] Disabling IRQ #78 Handle timestamp interrupts in pcf2127_rtc_irq(). Save time stamp before clearing TSF1 and TSF2 flags so that it can't be overwritten. Set a flag to mark if the timestamp is valid and only report to sysfs if the flag is set. To mimic the hardware behavior, don’t save another timestamp until the first one has been read by the userspace. However, if the alarm irq is not configured, keep the old way of handling timestamp interrupt in the timestamp0 sysfs calls. Signed-off-by: Mian Yousaf Kaukab <[email protected]> Reviewed-by: Bruno Thomsen <[email protected]> Tested-by: Bruno Thomsen <[email protected]> Signed-off-by: Alexandre Belloni <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 37aadf9 commit 2f86198

File tree

1 file changed

+133
-59
lines changed

1 file changed

+133
-59
lines changed

drivers/rtc/rtc-pcf2127.c

Lines changed: 133 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,20 @@
9494
#define PCF2127_WD_VAL_MAX 255
9595
#define PCF2127_WD_VAL_DEFAULT 60
9696

97+
/* Mask for currently enabled interrupts */
98+
#define PCF2127_CTRL1_IRQ_MASK (PCF2127_BIT_CTRL1_TSF1)
99+
#define PCF2127_CTRL2_IRQ_MASK ( \
100+
PCF2127_BIT_CTRL2_AF | \
101+
PCF2127_BIT_CTRL2_WDTF | \
102+
PCF2127_BIT_CTRL2_TSF2)
103+
97104
struct pcf2127 {
98105
struct rtc_device *rtc;
99106
struct watchdog_device wdd;
100107
struct regmap *regmap;
108+
time64_t ts;
109+
bool ts_valid;
110+
bool irq_enabled;
101111
};
102112

103113
/*
@@ -434,23 +444,96 @@ static int pcf2127_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
434444
return pcf2127_rtc_alarm_irq_enable(dev, alrm->enabled);
435445
}
436446

447+
/*
448+
* This function reads ctrl2 register, caller is responsible for calling
449+
* pcf2127_wdt_active_ping()
450+
*/
451+
static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts)
452+
{
453+
struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
454+
struct rtc_time tm;
455+
int ret;
456+
unsigned char data[25];
457+
458+
ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL1, data,
459+
sizeof(data));
460+
if (ret) {
461+
dev_err(dev, "%s: read error ret=%d\n", __func__, ret);
462+
return ret;
463+
}
464+
465+
dev_dbg(dev,
466+
"%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, ts_sc=%02x, ts_mn=%02x, ts_hr=%02x, ts_dm=%02x, ts_mo=%02x, ts_yr=%02x\n",
467+
__func__, data[PCF2127_REG_CTRL1], data[PCF2127_REG_CTRL2],
468+
data[PCF2127_REG_CTRL3], data[PCF2127_REG_TS_SC],
469+
data[PCF2127_REG_TS_MN], data[PCF2127_REG_TS_HR],
470+
data[PCF2127_REG_TS_DM], data[PCF2127_REG_TS_MO],
471+
data[PCF2127_REG_TS_YR]);
472+
473+
tm.tm_sec = bcd2bin(data[PCF2127_REG_TS_SC] & 0x7F);
474+
tm.tm_min = bcd2bin(data[PCF2127_REG_TS_MN] & 0x7F);
475+
tm.tm_hour = bcd2bin(data[PCF2127_REG_TS_HR] & 0x3F);
476+
tm.tm_mday = bcd2bin(data[PCF2127_REG_TS_DM] & 0x3F);
477+
/* TS_MO register (month) value range: 1-12 */
478+
tm.tm_mon = bcd2bin(data[PCF2127_REG_TS_MO] & 0x1F) - 1;
479+
tm.tm_year = bcd2bin(data[PCF2127_REG_TS_YR]);
480+
if (tm.tm_year < 70)
481+
tm.tm_year += 100; /* assume we are in 1970...2069 */
482+
483+
ret = rtc_valid_tm(&tm);
484+
if (ret) {
485+
dev_err(dev, "Invalid timestamp. ret=%d\n", ret);
486+
return ret;
487+
}
488+
489+
*ts = rtc_tm_to_time64(&tm);
490+
return 0;
491+
};
492+
493+
static void pcf2127_rtc_ts_snapshot(struct device *dev)
494+
{
495+
struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
496+
int ret;
497+
498+
/* Let userspace read the first timestamp */
499+
if (pcf2127->ts_valid)
500+
return;
501+
502+
ret = pcf2127_rtc_ts_read(dev, &pcf2127->ts);
503+
if (!ret)
504+
pcf2127->ts_valid = true;
505+
}
506+
437507
static irqreturn_t pcf2127_rtc_irq(int irq, void *dev)
438508
{
439509
struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
440-
unsigned int ctrl2 = 0;
510+
unsigned int ctrl1, ctrl2;
441511
int ret = 0;
442512

513+
ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1, &ctrl1);
514+
if (ret)
515+
return IRQ_NONE;
516+
443517
ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL2, &ctrl2);
444518
if (ret)
445519
return IRQ_NONE;
446520

447-
if (!(ctrl2 & PCF2127_BIT_CTRL2_AF))
521+
if (!(ctrl1 & PCF2127_CTRL1_IRQ_MASK || ctrl2 & PCF2127_CTRL2_IRQ_MASK))
448522
return IRQ_NONE;
449523

450-
regmap_write(pcf2127->regmap, PCF2127_REG_CTRL2,
451-
ctrl2 & ~(PCF2127_BIT_CTRL2_AF | PCF2127_BIT_CTRL2_WDTF));
524+
if (ctrl1 & PCF2127_BIT_CTRL1_TSF1 || ctrl2 & PCF2127_BIT_CTRL2_TSF2)
525+
pcf2127_rtc_ts_snapshot(dev);
526+
527+
if (ctrl1 & PCF2127_CTRL1_IRQ_MASK)
528+
regmap_write(pcf2127->regmap, PCF2127_REG_CTRL1,
529+
ctrl1 & ~PCF2127_CTRL1_IRQ_MASK);
530+
531+
if (ctrl2 & PCF2127_CTRL2_IRQ_MASK)
532+
regmap_write(pcf2127->regmap, PCF2127_REG_CTRL2,
533+
ctrl2 & ~PCF2127_CTRL2_IRQ_MASK);
452534

453-
rtc_update_irq(pcf2127->rtc, 1, RTC_IRQF | RTC_AF);
535+
if (ctrl2 & PCF2127_BIT_CTRL2_AF)
536+
rtc_update_irq(pcf2127->rtc, 1, RTC_IRQF | RTC_AF);
454537

455538
pcf2127_wdt_active_ping(&pcf2127->wdd);
456539

@@ -475,23 +558,27 @@ static ssize_t timestamp0_store(struct device *dev,
475558
struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent);
476559
int ret;
477560

478-
ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1,
479-
PCF2127_BIT_CTRL1_TSF1, 0);
480-
if (ret) {
481-
dev_err(dev, "%s: update ctrl1 ret=%d\n", __func__, ret);
482-
return ret;
483-
}
561+
if (pcf2127->irq_enabled) {
562+
pcf2127->ts_valid = false;
563+
} else {
564+
ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1,
565+
PCF2127_BIT_CTRL1_TSF1, 0);
566+
if (ret) {
567+
dev_err(dev, "%s: update ctrl1 ret=%d\n", __func__, ret);
568+
return ret;
569+
}
484570

485-
ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2,
486-
PCF2127_BIT_CTRL2_TSF2, 0);
487-
if (ret) {
488-
dev_err(dev, "%s: update ctrl2 ret=%d\n", __func__, ret);
489-
return ret;
490-
}
571+
ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2,
572+
PCF2127_BIT_CTRL2_TSF2, 0);
573+
if (ret) {
574+
dev_err(dev, "%s: update ctrl2 ret=%d\n", __func__, ret);
575+
return ret;
576+
}
491577

492-
ret = pcf2127_wdt_active_ping(&pcf2127->wdd);
493-
if (ret)
494-
return ret;
578+
ret = pcf2127_wdt_active_ping(&pcf2127->wdd);
579+
if (ret)
580+
return ret;
581+
}
495582

496583
return count;
497584
};
@@ -500,50 +587,36 @@ static ssize_t timestamp0_show(struct device *dev,
500587
struct device_attribute *attr, char *buf)
501588
{
502589
struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent);
503-
struct rtc_time tm;
590+
unsigned int ctrl1, ctrl2;
504591
int ret;
505-
unsigned char data[25];
506-
507-
ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL1, data,
508-
sizeof(data));
509-
if (ret) {
510-
dev_err(dev, "%s: read error ret=%d\n", __func__, ret);
511-
return ret;
512-
}
513-
514-
dev_dbg(dev,
515-
"%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, ts_sc=%02x, "
516-
"ts_mn=%02x, ts_hr=%02x, ts_dm=%02x, ts_mo=%02x, ts_yr=%02x\n",
517-
__func__, data[PCF2127_REG_CTRL1], data[PCF2127_REG_CTRL2],
518-
data[PCF2127_REG_CTRL3], data[PCF2127_REG_TS_SC],
519-
data[PCF2127_REG_TS_MN], data[PCF2127_REG_TS_HR],
520-
data[PCF2127_REG_TS_DM], data[PCF2127_REG_TS_MO],
521-
data[PCF2127_REG_TS_YR]);
592+
time64_t ts;
593+
594+
if (pcf2127->irq_enabled) {
595+
if (!pcf2127->ts_valid)
596+
return 0;
597+
ts = pcf2127->ts;
598+
} else {
599+
ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1, &ctrl1);
600+
if (ret)
601+
return 0;
522602

523-
ret = pcf2127_wdt_active_ping(&pcf2127->wdd);
524-
if (ret)
525-
return ret;
603+
ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL2, &ctrl2);
604+
if (ret)
605+
return 0;
526606

527-
if (!(data[PCF2127_REG_CTRL1] & PCF2127_BIT_CTRL1_TSF1) &&
528-
!(data[PCF2127_REG_CTRL2] & PCF2127_BIT_CTRL2_TSF2))
529-
return 0;
607+
if (!(ctrl1 & PCF2127_BIT_CTRL1_TSF1) &&
608+
!(ctrl2 & PCF2127_BIT_CTRL2_TSF2))
609+
return 0;
530610

531-
tm.tm_sec = bcd2bin(data[PCF2127_REG_TS_SC] & 0x7F);
532-
tm.tm_min = bcd2bin(data[PCF2127_REG_TS_MN] & 0x7F);
533-
tm.tm_hour = bcd2bin(data[PCF2127_REG_TS_HR] & 0x3F);
534-
tm.tm_mday = bcd2bin(data[PCF2127_REG_TS_DM] & 0x3F);
535-
/* TS_MO register (month) value range: 1-12 */
536-
tm.tm_mon = bcd2bin(data[PCF2127_REG_TS_MO] & 0x1F) - 1;
537-
tm.tm_year = bcd2bin(data[PCF2127_REG_TS_YR]);
538-
if (tm.tm_year < 70)
539-
tm.tm_year += 100; /* assume we are in 1970...2069 */
540-
541-
ret = rtc_valid_tm(&tm);
542-
if (ret)
543-
return ret;
611+
ret = pcf2127_rtc_ts_read(dev->parent, &ts);
612+
if (ret)
613+
return 0;
544614

545-
return sprintf(buf, "%llu\n",
546-
(unsigned long long)rtc_tm_to_time64(&tm));
615+
ret = pcf2127_wdt_active_ping(&pcf2127->wdd);
616+
if (ret)
617+
return ret;
618+
}
619+
return sprintf(buf, "%llu\n", (unsigned long long)ts);
547620
};
548621

549622
static DEVICE_ATTR_RW(timestamp0);
@@ -594,6 +667,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
594667
dev_err(dev, "failed to request alarm irq\n");
595668
return ret;
596669
}
670+
pcf2127->irq_enabled = true;
597671
}
598672

599673
if (alarm_irq > 0 || device_property_read_bool(dev, "wakeup-source")) {

0 commit comments

Comments
 (0)