diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 31fc0f1..8e59cf0 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -211,6 +211,55 @@ static int rtc_device_get_id(struct device *dev)
 	return id;
 }
 
+static void rtc_device_get_offset(struct rtc_device *rtc)
+{
+	u32 start_year;
+	int ret;
+
+	rtc->offset_secs = 0;
+	rtc->start_secs = rtc->min_hw_secs;
+
+	/*
+	 * 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->max_hw_secs)
+		return;
+
+	ret = device_property_read_u32(rtc->dev.parent, "start-year",
+				       &start_year);
+	if (ret)
+		return;
+
+	/*
+	 * Record the start time values in seconds, which are used to valid if
+	 * the setting time values are in the new expanded range.
+	 */
+	rtc->start_secs = max_t(time64_t, mktime64(start_year, 1, 1, 0, 0, 0),
+				rtc->min_hw_secs);
+
+	/*
+	 * If the start_secs is larger than the maximum seconds (max_hw_secs)
+	 * support by RTC hardware, which means the minimum seconds
+	 * (min_hw_secs) 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->min_hw_secs;
+	 *
+	 * If the start_secs is less than max_hw_secs, 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 (min_hw_secs) should be mapped to
+	 * max_hw_secs + 1, then the offset seconds formula should be:
+	 * rtc->offset_secs = rtc->max_hw_secs - rtc->min_hw_secs + 1;
+	 */
+	if (rtc->start_secs > rtc->max_hw_secs)
+		rtc->offset_secs = rtc->start_secs - rtc->min_hw_secs;
+	else
+		rtc->offset_secs = rtc->max_hw_secs - rtc->min_hw_secs + 1;
+}
+
 /**
  * rtc_device_register - register w/ RTC class
  * @dev: the device to register
@@ -253,6 +302,8 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
 		goto exit_ida;
 	}
 
+	rtc_device_get_offset(rtc);
+
 	/* Check to see if there is an ALARM already set in hw */
 	err = __rtc_read_alarm(rtc, &alrm);
 
@@ -449,6 +500,8 @@ int __rtc_register_device(struct module *owner, struct rtc_device *rtc)
 		return err;
 	}
 
+	rtc_device_get_offset(rtc);
+
 	/* Check to see if there is an ALARM already set in hw */
 	err = __rtc_read_alarm(rtc, &alrm);
 	if (!err && !rtc_valid_tm(&alrm.time))
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index c8090e3..eb96a90 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -20,6 +20,46 @@
 static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer);
 static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer);
 
+static void rtc_add_offset(struct rtc_device *rtc, struct rtc_time *tm)
+{
+	time64_t secs;
+
+	if (!rtc->offset_secs)
+		return;
+
+	secs = rtc_tm_to_time64(tm);
+	/*
+	 * Since the reading time values from RTC device are always less than
+	 * rtc->max_hw_secs, then if the reading time values are larger than
+	 * the rtc->start_secs, which means they did not subtract the offset
+	 * when writing into RTC device, so we do not need to add the offset.
+	 */
+	if (secs >= rtc->start_secs)
+		return;
+
+	rtc_time64_to_tm(secs + rtc->offset_secs, tm);
+}
+
+static void rtc_subtract_offset(struct rtc_device *rtc, struct rtc_time *tm)
+{
+	time64_t secs;
+
+	if (!rtc->offset_secs)
+		return;
+
+	secs = rtc_tm_to_time64(tm);
+	/*
+	 * If the setting time values are in the valid range of RTC hardware
+	 * device, then no need to subtract the offset when setting time to RTC
+	 * device. Otherwise we need to subtract the offset to make the time
+	 * values are valid for RTC hardware device.
+	 */
+	if (secs <= rtc->max_hw_secs)
+		return;
+
+	rtc_time64_to_tm(secs - rtc->offset_secs, tm);
+}
+
 static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
 {
 	int err;
@@ -36,6 +76,8 @@ static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
 			return err;
 		}
 
+		rtc_add_offset(rtc, tm);
+
 		err = rtc_valid_tm(tm);
 		if (err < 0)
 			dev_dbg(&rtc->dev, "read_time: rtc_time isn't valid\n");
@@ -69,6 +111,8 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
 	if (err)
 		return err;
 
+	rtc_subtract_offset(rtc, tm);
+
 	err = mutex_lock_interruptible(&rtc->ops_lock);
 	if (err)
 		return err;
@@ -123,6 +167,8 @@ static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *al
 	}
 
 	mutex_unlock(&rtc->ops_lock);
+
+	rtc_add_offset(rtc, &alarm->time);
 	return err;
 }
 
@@ -338,6 +384,7 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
 	if (err)
 		return err;
 
+	rtc_subtract_offset(rtc, &alarm->time);
 	scheduled = rtc_tm_to_time64(&alarm->time);
 
 	/* Make sure we're not setting alarms in the past */
@@ -1074,7 +1121,8 @@ int rtc_read_range(struct rtc_device *rtc, time64_t *max_hw_secs,
  * @ tm: time values need to valid.
  *
  * Only the rtc->max_hw_secs was set, then we can valid if the setting time
- * values are beyond the RTC range.
+ * values are beyond the RTC range. When drivers set one start time values,
+ * we need to valid if the setting time values are in the new expanded range.
  */
 int rtc_valid_range(struct rtc_device *rtc, struct rtc_time *tm)
 {
@@ -1084,7 +1132,8 @@ int rtc_valid_range(struct rtc_device *rtc, struct rtc_time *tm)
 		return 0;
 
 	secs = rtc_tm_to_time64(tm);
-	if (secs < rtc->min_hw_secs || secs > rtc->max_hw_secs)
+	if (secs < rtc->start_secs ||
+	    secs > (rtc->start_secs + rtc->max_hw_secs - rtc->min_hw_secs))
 		return -EINVAL;
 
 	return 0;
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index 19a8989..11879b7 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -156,6 +156,8 @@ struct rtc_device {
 
 	time64_t max_hw_secs;
 	time64_t min_hw_secs;
+	time64_t start_secs;
+	time64_t offset_secs;
 
 #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
 	struct work_struct uie_task;
