diff options
Diffstat (limited to 'drivers/rtc/rtc-da9052.c')
| -rw-r--r-- | drivers/rtc/rtc-da9052.c | 97 |
1 files changed, 76 insertions, 21 deletions
diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c index 613c43b7e9ae..1ba4371cbc2d 100644 --- a/drivers/rtc/rtc-da9052.c +++ b/drivers/rtc/rtc-da9052.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
| 17 | #include <linux/rtc.h> | 17 | #include <linux/rtc.h> |
| 18 | #include <linux/err.h> | 18 | #include <linux/err.h> |
| 19 | #include <linux/delay.h> | ||
| 19 | 20 | ||
| 20 | #include <linux/mfd/da9052/da9052.h> | 21 | #include <linux/mfd/da9052/da9052.h> |
| 21 | #include <linux/mfd/da9052/reg.h> | 22 | #include <linux/mfd/da9052/reg.h> |
| @@ -23,6 +24,8 @@ | |||
| 23 | #define rtc_err(rtc, fmt, ...) \ | 24 | #define rtc_err(rtc, fmt, ...) \ |
| 24 | dev_err(rtc->da9052->dev, "%s: " fmt, __func__, ##__VA_ARGS__) | 25 | dev_err(rtc->da9052->dev, "%s: " fmt, __func__, ##__VA_ARGS__) |
| 25 | 26 | ||
| 27 | #define DA9052_GET_TIME_RETRIES 5 | ||
| 28 | |||
| 26 | struct da9052_rtc { | 29 | struct da9052_rtc { |
| 27 | struct rtc_device *rtc; | 30 | struct rtc_device *rtc; |
| 28 | struct da9052 *da9052; | 31 | struct da9052 *da9052; |
| @@ -58,22 +61,43 @@ static irqreturn_t da9052_rtc_irq(int irq, void *data) | |||
| 58 | static int da9052_read_alarm(struct da9052_rtc *rtc, struct rtc_time *rtc_tm) | 61 | static int da9052_read_alarm(struct da9052_rtc *rtc, struct rtc_time *rtc_tm) |
| 59 | { | 62 | { |
| 60 | int ret; | 63 | int ret; |
| 61 | uint8_t v[5]; | 64 | uint8_t v[2][5]; |
| 65 | int idx = 1; | ||
| 66 | int timeout = DA9052_GET_TIME_RETRIES; | ||
| 62 | 67 | ||
| 63 | ret = da9052_group_read(rtc->da9052, DA9052_ALARM_MI_REG, 5, v); | 68 | ret = da9052_group_read(rtc->da9052, DA9052_ALARM_MI_REG, 5, &v[0][0]); |
| 64 | if (ret != 0) { | 69 | if (ret) { |
| 65 | rtc_err(rtc, "Failed to group read ALM: %d\n", ret); | 70 | rtc_err(rtc, "Failed to group read ALM: %d\n", ret); |
| 66 | return ret; | 71 | return ret; |
| 67 | } | 72 | } |
| 68 | 73 | ||
| 69 | rtc_tm->tm_year = (v[4] & DA9052_RTC_YEAR) + 100; | 74 | do { |
| 70 | rtc_tm->tm_mon = (v[3] & DA9052_RTC_MONTH) - 1; | 75 | ret = da9052_group_read(rtc->da9052, |
| 71 | rtc_tm->tm_mday = v[2] & DA9052_RTC_DAY; | 76 | DA9052_ALARM_MI_REG, 5, &v[idx][0]); |
| 72 | rtc_tm->tm_hour = v[1] & DA9052_RTC_HOUR; | 77 | if (ret) { |
| 73 | rtc_tm->tm_min = v[0] & DA9052_RTC_MIN; | 78 | rtc_err(rtc, "Failed to group read ALM: %d\n", ret); |
| 79 | return ret; | ||
| 80 | } | ||
| 74 | 81 | ||
| 75 | ret = rtc_valid_tm(rtc_tm); | 82 | if (memcmp(&v[0][0], &v[1][0], 5) == 0) { |
| 76 | return ret; | 83 | rtc_tm->tm_year = (v[0][4] & DA9052_RTC_YEAR) + 100; |
| 84 | rtc_tm->tm_mon = (v[0][3] & DA9052_RTC_MONTH) - 1; | ||
| 85 | rtc_tm->tm_mday = v[0][2] & DA9052_RTC_DAY; | ||
| 86 | rtc_tm->tm_hour = v[0][1] & DA9052_RTC_HOUR; | ||
| 87 | rtc_tm->tm_min = v[0][0] & DA9052_RTC_MIN; | ||
| 88 | |||
| 89 | ret = rtc_valid_tm(rtc_tm); | ||
| 90 | return ret; | ||
| 91 | } | ||
| 92 | |||
| 93 | idx = (1-idx); | ||
| 94 | msleep(20); | ||
| 95 | |||
| 96 | } while (timeout--); | ||
| 97 | |||
| 98 | rtc_err(rtc, "Timed out reading alarm time\n"); | ||
| 99 | |||
| 100 | return -EIO; | ||
| 77 | } | 101 | } |
| 78 | 102 | ||
| 79 | static int da9052_set_alarm(struct da9052_rtc *rtc, struct rtc_time *rtc_tm) | 103 | 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) | |||
| 135 | static int da9052_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm) | 159 | static int da9052_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm) |
| 136 | { | 160 | { |
| 137 | struct da9052_rtc *rtc = dev_get_drvdata(dev); | 161 | struct da9052_rtc *rtc = dev_get_drvdata(dev); |
| 138 | uint8_t v[6]; | ||
| 139 | int ret; | 162 | int ret; |
| 163 | uint8_t v[2][6]; | ||
| 164 | int idx = 1; | ||
| 165 | int timeout = DA9052_GET_TIME_RETRIES; | ||
| 140 | 166 | ||
| 141 | ret = da9052_group_read(rtc->da9052, DA9052_COUNT_S_REG, 6, v); | 167 | ret = da9052_group_read(rtc->da9052, DA9052_COUNT_S_REG, 6, &v[0][0]); |
| 142 | if (ret < 0) { | 168 | if (ret) { |
| 143 | rtc_err(rtc, "Failed to read RTC time : %d\n", ret); | 169 | rtc_err(rtc, "Failed to read RTC time : %d\n", ret); |
| 144 | return ret; | 170 | return ret; |
| 145 | } | 171 | } |
| 146 | 172 | ||
| 147 | rtc_tm->tm_year = (v[5] & DA9052_RTC_YEAR) + 100; | 173 | do { |
| 148 | rtc_tm->tm_mon = (v[4] & DA9052_RTC_MONTH) - 1; | 174 | ret = da9052_group_read(rtc->da9052, |
| 149 | rtc_tm->tm_mday = v[3] & DA9052_RTC_DAY; | 175 | DA9052_COUNT_S_REG, 6, &v[idx][0]); |
| 150 | rtc_tm->tm_hour = v[2] & DA9052_RTC_HOUR; | 176 | if (ret) { |
| 151 | rtc_tm->tm_min = v[1] & DA9052_RTC_MIN; | 177 | rtc_err(rtc, "Failed to read RTC time : %d\n", ret); |
| 152 | rtc_tm->tm_sec = v[0] & DA9052_RTC_SEC; | 178 | return ret; |
| 179 | } | ||
| 153 | 180 | ||
| 154 | ret = rtc_valid_tm(rtc_tm); | 181 | if (memcmp(&v[0][0], &v[1][0], 6) == 0) { |
| 155 | return ret; | 182 | rtc_tm->tm_year = (v[0][5] & DA9052_RTC_YEAR) + 100; |
| 183 | rtc_tm->tm_mon = (v[0][4] & DA9052_RTC_MONTH) - 1; | ||
| 184 | rtc_tm->tm_mday = v[0][3] & DA9052_RTC_DAY; | ||
| 185 | rtc_tm->tm_hour = v[0][2] & DA9052_RTC_HOUR; | ||
| 186 | rtc_tm->tm_min = v[0][1] & DA9052_RTC_MIN; | ||
| 187 | rtc_tm->tm_sec = v[0][0] & DA9052_RTC_SEC; | ||
| 188 | |||
| 189 | ret = rtc_valid_tm(rtc_tm); | ||
| 190 | return ret; | ||
| 191 | } | ||
| 192 | |||
| 193 | idx = (1-idx); | ||
| 194 | msleep(20); | ||
| 195 | |||
| 196 | } while (timeout--); | ||
| 197 | |||
| 198 | rtc_err(rtc, "Timed out reading time\n"); | ||
| 199 | |||
| 200 | return -EIO; | ||
| 156 | } | 201 | } |
| 157 | 202 | ||
| 158 | static int da9052_rtc_set_time(struct device *dev, struct rtc_time *tm) | 203 | static int da9052_rtc_set_time(struct device *dev, struct rtc_time *tm) |
| @@ -161,6 +206,10 @@ static int da9052_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
| 161 | uint8_t v[6]; | 206 | uint8_t v[6]; |
| 162 | int ret; | 207 | int ret; |
| 163 | 208 | ||
| 209 | /* DA9052 only has 6 bits for year - to represent 2000-2063 */ | ||
| 210 | if ((tm->tm_year < 100) || (tm->tm_year > 163)) | ||
| 211 | return -EINVAL; | ||
| 212 | |||
| 164 | rtc = dev_get_drvdata(dev); | 213 | rtc = dev_get_drvdata(dev); |
| 165 | 214 | ||
| 166 | v[0] = tm->tm_sec; | 215 | v[0] = tm->tm_sec; |
| @@ -198,6 +247,10 @@ static int da9052_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
| 198 | struct rtc_time *tm = &alrm->time; | 247 | struct rtc_time *tm = &alrm->time; |
| 199 | struct da9052_rtc *rtc = dev_get_drvdata(dev); | 248 | struct da9052_rtc *rtc = dev_get_drvdata(dev); |
| 200 | 249 | ||
| 250 | /* DA9052 only has 6 bits for year - to represent 2000-2063 */ | ||
| 251 | if ((tm->tm_year < 100) || (tm->tm_year > 163)) | ||
| 252 | return -EINVAL; | ||
| 253 | |||
| 201 | ret = da9052_rtc_enable_alarm(rtc, 0); | 254 | ret = da9052_rtc_enable_alarm(rtc, 0); |
| 202 | if (ret < 0) | 255 | if (ret < 0) |
| 203 | return ret; | 256 | return ret; |
| @@ -256,6 +309,8 @@ static int da9052_rtc_probe(struct platform_device *pdev) | |||
| 256 | return ret; | 309 | return ret; |
| 257 | } | 310 | } |
| 258 | 311 | ||
| 312 | device_init_wakeup(&pdev->dev, true); | ||
| 313 | |||
| 259 | rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, | 314 | rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, |
| 260 | &da9052_rtc_ops, THIS_MODULE); | 315 | &da9052_rtc_ops, THIS_MODULE); |
| 261 | return PTR_ERR_OR_ZERO(rtc->rtc); | 316 | return PTR_ERR_OR_ZERO(rtc->rtc); |
