Commit bcffb10f authored by Nikolaus Voss's avatar Nikolaus Voss Committed by Linus Torvalds

drivers/rtc/rtc-m41t93.c: don't let get_time() reset M41T93_FLAG_OF

If the rtc reports the time might be invalid due to oscillator failure,
M41T93_FLAG_OF flag must not be reset by get_time() as the read operation
doesn't make the time valid.

Without this patch, only the first get_time() reported an invalid time,
the second get_time() reported a valid time althought the reported time is
probably wrong due to oscillator failure.

Instead of resetting in get_time(), with this patch M41T93_FLAG_OF is
reset in set_time() when a valid time is to be written.
Signed-off-by: default avatarNikolaus Voss <n.voss@weinmann.de>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Cc: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent eb86c306
...@@ -48,6 +48,7 @@ static inline int m41t93_set_reg(struct spi_device *spi, u8 addr, u8 data) ...@@ -48,6 +48,7 @@ static inline int m41t93_set_reg(struct spi_device *spi, u8 addr, u8 data)
static int m41t93_set_time(struct device *dev, struct rtc_time *tm) static int m41t93_set_time(struct device *dev, struct rtc_time *tm)
{ {
struct spi_device *spi = to_spi_device(dev); struct spi_device *spi = to_spi_device(dev);
int tmp;
u8 buf[9] = {0x80}; /* write cmd + 8 data bytes */ u8 buf[9] = {0x80}; /* write cmd + 8 data bytes */
u8 * const data = &buf[1]; /* ptr to first data byte */ u8 * const data = &buf[1]; /* ptr to first data byte */
...@@ -62,6 +63,30 @@ static int m41t93_set_time(struct device *dev, struct rtc_time *tm) ...@@ -62,6 +63,30 @@ static int m41t93_set_time(struct device *dev, struct rtc_time *tm)
return -EINVAL; return -EINVAL;
} }
tmp = spi_w8r8(spi, M41T93_REG_FLAGS);
if (tmp < 0)
return tmp;
if (tmp & M41T93_FLAG_OF) {
dev_warn(&spi->dev, "OF bit is set, resetting.\n");
m41t93_set_reg(spi, M41T93_REG_FLAGS, tmp & ~M41T93_FLAG_OF);
tmp = spi_w8r8(spi, M41T93_REG_FLAGS);
if (tmp < 0) {
return tmp;
} else if (tmp & M41T93_FLAG_OF) {
/* OF cannot be immediately reset: oscillator has to be
* restarted. */
u8 reset_osc = buf[M41T93_REG_ST_SEC] | M41T93_FLAG_ST;
dev_warn(&spi->dev,
"OF bit is still set, kickstarting clock.\n");
m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc);
reset_osc &= ~M41T93_FLAG_ST;
m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc);
}
}
data[M41T93_REG_SSEC] = 0; data[M41T93_REG_SSEC] = 0;
data[M41T93_REG_ST_SEC] = bin2bcd(tm->tm_sec); data[M41T93_REG_ST_SEC] = bin2bcd(tm->tm_sec);
data[M41T93_REG_MIN] = bin2bcd(tm->tm_min); data[M41T93_REG_MIN] = bin2bcd(tm->tm_min);
...@@ -89,10 +114,7 @@ static int m41t93_get_time(struct device *dev, struct rtc_time *tm) ...@@ -89,10 +114,7 @@ static int m41t93_get_time(struct device *dev, struct rtc_time *tm)
1. halt bit (HT) is set: the clock is running but update of readout 1. halt bit (HT) is set: the clock is running but update of readout
registers has been disabled due to power failure. This is normal registers has been disabled due to power failure. This is normal
case after poweron. Time is valid after resetting HT bit. case after poweron. Time is valid after resetting HT bit.
2. oscillator fail bit (OF) is set. Oscillator has be stopped and 2. oscillator fail bit (OF) is set: time is invalid.
time is invalid:
a) OF can be immeditely reset.
b) OF cannot be immediately reset: oscillator has to be restarted.
*/ */
tmp = spi_w8r8(spi, M41T93_REG_ALM_HOUR_HT); tmp = spi_w8r8(spi, M41T93_REG_ALM_HOUR_HT);
if (tmp < 0) if (tmp < 0)
...@@ -110,21 +132,7 @@ static int m41t93_get_time(struct device *dev, struct rtc_time *tm) ...@@ -110,21 +132,7 @@ static int m41t93_get_time(struct device *dev, struct rtc_time *tm)
if (tmp & M41T93_FLAG_OF) { if (tmp & M41T93_FLAG_OF) {
ret = -EINVAL; ret = -EINVAL;
dev_warn(&spi->dev, "OF bit is set, resetting.\n"); dev_warn(&spi->dev, "OF bit is set, write time to restart.\n");
m41t93_set_reg(spi, M41T93_REG_FLAGS, tmp & ~M41T93_FLAG_OF);
tmp = spi_w8r8(spi, M41T93_REG_FLAGS);
if (tmp < 0)
return tmp;
else if (tmp & M41T93_FLAG_OF) {
u8 reset_osc = buf[M41T93_REG_ST_SEC] | M41T93_FLAG_ST;
dev_warn(&spi->dev,
"OF bit is still set, kickstarting clock.\n");
m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc);
reset_osc &= ~M41T93_FLAG_ST;
m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc);
}
} }
if (tmp & M41T93_FLAG_BL) if (tmp & M41T93_FLAG_BL)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment