Skip to content

Commit 0462681

Browse files
eichenbergeralexandrebelloni
authored andcommitted
rtc: snvs: Allow a time difference on clock register read
On an iMX6ULL the following message appears when a wakealarm is set: echo 0 > /sys/class/rtc/rtc1/wakealarm rtc rtc1: Timeout trying to get valid LPSRT Counter read This does not always happen but is reproducible quite often (7 out of 10 times). The problem appears because the iMX6ULL is not able to read the registers within one 32kHz clock cycle which is the base clock of the RTC. Therefore, this patch allows a difference of up to 320 cycles (10ms). 10ms was chosen to be big enough even on systems with less cpu power (e.g. iMX6ULL). According to the reference manual a difference is fine: - If the two consecutive reads are similar, the value is correct. The values have to be similar, not equal. Fixes: cd7f3a2 ("rtc: snvs: Add timeouts to avoid kernel lockups") Reviewed-by: Francesco Dolcini <[email protected]> Signed-off-by: Stefan Eichenberger <[email protected]> Signed-off-by: Francesco Dolcini <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexandre Belloni <[email protected]>
1 parent 83ebb7b commit 0462681

File tree

1 file changed

+14
-2
lines changed

1 file changed

+14
-2
lines changed

drivers/rtc/rtc-snvs.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@
3232
#define SNVS_LPPGDR_INIT 0x41736166
3333
#define CNTR_TO_SECS_SH 15
3434

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+
3543
struct snvs_rtc_data {
3644
struct rtc_device *rtc;
3745
struct regmap *regmap;
@@ -56,6 +64,7 @@ static u64 rtc_read_lpsrt(struct snvs_rtc_data *data)
5664
static u32 rtc_read_lp_counter(struct snvs_rtc_data *data)
5765
{
5866
u64 read1, read2;
67+
s64 diff;
5968
unsigned int timeout = 100;
6069

6170
/* As expected, the registers might update between the read of the LSB
@@ -66,7 +75,8 @@ static u32 rtc_read_lp_counter(struct snvs_rtc_data *data)
6675
do {
6776
read2 = read1;
6877
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);
7080
if (!timeout)
7181
dev_err(&data->rtc->dev, "Timeout trying to get valid LPSRT Counter read\n");
7282

@@ -78,13 +88,15 @@ static u32 rtc_read_lp_counter(struct snvs_rtc_data *data)
7888
static int rtc_read_lp_counter_lsb(struct snvs_rtc_data *data, u32 *lsb)
7989
{
8090
u32 count1, count2;
91+
s32 diff;
8192
unsigned int timeout = 100;
8293

8394
regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1);
8495
do {
8596
count2 = count1;
8697
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);
88100
if (!timeout) {
89101
dev_err(&data->rtc->dev, "Timeout trying to get valid LPSRT Counter read\n");
90102
return -ETIMEDOUT;

0 commit comments

Comments
 (0)