Skip to content

Commit

Permalink
drivers/rtc/rtc-m41t93.c: don't let get_time() reset M41T93_FLAG_OF
Browse files Browse the repository at this point in the history
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: Nikolaus Voss <n.voss@weinmann.de>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Cc: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Nikolaus Voss authored and Linus Torvalds committed May 29, 2012
1 parent eb86c30 commit bcffb10
Showing 1 changed file with 27 additions and 19 deletions.
46 changes: 27 additions & 19 deletions drivers/rtc/rtc-m41t93.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
struct spi_device *spi = to_spi_device(dev);
int tmp;
u8 buf[9] = {0x80}; /* write cmd + 8 data bytes */
u8 * const data = &buf[1]; /* ptr to first data byte */

Expand All @@ -62,6 +63,30 @@ static int m41t93_set_time(struct device *dev, struct rtc_time *tm)
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_ST_SEC] = bin2bcd(tm->tm_sec);
data[M41T93_REG_MIN] = bin2bcd(tm->tm_min);
Expand Down Expand Up @@ -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
registers has been disabled due to power failure. This is normal
case after poweron. Time is valid after resetting HT bit.
2. oscillator fail bit (OF) is set. Oscillator has be stopped and
time is invalid:
a) OF can be immeditely reset.
b) OF cannot be immediately reset: oscillator has to be restarted.
2. oscillator fail bit (OF) is set: time is invalid.
*/
tmp = spi_w8r8(spi, M41T93_REG_ALM_HOUR_HT);
if (tmp < 0)
Expand All @@ -110,21 +132,7 @@ static int m41t93_get_time(struct device *dev, struct rtc_time *tm)

if (tmp & M41T93_FLAG_OF) {
ret = -EINVAL;
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) {
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);
}
dev_warn(&spi->dev, "OF bit is set, write time to restart.\n");
}

if (tmp & M41T93_FLAG_BL)
Expand Down

0 comments on commit bcffb10

Please sign in to comment.