summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrea Scian <andrea.scian@dave.eu>2015-06-16 11:39:47 +0200
committerAlexandre Belloni <alexandre.belloni@free-electrons.com>2015-09-05 13:19:06 +0200
commit653ebd75e9e469e99a40ab14128d915386dc78c6 (patch)
tree1afde5a872c74e71f4e06fcdcb895757661bba88
parentrtc: use rtc_valid_tm() error code when reading date/time (diff)
downloadlinux-653ebd75e9e469e99a40ab14128d915386dc78c6.tar.xz
linux-653ebd75e9e469e99a40ab14128d915386dc78c6.zip
rtc: pcf2127: use OFS flag to detect unreliable date and warn the user
The PCF2127 datasheet states that it's wrong to say that the date in unreliable if BLF (battery low flag) is set but instead, OSF (seconds register) should be used to check if oscillator, for any reason, stopped. Battery may be low (usually below 2V5 threshold) but the date may be anyway correct (typically date is unreliable when input voltage is below 1V2). Signed-off-by: Andrea Scian <andrea.scian@dave.eu> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
-rw-r--r--drivers/rtc/rtc-pcf2127.c26
1 files changed, 23 insertions, 3 deletions
diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
index 350c5c7cb678..baf45c9ca65e 100644
--- a/drivers/rtc/rtc-pcf2127.c
+++ b/drivers/rtc/rtc-pcf2127.c
@@ -33,11 +33,14 @@
#define PCF2127_REG_MO (0x08)
#define PCF2127_REG_YR (0x09)
+#define PCF2127_OSF BIT(7) /* Oscillator Fail flag */
+
static struct i2c_driver pcf2127_driver;
struct pcf2127 {
struct rtc_device *rtc;
int voltage_low; /* indicates if a low_voltage was detected */
+ int oscillator_failed; /* OSF was detected and date is unreliable */
};
/*
@@ -59,7 +62,18 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm)
if (buf[PCF2127_REG_CTRL3] & 0x04) {
pcf2127->voltage_low = 1;
dev_info(&client->dev,
- "low voltage detected, date/time is not reliable.\n");
+ "low voltage detected, check/replace RTC battery.\n");
+ }
+
+ if (buf[PCF2127_REG_SC] & PCF2127_OSF) {
+ /*
+ * no need clear the flag here,
+ * it will be cleared once the new date is saved
+ */
+ pcf2127->oscillator_failed = 1;
+ dev_warn(&client->dev,
+ "oscillator stop detected, date/time is not reliable\n");
+ return -EINVAL;
}
dev_dbg(&client->dev,
@@ -93,6 +107,7 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm)
static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
+ struct pcf2127 *pcf2127 = i2c_get_clientdata(client);
unsigned char buf[8];
int i = 0, err;
@@ -106,7 +121,7 @@ static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm)
buf[i++] = PCF2127_REG_SC;
/* hours, minutes and seconds */
- buf[i++] = bin2bcd(tm->tm_sec);
+ buf[i++] = bin2bcd(tm->tm_sec); /* this will also clear OSF flag */
buf[i++] = bin2bcd(tm->tm_min);
buf[i++] = bin2bcd(tm->tm_hour);
buf[i++] = bin2bcd(tm->tm_mday);
@@ -126,6 +141,9 @@ static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm)
return -EIO;
}
+ /* clear OSF flag in client data */
+ pcf2127->oscillator_failed = 0;
+
return 0;
}
@@ -138,7 +156,9 @@ static int pcf2127_rtc_ioctl(struct device *dev,
switch (cmd) {
case RTC_VL_READ:
if (pcf2127->voltage_low)
- dev_info(dev, "low voltage detected, date/time is not reliable.\n");
+ dev_info(dev, "low voltage detected, check/replace battery\n");
+ if (pcf2127->oscillator_failed)
+ dev_info(dev, "oscillator stop detected, date/time is not reliable\n");
if (copy_to_user((void __user *)arg, &pcf2127->voltage_low,
sizeof(int)))