rtc: introduce features bitfield
authorAlexandre Belloni <alexandre.belloni@bootlin.com>
Sun, 10 Jan 2021 23:17:36 +0000 (00:17 +0100)
committerAlexandre Belloni <alexandre.belloni@bootlin.com>
Sat, 16 Jan 2021 22:19:26 +0000 (23:19 +0100)
Introduce a bitfield to allow the drivers to announce the available
features for an RTC.

The main use case would be to better handle alarms, that could be present
or not or have a minute resolution or may need a correct week day to be set.

Use the newly introduced RTC_FEATURE_ALARM bit to then test whether alarms
are available instead of relying on the presence of ops->set_alarm.

Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Link: https://lore.kernel.org/r/20210110231752.1418816-2-alexandre.belloni@bootlin.com
drivers/rtc/class.c
drivers/rtc/interface.c
include/linux/rtc.h
include/uapi/linux/rtc.h

index 7e470fbd5e4d22ea82b8162a0f8c1c4568638b92..03abd0aa229afaf27202a2a1748bbfad94435921 100644 (file)
@@ -231,6 +231,8 @@ static struct rtc_device *rtc_allocate_device(void)
        rtc->pie_timer.function = rtc_pie_update_irq;
        rtc->pie_enabled = 0;
 
+       set_bit(RTC_FEATURE_ALARM, rtc->features);
+
        return rtc;
 }
 
@@ -386,6 +388,9 @@ int __devm_rtc_register_device(struct module *owner, struct rtc_device *rtc)
                return -EINVAL;
        }
 
+       if (!rtc->ops->set_alarm)
+               clear_bit(RTC_FEATURE_ALARM, rtc->features);
+
        rtc->owner = owner;
        rtc_device_get_offset(rtc);
 
index 794a4f036b99834c8fa15bcc834dddcfaa1090ba..dcb34c73319e3b9a1b243eb7eb4c83fbf0eb04f1 100644 (file)
@@ -186,7 +186,7 @@ static int rtc_read_alarm_internal(struct rtc_device *rtc,
 
        if (!rtc->ops) {
                err = -ENODEV;
-       } else if (!rtc->ops->read_alarm) {
+       } else if (!test_bit(RTC_FEATURE_ALARM, rtc->features) || !rtc->ops->read_alarm) {
                err = -EINVAL;
        } else {
                alarm->enabled = 0;
@@ -392,7 +392,7 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
                return err;
        if (!rtc->ops) {
                err = -ENODEV;
-       } else if (!rtc->ops->read_alarm) {
+       } else if (!test_bit(RTC_FEATURE_ALARM, rtc->features) || !rtc->ops->read_alarm) {
                err = -EINVAL;
        } else {
                memset(alarm, 0, sizeof(struct rtc_wkalrm));
@@ -436,7 +436,7 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
 
        if (!rtc->ops)
                err = -ENODEV;
-       else if (!rtc->ops->set_alarm)
+       else if (!test_bit(RTC_FEATURE_ALARM, rtc->features))
                err = -EINVAL;
        else
                err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
@@ -451,7 +451,7 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
 
        if (!rtc->ops)
                return -ENODEV;
-       else if (!rtc->ops->set_alarm)
+       else if (!test_bit(RTC_FEATURE_ALARM, rtc->features))
                return -EINVAL;
 
        err = rtc_valid_tm(&alarm->time);
@@ -531,7 +531,7 @@ int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled)
                /* nothing */;
        else if (!rtc->ops)
                err = -ENODEV;
-       else if (!rtc->ops->alarm_irq_enable)
+       else if (!test_bit(RTC_FEATURE_ALARM, rtc->features) || !rtc->ops->alarm_irq_enable)
                err = -EINVAL;
        else
                err = rtc->ops->alarm_irq_enable(rtc->dev.parent, enabled);
@@ -843,7 +843,7 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
 
 static void rtc_alarm_disable(struct rtc_device *rtc)
 {
-       if (!rtc->ops || !rtc->ops->alarm_irq_enable)
+       if (!rtc->ops || !test_bit(RTC_FEATURE_ALARM, rtc->features) || !rtc->ops->alarm_irq_enable)
                return;
 
        rtc->ops->alarm_irq_enable(rtc->dev.parent, false);
index 568909449c131076ab79d74c7d036136d3aa73d4..bd611e26291d456eb43503f1079fd28c1aa377d0 100644 (file)
@@ -141,6 +141,8 @@ struct rtc_device {
         */
        unsigned long set_offset_nsec;
 
+       unsigned long features[BITS_TO_LONGS(RTC_FEATURE_CNT)];
+
        time64_t range_min;
        timeu64_t range_max;
        time64_t start_secs;
index fa9aff91cbf27c35651218d9c804702b1eca94e0..f950bff75e97efc95b6881dd076fd3afe054197c 100644 (file)
@@ -110,6 +110,11 @@ struct rtc_pll_info {
 #define RTC_AF 0x20    /* Alarm interrupt */
 #define RTC_UF 0x10    /* Update interrupt for 1Hz RTC */
 
+/* feature list */
+#define RTC_FEATURE_ALARM              0
+#define RTC_FEATURE_ALARM_RES_MINUTE   1
+#define RTC_FEATURE_NEED_WEEK_DAY      2
+#define RTC_FEATURE_CNT                        3
 
 #define RTC_MAX_FREQ   8192