Blame view
drivers/rtc/rtc-da9052.c
6.58 KB
fef931ff9
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* * Real time clock driver for DA9052 * * Copyright(c) 2012 Dialog Semiconductor Ltd. * * Author: Dajun Dajun Chen <dajun.chen@diasemi.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * */ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/rtc.h> |
11f54d058
|
18 |
#include <linux/err.h> |
fef931ff9
|
19 20 21 |
#include <linux/mfd/da9052/da9052.h> #include <linux/mfd/da9052/reg.h> |
7c994c08c
|
22 23 |
#define rtc_err(rtc, fmt, ...) \ dev_err(rtc->da9052->dev, "%s: " fmt, __func__, ##__VA_ARGS__) |
fef931ff9
|
24 25 26 27 |
struct da9052_rtc { struct rtc_device *rtc; struct da9052 *da9052; |
fef931ff9
|
28 |
}; |
7c994c08c
|
29 |
static int da9052_rtc_enable_alarm(struct da9052_rtc *rtc, bool enable) |
fef931ff9
|
30 31 32 |
{ int ret; if (enable) { |
7c994c08c
|
33 34 35 |
ret = da9052_reg_update(rtc->da9052, DA9052_ALARM_Y_REG, DA9052_ALARM_Y_ALARM_ON|DA9052_ALARM_Y_TICK_ON, DA9052_ALARM_Y_ALARM_ON); |
fef931ff9
|
36 |
if (ret != 0) |
7c994c08c
|
37 38 |
rtc_err(rtc, "Failed to enable ALM: %d ", ret); |
fef931ff9
|
39 |
} else { |
7c994c08c
|
40 41 |
ret = da9052_reg_update(rtc->da9052, DA9052_ALARM_Y_REG, DA9052_ALARM_Y_ALARM_ON|DA9052_ALARM_Y_TICK_ON, 0); |
fef931ff9
|
42 |
if (ret != 0) |
7c994c08c
|
43 44 |
rtc_err(rtc, "Write error: %d ", ret); |
fef931ff9
|
45 46 47 48 49 50 51 |
} return ret; } static irqreturn_t da9052_rtc_irq(int irq, void *data) { struct da9052_rtc *rtc = data; |
fef931ff9
|
52 |
|
7c994c08c
|
53 |
rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); |
fef931ff9
|
54 55 56 |
return IRQ_HANDLED; } |
7c994c08c
|
57 |
static int da9052_read_alarm(struct da9052_rtc *rtc, struct rtc_time *rtc_tm) |
fef931ff9
|
58 59 60 |
{ int ret; uint8_t v[5]; |
7c994c08c
|
61 |
ret = da9052_group_read(rtc->da9052, DA9052_ALARM_MI_REG, 5, v); |
fef931ff9
|
62 |
if (ret != 0) { |
7c994c08c
|
63 64 |
rtc_err(rtc, "Failed to group read ALM: %d ", ret); |
fef931ff9
|
65 66 67 68 69 70 71 72 73 74 |
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; ret = rtc_valid_tm(rtc_tm); |
fef931ff9
|
75 76 |
return ret; } |
7c994c08c
|
77 |
static int da9052_set_alarm(struct da9052_rtc *rtc, struct rtc_time *rtc_tm) |
fef931ff9
|
78 |
{ |
7c994c08c
|
79 80 |
struct da9052 *da9052 = rtc->da9052; unsigned long alm_time; |
fef931ff9
|
81 82 |
int ret; uint8_t v[3]; |
7c994c08c
|
83 84 85 86 87 88 89 90 91 |
ret = rtc_tm_to_time(rtc_tm, &alm_time); if (ret != 0) return ret; if (rtc_tm->tm_sec > 0) { alm_time += 60 - rtc_tm->tm_sec; rtc_time_to_tm(alm_time, rtc_tm); } BUG_ON(rtc_tm->tm_sec); /* it will cause repeated irqs if not zero */ |
fef931ff9
|
92 93 94 95 96 97 |
rtc_tm->tm_year -= 100; rtc_tm->tm_mon += 1; ret = da9052_reg_update(da9052, DA9052_ALARM_MI_REG, DA9052_RTC_MIN, rtc_tm->tm_min); if (ret != 0) { |
7c994c08c
|
98 99 |
rtc_err(rtc, "Failed to write ALRM MIN: %d ", ret); |
fef931ff9
|
100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
return ret; } v[0] = rtc_tm->tm_hour; v[1] = rtc_tm->tm_mday; v[2] = rtc_tm->tm_mon; ret = da9052_group_write(da9052, DA9052_ALARM_H_REG, 3, v); if (ret < 0) return ret; ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG, DA9052_RTC_YEAR, rtc_tm->tm_year); if (ret != 0) |
7c994c08c
|
114 115 |
rtc_err(rtc, "Failed to write ALRM YEAR: %d ", ret); |
fef931ff9
|
116 117 118 |
return ret; } |
7c994c08c
|
119 |
static int da9052_rtc_get_alarm_status(struct da9052_rtc *rtc) |
fef931ff9
|
120 121 |
{ int ret; |
7c994c08c
|
122 |
ret = da9052_reg_read(rtc->da9052, DA9052_ALARM_Y_REG); |
fef931ff9
|
123 |
if (ret < 0) { |
7c994c08c
|
124 125 |
rtc_err(rtc, "Failed to read ALM: %d ", ret); |
fef931ff9
|
126 127 |
return ret; } |
7c994c08c
|
128 129 |
return !!(ret&DA9052_ALARM_Y_ALARM_ON); |
fef931ff9
|
130 131 132 133 134 135 136 137 138 139 |
} 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; ret = da9052_group_read(rtc->da9052, DA9052_COUNT_S_REG, 6, v); if (ret < 0) { |
7c994c08c
|
140 141 |
rtc_err(rtc, "Failed to read RTC time : %d ", ret); |
fef931ff9
|
142 143 144 145 146 147 148 149 150 151 152 |
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; ret = rtc_valid_tm(rtc_tm); |
7c994c08c
|
153 |
return ret; |
fef931ff9
|
154 155 156 157 158 159 |
} static int da9052_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct da9052_rtc *rtc; uint8_t v[6]; |
7c994c08c
|
160 |
int ret; |
fef931ff9
|
161 162 163 164 165 166 167 168 169 |
rtc = dev_get_drvdata(dev); v[0] = tm->tm_sec; v[1] = tm->tm_min; v[2] = tm->tm_hour; v[3] = tm->tm_mday; v[4] = tm->tm_mon + 1; v[5] = tm->tm_year - 100; |
7c994c08c
|
170 171 172 173 174 |
ret = da9052_group_write(rtc->da9052, DA9052_COUNT_S_REG, 6, v); if (ret < 0) rtc_err(rtc, "failed to set RTC time: %d ", ret); return ret; |
fef931ff9
|
175 176 177 178 179 180 181 |
} static int da9052_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { int ret; struct rtc_time *tm = &alrm->time; struct da9052_rtc *rtc = dev_get_drvdata(dev); |
7c994c08c
|
182 183 184 185 |
ret = da9052_read_alarm(rtc, tm); if (ret < 0) { rtc_err(rtc, "failed to read RTC alarm: %d ", ret); |
fef931ff9
|
186 |
return ret; |
7c994c08c
|
187 |
} |
fef931ff9
|
188 |
|
7c994c08c
|
189 |
alrm->enabled = da9052_rtc_get_alarm_status(rtc); |
fef931ff9
|
190 191 192 193 194 195 196 197 |
return 0; } static int da9052_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { int ret; struct rtc_time *tm = &alrm->time; struct da9052_rtc *rtc = dev_get_drvdata(dev); |
7c994c08c
|
198 |
ret = da9052_rtc_enable_alarm(rtc, 0); |
fef931ff9
|
199 200 |
if (ret < 0) return ret; |
7c994c08c
|
201 202 |
ret = da9052_set_alarm(rtc, tm); if (ret < 0) |
fef931ff9
|
203 |
return ret; |
7c994c08c
|
204 |
ret = da9052_rtc_enable_alarm(rtc, 1); |
fef931ff9
|
205 206 207 208 209 210 |
return ret; } static int da9052_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct da9052_rtc *rtc = dev_get_drvdata(dev); |
7c994c08c
|
211 |
return da9052_rtc_enable_alarm(rtc, enabled); |
fef931ff9
|
212 213 214 215 216 217 218 219 220 |
} static const struct rtc_class_ops da9052_rtc_ops = { .read_time = da9052_rtc_read_time, .set_time = da9052_rtc_set_time, .read_alarm = da9052_rtc_read_alarm, .set_alarm = da9052_rtc_set_alarm, .alarm_irq_enable = da9052_rtc_alarm_irq_enable, }; |
5a167f454
|
221 |
static int da9052_rtc_probe(struct platform_device *pdev) |
fef931ff9
|
222 223 224 225 226 227 228 229 230 231 |
{ struct da9052_rtc *rtc; int ret; rtc = devm_kzalloc(&pdev->dev, sizeof(struct da9052_rtc), GFP_KERNEL); if (!rtc) return -ENOMEM; rtc->da9052 = dev_get_drvdata(pdev->dev.parent); platform_set_drvdata(pdev, rtc); |
7c994c08c
|
232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
ret = da9052_reg_write(rtc->da9052, DA9052_BBAT_CONT_REG, 0xFE); if (ret < 0) { rtc_err(rtc, "Failed to setup RTC battery charging: %d ", ret); return ret; } ret = da9052_reg_update(rtc->da9052, DA9052_ALARM_Y_REG, DA9052_ALARM_Y_TICK_ON, 0); if (ret != 0) rtc_err(rtc, "Failed to disable TICKS: %d ", ret); |
c2c0eed7f
|
246 |
ret = da9052_request_irq(rtc->da9052, DA9052_IRQ_ALARM, "ALM", |
925e8ea6b
|
247 |
da9052_rtc_irq, rtc); |
fef931ff9
|
248 |
if (ret != 0) { |
7c994c08c
|
249 250 |
rtc_err(rtc, "irq registration failed: %d ", ret); |
007def046
|
251 |
return ret; |
fef931ff9
|
252 |
} |
3689cd741
|
253 |
rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, |
fef931ff9
|
254 |
&da9052_rtc_ops, THIS_MODULE); |
dac30a984
|
255 |
return PTR_ERR_OR_ZERO(rtc->rtc); |
fef931ff9
|
256 |
} |
fef931ff9
|
257 258 |
static struct platform_driver da9052_rtc_driver = { .probe = da9052_rtc_probe, |
fef931ff9
|
259 260 261 262 263 264 265 |
.driver = { .name = "da9052-rtc", .owner = THIS_MODULE, }, }; module_platform_driver(da9052_rtc_driver); |
7c994c08c
|
266 |
MODULE_AUTHOR("Anthony Olech <Anthony.Olech@diasemi.com>"); |
fef931ff9
|
267 268 269 |
MODULE_DESCRIPTION("RTC driver for Dialog DA9052 PMIC"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:da9052-rtc"); |