diff --git a/arch/arm/boot/dts/hi3516cv300.dtsi b/arch/arm/boot/dts/hi3516cv300.dtsi index 2832476cce0..856a286d97a 100644 --- a/arch/arm/boot/dts/hi3516cv300.dtsi +++ b/arch/arm/boot/dts/hi3516cv300.dtsi @@ -641,7 +641,7 @@ }; rtc: rtc@12090000 { - compatible = "hisilicon,hi_rtc"; + compatible = "hisilicon,hi35xx-rtc"; interrupts = <2>; reg = <0x12090000 0x10000>; }; diff --git a/drivers/rtc/rtc-hibvt.c b/drivers/rtc/rtc-hibvt.c index 28d0bae6739..dccac991ddc 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); @@ -238,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; @@ -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); @@ -486,8 +505,15 @@ static int hibvt_rtc_init(struct hibvt_rtc *rtc) ret |= hibvt_spi_rtc_write(spi_reg, RTC_IMSC, INT_MSK_DEFAULT); ret |= hibvt_spi_rtc_write(spi_reg, RTC_SAR_CTRL, LV_CTL_DEFAULT); - + +#ifndef CONFIG_ARCH_HI3516CV300 + /* + * The HiSilicon SDK's own hi3516cv300 RTC driver never writes + * RTC_CLK_CFG, and the register reads 0 on a running board, so leave + * the oscillator settings of that family as they come. + */ ret |= hibvt_spi_rtc_write(spi_reg, RTC_CLK_CFG, 0x01); +#endif /* default FREQ COEF */ ret |= hibvt_spi_rtc_write(spi_reg, RTC_FREQ_H, FREQ_H_DEFAULT); @@ -500,11 +526,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; }