Skip to content

Commit 7572dca

Browse files
committed
ACPI: TAD: Add alarm support to the RTC class device interface
Add alarm support, based on Section 9.17 of ACPI 6.6 [1], to the RTC class device interface of the driver. The ACPI time and alarm device (TAD) can support two separate alarm timers, one for waking up the system when it is on AC power, and one for waking it up when it is on DC power. In principle, each of them can be set to a different value representing the number of seconds till the given alarm timer expires. However, the RTC class device can only set one alarm, so it will set both the alarm timers of the ACPI TAD (if the DC one is supported) to the same value. That is somewhat cumbersome because there is no way in the ACPI TAD firmware interface to set both timers in one go, so they need to be set sequentially, but that's how it goes. On the alarm read side, the driver assumes that both timers have been set to the same value, so it is sufficient to access one of them (the AC one specifically). Link: https://uefi.org/specs/ACPI/6.6/09_ACPI_Defined_Devices_and_Device_Specific_Objects.html#time-and-alarm-device [1] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com> Link: https://patch.msgid.link/2076980.usQuhbGJ8B@rafael.j.wysocki
1 parent 2ffc8bf commit 7572dca

1 file changed

Lines changed: 109 additions & 3 deletions

File tree

drivers/acpi/acpi_tad.c

Lines changed: 109 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
#include <linux/acpi.h>
2727
#include <linux/kernel.h>
28+
#include <linux/ktime.h>
2829
#include <linux/module.h>
2930
#include <linux/platform_device.h>
3031
#include <linux/pm_runtime.h>
@@ -658,12 +659,113 @@ static int acpi_tad_rtc_read_time(struct device *dev, struct rtc_time *tm)
658659
return 0;
659660
}
660661

662+
static int acpi_tad_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t)
663+
{
664+
struct acpi_tad_driver_data *dd = dev_get_drvdata(dev);
665+
s64 value = ACPI_TAD_WAKE_DISABLED;
666+
struct rtc_time tm_now;
667+
struct acpi_tad_rt rt;
668+
int ret;
669+
670+
PM_RUNTIME_ACQUIRE(dev, pm);
671+
if (PM_RUNTIME_ACQUIRE_ERR(&pm))
672+
return -ENXIO;
673+
674+
if (t->enabled) {
675+
/*
676+
* The value to pass to _STV is expected to be the number of
677+
* seconds between the time when the timer is programmed and the
678+
* time when it expires represented as a 32-bit integer.
679+
*/
680+
ret = __acpi_tad_get_real_time(dev, &rt);
681+
if (ret)
682+
return ret;
683+
684+
acpi_tad_rt_to_tm(&rt, &tm_now);
685+
686+
value = ktime_divns(ktime_sub(rtc_tm_to_ktime(t->time),
687+
rtc_tm_to_ktime(tm_now)), NSEC_PER_SEC);
688+
if (value <= 0 || value > U32_MAX)
689+
return -EINVAL;
690+
}
691+
692+
ret = __acpi_tad_wake_set(dev, "_STV", ACPI_TAD_AC_TIMER, value);
693+
if (ret && t->enabled)
694+
return ret;
695+
696+
/*
697+
* If a separate DC alarm timer is supported, set it to the same value
698+
* as the AC alarm timer.
699+
*/
700+
if (dd->capabilities & ACPI_TAD_DC_WAKE) {
701+
ret = __acpi_tad_wake_set(dev, "_STV", ACPI_TAD_DC_TIMER, value);
702+
if (ret && t->enabled) {
703+
__acpi_tad_wake_set(dev, "_STV", ACPI_TAD_AC_TIMER,
704+
ACPI_TAD_WAKE_DISABLED);
705+
return ret;
706+
}
707+
}
708+
709+
/* Assume success if the alarm is being disabled. */
710+
return 0;
711+
}
712+
713+
static int acpi_tad_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t)
714+
{
715+
unsigned long long retval;
716+
struct rtc_time tm_now;
717+
struct acpi_tad_rt rt;
718+
int ret;
719+
720+
PM_RUNTIME_ACQUIRE(dev, pm);
721+
if (PM_RUNTIME_ACQUIRE_ERR(&pm))
722+
return -ENXIO;
723+
724+
ret = __acpi_tad_get_real_time(dev, &rt);
725+
if (ret)
726+
return ret;
727+
728+
acpi_tad_rt_to_tm(&rt, &tm_now);
729+
730+
/*
731+
* Assume that the alarm was set by acpi_tad_rtc_set_alarm(), so the AC
732+
* and DC alarm timer settings are the same and it is sufficient to read
733+
* the former.
734+
*
735+
* The value returned by _TIV should be the number of seconds till the
736+
* expiration of the timer, represented as a 32-bit integer, or the
737+
* special ACPI_TAD_WAKE_DISABLED value meaning that the timer has
738+
* been disabled.
739+
*/
740+
ret = __acpi_tad_wake_read(dev, "_TIV", ACPI_TAD_AC_TIMER, &retval);
741+
if (ret)
742+
return ret;
743+
744+
if (retval > U32_MAX)
745+
return -ENODATA;
746+
747+
t->pending = 0;
748+
749+
if (retval != ACPI_TAD_WAKE_DISABLED) {
750+
t->enabled = 1;
751+
t->time = rtc_ktime_to_tm(ktime_add_ns(rtc_tm_to_ktime(tm_now),
752+
(u64)retval * NSEC_PER_SEC));
753+
} else {
754+
t->enabled = 0;
755+
t->time = tm_now;
756+
}
757+
758+
return 0;
759+
}
760+
661761
static const struct rtc_class_ops acpi_tad_rtc_ops = {
662762
.read_time = acpi_tad_rtc_read_time,
663763
.set_time = acpi_tad_rtc_set_time,
764+
.set_alarm = acpi_tad_rtc_set_alarm,
765+
.read_alarm = acpi_tad_rtc_read_alarm,
664766
};
665767

666-
static void acpi_tad_register_rtc(struct device *dev)
768+
static void acpi_tad_register_rtc(struct device *dev, unsigned long long caps)
667769
{
668770
struct rtc_device *rtc;
669771

@@ -676,10 +778,14 @@ static void acpi_tad_register_rtc(struct device *dev)
676778

677779
rtc->ops = &acpi_tad_rtc_ops;
678780

781+
if (!(caps & ACPI_TAD_AC_WAKE))
782+
clear_bit(RTC_FEATURE_ALARM, rtc->features);
783+
679784
devm_rtc_register_device(rtc);
680785
}
681786
#else /* !CONFIG_RTC_CLASS */
682-
static inline void acpi_tad_register_rtc(struct device *dev) {}
787+
static inline void acpi_tad_register_rtc(struct device *dev,
788+
unsigned long long caps) {}
683789
#endif /* !CONFIG_RTC_CLASS */
684790

685791
/* Platform driver interface */
@@ -765,7 +871,7 @@ static int acpi_tad_probe(struct platform_device *pdev)
765871
pm_runtime_suspend(dev);
766872

767873
if (caps & ACPI_TAD_RT)
768-
acpi_tad_register_rtc(dev);
874+
acpi_tad_register_rtc(dev, caps);
769875

770876
return 0;
771877
}

0 commit comments

Comments
 (0)