From 083acb3063893ee16ec1a8272ab2eb1fd7f17080 Mon Sep 17 00:00:00 2001 From: AI Dev Date: Tue, 13 Oct 2026 10:58:46 +0000 Subject: [PATCH 1/2] rtc: hibvt: judge the time by its counter, not the low-voltage flag Port of the hisilicon-hi3516ev200 fix. This branch's copy kept the vendor's handling of the backup supply low-voltage flag: read_time() logs "low voltage detected" and returns -EINVAL whenever the flag is set. The flag is "cleared" by writing 1 to RTC_INT_CLR, though, and that is the alarm bit. So once the flag is set it never clears, every read fails and logs an error, and the RTC stays unreadable. The flag is not a reliable verdict anyway. On a hi3516ev300 it stays set, and returns about 0.5 s after each correct clear, with a fresh backup cell that keeps the time through a 5-minute power cut. - Do not fail the read, or log, because of the flag. Clear it with LV_INT_MASK. - Judge the time by the counter: return -EINVAL for a value before 2000-01-01, which is what a counter that lost power reads. set_time() refuses the same range, so every time it accepts can be read back. --- drivers/rtc/rtc-hibvt.c | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/drivers/rtc/rtc-hibvt.c b/drivers/rtc/rtc-hibvt.c index 28d0bae6739..efe0d7ab028 100644 --- a/drivers/rtc/rtc-hibvt.c +++ b/drivers/rtc/rtc-hibvt.c @@ -98,6 +98,13 @@ union u_spi_rw { #define REG_LOCK_STAT BIT(1) #define REG_LOCK_BYPASS BIT(2) +/* + * A counter that lost every supply restarts from zero and reads as 1970. + * Times before 2000-01-01 are refused both ways, so such a counter reads + * as unset and every time set_time() accepts can be read back. + */ +#define RTC_MIN_VALID_SEC 946684800UL + #define RETRY_CNT 500 #define DATE_TO_SEC(d, h, m, s) (s + m*60 + h*60*60 + d*24*60*60) @@ -191,12 +198,15 @@ static int hibvt_rtc_read_time(struct device *dev, struct rtc_time *time) return ret; } - if (raw_value & LV_INT_MASK) { - dev_err(dev, - "low voltage detected, date/time is not reliable.\n"); - hibvt_spi_write(rtc->regs, RTC_INT_CLR, 1); - return -EINVAL; - } + /* + * Not a verdict on the time: on a hi3516ev300 the flag stays set, + * and returns about half a second after each clear, with a fresh + * backup cell that keeps the counter through a power cut, exactly as + * it did with a flat one. The counter below is what tells. Clear the + * flag by its own bit: writing 1 acknowledged the alarm instead. + */ + if (raw_value & LV_INT_MASK) + hibvt_spi_write(rtc->regs, RTC_INT_CLR, LV_INT_MASK); ret |= hibvt_spi_rtc_read(rtc->regs, RTC_LORD, &raw_value); if (raw_value & REG_LOCK_BYPASS) @@ -230,6 +240,13 @@ static int hibvt_rtc_read_time(struct device *dev, struct rtc_time *time) day = (dayl | (dayh << 8)); seconds = DATE_TO_SEC(day, hour, minute, second); + /* + * Report a counter that restarted from zero as unset, so hctosys + * leaves the clock alone instead of stepping it to 1970. + */ + if (seconds < RTC_MIN_VALID_SEC) + return -EINVAL; + rtc_time_to_tm(seconds, time); return rtc_valid_tm(time); @@ -247,6 +264,8 @@ static int hibvt_rtc_set_time(struct device *dev, struct rtc_time *time) ret = rtc_tm_to_time(time, &seconds); if (ret) return ret; + if (seconds < RTC_MIN_VALID_SEC) + return -EINVAL; days = SEC_TO_DAY(seconds); ret |= hibvt_spi_rtc_write(rtc->regs, RTC_LR_10MS, 0); @@ -500,11 +519,8 @@ static int hibvt_rtc_init(struct hibvt_rtc *rtc) return ret; } - if (val & LV_INT_MASK) { - dev_err(&rtc->rtc_dev->dev, - "low voltage detected, date/time is not reliable.\n"); - hibvt_spi_write(rtc->regs, RTC_INT_CLR, 1); - } + if (val & LV_INT_MASK) + hibvt_spi_write(rtc->regs, RTC_INT_CLR, LV_INT_MASK); return ret; } From 0e9e3dd4956641b9551183c107b664666d307432 Mon Sep 17 00:00:00 2001 From: AI Dev Date: Tue, 20 Oct 2026 14:03:11 +0000 Subject: [PATCH 2/2] rtc: hibvt: return set_time()'s SPI errors as errors set_time() collected the SPI write results in an unsigned char, so a bridge timeout (-EIO) came back as 251: RTC_SET_TIME reported success for a write that never reached the RTC. Every other function here already uses int. --- drivers/rtc/rtc-hibvt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-hibvt.c b/drivers/rtc/rtc-hibvt.c index efe0d7ab028..9c4d66fce3f 100644 --- a/drivers/rtc/rtc-hibvt.c +++ b/drivers/rtc/rtc-hibvt.c @@ -255,7 +255,7 @@ static int hibvt_rtc_read_time(struct device *dev, struct rtc_time *time) static int hibvt_rtc_set_time(struct device *dev, struct rtc_time *time) { struct hibvt_rtc *rtc = dev_get_drvdata(dev); - unsigned char ret = 0; + int ret = 0; unsigned int days; unsigned long seconds = 0; unsigned int cnt = RETRY_CNT;