Commit | Line | Data |
---|---|---|
97fb5e8d | 1 | // SPDX-License-Identifier: GPL-2.0-only |
3ca04951 JH |
2 | /* |
3 | * pm8xxx RTC driver | |
4 | * | |
5 | * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. | |
6 | * Copyright (c) 2023, Linaro Limited | |
9a9a54ad | 7 | */ |
5a418558 | 8 | #include <linux/of.h> |
9a9a54ad | 9 | #include <linux/module.h> |
3ca04951 | 10 | #include <linux/nvmem-consumer.h> |
9a9a54ad AG |
11 | #include <linux/init.h> |
12 | #include <linux/rtc.h> | |
5d7dc4cf | 13 | #include <linux/platform_device.h> |
9a9a54ad | 14 | #include <linux/pm.h> |
b5bf5b28 | 15 | #include <linux/pm_wakeirq.h> |
5d7dc4cf | 16 | #include <linux/regmap.h> |
9a9a54ad AG |
17 | #include <linux/slab.h> |
18 | #include <linux/spinlock.h> | |
19 | ||
79dd7566 JH |
20 | #include <asm/unaligned.h> |
21 | ||
9a9a54ad AG |
22 | /* RTC_CTRL register bit fields */ |
23 | #define PM8xxx_RTC_ENABLE BIT(7) | |
9a9a54ad | 24 | #define PM8xxx_RTC_ALARM_CLEAR BIT(0) |
121f54ef | 25 | #define PM8xxx_RTC_ALARM_ENABLE BIT(7) |
9a9a54ad AG |
26 | |
27 | #define NUM_8_BIT_RTC_REGS 0x4 | |
28 | ||
c8d523a4 SV |
29 | /** |
30 | * struct pm8xxx_rtc_regs - describe RTC registers per PMIC versions | |
3c332639 JH |
31 | * @ctrl: address of control register |
32 | * @write: base address of write registers | |
33 | * @read: base address of read registers | |
34 | * @alarm_ctrl: address of alarm control register | |
35 | * @alarm_ctrl2: address of alarm control2 register | |
36 | * @alarm_rw: base address of alarm read-write registers | |
37 | * @alarm_en: alarm enable mask | |
c8d523a4 SV |
38 | */ |
39 | struct pm8xxx_rtc_regs { | |
40 | unsigned int ctrl; | |
41 | unsigned int write; | |
42 | unsigned int read; | |
43 | unsigned int alarm_ctrl; | |
44 | unsigned int alarm_ctrl2; | |
45 | unsigned int alarm_rw; | |
46 | unsigned int alarm_en; | |
47 | }; | |
48 | ||
9a9a54ad | 49 | /** |
3c332639 JH |
50 | * struct pm8xxx_rtc - RTC driver internal structure |
51 | * @rtc: RTC device | |
52 | * @regmap: regmap used to access registers | |
53 | * @allow_set_time: whether the time can be set | |
4727b58f | 54 | * @alarm_irq: alarm irq number |
3c332639 | 55 | * @regs: register description |
a375510e | 56 | * @dev: device structure |
3ca04951 JH |
57 | * @nvmem_cell: nvmem cell for offset |
58 | * @offset: offset from epoch in seconds | |
9a9a54ad AG |
59 | */ |
60 | struct pm8xxx_rtc { | |
61 | struct rtc_device *rtc; | |
5d7dc4cf | 62 | struct regmap *regmap; |
5a418558 | 63 | bool allow_set_time; |
4727b58f | 64 | int alarm_irq; |
c8d523a4 | 65 | const struct pm8xxx_rtc_regs *regs; |
a375510e | 66 | struct device *dev; |
3ca04951 JH |
67 | struct nvmem_cell *nvmem_cell; |
68 | u32 offset; | |
9a9a54ad AG |
69 | }; |
70 | ||
3ca04951 JH |
71 | static int pm8xxx_rtc_read_nvmem_offset(struct pm8xxx_rtc *rtc_dd) |
72 | { | |
73 | size_t len; | |
74 | void *buf; | |
75 | int rc; | |
76 | ||
77 | buf = nvmem_cell_read(rtc_dd->nvmem_cell, &len); | |
78 | if (IS_ERR(buf)) { | |
79 | rc = PTR_ERR(buf); | |
80 | dev_dbg(rtc_dd->dev, "failed to read nvmem offset: %d\n", rc); | |
81 | return rc; | |
82 | } | |
83 | ||
84 | if (len != sizeof(u32)) { | |
85 | dev_dbg(rtc_dd->dev, "unexpected nvmem cell size %zu\n", len); | |
86 | kfree(buf); | |
87 | return -EINVAL; | |
88 | } | |
89 | ||
90 | rtc_dd->offset = get_unaligned_le32(buf); | |
91 | ||
92 | kfree(buf); | |
93 | ||
94 | return 0; | |
95 | } | |
96 | ||
97 | static int pm8xxx_rtc_write_nvmem_offset(struct pm8xxx_rtc *rtc_dd, u32 offset) | |
98 | { | |
99 | u8 buf[sizeof(u32)]; | |
100 | int rc; | |
101 | ||
102 | put_unaligned_le32(offset, buf); | |
103 | ||
104 | rc = nvmem_cell_write(rtc_dd->nvmem_cell, buf, sizeof(buf)); | |
105 | if (rc < 0) { | |
106 | dev_dbg(rtc_dd->dev, "failed to write nvmem offset: %d\n", rc); | |
107 | return rc; | |
108 | } | |
109 | ||
110 | return 0; | |
111 | } | |
112 | ||
113 | static int pm8xxx_rtc_read_offset(struct pm8xxx_rtc *rtc_dd) | |
114 | { | |
115 | if (!rtc_dd->nvmem_cell) | |
116 | return 0; | |
117 | ||
118 | return pm8xxx_rtc_read_nvmem_offset(rtc_dd); | |
119 | } | |
120 | ||
da862c3d JH |
121 | static int pm8xxx_rtc_read_raw(struct pm8xxx_rtc *rtc_dd, u32 *secs) |
122 | { | |
123 | const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; | |
124 | u8 value[NUM_8_BIT_RTC_REGS]; | |
125 | unsigned int reg; | |
126 | int rc; | |
127 | ||
128 | rc = regmap_bulk_read(rtc_dd->regmap, regs->read, value, sizeof(value)); | |
129 | if (rc) | |
130 | return rc; | |
131 | ||
132 | /* | |
133 | * Read the LSB again and check if there has been a carry over. | |
134 | * If there has, redo the read operation. | |
135 | */ | |
136 | rc = regmap_read(rtc_dd->regmap, regs->read, ®); | |
137 | if (rc < 0) | |
138 | return rc; | |
139 | ||
140 | if (reg < value[0]) { | |
141 | rc = regmap_bulk_read(rtc_dd->regmap, regs->read, value, | |
142 | sizeof(value)); | |
143 | if (rc) | |
144 | return rc; | |
145 | } | |
146 | ||
147 | *secs = get_unaligned_le32(value); | |
148 | ||
149 | return 0; | |
150 | } | |
151 | ||
3ca04951 JH |
152 | static int pm8xxx_rtc_update_offset(struct pm8xxx_rtc *rtc_dd, u32 secs) |
153 | { | |
154 | u32 raw_secs; | |
155 | u32 offset; | |
156 | int rc; | |
157 | ||
158 | if (!rtc_dd->nvmem_cell) | |
159 | return -ENODEV; | |
160 | ||
161 | rc = pm8xxx_rtc_read_raw(rtc_dd, &raw_secs); | |
162 | if (rc) | |
163 | return rc; | |
164 | ||
165 | offset = secs - raw_secs; | |
166 | ||
167 | if (offset == rtc_dd->offset) | |
168 | return 0; | |
169 | ||
170 | rc = pm8xxx_rtc_write_nvmem_offset(rtc_dd, offset); | |
171 | if (rc) | |
172 | return rc; | |
173 | ||
174 | rtc_dd->offset = offset; | |
175 | ||
176 | return 0; | |
177 | } | |
178 | ||
9a9a54ad AG |
179 | /* |
180 | * Steps to write the RTC registers. | |
181 | * 1. Disable alarm if enabled. | |
83220bf3 MA |
182 | * 2. Disable rtc if enabled. |
183 | * 3. Write 0x00 to LSB. | |
184 | * 4. Write Byte[1], Byte[2], Byte[3] then Byte[0]. | |
185 | * 5. Enable rtc if disabled in step 2. | |
186 | * 6. Enable alarm if disabled in step 1. | |
9a9a54ad | 187 | */ |
3ca04951 | 188 | static int __pm8xxx_rtc_set_time(struct pm8xxx_rtc *rtc_dd, u32 secs) |
9a9a54ad | 189 | { |
c8d523a4 | 190 | const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; |
182c23bb JH |
191 | u8 value[NUM_8_BIT_RTC_REGS]; |
192 | bool alarm_enabled; | |
79dd7566 | 193 | int rc; |
9a9a54ad | 194 | |
79dd7566 | 195 | put_unaligned_le32(secs, value); |
9a9a54ad | 196 | |
182c23bb JH |
197 | rc = regmap_update_bits_check(rtc_dd->regmap, regs->alarm_ctrl, |
198 | regs->alarm_en, 0, &alarm_enabled); | |
c8d523a4 | 199 | if (rc) |
8d273f33 | 200 | return rc; |
c8d523a4 | 201 | |
3c332639 | 202 | /* Disable RTC */ |
182c23bb | 203 | rc = regmap_update_bits(rtc_dd->regmap, regs->ctrl, PM8xxx_RTC_ENABLE, 0); |
83220bf3 | 204 | if (rc) |
8d273f33 | 205 | return rc; |
83220bf3 | 206 | |
9a9a54ad | 207 | /* Write 0 to Byte[0] */ |
c8d523a4 | 208 | rc = regmap_write(rtc_dd->regmap, regs->write, 0); |
eb245631 | 209 | if (rc) |
8d273f33 | 210 | return rc; |
9a9a54ad AG |
211 | |
212 | /* Write Byte[1], Byte[2], Byte[3] */ | |
c8d523a4 | 213 | rc = regmap_bulk_write(rtc_dd->regmap, regs->write + 1, |
5d7dc4cf | 214 | &value[1], sizeof(value) - 1); |
eb245631 | 215 | if (rc) |
8d273f33 | 216 | return rc; |
9a9a54ad AG |
217 | |
218 | /* Write Byte[0] */ | |
c8d523a4 | 219 | rc = regmap_write(rtc_dd->regmap, regs->write, value[0]); |
eb245631 | 220 | if (rc) |
8d273f33 | 221 | return rc; |
9a9a54ad | 222 | |
3c332639 | 223 | /* Enable RTC */ |
182c23bb JH |
224 | rc = regmap_update_bits(rtc_dd->regmap, regs->ctrl, PM8xxx_RTC_ENABLE, |
225 | PM8xxx_RTC_ENABLE); | |
226 | if (rc) | |
8d273f33 | 227 | return rc; |
83220bf3 | 228 | |
9a9a54ad | 229 | if (alarm_enabled) { |
182c23bb JH |
230 | rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl, |
231 | regs->alarm_en, regs->alarm_en); | |
eb245631 | 232 | if (rc) |
8d273f33 | 233 | return rc; |
9a9a54ad AG |
234 | } |
235 | ||
8d273f33 | 236 | return 0; |
9a9a54ad AG |
237 | } |
238 | ||
3ca04951 JH |
239 | static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) |
240 | { | |
241 | struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); | |
242 | u32 secs; | |
243 | int rc; | |
244 | ||
245 | secs = rtc_tm_to_time64(tm); | |
246 | ||
247 | if (rtc_dd->allow_set_time) | |
248 | rc = __pm8xxx_rtc_set_time(rtc_dd, secs); | |
249 | else | |
250 | rc = pm8xxx_rtc_update_offset(rtc_dd, secs); | |
251 | ||
252 | if (rc) | |
253 | return rc; | |
254 | ||
255 | dev_dbg(dev, "set time: %ptRd %ptRt (%u + %u)\n", tm, tm, | |
256 | secs - rtc_dd->offset, rtc_dd->offset); | |
257 | return 0; | |
258 | } | |
259 | ||
9a9a54ad AG |
260 | static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) |
261 | { | |
9a9a54ad | 262 | struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); |
35d9c472 | 263 | u32 secs; |
da862c3d | 264 | int rc; |
9a9a54ad | 265 | |
da862c3d | 266 | rc = pm8xxx_rtc_read_raw(rtc_dd, &secs); |
eb245631 | 267 | if (rc) |
9a9a54ad | 268 | return rc; |
9a9a54ad | 269 | |
3ca04951 | 270 | secs += rtc_dd->offset; |
4c470b2f | 271 | rtc_time64_to_tm(secs, tm); |
9a9a54ad | 272 | |
3ca04951 JH |
273 | dev_dbg(dev, "read time: %ptRd %ptRt (%u + %u)\n", tm, tm, |
274 | secs - rtc_dd->offset, rtc_dd->offset); | |
9a9a54ad AG |
275 | return 0; |
276 | } | |
277 | ||
278 | static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) | |
279 | { | |
9a9a54ad | 280 | struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); |
c8d523a4 | 281 | const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; |
9e5a7991 | 282 | u8 value[NUM_8_BIT_RTC_REGS]; |
35d9c472 | 283 | u32 secs; |
79dd7566 | 284 | int rc; |
9a9a54ad | 285 | |
4c470b2f | 286 | secs = rtc_tm_to_time64(&alarm->time); |
3ca04951 | 287 | secs -= rtc_dd->offset; |
79dd7566 | 288 | put_unaligned_le32(secs, value); |
9a9a54ad | 289 | |
c88db0ef JH |
290 | rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl, |
291 | regs->alarm_en, 0); | |
292 | if (rc) | |
293 | return rc; | |
294 | ||
c8d523a4 | 295 | rc = regmap_bulk_write(rtc_dd->regmap, regs->alarm_rw, value, |
5d7dc4cf | 296 | sizeof(value)); |
eb245631 | 297 | if (rc) |
8d273f33 | 298 | return rc; |
9a9a54ad | 299 | |
c88db0ef JH |
300 | if (alarm->enabled) { |
301 | rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl, | |
302 | regs->alarm_en, regs->alarm_en); | |
303 | if (rc) | |
8d273f33 | 304 | return rc; |
9a9a54ad AG |
305 | } |
306 | ||
c996956f | 307 | dev_dbg(dev, "set alarm: %ptRd %ptRt\n", &alarm->time, &alarm->time); |
8d273f33 JH |
308 | |
309 | return 0; | |
9a9a54ad AG |
310 | } |
311 | ||
312 | static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) | |
313 | { | |
9a9a54ad | 314 | struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); |
c8d523a4 | 315 | const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; |
9e5a7991 JH |
316 | u8 value[NUM_8_BIT_RTC_REGS]; |
317 | unsigned int ctrl_reg; | |
35d9c472 | 318 | u32 secs; |
9e5a7991 | 319 | int rc; |
9a9a54ad | 320 | |
c8d523a4 | 321 | rc = regmap_bulk_read(rtc_dd->regmap, regs->alarm_rw, value, |
5d7dc4cf | 322 | sizeof(value)); |
eb245631 | 323 | if (rc) |
9a9a54ad | 324 | return rc; |
9a9a54ad | 325 | |
79dd7566 | 326 | secs = get_unaligned_le32(value); |
3ca04951 | 327 | secs += rtc_dd->offset; |
4c470b2f | 328 | rtc_time64_to_tm(secs, &alarm->time); |
9a9a54ad | 329 | |
121f54ef | 330 | rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg); |
eb245631 | 331 | if (rc) |
121f54ef | 332 | return rc; |
eb245631 | 333 | |
121f54ef GW |
334 | alarm->enabled = !!(ctrl_reg & PM8xxx_RTC_ALARM_ENABLE); |
335 | ||
c996956f | 336 | dev_dbg(dev, "read alarm: %ptRd %ptRt\n", &alarm->time, &alarm->time); |
9a9a54ad AG |
337 | |
338 | return 0; | |
339 | } | |
340 | ||
341 | static int pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) | |
342 | { | |
9a9a54ad | 343 | struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); |
c8d523a4 | 344 | const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; |
34ce2977 | 345 | u8 value[NUM_8_BIT_RTC_REGS] = {0}; |
182c23bb | 346 | unsigned int val; |
9e5a7991 | 347 | int rc; |
9a9a54ad | 348 | |
5bed811d | 349 | if (enable) |
182c23bb | 350 | val = regs->alarm_en; |
5bed811d | 351 | else |
182c23bb | 352 | val = 0; |
9a9a54ad | 353 | |
182c23bb JH |
354 | rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl, |
355 | regs->alarm_en, val); | |
eb245631 | 356 | if (rc) |
8d273f33 | 357 | return rc; |
9a9a54ad | 358 | |
3c332639 | 359 | /* Clear alarm register */ |
34ce2977 | 360 | if (!enable) { |
361 | rc = regmap_bulk_write(rtc_dd->regmap, regs->alarm_rw, value, | |
362 | sizeof(value)); | |
eb245631 | 363 | if (rc) |
8d273f33 | 364 | return rc; |
34ce2977 | 365 | } |
366 | ||
8d273f33 | 367 | return 0; |
9a9a54ad AG |
368 | } |
369 | ||
5a418558 | 370 | static const struct rtc_class_ops pm8xxx_rtc_ops = { |
9a9a54ad | 371 | .read_time = pm8xxx_rtc_read_time, |
5a418558 | 372 | .set_time = pm8xxx_rtc_set_time, |
9a9a54ad AG |
373 | .set_alarm = pm8xxx_rtc_set_alarm, |
374 | .read_alarm = pm8xxx_rtc_read_alarm, | |
375 | .alarm_irq_enable = pm8xxx_rtc_alarm_irq_enable, | |
376 | }; | |
377 | ||
378 | static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id) | |
379 | { | |
380 | struct pm8xxx_rtc *rtc_dd = dev_id; | |
c8d523a4 | 381 | const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; |
9a9a54ad | 382 | int rc; |
9a9a54ad AG |
383 | |
384 | rtc_update_irq(rtc_dd->rtc, 1, RTC_IRQF | RTC_AF); | |
385 | ||
3c332639 | 386 | /* Disable alarm */ |
182c23bb JH |
387 | rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl, |
388 | regs->alarm_en, 0); | |
8d273f33 | 389 | if (rc) |
cb9bb7b2 | 390 | return IRQ_NONE; |
9a9a54ad | 391 | |
3c332639 | 392 | /* Clear alarm status */ |
182c23bb JH |
393 | rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl2, |
394 | PM8xxx_RTC_ALARM_CLEAR, 0); | |
eb245631 | 395 | if (rc) |
cb9bb7b2 JH |
396 | return IRQ_NONE; |
397 | ||
9a9a54ad AG |
398 | return IRQ_HANDLED; |
399 | } | |
400 | ||
c8d523a4 SV |
401 | static int pm8xxx_rtc_enable(struct pm8xxx_rtc *rtc_dd) |
402 | { | |
403 | const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; | |
c8d523a4 | 404 | |
182c23bb JH |
405 | return regmap_update_bits(rtc_dd->regmap, regs->ctrl, PM8xxx_RTC_ENABLE, |
406 | PM8xxx_RTC_ENABLE); | |
c8d523a4 SV |
407 | } |
408 | ||
409 | static const struct pm8xxx_rtc_regs pm8921_regs = { | |
410 | .ctrl = 0x11d, | |
411 | .write = 0x11f, | |
412 | .read = 0x123, | |
413 | .alarm_rw = 0x127, | |
414 | .alarm_ctrl = 0x11d, | |
415 | .alarm_ctrl2 = 0x11e, | |
416 | .alarm_en = BIT(1), | |
417 | }; | |
418 | ||
419 | static const struct pm8xxx_rtc_regs pm8058_regs = { | |
420 | .ctrl = 0x1e8, | |
421 | .write = 0x1ea, | |
422 | .read = 0x1ee, | |
423 | .alarm_rw = 0x1f2, | |
424 | .alarm_ctrl = 0x1e8, | |
425 | .alarm_ctrl2 = 0x1e9, | |
426 | .alarm_en = BIT(1), | |
427 | }; | |
428 | ||
429 | static const struct pm8xxx_rtc_regs pm8941_regs = { | |
430 | .ctrl = 0x6046, | |
431 | .write = 0x6040, | |
432 | .read = 0x6048, | |
433 | .alarm_rw = 0x6140, | |
434 | .alarm_ctrl = 0x6146, | |
435 | .alarm_ctrl2 = 0x6148, | |
436 | .alarm_en = BIT(7), | |
437 | }; | |
438 | ||
c8f0ca8b | 439 | static const struct pm8xxx_rtc_regs pmk8350_regs = { |
440 | .ctrl = 0x6146, | |
441 | .write = 0x6140, | |
442 | .read = 0x6148, | |
443 | .alarm_rw = 0x6240, | |
444 | .alarm_ctrl = 0x6246, | |
445 | .alarm_ctrl2 = 0x6248, | |
446 | .alarm_en = BIT(7), | |
447 | }; | |
448 | ||
5a418558 | 449 | static const struct of_device_id pm8xxx_id_table[] = { |
c8d523a4 SV |
450 | { .compatible = "qcom,pm8921-rtc", .data = &pm8921_regs }, |
451 | { .compatible = "qcom,pm8058-rtc", .data = &pm8058_regs }, | |
452 | { .compatible = "qcom,pm8941-rtc", .data = &pm8941_regs }, | |
c8f0ca8b | 453 | { .compatible = "qcom,pmk8350-rtc", .data = &pmk8350_regs }, |
5a418558 JC |
454 | { }, |
455 | }; | |
456 | MODULE_DEVICE_TABLE(of, pm8xxx_id_table); | |
457 | ||
5a167f45 | 458 | static int pm8xxx_rtc_probe(struct platform_device *pdev) |
9a9a54ad | 459 | { |
5a418558 | 460 | const struct of_device_id *match; |
9e5a7991 JH |
461 | struct pm8xxx_rtc *rtc_dd; |
462 | int rc; | |
9a9a54ad | 463 | |
5a418558 JC |
464 | match = of_match_node(pm8xxx_id_table, pdev->dev.of_node); |
465 | if (!match) | |
466 | return -ENXIO; | |
9a9a54ad | 467 | |
c417299c | 468 | rtc_dd = devm_kzalloc(&pdev->dev, sizeof(*rtc_dd), GFP_KERNEL); |
49ae425b | 469 | if (rtc_dd == NULL) |
9a9a54ad | 470 | return -ENOMEM; |
9a9a54ad | 471 | |
5d7dc4cf | 472 | rtc_dd->regmap = dev_get_regmap(pdev->dev.parent, NULL); |
c94fb939 | 473 | if (!rtc_dd->regmap) |
5d7dc4cf | 474 | return -ENXIO; |
5d7dc4cf | 475 | |
4727b58f JH |
476 | rtc_dd->alarm_irq = platform_get_irq(pdev, 0); |
477 | if (rtc_dd->alarm_irq < 0) | |
c417299c | 478 | return -ENXIO; |
9a9a54ad | 479 | |
5a418558 JC |
480 | rtc_dd->allow_set_time = of_property_read_bool(pdev->dev.of_node, |
481 | "allow-set-time"); | |
9a9a54ad | 482 | |
3ca04951 JH |
483 | rtc_dd->nvmem_cell = devm_nvmem_cell_get(&pdev->dev, "offset"); |
484 | if (IS_ERR(rtc_dd->nvmem_cell)) { | |
485 | rc = PTR_ERR(rtc_dd->nvmem_cell); | |
486 | if (rc != -ENOENT) | |
487 | return rc; | |
488 | rtc_dd->nvmem_cell = NULL; | |
489 | } | |
490 | ||
c8d523a4 | 491 | rtc_dd->regs = match->data; |
a375510e | 492 | rtc_dd->dev = &pdev->dev; |
9a9a54ad | 493 | |
3ca04951 JH |
494 | if (!rtc_dd->allow_set_time) { |
495 | rc = pm8xxx_rtc_read_offset(rtc_dd); | |
496 | if (rc) | |
497 | return rc; | |
498 | } | |
499 | ||
c8d523a4 SV |
500 | rc = pm8xxx_rtc_enable(rtc_dd); |
501 | if (rc) | |
c417299c | 502 | return rc; |
9a9a54ad AG |
503 | |
504 | platform_set_drvdata(pdev, rtc_dd); | |
505 | ||
fda9909d JC |
506 | device_init_wakeup(&pdev->dev, 1); |
507 | ||
d5d55b70 AB |
508 | rtc_dd->rtc = devm_rtc_allocate_device(&pdev->dev); |
509 | if (IS_ERR(rtc_dd->rtc)) | |
c417299c | 510 | return PTR_ERR(rtc_dd->rtc); |
d5d55b70 AB |
511 | |
512 | rtc_dd->rtc->ops = &pm8xxx_rtc_ops; | |
3cfe5260 | 513 | rtc_dd->rtc->range_max = U32_MAX; |
9a9a54ad | 514 | |
4727b58f | 515 | rc = devm_request_any_context_irq(&pdev->dev, rtc_dd->alarm_irq, |
bffcbc08 JC |
516 | pm8xxx_alarm_trigger, |
517 | IRQF_TRIGGER_RISING, | |
518 | "pm8xxx_rtc_alarm", rtc_dd); | |
c94fb939 | 519 | if (rc < 0) |
c417299c | 520 | return rc; |
9a9a54ad | 521 | |
b5bf5b28 LP |
522 | rc = devm_rtc_register_device(rtc_dd->rtc); |
523 | if (rc) | |
524 | return rc; | |
9a9a54ad | 525 | |
4727b58f | 526 | rc = dev_pm_set_wake_irq(&pdev->dev, rtc_dd->alarm_irq); |
b5bf5b28 LP |
527 | if (rc) |
528 | return rc; | |
9a9a54ad AG |
529 | |
530 | return 0; | |
531 | } | |
532 | ||
b5bf5b28 | 533 | static int pm8xxx_remove(struct platform_device *pdev) |
9a9a54ad | 534 | { |
b5bf5b28 | 535 | dev_pm_clear_wake_irq(&pdev->dev); |
9a9a54ad AG |
536 | return 0; |
537 | } | |
9a9a54ad AG |
538 | |
539 | static struct platform_driver pm8xxx_rtc_driver = { | |
540 | .probe = pm8xxx_rtc_probe, | |
b5bf5b28 | 541 | .remove = pm8xxx_remove, |
9a9a54ad | 542 | .driver = { |
5a418558 | 543 | .name = "rtc-pm8xxx", |
5a418558 | 544 | .of_match_table = pm8xxx_id_table, |
9a9a54ad AG |
545 | }, |
546 | }; | |
547 | ||
0c4eae66 | 548 | module_platform_driver(pm8xxx_rtc_driver); |
9a9a54ad AG |
549 | |
550 | MODULE_ALIAS("platform:rtc-pm8xxx"); | |
551 | MODULE_DESCRIPTION("PMIC8xxx RTC driver"); | |
552 | MODULE_LICENSE("GPL v2"); | |
553 | MODULE_AUTHOR("Anirudh Ghayal <aghayal@codeaurora.org>"); | |
3ca04951 | 554 | MODULE_AUTHOR("Johan Hovold <johan@kernel.org>"); |