All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 0/7] ACPI: TAD: Assorted improvements and RTC class device interface
@ 2026-03-04 18:11 Rafael J. Wysocki
  2026-03-04 18:12 ` [PATCH v1 1/7] ACPI: TAD: Create one attribute group Rafael J. Wysocki
                   ` (6 more replies)
  0 siblings, 7 replies; 9+ messages in thread
From: Rafael J. Wysocki @ 2026-03-04 18:11 UTC (permalink / raw)
  To: Linux ACPI; +Cc: Alexandre Belloni, LKML, linux-rtc, Linux PM

Hi All,

This is a proper v1 of the series posted previously as a prototype:

https://lore.kernel.org/linux-acpi/4727679.LvFx2qVVIh@rafael.j.wysocki/

The code has changed somewhat, most importantly the first patch has been
split and review feedback on patch [6/7] (previously [5/6]) have been
taken into account.

This series is on top of linux-next.

Thanks!




^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v1 1/7] ACPI: TAD: Create one attribute group
  2026-03-04 18:11 [PATCH v1 0/7] ACPI: TAD: Assorted improvements and RTC class device interface Rafael J. Wysocki
@ 2026-03-04 18:12 ` Rafael J. Wysocki
  2026-03-04 18:13 ` [PATCH v1 2/7] ACPI: TAD: Support RTC without wakeup Rafael J. Wysocki
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Rafael J. Wysocki @ 2026-03-04 18:12 UTC (permalink / raw)
  To: Linux ACPI; +Cc: Alexandre Belloni, LKML, linux-rtc, Linux PM

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Instead of creating three attribute groups, one for each supported
subset of capabilities, create just one and use an .is_visible()
callback in it to decide which attributes to use.

No intentional functional impact.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/acpi_tad.c |   80 +++++++++++++++++++++---------------------------
 1 file changed, 35 insertions(+), 45 deletions(-)

--- a/drivers/acpi/acpi_tad.c
+++ b/drivers/acpi/acpi_tad.c
@@ -249,14 +249,6 @@ static ssize_t time_show(struct device *
 
 static DEVICE_ATTR_RW(time);
 
-static struct attribute *acpi_tad_time_attrs[] = {
-	&dev_attr_time.attr,
-	NULL,
-};
-static const struct attribute_group acpi_tad_time_attr_group = {
-	.attrs	= acpi_tad_time_attrs,
-};
-
 static int acpi_tad_wake_set(struct device *dev, char *method, u32 timer_id,
 			     u32 value)
 {
@@ -486,17 +478,6 @@ static ssize_t ac_status_show(struct dev
 
 static DEVICE_ATTR_RW(ac_status);
 
-static struct attribute *acpi_tad_attrs[] = {
-	&dev_attr_caps.attr,
-	&dev_attr_ac_alarm.attr,
-	&dev_attr_ac_policy.attr,
-	&dev_attr_ac_status.attr,
-	NULL,
-};
-static const struct attribute_group acpi_tad_attr_group = {
-	.attrs	= acpi_tad_attrs,
-};
-
 static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr,
 			      const char *buf, size_t count)
 {
@@ -545,14 +526,44 @@ static ssize_t dc_status_show(struct dev
 
 static DEVICE_ATTR_RW(dc_status);
 
-static struct attribute *acpi_tad_dc_attrs[] = {
+static struct attribute *acpi_tad_attrs[] = {
+	&dev_attr_caps.attr,
+	&dev_attr_ac_alarm.attr,
+	&dev_attr_ac_policy.attr,
+	&dev_attr_ac_status.attr,
 	&dev_attr_dc_alarm.attr,
 	&dev_attr_dc_policy.attr,
 	&dev_attr_dc_status.attr,
+	&dev_attr_time.attr,
 	NULL,
 };
-static const struct attribute_group acpi_tad_dc_attr_group = {
-	.attrs	= acpi_tad_dc_attrs,
+
+static umode_t acpi_tad_attr_is_visible(struct kobject *kobj,
+					struct attribute *a, int n)
+{
+	struct acpi_tad_driver_data *dd = dev_get_drvdata(kobj_to_dev(kobj));
+
+	if (a == &dev_attr_caps.attr)
+		return a->mode;
+
+	if (a == &dev_attr_ac_alarm.attr || a == &dev_attr_ac_policy.attr ||
+	    a == &dev_attr_ac_status.attr)
+		return a->mode;
+
+	if ((dd->capabilities & ACPI_TAD_DC_WAKE) &&
+	    (a == &dev_attr_dc_alarm.attr || a == &dev_attr_dc_policy.attr ||
+	     a == &dev_attr_dc_status.attr))
+		return a->mode;
+
+	if ((dd->capabilities & ACPI_TAD_RT) && a == &dev_attr_time.attr)
+		return a->mode;
+
+	return 0;
+}
+
+static const struct attribute_group acpi_tad_attr_group = {
+	.attrs	= acpi_tad_attrs,
+	.is_visible = acpi_tad_attr_is_visible,
 };
 
 static int acpi_tad_disable_timer(struct device *dev, u32 timer_id)
@@ -567,12 +578,6 @@ static void acpi_tad_remove(struct platf
 
 	device_init_wakeup(dev, false);
 
-	if (dd->capabilities & ACPI_TAD_RT)
-		sysfs_remove_group(&dev->kobj, &acpi_tad_time_attr_group);
-
-	if (dd->capabilities & ACPI_TAD_DC_WAKE)
-		sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group);
-
 	sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group);
 
 	scoped_guard(pm_runtime_noresume, dev) {
@@ -633,6 +638,7 @@ static int acpi_tad_probe(struct platfor
 	device_init_wakeup(dev, true);
 	dev_pm_set_driver_flags(dev, DPM_FLAG_SMART_SUSPEND |
 				     DPM_FLAG_MAY_SKIP_RESUME);
+
 	/*
 	 * The platform bus type layer tells the ACPI PM domain powers up the
 	 * device, so set the runtime PM status of it to "active".
@@ -643,24 +649,8 @@ static int acpi_tad_probe(struct platfor
 
 	ret = sysfs_create_group(&dev->kobj, &acpi_tad_attr_group);
 	if (ret)
-		goto fail;
-
-	if (caps & ACPI_TAD_DC_WAKE) {
-		ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group);
-		if (ret)
-			goto fail;
-	}
-
-	if (caps & ACPI_TAD_RT) {
-		ret = sysfs_create_group(&dev->kobj, &acpi_tad_time_attr_group);
-		if (ret)
-			goto fail;
-	}
-
-	return 0;
+		acpi_tad_remove(pdev);
 
-fail:
-	acpi_tad_remove(pdev);
 	return ret;
 }
 




^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v1 2/7] ACPI: TAD: Support RTC without wakeup
  2026-03-04 18:11 [PATCH v1 0/7] ACPI: TAD: Assorted improvements and RTC class device interface Rafael J. Wysocki
  2026-03-04 18:12 ` [PATCH v1 1/7] ACPI: TAD: Create one attribute group Rafael J. Wysocki
@ 2026-03-04 18:13 ` Rafael J. Wysocki
  2026-03-04 18:14 ` [PATCH v1 3/7] ACPI: TAD: Use __free() for cleanup in time_store() Rafael J. Wysocki
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Rafael J. Wysocki @ 2026-03-04 18:13 UTC (permalink / raw)
  To: Linux ACPI; +Cc: Alexandre Belloni, LKML, linux-rtc, Linux PM

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

The ACPI TAD can provide a functional RTC without wakeup capabilities,
so stop failing probe if AC wakeup is not supported.

Also, if _PRW is missing, do not fail probe, but clear the wakeup bits
in capabilities.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/acpi_tad.c |   26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

--- a/drivers/acpi/acpi_tad.c
+++ b/drivers/acpi/acpi_tad.c
@@ -546,8 +546,9 @@ static umode_t acpi_tad_attr_is_visible(
 	if (a == &dev_attr_caps.attr)
 		return a->mode;
 
-	if (a == &dev_attr_ac_alarm.attr || a == &dev_attr_ac_policy.attr ||
-	    a == &dev_attr_ac_status.attr)
+	if ((dd->capabilities & ACPI_TAD_AC_WAKE) &&
+	    (a == &dev_attr_ac_alarm.attr || a == &dev_attr_ac_policy.attr ||
+	     a == &dev_attr_ac_status.attr))
 		return a->mode;
 
 	if ((dd->capabilities & ACPI_TAD_DC_WAKE) &&
@@ -581,8 +582,10 @@ static void acpi_tad_remove(struct platf
 	sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group);
 
 	scoped_guard(pm_runtime_noresume, dev) {
-		acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER);
-		acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER);
+		if (dd->capabilities & ACPI_TAD_AC_WAKE) {
+			acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER);
+			acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER);
+		}
 		if (dd->capabilities & ACPI_TAD_DC_WAKE) {
 			acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER);
 			acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER);
@@ -612,14 +615,9 @@ static int acpi_tad_probe(struct platfor
 		return -ENODEV;
 	}
 
-	if (!(caps & ACPI_TAD_AC_WAKE)) {
-		dev_info(dev, "Unsupported capabilities\n");
-		return -ENODEV;
-	}
-
 	if (!acpi_has_method(handle, "_PRW")) {
 		dev_info(dev, "Missing _PRW\n");
-		return -ENODEV;
+		caps &= ~(ACPI_TAD_AC_WAKE | ACPI_TAD_DC_WAKE);
 	}
 
 	dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL);
@@ -635,9 +633,11 @@ static int acpi_tad_probe(struct platfor
 	 * runtime suspend.  Everything else should be taken care of by the ACPI
 	 * PM domain callbacks.
 	 */
-	device_init_wakeup(dev, true);
-	dev_pm_set_driver_flags(dev, DPM_FLAG_SMART_SUSPEND |
-				     DPM_FLAG_MAY_SKIP_RESUME);
+	if (ACPI_TAD_AC_WAKE | ACPI_TAD_DC_WAKE) {
+		device_init_wakeup(dev, true);
+		dev_pm_set_driver_flags(dev, DPM_FLAG_SMART_SUSPEND |
+					     DPM_FLAG_MAY_SKIP_RESUME);
+	}
 
 	/*
 	 * The platform bus type layer tells the ACPI PM domain powers up the




^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v1 3/7] ACPI: TAD: Use __free() for cleanup in time_store()
  2026-03-04 18:11 [PATCH v1 0/7] ACPI: TAD: Assorted improvements and RTC class device interface Rafael J. Wysocki
  2026-03-04 18:12 ` [PATCH v1 1/7] ACPI: TAD: Create one attribute group Rafael J. Wysocki
  2026-03-04 18:13 ` [PATCH v1 2/7] ACPI: TAD: Support RTC without wakeup Rafael J. Wysocki
@ 2026-03-04 18:14 ` Rafael J. Wysocki
  2026-03-04 18:14 ` [PATCH v1 4/7] ACPI: TAD: Rearrange RT data validation checking Rafael J. Wysocki
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Rafael J. Wysocki @ 2026-03-04 18:14 UTC (permalink / raw)
  To: Linux ACPI; +Cc: Alexandre Belloni, LKML, linux-rtc, Linux PM

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Use __free() for the automatic freeing of memory pointed to by local
variable str in time_store() which allows the code to become somewhat
easier to follow.

No intentional functional impact.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/acpi_tad.c |   28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

--- a/drivers/acpi/acpi_tad.c
+++ b/drivers/acpi/acpi_tad.c
@@ -167,57 +167,57 @@ static ssize_t time_store(struct device
 			  const char *buf, size_t count)
 {
 	struct acpi_tad_rt rt;
-	char *str, *s;
-	int val, ret = -ENODATA;
+	int val, ret;
+	char *s;
 
-	str = kmemdup_nul(buf, count, GFP_KERNEL);
+	char *str __free(kfree) = kmemdup_nul(buf, count, GFP_KERNEL);
 	if (!str)
 		return -ENOMEM;
 
 	s = acpi_tad_rt_next_field(str, &val);
 	if (!s)
-		goto out_free;
+		return -ENODATA;
 
 	rt.year = val;
 
 	s = acpi_tad_rt_next_field(s, &val);
 	if (!s)
-		goto out_free;
+		return -ENODATA;
 
 	rt.month = val;
 
 	s = acpi_tad_rt_next_field(s, &val);
 	if (!s)
-		goto out_free;
+		return -ENODATA;
 
 	rt.day = val;
 
 	s = acpi_tad_rt_next_field(s, &val);
 	if (!s)
-		goto out_free;
+		return -ENODATA;
 
 	rt.hour = val;
 
 	s = acpi_tad_rt_next_field(s, &val);
 	if (!s)
-		goto out_free;
+		return -ENODATA;
 
 	rt.minute = val;
 
 	s = acpi_tad_rt_next_field(s, &val);
 	if (!s)
-		goto out_free;
+		return -ENODATA;
 
 	rt.second = val;
 
 	s = acpi_tad_rt_next_field(s, &val);
 	if (!s)
-		goto out_free;
+		return -ENODATA;
 
 	rt.tz = val;
 
 	if (kstrtoint(s, 10, &val))
-		goto out_free;
+		return -ENODATA;
 
 	rt.daylight = val;
 
@@ -226,10 +226,10 @@ static ssize_t time_store(struct device
 	memset(rt.padding, 0, 3);
 
 	ret = acpi_tad_set_real_time(dev, &rt);
+	if (ret)
+		return ret;
 
-out_free:
-	kfree(str);
-	return ret ? ret : count;
+	return count;
 }
 
 static ssize_t time_show(struct device *dev, struct device_attribute *attr,




^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v1 4/7] ACPI: TAD: Rearrange RT data validation checking
  2026-03-04 18:11 [PATCH v1 0/7] ACPI: TAD: Assorted improvements and RTC class device interface Rafael J. Wysocki
                   ` (2 preceding siblings ...)
  2026-03-04 18:14 ` [PATCH v1 3/7] ACPI: TAD: Use __free() for cleanup in time_store() Rafael J. Wysocki
@ 2026-03-04 18:14 ` Rafael J. Wysocki
  2026-03-04 18:15 ` [PATCH v1 5/7] ACPI: TAD: Clear unused RT data in acpi_tad_set_real_time() Rafael J. Wysocki
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Rafael J. Wysocki @ 2026-03-04 18:14 UTC (permalink / raw)
  To: Linux ACPI; +Cc: Alexandre Belloni, LKML, linux-rtc, Linux PM

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Move RT data validation checks from acpi_tad_set_real_time() to
a separate function called acpi_tad_rt_is_invalid() and use it
also in acpi_tad_get_real_time() to validate data coming from
the platform firmware.

Also make acpi_tad_set_real_time() return -EINVAL when the RT data
passed to it is invalid (instead of -ERANGE which is somewhat
confusing) and introduce ACPI_TAD_TZ_UNSPEC to represent the
"unspecified timezone" value.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/acpi_tad.c |   24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)

--- a/drivers/acpi/acpi_tad.c
+++ b/drivers/acpi/acpi_tad.c
@@ -49,6 +49,9 @@ MODULE_AUTHOR("Rafael J. Wysocki");
 /* Special value for disabled timer or expired timer wake policy. */
 #define ACPI_TAD_WAKE_DISABLED	(~(u32)0)
 
+/* ACPI TAD RTC */
+#define ACPI_TAD_TZ_UNSPEC	2047
+
 struct acpi_tad_driver_data {
 	u32 capabilities;
 };
@@ -67,6 +70,16 @@ struct acpi_tad_rt {
 	u8 padding[3]; /* must be 0 */
 } __packed;
 
+static bool acpi_tad_rt_is_invalid(struct acpi_tad_rt *rt)
+{
+	return rt->year < 1900 || rt->year > 9999 ||
+	    rt->month < 1 || rt->month > 12 ||
+	    rt->hour > 23 || rt->minute > 59 || rt->second > 59 ||
+	    rt->tz < -1440 ||
+	    (rt->tz > 1440 && rt->tz != ACPI_TAD_TZ_UNSPEC) ||
+	    rt->daylight > 3;
+}
+
 static int acpi_tad_set_real_time(struct device *dev, struct acpi_tad_rt *rt)
 {
 	acpi_handle handle = ACPI_HANDLE(dev);
@@ -80,12 +93,8 @@ static int acpi_tad_set_real_time(struct
 	unsigned long long retval;
 	acpi_status status;
 
-	if (rt->year < 1900 || rt->year > 9999 ||
-	    rt->month < 1 || rt->month > 12 ||
-	    rt->hour > 23 || rt->minute > 59 || rt->second > 59 ||
-	    rt->tz < -1440 || (rt->tz > 1440 && rt->tz != 2047) ||
-	    rt->daylight > 3)
-		return -ERANGE;
+	if (acpi_tad_rt_is_invalid(rt))
+		return -EINVAL;
 
 	args[0].buffer.pointer = (u8 *)rt;
 	args[0].buffer.length = sizeof(*rt);
@@ -145,6 +154,9 @@ static int acpi_tad_get_real_time(struct
 	if (ret)
 		return ret;
 
+	if (acpi_tad_rt_is_invalid(rt))
+		return -ENODATA;
+
 	return 0;
 }
 




^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v1 5/7] ACPI: TAD: Clear unused RT data in acpi_tad_set_real_time()
  2026-03-04 18:11 [PATCH v1 0/7] ACPI: TAD: Assorted improvements and RTC class device interface Rafael J. Wysocki
                   ` (3 preceding siblings ...)
  2026-03-04 18:14 ` [PATCH v1 4/7] ACPI: TAD: Rearrange RT data validation checking Rafael J. Wysocki
@ 2026-03-04 18:15 ` Rafael J. Wysocki
  2026-03-04 18:16 ` [PATCH v1 6/7] ACPI: TAD: Add RTC class device interface Rafael J. Wysocki
  2026-03-04 18:16 ` [PATCH v1 7/7] ACPI: TAD: Update the driver description comment Rafael J. Wysocki
  6 siblings, 0 replies; 9+ messages in thread
From: Rafael J. Wysocki @ 2026-03-04 18:15 UTC (permalink / raw)
  To: Linux ACPI; +Cc: Alexandre Belloni, LKML, linux-rtc, Linux PM

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Move the clearing of the fields in struct acpi_tad_rt that are not used
on the real time setting side to acpi_tad_set_real_time().

No intentional functional impact.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/acpi_tad.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

--- a/drivers/acpi/acpi_tad.c
+++ b/drivers/acpi/acpi_tad.c
@@ -96,6 +96,10 @@ static int acpi_tad_set_real_time(struct
 	if (acpi_tad_rt_is_invalid(rt))
 		return -EINVAL;
 
+	rt->valid = 0;
+	rt->msec = 0;
+	memset(rt->padding, 0, 3);
+
 	args[0].buffer.pointer = (u8 *)rt;
 	args[0].buffer.length = sizeof(*rt);
 
@@ -233,10 +237,6 @@ static ssize_t time_store(struct device
 
 	rt.daylight = val;
 
-	rt.valid = 0;
-	rt.msec = 0;
-	memset(rt.padding, 0, 3);
-
 	ret = acpi_tad_set_real_time(dev, &rt);
 	if (ret)
 		return ret;




^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v1 6/7] ACPI: TAD: Add RTC class device interface
  2026-03-04 18:11 [PATCH v1 0/7] ACPI: TAD: Assorted improvements and RTC class device interface Rafael J. Wysocki
                   ` (4 preceding siblings ...)
  2026-03-04 18:15 ` [PATCH v1 5/7] ACPI: TAD: Clear unused RT data in acpi_tad_set_real_time() Rafael J. Wysocki
@ 2026-03-04 18:16 ` Rafael J. Wysocki
  2026-03-05  7:48   ` Alexandre Belloni
  2026-03-04 18:16 ` [PATCH v1 7/7] ACPI: TAD: Update the driver description comment Rafael J. Wysocki
  6 siblings, 1 reply; 9+ messages in thread
From: Rafael J. Wysocki @ 2026-03-04 18:16 UTC (permalink / raw)
  To: Linux ACPI; +Cc: Alexandre Belloni, LKML, linux-rtc, Linux PM

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

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>
---
 drivers/acpi/acpi_tad.c |   78 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 76 insertions(+), 2 deletions(-)

--- a/drivers/acpi/acpi_tad.c
+++ b/drivers/acpi/acpi_tad.c
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/rtc.h>
 #include <linux/suspend.h>
 
 MODULE_DESCRIPTION("ACPI Time and Alarm (TAD) Device Driver");
@@ -51,6 +52,7 @@ MODULE_AUTHOR("Rafael J. Wysocki");
 
 /* ACPI TAD RTC */
 #define ACPI_TAD_TZ_UNSPEC	2047
+#define ACPI_TAD_TIME_ISDST	3
 
 struct acpi_tad_driver_data {
 	u32 capabilities;
@@ -164,6 +166,8 @@ static int acpi_tad_get_real_time(struct
 	return 0;
 }
 
+/* sysfs interface */
+
 static char *acpi_tad_rt_next_field(char *s, int *val)
 {
 	char *p;
@@ -579,6 +583,71 @@ static const struct attribute_group acpi
 	.is_visible = acpi_tad_attr_is_visible,
 };
 
+#ifdef CONFIG_RTC_CLASS
+/* RTC class device interface */
+
+static int acpi_tad_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct acpi_tad_rt rt;
+
+	rt.year = tm->tm_year + 1900;
+	rt.month = tm->tm_mon + 1;
+	rt.day = tm->tm_mday;
+	rt.hour = tm->tm_hour;
+	rt.minute = tm->tm_min;
+	rt.second = tm->tm_sec;
+	rt.tz = ACPI_TAD_TZ_UNSPEC;
+	rt.daylight = ACPI_TAD_TIME_ISDST * !!tm->tm_isdst;
+
+	return acpi_tad_set_real_time(dev, &rt);
+}
+
+static int acpi_tad_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct acpi_tad_rt rt;
+	int ret;
+
+	ret = acpi_tad_get_real_time(dev, &rt);
+	if (ret)
+		return ret;
+
+	tm->tm_year = rt.year - 1900;
+	tm->tm_mon = rt.month - 1;
+	tm->tm_mday = rt.day;
+	tm->tm_hour = rt.hour;
+	tm->tm_min = rt.minute;
+	tm->tm_sec = rt.second;
+	tm->tm_isdst = rt.daylight == ACPI_TAD_TIME_ISDST;
+
+	return 0;
+}
+
+static const struct rtc_class_ops acpi_tad_rtc_ops = {
+	.read_time = acpi_tad_rtc_read_time,
+	.set_time = acpi_tad_rtc_set_time,
+};
+
+static void acpi_tad_register_rtc(struct device *dev)
+{
+	struct rtc_device *rtc;
+
+	rtc = devm_rtc_allocate_device(dev);
+	if (IS_ERR(rtc))
+		return;
+
+	rtc->range_min = mktime64(1900,  1,  1,  0,  0,  0);
+	rtc->range_max = mktime64(9999, 12, 31, 23, 59, 59);
+
+	rtc->ops = &acpi_tad_rtc_ops;
+
+	devm_rtc_register_device(rtc);
+}
+#else /* !CONFIG_RTC_CLASS */
+static inline void acpi_tad_register_rtc(struct device *dev) {}
+#endif /* !CONFIG_RTC_CLASS */
+
+/* Platform driver interface */
+
 static int acpi_tad_disable_timer(struct device *dev, u32 timer_id)
 {
 	return acpi_tad_wake_set(dev, "_STV", timer_id, ACPI_TAD_WAKE_DISABLED);
@@ -660,10 +729,15 @@ static int acpi_tad_probe(struct platfor
 	pm_runtime_suspend(dev);
 
 	ret = sysfs_create_group(&dev->kobj, &acpi_tad_attr_group);
-	if (ret)
+	if (ret) {
 		acpi_tad_remove(pdev);
+		return ret;
+	}
 
-	return ret;
+	if (caps & ACPI_TAD_RT)
+		acpi_tad_register_rtc(dev);
+
+	return 0;
 }
 
 static const struct acpi_device_id acpi_tad_ids[] = {




^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v1 7/7] ACPI: TAD: Update the driver description comment
  2026-03-04 18:11 [PATCH v1 0/7] ACPI: TAD: Assorted improvements and RTC class device interface Rafael J. Wysocki
                   ` (5 preceding siblings ...)
  2026-03-04 18:16 ` [PATCH v1 6/7] ACPI: TAD: Add RTC class device interface Rafael J. Wysocki
@ 2026-03-04 18:16 ` Rafael J. Wysocki
  6 siblings, 0 replies; 9+ messages in thread
From: Rafael J. Wysocki @ 2026-03-04 18:16 UTC (permalink / raw)
  To: Linux ACPI; +Cc: Alexandre Belloni, LKML, linux-rtc, Linux PM

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Update the preamble comment describing the driver to match the code
after previous changes along with the copyright information.

No functional impact.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/acpi_tad.c |   13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

--- a/drivers/acpi/acpi_tad.c
+++ b/drivers/acpi/acpi_tad.c
@@ -2,12 +2,10 @@
 /*
  * ACPI Time and Alarm (TAD) Device Driver
  *
- * Copyright (C) 2018 Intel Corporation
+ * Copyright (C) 2018 - 2026 Intel Corporation
  * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  *
- * This driver is based on Section 9.18 of the ACPI 6.2 specification revision.
- *
- * It only supports the system wakeup capabilities of the TAD.
+ * This driver is based on ACPI 6.6, Section 9.17.
  *
  * Provided are sysfs attributes, available under the TAD platform device,
  * allowing user space to manage the AC and DC wakeup timers of the TAD:
@@ -18,6 +16,11 @@
  *
  * The wakeup events handling and power management of the TAD is expected to
  * be taken care of by the ACPI PM domain attached to its platform device.
+ *
+ * If the TAD supports the get/set real time features, as indicated by the
+ * capability mask returned by _GCP under the TAD object, additional sysfs
+ * attributes are created allowing the real time to be set and read and an RTC
+ * class device is registered under the TAD platform device.
  */
 
 #include <linux/acpi.h>
@@ -32,7 +35,7 @@ MODULE_DESCRIPTION("ACPI Time and Alarm
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Rafael J. Wysocki");
 
-/* ACPI TAD capability flags (ACPI 6.2, Section 9.18.2) */
+/* ACPI TAD capability flags (ACPI 6.6, Section 9.17.2) */
 #define ACPI_TAD_AC_WAKE	BIT(0)
 #define ACPI_TAD_DC_WAKE	BIT(1)
 #define ACPI_TAD_RT		BIT(2)




^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v1 6/7] ACPI: TAD: Add RTC class device interface
  2026-03-04 18:16 ` [PATCH v1 6/7] ACPI: TAD: Add RTC class device interface Rafael J. Wysocki
@ 2026-03-05  7:48   ` Alexandre Belloni
  0 siblings, 0 replies; 9+ messages in thread
From: Alexandre Belloni @ 2026-03-05  7:48 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Linux ACPI, LKML, linux-rtc, Linux PM

On 04/03/2026 19:16:01+0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> 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>

> ---
>  drivers/acpi/acpi_tad.c |   78 ++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 76 insertions(+), 2 deletions(-)
> 
> --- a/drivers/acpi/acpi_tad.c
> +++ b/drivers/acpi/acpi_tad.c
> @@ -25,6 +25,7 @@
>  #include <linux/module.h>
>  #include <linux/platform_device.h>
>  #include <linux/pm_runtime.h>
> +#include <linux/rtc.h>
>  #include <linux/suspend.h>
>  
>  MODULE_DESCRIPTION("ACPI Time and Alarm (TAD) Device Driver");
> @@ -51,6 +52,7 @@ MODULE_AUTHOR("Rafael J. Wysocki");
>  
>  /* ACPI TAD RTC */
>  #define ACPI_TAD_TZ_UNSPEC	2047
> +#define ACPI_TAD_TIME_ISDST	3
>  
>  struct acpi_tad_driver_data {
>  	u32 capabilities;
> @@ -164,6 +166,8 @@ static int acpi_tad_get_real_time(struct
>  	return 0;
>  }
>  
> +/* sysfs interface */
> +
>  static char *acpi_tad_rt_next_field(char *s, int *val)
>  {
>  	char *p;
> @@ -579,6 +583,71 @@ static const struct attribute_group acpi
>  	.is_visible = acpi_tad_attr_is_visible,
>  };
>  
> +#ifdef CONFIG_RTC_CLASS
> +/* RTC class device interface */
> +
> +static int acpi_tad_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct acpi_tad_rt rt;
> +
> +	rt.year = tm->tm_year + 1900;
> +	rt.month = tm->tm_mon + 1;
> +	rt.day = tm->tm_mday;
> +	rt.hour = tm->tm_hour;
> +	rt.minute = tm->tm_min;
> +	rt.second = tm->tm_sec;
> +	rt.tz = ACPI_TAD_TZ_UNSPEC;
> +	rt.daylight = ACPI_TAD_TIME_ISDST * !!tm->tm_isdst;
> +
> +	return acpi_tad_set_real_time(dev, &rt);
> +}
> +
> +static int acpi_tad_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct acpi_tad_rt rt;
> +	int ret;
> +
> +	ret = acpi_tad_get_real_time(dev, &rt);
> +	if (ret)
> +		return ret;
> +
> +	tm->tm_year = rt.year - 1900;
> +	tm->tm_mon = rt.month - 1;
> +	tm->tm_mday = rt.day;
> +	tm->tm_hour = rt.hour;
> +	tm->tm_min = rt.minute;
> +	tm->tm_sec = rt.second;
> +	tm->tm_isdst = rt.daylight == ACPI_TAD_TIME_ISDST;
> +
> +	return 0;
> +}
> +
> +static const struct rtc_class_ops acpi_tad_rtc_ops = {
> +	.read_time = acpi_tad_rtc_read_time,
> +	.set_time = acpi_tad_rtc_set_time,
> +};
> +
> +static void acpi_tad_register_rtc(struct device *dev)
> +{
> +	struct rtc_device *rtc;
> +
> +	rtc = devm_rtc_allocate_device(dev);
> +	if (IS_ERR(rtc))
> +		return;
> +
> +	rtc->range_min = mktime64(1900,  1,  1,  0,  0,  0);
> +	rtc->range_max = mktime64(9999, 12, 31, 23, 59, 59);
> +
> +	rtc->ops = &acpi_tad_rtc_ops;
> +
> +	devm_rtc_register_device(rtc);
> +}
> +#else /* !CONFIG_RTC_CLASS */
> +static inline void acpi_tad_register_rtc(struct device *dev) {}
> +#endif /* !CONFIG_RTC_CLASS */
> +
> +/* Platform driver interface */
> +
>  static int acpi_tad_disable_timer(struct device *dev, u32 timer_id)
>  {
>  	return acpi_tad_wake_set(dev, "_STV", timer_id, ACPI_TAD_WAKE_DISABLED);
> @@ -660,10 +729,15 @@ static int acpi_tad_probe(struct platfor
>  	pm_runtime_suspend(dev);
>  
>  	ret = sysfs_create_group(&dev->kobj, &acpi_tad_attr_group);
> -	if (ret)
> +	if (ret) {
>  		acpi_tad_remove(pdev);
> +		return ret;
> +	}
>  
> -	return ret;
> +	if (caps & ACPI_TAD_RT)
> +		acpi_tad_register_rtc(dev);
> +
> +	return 0;
>  }
>  
>  static const struct acpi_device_id acpi_tad_ids[] = {
> 
> 
> 

-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-03-05  7:48 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-04 18:11 [PATCH v1 0/7] ACPI: TAD: Assorted improvements and RTC class device interface Rafael J. Wysocki
2026-03-04 18:12 ` [PATCH v1 1/7] ACPI: TAD: Create one attribute group Rafael J. Wysocki
2026-03-04 18:13 ` [PATCH v1 2/7] ACPI: TAD: Support RTC without wakeup Rafael J. Wysocki
2026-03-04 18:14 ` [PATCH v1 3/7] ACPI: TAD: Use __free() for cleanup in time_store() Rafael J. Wysocki
2026-03-04 18:14 ` [PATCH v1 4/7] ACPI: TAD: Rearrange RT data validation checking Rafael J. Wysocki
2026-03-04 18:15 ` [PATCH v1 5/7] ACPI: TAD: Clear unused RT data in acpi_tad_set_real_time() Rafael J. Wysocki
2026-03-04 18:16 ` [PATCH v1 6/7] ACPI: TAD: Add RTC class device interface Rafael J. Wysocki
2026-03-05  7:48   ` Alexandre Belloni
2026-03-04 18:16 ` [PATCH v1 7/7] ACPI: TAD: Update the driver description comment Rafael J. Wysocki

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.