|
@@ -211,6 +211,73 @@ static int rtc_device_get_id(struct device *dev)
|
|
|
return id;
|
|
|
}
|
|
|
|
|
|
+static void rtc_device_get_offset(struct rtc_device *rtc)
|
|
|
+{
|
|
|
+ time64_t range_secs;
|
|
|
+ u32 start_year;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If RTC driver did not implement the range of RTC hardware device,
|
|
|
+ * then we can not expand the RTC range by adding or subtracting one
|
|
|
+ * offset.
|
|
|
+ */
|
|
|
+ if (rtc->range_min == rtc->range_max)
|
|
|
+ return;
|
|
|
+
|
|
|
+ ret = device_property_read_u32(rtc->dev.parent, "start-year",
|
|
|
+ &start_year);
|
|
|
+ if (!ret) {
|
|
|
+ rtc->start_secs = mktime64(start_year, 1, 1, 0, 0, 0);
|
|
|
+ rtc->set_start_time = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If user did not implement the start time for RTC driver, then no
|
|
|
+ * need to expand the RTC range.
|
|
|
+ */
|
|
|
+ if (!rtc->set_start_time)
|
|
|
+ return;
|
|
|
+
|
|
|
+ range_secs = rtc->range_max - rtc->range_min + 1;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If the start_secs is larger than the maximum seconds (rtc->range_max)
|
|
|
+ * supported by RTC hardware or the maximum seconds of new expanded
|
|
|
+ * range (start_secs + rtc->range_max - rtc->range_min) is less than
|
|
|
+ * rtc->range_min, which means the minimum seconds (rtc->range_min) of
|
|
|
+ * RTC hardware will be mapped to start_secs by adding one offset, so
|
|
|
+ * the offset seconds calculation formula should be:
|
|
|
+ * rtc->offset_secs = rtc->start_secs - rtc->range_min;
|
|
|
+ *
|
|
|
+ * If the start_secs is larger than the minimum seconds (rtc->range_min)
|
|
|
+ * supported by RTC hardware, then there is one region is overlapped
|
|
|
+ * between the original RTC hardware range and the new expanded range,
|
|
|
+ * and this overlapped region do not need to be mapped into the new
|
|
|
+ * expanded range due to it is valid for RTC device. So the minimum
|
|
|
+ * seconds of RTC hardware (rtc->range_min) should be mapped to
|
|
|
+ * rtc->range_max + 1, then the offset seconds formula should be:
|
|
|
+ * rtc->offset_secs = rtc->range_max - rtc->range_min + 1;
|
|
|
+ *
|
|
|
+ * If the start_secs is less than the minimum seconds (rtc->range_min),
|
|
|
+ * which is similar to case 2. So the start_secs should be mapped to
|
|
|
+ * start_secs + rtc->range_max - rtc->range_min + 1, then the
|
|
|
+ * offset seconds formula should be:
|
|
|
+ * rtc->offset_secs = -(rtc->range_max - rtc->range_min + 1);
|
|
|
+ *
|
|
|
+ * Otherwise the offset seconds should be 0.
|
|
|
+ */
|
|
|
+ if (rtc->start_secs > rtc->range_max ||
|
|
|
+ rtc->start_secs + range_secs - 1 < rtc->range_min)
|
|
|
+ rtc->offset_secs = rtc->start_secs - rtc->range_min;
|
|
|
+ else if (rtc->start_secs > rtc->range_min)
|
|
|
+ rtc->offset_secs = range_secs;
|
|
|
+ else if (rtc->start_secs < rtc->range_min)
|
|
|
+ rtc->offset_secs = -range_secs;
|
|
|
+ else
|
|
|
+ rtc->offset_secs = 0;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* rtc_device_register - register w/ RTC class
|
|
|
* @dev: the device to register
|
|
@@ -247,6 +314,8 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
|
|
|
|
|
|
dev_set_name(&rtc->dev, "rtc%d", id);
|
|
|
|
|
|
+ rtc_device_get_offset(rtc);
|
|
|
+
|
|
|
/* Check to see if there is an ALARM already set in hw */
|
|
|
err = __rtc_read_alarm(rtc, &alrm);
|
|
|
|
|
@@ -436,6 +505,7 @@ int __rtc_register_device(struct module *owner, struct rtc_device *rtc)
|
|
|
return -EINVAL;
|
|
|
|
|
|
rtc->owner = owner;
|
|
|
+ rtc_device_get_offset(rtc);
|
|
|
|
|
|
/* Check to see if there is an ALARM already set in hw */
|
|
|
err = __rtc_read_alarm(rtc, &alrm);
|