| .. | .. |
|---|
| 32 | 32 | #define SNVS_LPPGDR_INIT 0x41736166 |
|---|
| 33 | 33 | #define CNTR_TO_SECS_SH 15 |
|---|
| 34 | 34 | |
|---|
| 35 | +/* The maximum RTC clock cycles that are allowed to pass between two |
|---|
| 36 | + * consecutive clock counter register reads. If the values are corrupted a |
|---|
| 37 | + * bigger difference is expected. The RTC frequency is 32kHz. With 320 cycles |
|---|
| 38 | + * we end at 10ms which should be enough for most cases. If it once takes |
|---|
| 39 | + * longer than expected we do a retry. |
|---|
| 40 | + */ |
|---|
| 41 | +#define MAX_RTC_READ_DIFF_CYCLES 320 |
|---|
| 42 | + |
|---|
| 35 | 43 | struct snvs_rtc_data { |
|---|
| 36 | 44 | struct rtc_device *rtc; |
|---|
| 37 | 45 | struct regmap *regmap; |
|---|
| .. | .. |
|---|
| 56 | 64 | static u32 rtc_read_lp_counter(struct snvs_rtc_data *data) |
|---|
| 57 | 65 | { |
|---|
| 58 | 66 | u64 read1, read2; |
|---|
| 67 | + s64 diff; |
|---|
| 59 | 68 | unsigned int timeout = 100; |
|---|
| 60 | 69 | |
|---|
| 61 | 70 | /* As expected, the registers might update between the read of the LSB |
|---|
| .. | .. |
|---|
| 66 | 75 | do { |
|---|
| 67 | 76 | read2 = read1; |
|---|
| 68 | 77 | read1 = rtc_read_lpsrt(data); |
|---|
| 69 | | - } while (read1 != read2 && --timeout); |
|---|
| 78 | + diff = read1 - read2; |
|---|
| 79 | + } while (((diff < 0) || (diff > MAX_RTC_READ_DIFF_CYCLES)) && --timeout); |
|---|
| 70 | 80 | if (!timeout) |
|---|
| 71 | 81 | dev_err(&data->rtc->dev, "Timeout trying to get valid LPSRT Counter read\n"); |
|---|
| 72 | 82 | |
|---|
| .. | .. |
|---|
| 78 | 88 | static int rtc_read_lp_counter_lsb(struct snvs_rtc_data *data, u32 *lsb) |
|---|
| 79 | 89 | { |
|---|
| 80 | 90 | u32 count1, count2; |
|---|
| 91 | + s32 diff; |
|---|
| 81 | 92 | unsigned int timeout = 100; |
|---|
| 82 | 93 | |
|---|
| 83 | 94 | regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1); |
|---|
| 84 | 95 | do { |
|---|
| 85 | 96 | count2 = count1; |
|---|
| 86 | 97 | regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1); |
|---|
| 87 | | - } while (count1 != count2 && --timeout); |
|---|
| 98 | + diff = count1 - count2; |
|---|
| 99 | + } while (((diff < 0) || (diff > MAX_RTC_READ_DIFF_CYCLES)) && --timeout); |
|---|
| 88 | 100 | if (!timeout) { |
|---|
| 89 | 101 | dev_err(&data->rtc->dev, "Timeout trying to get valid LPSRT Counter read\n"); |
|---|
| 90 | 102 | return -ETIMEDOUT; |
|---|