diff options
author | Alexandre Belloni <alexandre.belloni@bootlin.com> | 2019-10-07 16:47:22 +0300 |
---|---|---|
committer | Alexandre Belloni <alexandre.belloni@bootlin.com> | 2019-10-07 16:49:35 +0300 |
commit | d9dcfa5f7084a0c648d9f0946994f4320a411a40 (patch) | |
tree | 083aece3ba798a1b885ad57e97babb304a01a0f7 | |
parent | 3ce20a23e2199bd98eb85fbaa524104931cd14dd (diff) | |
download | linux-d9dcfa5f7084a0c648d9f0946994f4320a411a40.tar.xz |
rtc: ds1347: properly handle oscillator failures
The comment in the probe function stating that it disables oscillator stop
detection and glitch filtering is incorrect as it sets bits 3 and 4 while
it should be setting 5 and 6 to achieve that. Then, it is safe to assume
that the oscillator failure detection is actually enabled.
Properly handle oscillator failures by returning -EINVAL when the time and
date are know to be incorrect and reset the flag when the time is set.
Link: https://lore.kernel.org/r/20191007134724.15505-8-alexandre.belloni@bootlin.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
-rw-r--r-- | drivers/rtc/rtc-ds1347.c | 30 |
1 files changed, 23 insertions, 7 deletions
diff --git a/drivers/rtc/rtc-ds1347.c b/drivers/rtc/rtc-ds1347.c index 22a75b01f1ac..eeaf43586bce 100644 --- a/drivers/rtc/rtc-ds1347.c +++ b/drivers/rtc/rtc-ds1347.c @@ -29,6 +29,9 @@ #define DS1347_STATUS_REG 0x17 #define DS1347_CLOCK_BURST 0x3F +#define DS1347_NEOSC_BIT BIT(7) +#define DS1347_OSF_BIT BIT(2) + static const struct regmap_range ds1347_ranges[] = { { .range_min = DS1347_SECONDS_REG, @@ -44,9 +47,17 @@ static const struct regmap_access_table ds1347_access_table = { static int ds1347_read_time(struct device *dev, struct rtc_time *dt) { struct regmap *map = dev_get_drvdata(dev); + unsigned int status; int err; unsigned char buf[8]; + err = regmap_read(map, DS1347_STATUS_REG, &status); + if (err) + return err; + + if (status & DS1347_OSF_BIT) + return -EINVAL; + err = regmap_bulk_read(map, DS1347_CLOCK_BURST, buf, 8); if (err) return err; @@ -66,6 +77,12 @@ static int ds1347_set_time(struct device *dev, struct rtc_time *dt) { struct regmap *map = dev_get_drvdata(dev); unsigned char buf[8]; + int err; + + err = regmap_update_bits(map, DS1347_STATUS_REG, + DS1347_NEOSC_BIT, DS1347_NEOSC_BIT); + if (err) + return err; buf[0] = bin2bcd(dt->tm_sec); buf[1] = bin2bcd(dt->tm_min); @@ -82,7 +99,12 @@ static int ds1347_set_time(struct device *dev, struct rtc_time *dt) buf[7] = bin2bcd(0x00); /* write the rtc settings */ - return regmap_bulk_write(map, DS1347_CLOCK_BURST, buf, 8); + err = regmap_bulk_write(map, DS1347_CLOCK_BURST, buf, 8); + if (err) + return err; + + return regmap_update_bits(map, DS1347_STATUS_REG, + DS1347_NEOSC_BIT | DS1347_OSF_BIT, 0); } static const struct rtc_class_ops ds1347_rtc_ops = { @@ -123,12 +145,6 @@ static int ds1347_probe(struct spi_device *spi) data = data & ~(1<<7); regmap_write(map, DS1347_CONTROL_REG, data); - /* Enable the oscillator , disable the oscillator stop flag, - and glitch filter to reduce current consumption */ - regmap_read(map, DS1347_STATUS_REG, &data); - data = data & 0x1B; - regmap_write(map, DS1347_STATUS_REG, data); - rtc = devm_rtc_allocate_device(&spi->dev); if (IS_ERR(rtc)) return PTR_ERR(rtc); |