rtc: pcf8523: don’t return invalid date when battery is low [Linux 4.14.128]

rtc: pcf8523: don’t return invalid date when battery is low [Linux 4.14.128]

This Linux kernel change "rtc: pcf8523: don’t return invalid date when battery is low" is included in the Linux 4.14.128 release. This change is authored by Baruch Siach <baruch [at] tkos.co.il> on Wed Dec 5 17:00:09 2018 +0200. The commit for this change in Linux stable tree is 3177ab5 (patch) which is from upstream commit ecb4a35. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream ecb4a35.

rtc: pcf8523: don't return invalid date when battery is low

commit ecb4a353d3afd45b9bb30c85d03ee113a0589079 upstream.

The RTC_VL_READ ioctl reports the low battery condition. Still,
pcf8523_rtc_read_time() happily returns invalid dates in this case.
Check the battery health on pcf8523_rtc_read_time() to avoid that.

Reported-by: Erik Čuk <erik.cuk@domel.com>
Signed-off-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

There are 32 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/rtc/rtc-pcf8523.c | 32 ++++++++++++++++++++++++--------
 1 file changed, 24 insertions(+), 8 deletions(-)

diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c
index 28c48b3..3c8c6f9 100644
--- a/drivers/rtc/rtc-pcf8523.c
+++ b/drivers/rtc/rtc-pcf8523.c
@@ -82,6 +82,18 @@ static int pcf8523_write(struct i2c_client *client, u8 reg, u8 value)
    return 0;
 }

+static int pcf8523_voltage_low(struct i2c_client *client)
+{
+   u8 value;
+   int err;
+
+   err = pcf8523_read(client, REG_CONTROL3, &value);
+   if (err < 0)
+       return err;
+
+   return !!(value & REG_CONTROL3_BLF);
+}
+
 static int pcf8523_select_capacitance(struct i2c_client *client, bool high)
 {
    u8 value;
@@ -164,6 +176,14 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm)
    struct i2c_msg msgs[2];
    int err;

+   err = pcf8523_voltage_low(client);
+   if (err < 0) {
+       return err;
+   } else if (err > 0) {
+       dev_err(dev, "low voltage detected, time is unreliable\n");
+       return -EINVAL;
+   }
+
    msgs[0].addr = client->addr;
    msgs[0].flags = 0;
    msgs[0].len = 1;
@@ -248,17 +268,13 @@ static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd,
                 unsigned long arg)
 {
    struct i2c_client *client = to_i2c_client(dev);
-   u8 value;
-   int ret = 0, err;
+   int ret;

    switch (cmd) {
    case RTC_VL_READ:
-       err = pcf8523_read(client, REG_CONTROL3, &value);
-       if (err < 0)
-           return err;
-
-       if (value & REG_CONTROL3_BLF)
-           ret = 1;
+       ret = pcf8523_voltage_low(client);
+       if (ret < 0)
+           return ret;

        if (copy_to_user((void __user *)arg, &ret, sizeof(int)))
            return -EFAULT;

Leave a Reply

Your email address will not be published. Required fields are marked *