Skip to content

Commit 8a1e7f4

Browse files
committed
ACPI: TAD: Add RTC class device interface
Add an RTC class device interface allowing to read and set the real time value to the ACPI TAD driver. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com> Link: https://patch.msgid.link/2352027.iZASKD2KPV@rafael.j.wysocki
1 parent fca4f23 commit 8a1e7f4

1 file changed

Lines changed: 76 additions & 2 deletions

File tree

drivers/acpi/acpi_tad.c

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <linux/module.h>
2626
#include <linux/platform_device.h>
2727
#include <linux/pm_runtime.h>
28+
#include <linux/rtc.h>
2829
#include <linux/suspend.h>
2930

3031
MODULE_DESCRIPTION("ACPI Time and Alarm (TAD) Device Driver");
@@ -51,6 +52,7 @@ MODULE_AUTHOR("Rafael J. Wysocki");
5152

5253
/* ACPI TAD RTC */
5354
#define ACPI_TAD_TZ_UNSPEC 2047
55+
#define ACPI_TAD_TIME_ISDST 3
5456

5557
struct acpi_tad_driver_data {
5658
u32 capabilities;
@@ -164,6 +166,8 @@ static int acpi_tad_get_real_time(struct device *dev, struct acpi_tad_rt *rt)
164166
return 0;
165167
}
166168

169+
/* sysfs interface */
170+
167171
static char *acpi_tad_rt_next_field(char *s, int *val)
168172
{
169173
char *p;
@@ -579,6 +583,71 @@ static const struct attribute_group acpi_tad_attr_group = {
579583
.is_visible = acpi_tad_attr_is_visible,
580584
};
581585

586+
#ifdef CONFIG_RTC_CLASS
587+
/* RTC class device interface */
588+
589+
static int acpi_tad_rtc_set_time(struct device *dev, struct rtc_time *tm)
590+
{
591+
struct acpi_tad_rt rt;
592+
593+
rt.year = tm->tm_year + 1900;
594+
rt.month = tm->tm_mon + 1;
595+
rt.day = tm->tm_mday;
596+
rt.hour = tm->tm_hour;
597+
rt.minute = tm->tm_min;
598+
rt.second = tm->tm_sec;
599+
rt.tz = ACPI_TAD_TZ_UNSPEC;
600+
rt.daylight = ACPI_TAD_TIME_ISDST * !!tm->tm_isdst;
601+
602+
return acpi_tad_set_real_time(dev, &rt);
603+
}
604+
605+
static int acpi_tad_rtc_read_time(struct device *dev, struct rtc_time *tm)
606+
{
607+
struct acpi_tad_rt rt;
608+
int ret;
609+
610+
ret = acpi_tad_get_real_time(dev, &rt);
611+
if (ret)
612+
return ret;
613+
614+
tm->tm_year = rt.year - 1900;
615+
tm->tm_mon = rt.month - 1;
616+
tm->tm_mday = rt.day;
617+
tm->tm_hour = rt.hour;
618+
tm->tm_min = rt.minute;
619+
tm->tm_sec = rt.second;
620+
tm->tm_isdst = rt.daylight == ACPI_TAD_TIME_ISDST;
621+
622+
return 0;
623+
}
624+
625+
static const struct rtc_class_ops acpi_tad_rtc_ops = {
626+
.read_time = acpi_tad_rtc_read_time,
627+
.set_time = acpi_tad_rtc_set_time,
628+
};
629+
630+
static void acpi_tad_register_rtc(struct device *dev)
631+
{
632+
struct rtc_device *rtc;
633+
634+
rtc = devm_rtc_allocate_device(dev);
635+
if (IS_ERR(rtc))
636+
return;
637+
638+
rtc->range_min = mktime64(1900, 1, 1, 0, 0, 0);
639+
rtc->range_max = mktime64(9999, 12, 31, 23, 59, 59);
640+
641+
rtc->ops = &acpi_tad_rtc_ops;
642+
643+
devm_rtc_register_device(rtc);
644+
}
645+
#else /* !CONFIG_RTC_CLASS */
646+
static inline void acpi_tad_register_rtc(struct device *dev) {}
647+
#endif /* !CONFIG_RTC_CLASS */
648+
649+
/* Platform driver interface */
650+
582651
static int acpi_tad_disable_timer(struct device *dev, u32 timer_id)
583652
{
584653
return acpi_tad_wake_set(dev, "_STV", timer_id, ACPI_TAD_WAKE_DISABLED);
@@ -660,10 +729,15 @@ static int acpi_tad_probe(struct platform_device *pdev)
660729
pm_runtime_suspend(dev);
661730

662731
ret = sysfs_create_group(&dev->kobj, &acpi_tad_attr_group);
663-
if (ret)
732+
if (ret) {
664733
acpi_tad_remove(pdev);
734+
return ret;
735+
}
665736

666-
return ret;
737+
if (caps & ACPI_TAD_RT)
738+
acpi_tad_register_rtc(dev);
739+
740+
return 0;
667741
}
668742

669743
static const struct acpi_device_id acpi_tad_ids[] = {

0 commit comments

Comments
 (0)