Skip to content

Commit 8a914ba

Browse files
liambeguinalexandrebelloni
authored andcommitted
rtc: pcf2127: add alarm support
Add alarm support for the pcf2127 RTC chip family. Tested on pca2129. Signed-off-by: Liam Beguin <[email protected]> Signed-off-by: Alexandre Belloni <[email protected]> Reviewed-by: Bruno Thomsen <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 985b30d commit 8a914ba

File tree

1 file changed

+134
-0
lines changed

1 file changed

+134
-0
lines changed

drivers/rtc/rtc-pcf2127.c

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/slab.h>
2121
#include <linux/module.h>
2222
#include <linux/of.h>
23+
#include <linux/of_irq.h>
2324
#include <linux/regmap.h>
2425
#include <linux/watchdog.h>
2526

@@ -28,7 +29,9 @@
2829
#define PCF2127_BIT_CTRL1_TSF1 BIT(4)
2930
/* Control register 2 */
3031
#define PCF2127_REG_CTRL2 0x01
32+
#define PCF2127_BIT_CTRL2_AIE BIT(1)
3133
#define PCF2127_BIT_CTRL2_TSIE BIT(2)
34+
#define PCF2127_BIT_CTRL2_AF BIT(4)
3235
#define PCF2127_BIT_CTRL2_TSF2 BIT(5)
3336
/* Control register 3 */
3437
#define PCF2127_REG_CTRL3 0x02
@@ -46,6 +49,12 @@
4649
#define PCF2127_REG_DW 0x07
4750
#define PCF2127_REG_MO 0x08
4851
#define PCF2127_REG_YR 0x09
52+
/* Alarm registers */
53+
#define PCF2127_REG_ALARM_SC 0x0A
54+
#define PCF2127_REG_ALARM_MN 0x0B
55+
#define PCF2127_REG_ALARM_HR 0x0C
56+
#define PCF2127_REG_ALARM_DM 0x0D
57+
#define PCF2127_REG_ALARM_DW 0x0E
4958
/* Watchdog registers */
5059
#define PCF2127_REG_WD_CTL 0x10
5160
#define PCF2127_BIT_WD_CTL_TF0 BIT(0)
@@ -324,6 +333,114 @@ static const struct watchdog_ops pcf2127_watchdog_ops = {
324333
.set_timeout = pcf2127_wdt_set_timeout,
325334
};
326335

336+
/* Alarm */
337+
static int pcf2127_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
338+
{
339+
struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
340+
unsigned int buf[5], ctrl2;
341+
int ret;
342+
343+
ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL2, &ctrl2);
344+
if (ret)
345+
return ret;
346+
347+
ret = pcf2127_wdt_active_ping(&pcf2127->wdd);
348+
if (ret)
349+
return ret;
350+
351+
ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_ALARM_SC, buf,
352+
sizeof(buf));
353+
if (ret)
354+
return ret;
355+
356+
alrm->enabled = ctrl2 & PCF2127_BIT_CTRL2_AIE;
357+
alrm->pending = ctrl2 & PCF2127_BIT_CTRL2_AF;
358+
359+
alrm->time.tm_sec = bcd2bin(buf[0] & 0x7F);
360+
alrm->time.tm_min = bcd2bin(buf[1] & 0x7F);
361+
alrm->time.tm_hour = bcd2bin(buf[2] & 0x3F);
362+
alrm->time.tm_mday = bcd2bin(buf[3] & 0x3F);
363+
alrm->time.tm_wday = buf[4] & 0x07;
364+
365+
return 0;
366+
}
367+
368+
static int pcf2127_rtc_alarm_irq_enable(struct device *dev, u32 enable)
369+
{
370+
struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
371+
int ret;
372+
373+
ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2,
374+
PCF2127_BIT_CTRL2_AIE,
375+
enable ? PCF2127_BIT_CTRL2_AIE : 0);
376+
if (ret)
377+
return ret;
378+
379+
return pcf2127_wdt_active_ping(&pcf2127->wdd);
380+
}
381+
382+
static int pcf2127_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
383+
{
384+
struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
385+
uint8_t buf[5];
386+
int ret;
387+
388+
ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2,
389+
PCF2127_BIT_CTRL2_AF, 0);
390+
if (ret)
391+
return ret;
392+
393+
ret = pcf2127_wdt_active_ping(&pcf2127->wdd);
394+
if (ret)
395+
return ret;
396+
397+
buf[0] = bin2bcd(alrm->time.tm_sec);
398+
buf[1] = bin2bcd(alrm->time.tm_min);
399+
buf[2] = bin2bcd(alrm->time.tm_hour);
400+
buf[3] = bin2bcd(alrm->time.tm_mday);
401+
buf[4] = (alrm->time.tm_wday & 0x07);
402+
403+
ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_ALARM_SC, buf,
404+
sizeof(buf));
405+
if (ret)
406+
return ret;
407+
408+
return pcf2127_rtc_alarm_irq_enable(dev, alrm->enabled);
409+
}
410+
411+
static irqreturn_t pcf2127_rtc_irq(int irq, void *dev)
412+
{
413+
struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
414+
unsigned int ctrl2 = 0;
415+
int ret = 0;
416+
417+
ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL2, &ctrl2);
418+
if (ret)
419+
return IRQ_NONE;
420+
421+
if (ctrl2 & PCF2127_BIT_CTRL2_AF) {
422+
regmap_write(pcf2127->regmap, PCF2127_REG_CTRL2,
423+
ctrl2 & ~PCF2127_BIT_CTRL2_AF);
424+
425+
rtc_update_irq(pcf2127->rtc, 1, RTC_IRQF | RTC_AF);
426+
}
427+
428+
ret = pcf2127_wdt_active_ping(&pcf2127->wdd);
429+
if (ret)
430+
return IRQ_NONE;
431+
432+
return IRQ_HANDLED;
433+
}
434+
435+
static const struct rtc_class_ops pcf2127_rtc_alrm_ops = {
436+
.ioctl = pcf2127_rtc_ioctl,
437+
.read_time = pcf2127_rtc_read_time,
438+
.set_time = pcf2127_rtc_set_time,
439+
.read_alarm = pcf2127_rtc_read_alarm,
440+
.set_alarm = pcf2127_rtc_set_alarm,
441+
.alarm_irq_enable = pcf2127_rtc_alarm_irq_enable,
442+
};
443+
327444
/* sysfs interface */
328445

329446
static ssize_t timestamp0_store(struct device *dev,
@@ -419,6 +536,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
419536
const char *name, bool has_nvmem)
420537
{
421538
struct pcf2127 *pcf2127;
539+
int alarm_irq = 0;
422540
u32 wdd_timeout;
423541
int ret = 0;
424542

@@ -441,6 +559,22 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
441559
pcf2127->rtc->range_max = RTC_TIMESTAMP_END_2099;
442560
pcf2127->rtc->set_start_time = true; /* Sets actual start to 1970 */
443561

562+
alarm_irq = of_irq_get_byname(dev->of_node, "alarm");
563+
if (alarm_irq >= 0) {
564+
ret = devm_request_irq(dev, alarm_irq, pcf2127_rtc_irq,
565+
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
566+
dev_name(dev), dev);
567+
if (ret) {
568+
dev_err(dev, "failed to request alarm irq\n");
569+
return ret;
570+
}
571+
}
572+
573+
if (alarm_irq >= 0 || device_property_read_bool(dev, "wakeup-source")) {
574+
device_init_wakeup(dev, true);
575+
pcf2127->rtc->ops = &pcf2127_rtc_alrm_ops;
576+
}
577+
444578
pcf2127->wdd.parent = dev;
445579
pcf2127->wdd.info = &pcf2127_wdt_info;
446580
pcf2127->wdd.ops = &pcf2127_watchdog_ops;

0 commit comments

Comments
 (0)