These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / rtc / rtc-pcf2127.c
index 9bd842e..629bfdf 100644 (file)
 #include <linux/module.h>
 #include <linux/of.h>
 
-#define DRV_VERSION "0.0.1"
-
 #define PCF2127_REG_CTRL1       (0x00)  /* Control Register 1 */
 #define PCF2127_REG_CTRL2       (0x01)  /* Control Register 2 */
+
 #define PCF2127_REG_CTRL3       (0x02)  /* Control Register 3 */
+#define PCF2127_REG_CTRL3_BLF          BIT(2)
+
 #define PCF2127_REG_SC          (0x03)  /* datetime */
 #define PCF2127_REG_MN          (0x04)
 #define PCF2127_REG_HR          (0x05)
 #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 */
 };
 
 /*
@@ -46,7 +48,6 @@ struct pcf2127 {
  */
 static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm)
 {
-       struct pcf2127 *pcf2127 = i2c_get_clientdata(client);
        unsigned char buf[10] = { PCF2127_REG_CTRL1 };
 
        /* read registers */
@@ -56,10 +57,18 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm)
                return -EIO;
        }
 
-       if (buf[PCF2127_REG_CTRL3] & 0x04) {
-               pcf2127->voltage_low = 1;
+       if (buf[PCF2127_REG_CTRL3] & PCF2127_REG_CTRL3_BLF)
                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
+                */
+               dev_warn(&client->dev,
+                        "oscillator stop detected, date/time is not reliable\n");
+               return -EINVAL;
        }
 
        dev_dbg(&client->dev,
@@ -88,13 +97,7 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm)
                tm->tm_sec, tm->tm_min, tm->tm_hour,
                tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
 
-       /* the clock can give out invalid datetime, but we cannot return
-        * -EINVAL otherwise hwclock will refuse to set the time on bootup.
-        */
-       if (rtc_valid_tm(tm) < 0)
-               dev_err(&client->dev, "retrieved date/time is not valid.\n");
-
-       return 0;
+       return rtc_valid_tm(tm);
 }
 
 static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm)
@@ -112,7 +115,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);
@@ -139,15 +142,28 @@ static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm)
 static int pcf2127_rtc_ioctl(struct device *dev,
                                unsigned int cmd, unsigned long arg)
 {
-       struct pcf2127 *pcf2127 = i2c_get_clientdata(to_i2c_client(dev));
+       struct i2c_client *client = to_i2c_client(dev);
+       unsigned char buf = PCF2127_REG_CTRL3;
+       int touser;
+       int ret;
 
        switch (cmd) {
        case RTC_VL_READ:
-               if (pcf2127->voltage_low)
-                       dev_info(dev, "low voltage detected, date/time is not reliable.\n");
+               ret = i2c_master_send(client, &buf, 1);
+               if (!ret)
+                       ret = -EIO;
+               if (ret < 0)
+                       return ret;
+
+               ret = i2c_master_recv(client, &buf, 1);
+               if (!ret)
+                       ret = -EIO;
+               if (ret < 0)
+                       return ret;
 
-               if (copy_to_user((void __user *)arg, &pcf2127->voltage_low,
-                                       sizeof(int)))
+               touser = buf & PCF2127_REG_CTRL3_BLF ? 1 : 0;
+
+               if (copy_to_user((void __user *)arg, &touser, sizeof(int)))
                        return -EFAULT;
                return 0;
        default:
@@ -189,8 +205,6 @@ static int pcf2127_probe(struct i2c_client *client,
        if (!pcf2127)
                return -ENOMEM;
 
-       dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
-
        i2c_set_clientdata(client, pcf2127);
 
        pcf2127->rtc = devm_rtc_device_register(&client->dev,
@@ -217,7 +231,6 @@ MODULE_DEVICE_TABLE(of, pcf2127_of_match);
 static struct i2c_driver pcf2127_driver = {
        .driver         = {
                .name   = "rtc-pcf2127",
-               .owner  = THIS_MODULE,
                .of_match_table = of_match_ptr(pcf2127_of_match),
        },
        .probe          = pcf2127_probe,
@@ -228,5 +241,4 @@ module_i2c_driver(pcf2127_driver);
 
 MODULE_AUTHOR("Renaud Cerrato <r.cerrato@til-technologies.fr>");
 MODULE_DESCRIPTION("NXP PCF2127 RTC driver");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL v2");