diff options
Diffstat (limited to 'kernel/drivers/rtc/rtc-pcf2127.c')
-rw-r--r-- | kernel/drivers/rtc/rtc-pcf2127.c | 62 |
1 files changed, 37 insertions, 25 deletions
diff --git a/kernel/drivers/rtc/rtc-pcf2127.c b/kernel/drivers/rtc/rtc-pcf2127.c index 9bd842e97..629bfdf8c 100644 --- a/kernel/drivers/rtc/rtc-pcf2127.c +++ b/kernel/drivers/rtc/rtc-pcf2127.c @@ -20,11 +20,12 @@ #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) @@ -33,11 +34,12 @@ #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"); |