rtc: da9052: Corrections to access, validation and capability
Subsystems (2)
cover rtc: da9052: Corrections to access, validation and capability
Hi,
This patch set is based on mainline v4.0-rc2.
It makes corrections to restrict the year setting to the range defined for the device to support. It also prevents erroneous values being returned, as was discovered possible when reading a time immediately after setting it.
And lastly, it enables the wake-from-suspend capability.
Best regards,
Adam
Adam Ward (3):
rtc: da9052: Add extra reads with timeouts to avoid returning
partially updated values
rtc: da9052: Add constraints to set valid year
rtc: da9052: Register ability of alarm to wake device from suspend
drivers/rtc/rtc-da9052.c | 97 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 76 insertions(+), 21 deletions(-)
Signature · 1 line
end-of-patch for rtc: da9052: Corrections to access, validation and capability
PATCH 1/3 rtc: da9052: Add extra reads with timeouts to avoid returning partially updated values
The RTC is in a different clock domain so a quick read after write can retrieve a mangled value of the old/new values
--- drivers/rtc/rtc-da9052.c | 87 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 21 deletions(-)
drivers/rtc/rtc-da9052.c +66 -21
@@ -16,6 +16,7 @@#include <linux/platform_device.h> #include <linux/rtc.h> #include <linux/err.h> +#include <linux/delay.h> #include <linux/mfd/da9052/da9052.h> #include <linux/mfd/da9052/reg.h>
@@ -23,6 +24,8 @@#define rtc_err (rtc, fmt, ...) \ dev_err(rtc->da9052->dev, "%s: " fmt, __func__, ##__VA_ARGS__) +#define DA9052_GET_TIME_RETRIES 5 +struct da9052_rtc {struct rtc_device *rtc;struct da9052 *da9052;
@@ -58,22 +61,43 @@ static irqreturn_t da9052_rtc_irq(int irq, void *data)static int da9052_read_alarm (struct da9052_rtc *rtc,struct rtc_time *rtc_tm) {int ret; -uint8_t v[5 ]; +uint8_t v[2 ][5 ]; +int idx =1 ; +int timeout =DA9052_GET_TIME_RETRIES ; - ret =da9052_group_read (rtc->da9052,DA9052_ALARM_MI_REG ,5 , v); -if (ret !=0 ) { + ret =da9052_group_read (rtc->da9052,DA9052_ALARM_MI_REG ,5 , &v[0 ][0 ]); +if (ret) {rtc_err (rtc,"Failed to group read ALM: %d\n" , ret);return ret; } - rtc_tm->tm_year = (v[4 ] &DA9052_RTC_YEAR ) +100 ; - rtc_tm->tm_mon = (v[3 ] &DA9052_RTC_MONTH ) -1 ; - rtc_tm->tm_mday = v[2 ] &DA9052_RTC_DAY ; - rtc_tm->tm_hour = v[1 ] &DA9052_RTC_HOUR ; - rtc_tm->tm_min = v[0 ] &DA9052_RTC_MIN ; +do { + ret =da9052_group_read (rtc->da9052, +DA9052_ALARM_MI_REG ,5 , &v[idx][0 ]); +if (ret) { +rtc_err (rtc,"Failed to group read ALM: %d\n" , ret); +return ret; + } - ret =rtc_valid_tm (rtc_tm); -return ret; +if (memcmp (&v[0 ][0 ], &v[1 ][0 ],5 ) ==0 ) { + rtc_tm->tm_year = (v[0 ][4 ] &DA9052_RTC_YEAR ) +100 ; + rtc_tm->tm_mon = (v[0 ][3 ] &DA9052_RTC_MONTH ) -1 ; + rtc_tm->tm_mday = v[0 ][2 ] &DA9052_RTC_DAY ; + rtc_tm->tm_hour = v[0 ][1 ] &DA9052_RTC_HOUR ; + rtc_tm->tm_min = v[0 ][0 ] &DA9052_RTC_MIN ; + + ret =rtc_valid_tm (rtc_tm); +return ret; + } + + idx = (1 -idx); +msleep (20 ); + + }while (timeout--); + +rtc_err (rtc,"Timed out reading alarm time\n" ); + +return -EIO ; }static int da9052_set_alarm (struct da9052_rtc *rtc,struct rtc_time *rtc_tm)
@@ -135,24 +159,45 @@ static int da9052_rtc_get_alarm_status(struct da9052_rtc *rtc)static int da9052_rtc_read_time (struct device *dev,struct rtc_time *rtc_tm) {struct da9052_rtc *rtc =dev_get_drvdata (dev); -uint8_t v[6 ];int ret; +uint8_t v[2 ][6 ]; +int idx =1 ; +int timeout =DA9052_GET_TIME_RETRIES ; - ret =da9052_group_read (rtc->da9052,DA9052_COUNT_S_REG ,6 , v); -if (ret <0 ) { + ret =da9052_group_read (rtc->da9052,DA9052_COUNT_S_REG ,6 , &v[0 ][0 ]); +if (ret) {rtc_err (rtc,"Failed to read RTC time : %d\n" , ret);return ret; } - rtc_tm->tm_year = (v[5 ] &DA9052_RTC_YEAR ) +100 ; - rtc_tm->tm_mon = (v[4 ] &DA9052_RTC_MONTH ) -1 ; - rtc_tm->tm_mday = v[3 ] &DA9052_RTC_DAY ; - rtc_tm->tm_hour = v[2 ] &DA9052_RTC_HOUR ; - rtc_tm->tm_min = v[1 ] &DA9052_RTC_MIN ; - rtc_tm->tm_sec = v[0 ] &DA9052_RTC_SEC ; +do { + ret =da9052_group_read (rtc->da9052, +DA9052_COUNT_S_REG ,6 , &v[idx][0 ]); +if (ret) { +rtc_err (rtc,"Failed to read RTC time : %d\n" , ret); +return ret; + } - ret =rtc_valid_tm (rtc_tm); -return ret; +if (memcmp (&v[0 ][0 ], &v[1 ][0 ],6 ) ==0 ) { + rtc_tm->tm_year = (v[0 ][5 ] &DA9052_RTC_YEAR ) +100 ; + rtc_tm->tm_mon = (v[0 ][4 ] &DA9052_RTC_MONTH ) -1 ; + rtc_tm->tm_mday = v[0 ][3 ] &DA9052_RTC_DAY ; + rtc_tm->tm_hour = v[0 ][2 ] &DA9052_RTC_HOUR ; + rtc_tm->tm_min = v[0 ][1 ] &DA9052_RTC_MIN ; + rtc_tm->tm_sec = v[0 ][0 ] &DA9052_RTC_SEC ; + + ret =rtc_valid_tm (rtc_tm); +return ret; + } + + idx = (1 -idx); +msleep (20 ); + + }while (timeout--); + +rtc_err (rtc,"Timed out reading time\n" ); + +return -EIO ; }static int da9052_rtc_set_time (struct device *dev,struct rtc_time *tm)
Signature · 1 line
end-of-patch for rtc: da9052: Corrections to access, validation and capability
PATCH 2/3 rtc: da9052: Add constraints to set valid year
In reply to Adam Ward--- drivers/rtc/rtc-da9052.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/rtc/rtc-da9052.c +8 -0
@@ -206,6 +206,10 @@ static int da9052_rtc_set_time(struct device *dev, struct rtc_time *tm)uint8_t v[6 ];int ret; +/* DA9052 only has 6 bits for year - to represent 2000-2063 */ +if ((tm->tm_year <100 ) || (tm->tm_year >163 )) +return -EINVAL ; + rtc =dev_get_drvdata (dev); v[0 ] = tm->tm_sec;
@@ -243,6 +247,10 @@ static int da9052_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)struct rtc_time *tm = &alrm->time;struct da9052_rtc *rtc =dev_get_drvdata (dev); +/* DA9052 only has 6 bits for year - to represent 2000-2063 */ +if ((tm->tm_year <100 ) || (tm->tm_year >163 )) +return -EINVAL ; + ret =da9052_rtc_enable_alarm (rtc,0 );if (ret <0 )return ret;
Signature · 1 line
end-of-patch for rtc: da9052: Corrections to access, validation and capability
PATCH 3/3 rtc: da9052: Register ability of alarm to wake device from suspend
In reply to Adam Ward--- drivers/rtc/rtc-da9052.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/rtc/rtc-da9052.c +2 -0
@@ -309,6 +309,8 @@ static int da9052_rtc_probe(struct platform_device *pdev)return ret; } +device_init_wakeup (&pdev->dev, true); + rtc->rtc =devm_rtc_device_register (&pdev->dev, pdev->name, &da9052_rtc_ops,THIS_MODULE );return PTR_ERR_OR_ZERO (rtc->rtc);
Signature · 1 line
end-of-patch for rtc: da9052: Corrections to access, validation and capability