Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
f803f0d0 TR |
2 | /* |
3 | * Copyright (C) 2012 Avionic Design GmbH | |
f803f0d0 TR |
4 | */ |
5 | ||
6 | #include <linux/bcd.h> | |
f8d4e4fa | 7 | #include <linux/bitfield.h> |
f803f0d0 TR |
8 | #include <linux/i2c.h> |
9 | #include <linux/module.h> | |
91f3849d | 10 | #include <linux/regmap.h> |
f803f0d0 TR |
11 | #include <linux/rtc.h> |
12 | #include <linux/of.h> | |
13e37b7f | 13 | #include <linux/pm_wakeirq.h> |
f803f0d0 | 14 | |
4aa90c03 AB |
15 | #define PCF8523_REG_CONTROL1 0x00 |
16 | #define PCF8523_CONTROL1_CAP_SEL BIT(7) | |
17 | #define PCF8523_CONTROL1_STOP BIT(5) | |
18 | #define PCF8523_CONTROL1_AIE BIT(1) | |
19 | ||
20 | #define PCF8523_REG_CONTROL2 0x01 | |
21 | #define PCF8523_CONTROL2_AF BIT(3) | |
22 | ||
23 | #define PCF8523_REG_CONTROL3 0x02 | |
b48cc753 | 24 | #define PCF8523_CONTROL3_PM GENMASK(7, 5) |
f8d4e4fa | 25 | #define PCF8523_PM_STANDBY 0x7 |
4aa90c03 | 26 | #define PCF8523_CONTROL3_BLF BIT(2) /* battery low bit, read-only */ |
7d7234a4 | 27 | #define PCF8523_CONTROL3_BSF BIT(3) |
4aa90c03 AB |
28 | |
29 | #define PCF8523_REG_SECONDS 0x03 | |
30 | #define PCF8523_SECONDS_OS BIT(7) | |
31 | ||
32 | #define PCF8523_REG_MINUTES 0x04 | |
33 | #define PCF8523_REG_HOURS 0x05 | |
34 | #define PCF8523_REG_DAYS 0x06 | |
35 | #define PCF8523_REG_WEEKDAYS 0x07 | |
36 | #define PCF8523_REG_MONTHS 0x08 | |
37 | #define PCF8523_REG_YEARS 0x09 | |
38 | ||
39 | #define PCF8523_REG_MINUTE_ALARM 0x0a | |
40 | #define PCF8523_REG_HOUR_ALARM 0x0b | |
41 | #define PCF8523_REG_DAY_ALARM 0x0c | |
42 | #define PCF8523_REG_WEEKDAY_ALARM 0x0d | |
13e37b7f AB |
43 | #define ALARM_DIS BIT(7) |
44 | ||
4aa90c03 AB |
45 | #define PCF8523_REG_OFFSET 0x0e |
46 | #define PCF8523_OFFSET_MODE BIT(7) | |
bc3bee02 | 47 | |
4aa90c03 | 48 | #define PCF8523_TMR_CLKOUT_CTRL 0x0f |
13e37b7f AB |
49 | |
50 | struct pcf8523 { | |
51 | struct rtc_device *rtc; | |
91f3849d | 52 | struct regmap *regmap; |
13e37b7f AB |
53 | }; |
54 | ||
91f3849d | 55 | static int pcf8523_load_capacitance(struct pcf8523 *pcf8523, struct device_node *node) |
f803f0d0 | 56 | { |
91f3849d | 57 | u32 load, value = 0; |
f803f0d0 | 58 | |
189927e7 | 59 | load = 12500; |
91f3849d | 60 | of_property_read_u32(node, "quartz-load-femtofarads", &load); |
189927e7 SR |
61 | |
62 | switch (load) { | |
63 | default: | |
91f3849d | 64 | dev_warn(&pcf8523->rtc->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 12500", |
189927e7 | 65 | load); |
df561f66 | 66 | fallthrough; |
189927e7 | 67 | case 12500: |
dc87fad6 | 68 | value = PCF8523_CONTROL1_CAP_SEL; |
189927e7 SR |
69 | break; |
70 | case 7000: | |
189927e7 SR |
71 | break; |
72 | } | |
f803f0d0 | 73 | |
91f3849d AB |
74 | return regmap_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL1, |
75 | PCF8523_CONTROL1_CAP_SEL, value); | |
f803f0d0 TR |
76 | } |
77 | ||
13e37b7f AB |
78 | static irqreturn_t pcf8523_irq(int irq, void *dev_id) |
79 | { | |
91f3849d AB |
80 | struct pcf8523 *pcf8523 = dev_id; |
81 | u32 value; | |
13e37b7f AB |
82 | int err; |
83 | ||
91f3849d | 84 | err = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL2, &value); |
13e37b7f AB |
85 | if (err < 0) |
86 | return IRQ_HANDLED; | |
87 | ||
4aa90c03 AB |
88 | if (value & PCF8523_CONTROL2_AF) { |
89 | value &= ~PCF8523_CONTROL2_AF; | |
91f3849d | 90 | regmap_write(pcf8523->regmap, PCF8523_REG_CONTROL2, value); |
13e37b7f AB |
91 | rtc_update_irq(pcf8523->rtc, 1, RTC_IRQF | RTC_AF); |
92 | ||
93 | return IRQ_HANDLED; | |
94 | } | |
95 | ||
96 | return IRQ_NONE; | |
97 | } | |
98 | ||
f803f0d0 TR |
99 | static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) |
100 | { | |
91f3849d | 101 | struct pcf8523 *pcf8523 = dev_get_drvdata(dev); |
fe0157ba | 102 | u8 regs[10]; |
f803f0d0 TR |
103 | int err; |
104 | ||
fe0157ba | 105 | err = regmap_bulk_read(pcf8523->regmap, PCF8523_REG_CONTROL1, regs, |
91f3849d | 106 | sizeof(regs)); |
f803f0d0 TR |
107 | if (err < 0) |
108 | return err; | |
109 | ||
fe0157ba | 110 | if ((regs[0] & PCF8523_CONTROL1_STOP) || (regs[3] & PCF8523_SECONDS_OS)) |
ede44c90 | 111 | return -EINVAL; |
f803f0d0 | 112 | |
fe0157ba | 113 | tm->tm_sec = bcd2bin(regs[3] & 0x7f); |
114 | tm->tm_min = bcd2bin(regs[4] & 0x7f); | |
115 | tm->tm_hour = bcd2bin(regs[5] & 0x3f); | |
116 | tm->tm_mday = bcd2bin(regs[6] & 0x3f); | |
117 | tm->tm_wday = regs[7] & 0x7; | |
118 | tm->tm_mon = bcd2bin(regs[8] & 0x1f) - 1; | |
119 | tm->tm_year = bcd2bin(regs[9]) + 100; | |
f803f0d0 | 120 | |
22652ba7 | 121 | return 0; |
f803f0d0 TR |
122 | } |
123 | ||
124 | static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm) | |
125 | { | |
91f3849d AB |
126 | struct pcf8523 *pcf8523 = dev_get_drvdata(dev); |
127 | u8 regs[7]; | |
f803f0d0 TR |
128 | int err; |
129 | ||
91f3849d AB |
130 | err = regmap_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL1, |
131 | PCF8523_CONTROL1_STOP, PCF8523_CONTROL1_STOP); | |
f803f0d0 TR |
132 | if (err < 0) |
133 | return err; | |
134 | ||
4aa90c03 | 135 | /* This will purposely overwrite PCF8523_SECONDS_OS */ |
91f3849d AB |
136 | regs[0] = bin2bcd(tm->tm_sec); |
137 | regs[1] = bin2bcd(tm->tm_min); | |
138 | regs[2] = bin2bcd(tm->tm_hour); | |
139 | regs[3] = bin2bcd(tm->tm_mday); | |
140 | regs[4] = tm->tm_wday; | |
141 | regs[5] = bin2bcd(tm->tm_mon + 1); | |
142 | regs[6] = bin2bcd(tm->tm_year - 100); | |
143 | ||
144 | err = regmap_bulk_write(pcf8523->regmap, PCF8523_REG_SECONDS, regs, | |
145 | sizeof(regs)); | |
f803f0d0 TR |
146 | if (err < 0) { |
147 | /* | |
148 | * If the time cannot be set, restart the RTC anyway. Note | |
149 | * that errors are ignored if the RTC cannot be started so | |
150 | * that we have a chance to propagate the original error. | |
151 | */ | |
91f3849d AB |
152 | regmap_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL1, |
153 | PCF8523_CONTROL1_STOP, 0); | |
f803f0d0 TR |
154 | return err; |
155 | } | |
156 | ||
91f3849d AB |
157 | return regmap_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL1, |
158 | PCF8523_CONTROL1_STOP, 0); | |
f803f0d0 TR |
159 | } |
160 | ||
13e37b7f AB |
161 | static int pcf8523_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm) |
162 | { | |
91f3849d AB |
163 | struct pcf8523 *pcf8523 = dev_get_drvdata(dev); |
164 | u8 regs[4]; | |
165 | u32 value; | |
13e37b7f AB |
166 | int err; |
167 | ||
91f3849d AB |
168 | err = regmap_bulk_read(pcf8523->regmap, PCF8523_REG_MINUTE_ALARM, regs, |
169 | sizeof(regs)); | |
13e37b7f AB |
170 | if (err < 0) |
171 | return err; | |
172 | ||
173 | tm->time.tm_sec = 0; | |
174 | tm->time.tm_min = bcd2bin(regs[0] & 0x7F); | |
175 | tm->time.tm_hour = bcd2bin(regs[1] & 0x3F); | |
176 | tm->time.tm_mday = bcd2bin(regs[2] & 0x3F); | |
177 | tm->time.tm_wday = bcd2bin(regs[3] & 0x7); | |
178 | ||
91f3849d | 179 | err = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL1, &value); |
13e37b7f AB |
180 | if (err < 0) |
181 | return err; | |
4aa90c03 | 182 | tm->enabled = !!(value & PCF8523_CONTROL1_AIE); |
13e37b7f | 183 | |
91f3849d | 184 | err = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL2, &value); |
13e37b7f AB |
185 | if (err < 0) |
186 | return err; | |
4aa90c03 | 187 | tm->pending = !!(value & PCF8523_CONTROL2_AF); |
13e37b7f AB |
188 | |
189 | return 0; | |
190 | } | |
191 | ||
192 | static int pcf8523_irq_enable(struct device *dev, unsigned int enabled) | |
193 | { | |
91f3849d | 194 | struct pcf8523 *pcf8523 = dev_get_drvdata(dev); |
13e37b7f | 195 | |
91f3849d AB |
196 | return regmap_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL1, |
197 | PCF8523_CONTROL1_AIE, enabled ? | |
198 | PCF8523_CONTROL1_AIE : 0); | |
13e37b7f AB |
199 | } |
200 | ||
201 | static int pcf8523_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) | |
202 | { | |
91f3849d | 203 | struct pcf8523 *pcf8523 = dev_get_drvdata(dev); |
13e37b7f AB |
204 | u8 regs[5]; |
205 | int err; | |
206 | ||
207 | err = pcf8523_irq_enable(dev, 0); | |
208 | if (err) | |
209 | return err; | |
210 | ||
91f3849d | 211 | err = regmap_write(pcf8523->regmap, PCF8523_REG_CONTROL2, 0); |
13e37b7f AB |
212 | if (err < 0) |
213 | return err; | |
214 | ||
91f3849d AB |
215 | regs[0] = bin2bcd(tm->time.tm_min); |
216 | regs[1] = bin2bcd(tm->time.tm_hour); | |
217 | regs[2] = bin2bcd(tm->time.tm_mday); | |
218 | regs[3] = ALARM_DIS; | |
219 | ||
220 | err = regmap_bulk_write(pcf8523->regmap, PCF8523_REG_MINUTE_ALARM, regs, | |
221 | sizeof(regs)); | |
13e37b7f AB |
222 | if (err < 0) |
223 | return err; | |
224 | ||
225 | if (tm->enabled) | |
226 | return pcf8523_irq_enable(dev, tm->enabled); | |
227 | ||
228 | return 0; | |
229 | } | |
230 | ||
f8d4e4fa AB |
231 | static int pcf8523_param_get(struct device *dev, struct rtc_param *param) |
232 | { | |
233 | struct pcf8523 *pcf8523 = dev_get_drvdata(dev); | |
234 | int ret; | |
85bcb01f | 235 | u32 value; |
f8d4e4fa | 236 | |
b48cc753 | 237 | switch (param->param) { |
f8d4e4fa AB |
238 | case RTC_PARAM_BACKUP_SWITCH_MODE: |
239 | ret = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL3, &value); | |
240 | if (ret < 0) | |
241 | return ret; | |
242 | ||
243 | value = FIELD_GET(PCF8523_CONTROL3_PM, value); | |
244 | ||
b48cc753 | 245 | switch (value) { |
f8d4e4fa AB |
246 | case 0x0: |
247 | case 0x4: | |
248 | param->uvalue = RTC_BSM_LEVEL; | |
249 | break; | |
250 | case 0x1: | |
251 | case 0x5: | |
252 | param->uvalue = RTC_BSM_DIRECT; | |
253 | break; | |
254 | case PCF8523_PM_STANDBY: | |
255 | param->uvalue = RTC_BSM_STANDBY; | |
256 | break; | |
257 | default: | |
258 | param->uvalue = RTC_BSM_DISABLED; | |
259 | } | |
260 | ||
261 | break; | |
262 | ||
263 | default: | |
264 | return -EINVAL; | |
265 | } | |
266 | ||
267 | return 0; | |
268 | } | |
269 | ||
270 | static int pcf8523_param_set(struct device *dev, struct rtc_param *param) | |
271 | { | |
272 | struct pcf8523 *pcf8523 = dev_get_drvdata(dev); | |
85bcb01f | 273 | u8 mode; |
f8d4e4fa | 274 | |
b48cc753 | 275 | switch (param->param) { |
f8d4e4fa AB |
276 | case RTC_PARAM_BACKUP_SWITCH_MODE: |
277 | switch (param->uvalue) { | |
278 | case RTC_BSM_DISABLED: | |
279 | mode = 0x2; | |
280 | break; | |
281 | case RTC_BSM_DIRECT: | |
282 | mode = 0x1; | |
283 | break; | |
284 | case RTC_BSM_LEVEL: | |
285 | mode = 0x0; | |
286 | break; | |
287 | case RTC_BSM_STANDBY: | |
288 | mode = PCF8523_PM_STANDBY; | |
289 | break; | |
290 | default: | |
291 | return -EINVAL; | |
292 | } | |
293 | ||
294 | return regmap_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL3, | |
295 | PCF8523_CONTROL3_PM, | |
296 | FIELD_PREP(PCF8523_CONTROL3_PM, mode)); | |
297 | ||
298 | break; | |
299 | ||
300 | default: | |
301 | return -EINVAL; | |
302 | } | |
303 | ||
304 | return 0; | |
305 | } | |
306 | ||
f32bc70d JN |
307 | static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd, |
308 | unsigned long arg) | |
309 | { | |
91f3849d | 310 | struct pcf8523 *pcf8523 = dev_get_drvdata(dev); |
a1cfe7cc | 311 | unsigned int flags = 0; |
91f3849d | 312 | u32 value; |
ecb4a353 | 313 | int ret; |
f32bc70d JN |
314 | |
315 | switch (cmd) { | |
316 | case RTC_VL_READ: | |
91f3849d | 317 | ret = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL3, &value); |
ecb4a353 BS |
318 | if (ret < 0) |
319 | return ret; | |
7d7234a4 AB |
320 | |
321 | if (value & PCF8523_CONTROL3_BLF) | |
a1cfe7cc AB |
322 | flags |= RTC_VL_BACKUP_LOW; |
323 | ||
91f3849d | 324 | ret = regmap_read(pcf8523->regmap, PCF8523_REG_SECONDS, &value); |
a1cfe7cc AB |
325 | if (ret < 0) |
326 | return ret; | |
327 | ||
4aa90c03 | 328 | if (value & PCF8523_SECONDS_OS) |
a1cfe7cc | 329 | flags |= RTC_VL_DATA_INVALID; |
f32bc70d | 330 | |
a1cfe7cc | 331 | return put_user(flags, (unsigned int __user *)arg); |
f32bc70d | 332 | |
f32bc70d JN |
333 | default: |
334 | return -ENOIOCTLCMD; | |
335 | } | |
336 | } | |
f32bc70d | 337 | |
bc3bee02 RK |
338 | static int pcf8523_rtc_read_offset(struct device *dev, long *offset) |
339 | { | |
91f3849d | 340 | struct pcf8523 *pcf8523 = dev_get_drvdata(dev); |
bc3bee02 | 341 | int err; |
91f3849d | 342 | u32 value; |
bc3bee02 RK |
343 | s8 val; |
344 | ||
91f3849d | 345 | err = regmap_read(pcf8523->regmap, PCF8523_REG_OFFSET, &value); |
bc3bee02 RK |
346 | if (err < 0) |
347 | return err; | |
348 | ||
349 | /* sign extend the 7-bit offset value */ | |
350 | val = value << 1; | |
4aa90c03 | 351 | *offset = (value & PCF8523_OFFSET_MODE ? 4069 : 4340) * (val >> 1); |
bc3bee02 RK |
352 | |
353 | return 0; | |
354 | } | |
355 | ||
356 | static int pcf8523_rtc_set_offset(struct device *dev, long offset) | |
357 | { | |
91f3849d | 358 | struct pcf8523 *pcf8523 = dev_get_drvdata(dev); |
bc3bee02 | 359 | long reg_m0, reg_m1; |
91f3849d | 360 | u32 value; |
bc3bee02 RK |
361 | |
362 | reg_m0 = clamp(DIV_ROUND_CLOSEST(offset, 4340), -64L, 63L); | |
363 | reg_m1 = clamp(DIV_ROUND_CLOSEST(offset, 4069), -64L, 63L); | |
364 | ||
365 | if (abs(reg_m0 * 4340 - offset) < abs(reg_m1 * 4069 - offset)) | |
366 | value = reg_m0 & 0x7f; | |
367 | else | |
4aa90c03 | 368 | value = (reg_m1 & 0x7f) | PCF8523_OFFSET_MODE; |
bc3bee02 | 369 | |
91f3849d | 370 | return regmap_write(pcf8523->regmap, PCF8523_REG_OFFSET, value); |
bc3bee02 RK |
371 | } |
372 | ||
f803f0d0 TR |
373 | static const struct rtc_class_ops pcf8523_rtc_ops = { |
374 | .read_time = pcf8523_rtc_read_time, | |
375 | .set_time = pcf8523_rtc_set_time, | |
13e37b7f AB |
376 | .read_alarm = pcf8523_rtc_read_alarm, |
377 | .set_alarm = pcf8523_rtc_set_alarm, | |
378 | .alarm_irq_enable = pcf8523_irq_enable, | |
f32bc70d | 379 | .ioctl = pcf8523_rtc_ioctl, |
bc3bee02 RK |
380 | .read_offset = pcf8523_rtc_read_offset, |
381 | .set_offset = pcf8523_rtc_set_offset, | |
f8d4e4fa AB |
382 | .param_get = pcf8523_param_get, |
383 | .param_set = pcf8523_param_set, | |
f803f0d0 TR |
384 | }; |
385 | ||
91f3849d | 386 | static const struct regmap_config regmap_config = { |
b48cc753 JC |
387 | .reg_bits = 8, |
388 | .val_bits = 8, | |
389 | .max_register = 0x13, | |
91f3849d AB |
390 | }; |
391 | ||
3f4a3322 | 392 | static int pcf8523_probe(struct i2c_client *client) |
f803f0d0 | 393 | { |
13e37b7f | 394 | struct pcf8523 *pcf8523; |
93966243 | 395 | struct rtc_device *rtc; |
13e37b7f | 396 | bool wakeup_source = false; |
f8d4e4fa | 397 | u32 value; |
f803f0d0 TR |
398 | int err; |
399 | ||
400 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) | |
401 | return -ENODEV; | |
402 | ||
13e37b7f AB |
403 | pcf8523 = devm_kzalloc(&client->dev, sizeof(struct pcf8523), GFP_KERNEL); |
404 | if (!pcf8523) | |
405 | return -ENOMEM; | |
406 | ||
91f3849d AB |
407 | pcf8523->regmap = devm_regmap_init_i2c(client, ®map_config); |
408 | if (IS_ERR(pcf8523->regmap)) | |
409 | return PTR_ERR(pcf8523->regmap); | |
410 | ||
13e37b7f | 411 | i2c_set_clientdata(client, pcf8523); |
13e37b7f | 412 | |
91f3849d AB |
413 | rtc = devm_rtc_allocate_device(&client->dev); |
414 | if (IS_ERR(rtc)) | |
415 | return PTR_ERR(rtc); | |
416 | pcf8523->rtc = rtc; | |
417 | ||
418 | err = pcf8523_load_capacitance(pcf8523, client->dev.of_node); | |
f803f0d0 | 419 | if (err < 0) |
189927e7 SR |
420 | dev_warn(&client->dev, "failed to set xtal load capacitance: %d", |
421 | err); | |
f803f0d0 | 422 | |
f8d4e4fa | 423 | err = regmap_read(pcf8523->regmap, PCF8523_REG_SECONDS, &value); |
f803f0d0 TR |
424 | if (err < 0) |
425 | return err; | |
426 | ||
f8d4e4fa AB |
427 | if (value & PCF8523_SECONDS_OS) { |
428 | err = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL3, &value); | |
429 | if (err < 0) | |
430 | return err; | |
431 | ||
432 | if (FIELD_GET(PCF8523_CONTROL3_PM, value) == PCF8523_PM_STANDBY) { | |
433 | err = regmap_write(pcf8523->regmap, PCF8523_REG_CONTROL3, | |
434 | value & ~PCF8523_CONTROL3_PM); | |
435 | if (err < 0) | |
436 | return err; | |
437 | } | |
438 | } | |
439 | ||
88614405 | 440 | rtc->ops = &pcf8523_rtc_ops; |
219cc0f9 AB |
441 | rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; |
442 | rtc->range_max = RTC_TIMESTAMP_END_2099; | |
e51cdef0 | 443 | set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->features); |
c1325e73 | 444 | clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features); |
13e37b7f AB |
445 | |
446 | if (client->irq > 0) { | |
3542db1d AB |
447 | unsigned long irqflags = IRQF_TRIGGER_LOW; |
448 | ||
449 | if (dev_fwnode(&client->dev)) | |
450 | irqflags = 0; | |
451 | ||
91f3849d | 452 | err = regmap_write(pcf8523->regmap, PCF8523_TMR_CLKOUT_CTRL, 0x38); |
13e37b7f AB |
453 | if (err < 0) |
454 | return err; | |
455 | ||
456 | err = devm_request_threaded_irq(&client->dev, client->irq, | |
457 | NULL, pcf8523_irq, | |
3542db1d | 458 | IRQF_SHARED | IRQF_ONESHOT | irqflags, |
91f3849d | 459 | dev_name(&rtc->dev), pcf8523); |
13e37b7f AB |
460 | if (err) |
461 | return err; | |
462 | ||
463 | dev_pm_set_wake_irq(&client->dev, client->irq); | |
464 | } | |
465 | ||
13e37b7f | 466 | wakeup_source = of_property_read_bool(client->dev.of_node, "wakeup-source"); |
13e37b7f AB |
467 | if (client->irq > 0 || wakeup_source) |
468 | device_init_wakeup(&client->dev, true); | |
88614405 AB |
469 | |
470 | return devm_rtc_register_device(rtc); | |
f803f0d0 TR |
471 | } |
472 | ||
f803f0d0 TR |
473 | static const struct i2c_device_id pcf8523_id[] = { |
474 | { "pcf8523", 0 }, | |
475 | { } | |
476 | }; | |
477 | MODULE_DEVICE_TABLE(i2c, pcf8523_id); | |
478 | ||
f803f0d0 TR |
479 | static const struct of_device_id pcf8523_of_match[] = { |
480 | { .compatible = "nxp,pcf8523" }, | |
7c617e0c | 481 | { .compatible = "microcrystal,rv8523" }, |
f803f0d0 TR |
482 | { } |
483 | }; | |
484 | MODULE_DEVICE_TABLE(of, pcf8523_of_match); | |
f803f0d0 TR |
485 | |
486 | static struct i2c_driver pcf8523_driver = { | |
487 | .driver = { | |
94959a3a | 488 | .name = "rtc-pcf8523", |
ebf48cbe | 489 | .of_match_table = pcf8523_of_match, |
f803f0d0 | 490 | }, |
31b0cecb | 491 | .probe = pcf8523_probe, |
f803f0d0 TR |
492 | .id_table = pcf8523_id, |
493 | }; | |
494 | module_i2c_driver(pcf8523_driver); | |
495 | ||
496 | MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); | |
497 | MODULE_DESCRIPTION("NXP PCF8523 RTC driver"); | |
498 | MODULE_LICENSE("GPL v2"); |