Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
1d6316f5 RG |
2 | /* rtc-ds1343.c |
3 | * | |
4 | * Driver for Dallas Semiconductor DS1343 Low Current, SPI Compatible | |
5 | * Real Time Clock | |
6 | * | |
7 | * Author : Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com> | |
571eb883 | 8 | * Ankur Srivastava <sankurece@gmail.com> : DS1343 Nvram Support |
1d6316f5 RG |
9 | */ |
10 | ||
11 | #include <linux/init.h> | |
12 | #include <linux/module.h> | |
13 | #include <linux/interrupt.h> | |
14 | #include <linux/device.h> | |
15 | #include <linux/spi/spi.h> | |
16 | #include <linux/regmap.h> | |
17 | #include <linux/rtc.h> | |
18 | #include <linux/bcd.h> | |
19 | #include <linux/pm.h> | |
caff0cc4 | 20 | #include <linux/pm_wakeirq.h> |
1d6316f5 RG |
21 | #include <linux/slab.h> |
22 | ||
1d6316f5 RG |
23 | #define DALLAS_MAXIM_DS1343 0 |
24 | #define DALLAS_MAXIM_DS1344 1 | |
25 | ||
26 | /* RTC DS1343 Registers */ | |
27 | #define DS1343_SECONDS_REG 0x00 | |
28 | #define DS1343_MINUTES_REG 0x01 | |
29 | #define DS1343_HOURS_REG 0x02 | |
30 | #define DS1343_DAY_REG 0x03 | |
31 | #define DS1343_DATE_REG 0x04 | |
32 | #define DS1343_MONTH_REG 0x05 | |
33 | #define DS1343_YEAR_REG 0x06 | |
34 | #define DS1343_ALM0_SEC_REG 0x07 | |
35 | #define DS1343_ALM0_MIN_REG 0x08 | |
36 | #define DS1343_ALM0_HOUR_REG 0x09 | |
37 | #define DS1343_ALM0_DAY_REG 0x0A | |
38 | #define DS1343_ALM1_SEC_REG 0x0B | |
39 | #define DS1343_ALM1_MIN_REG 0x0C | |
40 | #define DS1343_ALM1_HOUR_REG 0x0D | |
41 | #define DS1343_ALM1_DAY_REG 0x0E | |
42 | #define DS1343_CONTROL_REG 0x0F | |
43 | #define DS1343_STATUS_REG 0x10 | |
44 | #define DS1343_TRICKLE_REG 0x11 | |
571eb883 RG |
45 | #define DS1343_NVRAM 0x20 |
46 | ||
47 | #define DS1343_NVRAM_LEN 96 | |
1d6316f5 RG |
48 | |
49 | /* DS1343 Control Registers bits */ | |
50 | #define DS1343_EOSC 0x80 | |
51 | #define DS1343_DOSF 0x20 | |
52 | #define DS1343_EGFIL 0x10 | |
53 | #define DS1343_SQW 0x08 | |
54 | #define DS1343_INTCN 0x04 | |
55 | #define DS1343_A1IE 0x02 | |
56 | #define DS1343_A0IE 0x01 | |
57 | ||
58 | /* DS1343 Status Registers bits */ | |
59 | #define DS1343_OSF 0x80 | |
60 | #define DS1343_IRQF1 0x02 | |
61 | #define DS1343_IRQF0 0x01 | |
62 | ||
63 | /* DS1343 Trickle Charger Registers bits */ | |
64 | #define DS1343_TRICKLE_MAGIC 0xa0 | |
65 | #define DS1343_TRICKLE_DS1 0x08 | |
66 | #define DS1343_TRICKLE_1K 0x01 | |
67 | #define DS1343_TRICKLE_2K 0x02 | |
68 | #define DS1343_TRICKLE_4K 0x03 | |
69 | ||
70 | static const struct spi_device_id ds1343_id[] = { | |
71 | { "ds1343", DALLAS_MAXIM_DS1343 }, | |
72 | { "ds1344", DALLAS_MAXIM_DS1344 }, | |
73 | { } | |
74 | }; | |
75 | MODULE_DEVICE_TABLE(spi, ds1343_id); | |
76 | ||
77 | struct ds1343_priv { | |
78 | struct spi_device *spi; | |
79 | struct rtc_device *rtc; | |
80 | struct regmap *map; | |
81 | struct mutex mutex; | |
82 | unsigned int irqen; | |
10b06b87 | 83 | int irq; |
1d6316f5 RG |
84 | int alarm_sec; |
85 | int alarm_min; | |
86 | int alarm_hour; | |
87 | int alarm_mday; | |
88 | }; | |
89 | ||
90 | static int ds1343_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) | |
91 | { | |
92 | switch (cmd) { | |
93 | #ifdef RTC_SET_CHARGE | |
94 | case RTC_SET_CHARGE: | |
95 | { | |
96 | int val; | |
97 | ||
98 | if (copy_from_user(&val, (int __user *)arg, sizeof(int))) | |
99 | return -EFAULT; | |
100 | ||
101 | return regmap_write(priv->map, DS1343_TRICKLE_REG, val); | |
102 | } | |
103 | break; | |
104 | #endif | |
105 | } | |
106 | ||
107 | return -ENOIOCTLCMD; | |
108 | } | |
109 | ||
110 | static ssize_t ds1343_show_glitchfilter(struct device *dev, | |
111 | struct device_attribute *attr, char *buf) | |
112 | { | |
113 | struct ds1343_priv *priv = dev_get_drvdata(dev); | |
114 | int glitch_filt_status, data; | |
115 | ||
116 | regmap_read(priv->map, DS1343_CONTROL_REG, &data); | |
117 | ||
118 | glitch_filt_status = !!(data & DS1343_EGFIL); | |
119 | ||
120 | if (glitch_filt_status) | |
121 | return sprintf(buf, "enabled\n"); | |
122 | else | |
123 | return sprintf(buf, "disabled\n"); | |
124 | } | |
125 | ||
126 | static ssize_t ds1343_store_glitchfilter(struct device *dev, | |
127 | struct device_attribute *attr, | |
128 | const char *buf, size_t count) | |
129 | { | |
130 | struct ds1343_priv *priv = dev_get_drvdata(dev); | |
131 | int data; | |
132 | ||
133 | regmap_read(priv->map, DS1343_CONTROL_REG, &data); | |
134 | ||
135 | if (strncmp(buf, "enabled", 7) == 0) | |
136 | data |= DS1343_EGFIL; | |
137 | ||
138 | else if (strncmp(buf, "disabled", 8) == 0) | |
139 | data &= ~(DS1343_EGFIL); | |
140 | ||
141 | else | |
142 | return -EINVAL; | |
143 | ||
144 | regmap_write(priv->map, DS1343_CONTROL_REG, data); | |
145 | ||
146 | return count; | |
147 | } | |
148 | ||
149 | static DEVICE_ATTR(glitch_filter, S_IRUGO | S_IWUSR, ds1343_show_glitchfilter, | |
150 | ds1343_store_glitchfilter); | |
151 | ||
d7501f70 AB |
152 | static int ds1343_nvram_write(void *priv, unsigned int off, void *val, |
153 | size_t bytes) | |
571eb883 | 154 | { |
d7501f70 | 155 | struct ds1343_priv *ds1343 = priv; |
571eb883 | 156 | |
d7501f70 | 157 | return regmap_bulk_write(ds1343->map, DS1343_NVRAM + off, val, bytes); |
571eb883 RG |
158 | } |
159 | ||
d7501f70 AB |
160 | static int ds1343_nvram_read(void *priv, unsigned int off, void *val, |
161 | size_t bytes) | |
571eb883 | 162 | { |
d7501f70 | 163 | struct ds1343_priv *ds1343 = priv; |
571eb883 | 164 | |
d7501f70 | 165 | return regmap_bulk_read(ds1343->map, DS1343_NVRAM + off, val, bytes); |
571eb883 RG |
166 | } |
167 | ||
1d6316f5 RG |
168 | static ssize_t ds1343_show_tricklecharger(struct device *dev, |
169 | struct device_attribute *attr, char *buf) | |
170 | { | |
171 | struct ds1343_priv *priv = dev_get_drvdata(dev); | |
172 | int data; | |
173 | char *diodes = "disabled", *resistors = " "; | |
174 | ||
175 | regmap_read(priv->map, DS1343_TRICKLE_REG, &data); | |
176 | ||
177 | if ((data & 0xf0) == DS1343_TRICKLE_MAGIC) { | |
178 | switch (data & 0x0c) { | |
179 | case DS1343_TRICKLE_DS1: | |
180 | diodes = "one diode,"; | |
181 | break; | |
182 | ||
183 | default: | |
184 | diodes = "no diode,"; | |
185 | break; | |
186 | } | |
187 | ||
188 | switch (data & 0x03) { | |
189 | case DS1343_TRICKLE_1K: | |
190 | resistors = "1k Ohm"; | |
191 | break; | |
192 | ||
193 | case DS1343_TRICKLE_2K: | |
194 | resistors = "2k Ohm"; | |
195 | break; | |
196 | ||
197 | case DS1343_TRICKLE_4K: | |
198 | resistors = "4k Ohm"; | |
199 | break; | |
200 | ||
201 | default: | |
202 | diodes = "disabled"; | |
203 | break; | |
204 | } | |
205 | } | |
206 | ||
207 | return sprintf(buf, "%s %s\n", diodes, resistors); | |
208 | } | |
209 | ||
210 | static DEVICE_ATTR(trickle_charger, S_IRUGO, ds1343_show_tricklecharger, NULL); | |
211 | ||
212 | static int ds1343_sysfs_register(struct device *dev) | |
213 | { | |
214 | int err; | |
215 | ||
216 | err = device_create_file(dev, &dev_attr_glitch_filter); | |
217 | if (err) | |
218 | return err; | |
219 | ||
10b06b87 | 220 | err = device_create_file(dev, &dev_attr_trickle_charger); |
1d6316f5 | 221 | if (!err) |
ab392864 | 222 | return 0; |
1d6316f5 | 223 | |
1d6316f5 RG |
224 | device_remove_file(dev, &dev_attr_glitch_filter); |
225 | ||
226 | return err; | |
227 | } | |
228 | ||
229 | static void ds1343_sysfs_unregister(struct device *dev) | |
230 | { | |
231 | device_remove_file(dev, &dev_attr_glitch_filter); | |
10b06b87 | 232 | device_remove_file(dev, &dev_attr_trickle_charger); |
1d6316f5 RG |
233 | } |
234 | ||
235 | static int ds1343_read_time(struct device *dev, struct rtc_time *dt) | |
236 | { | |
237 | struct ds1343_priv *priv = dev_get_drvdata(dev); | |
238 | unsigned char buf[7]; | |
239 | int res; | |
240 | ||
241 | res = regmap_bulk_read(priv->map, DS1343_SECONDS_REG, buf, 7); | |
242 | if (res) | |
243 | return res; | |
244 | ||
245 | dt->tm_sec = bcd2bin(buf[0]); | |
246 | dt->tm_min = bcd2bin(buf[1]); | |
247 | dt->tm_hour = bcd2bin(buf[2] & 0x3F); | |
248 | dt->tm_wday = bcd2bin(buf[3]) - 1; | |
249 | dt->tm_mday = bcd2bin(buf[4]); | |
250 | dt->tm_mon = bcd2bin(buf[5] & 0x1F) - 1; | |
251 | dt->tm_year = bcd2bin(buf[6]) + 100; /* year offset from 1900 */ | |
252 | ||
22652ba7 | 253 | return 0; |
1d6316f5 RG |
254 | } |
255 | ||
256 | static int ds1343_set_time(struct device *dev, struct rtc_time *dt) | |
257 | { | |
258 | struct ds1343_priv *priv = dev_get_drvdata(dev); | |
259 | int res; | |
260 | ||
261 | res = regmap_write(priv->map, DS1343_SECONDS_REG, | |
262 | bin2bcd(dt->tm_sec)); | |
263 | if (res) | |
264 | return res; | |
265 | ||
266 | res = regmap_write(priv->map, DS1343_MINUTES_REG, | |
267 | bin2bcd(dt->tm_min)); | |
268 | if (res) | |
269 | return res; | |
270 | ||
271 | res = regmap_write(priv->map, DS1343_HOURS_REG, | |
272 | bin2bcd(dt->tm_hour) & 0x3F); | |
273 | if (res) | |
274 | return res; | |
275 | ||
276 | res = regmap_write(priv->map, DS1343_DAY_REG, | |
277 | bin2bcd(dt->tm_wday + 1)); | |
278 | if (res) | |
279 | return res; | |
280 | ||
281 | res = regmap_write(priv->map, DS1343_DATE_REG, | |
282 | bin2bcd(dt->tm_mday)); | |
283 | if (res) | |
284 | return res; | |
285 | ||
286 | res = regmap_write(priv->map, DS1343_MONTH_REG, | |
287 | bin2bcd(dt->tm_mon + 1)); | |
288 | if (res) | |
289 | return res; | |
290 | ||
291 | dt->tm_year %= 100; | |
292 | ||
293 | res = regmap_write(priv->map, DS1343_YEAR_REG, | |
294 | bin2bcd(dt->tm_year)); | |
295 | if (res) | |
296 | return res; | |
297 | ||
298 | return 0; | |
299 | } | |
300 | ||
301 | static int ds1343_update_alarm(struct device *dev) | |
302 | { | |
303 | struct ds1343_priv *priv = dev_get_drvdata(dev); | |
304 | unsigned int control, stat; | |
305 | unsigned char buf[4]; | |
306 | int res = 0; | |
307 | ||
308 | res = regmap_read(priv->map, DS1343_CONTROL_REG, &control); | |
309 | if (res) | |
310 | return res; | |
311 | ||
312 | res = regmap_read(priv->map, DS1343_STATUS_REG, &stat); | |
313 | if (res) | |
314 | return res; | |
315 | ||
316 | control &= ~(DS1343_A0IE); | |
317 | stat &= ~(DS1343_IRQF0); | |
318 | ||
319 | res = regmap_write(priv->map, DS1343_CONTROL_REG, control); | |
320 | if (res) | |
321 | return res; | |
322 | ||
323 | res = regmap_write(priv->map, DS1343_STATUS_REG, stat); | |
324 | if (res) | |
325 | return res; | |
326 | ||
327 | buf[0] = priv->alarm_sec < 0 || (priv->irqen & RTC_UF) ? | |
328 | 0x80 : bin2bcd(priv->alarm_sec) & 0x7F; | |
329 | buf[1] = priv->alarm_min < 0 || (priv->irqen & RTC_UF) ? | |
330 | 0x80 : bin2bcd(priv->alarm_min) & 0x7F; | |
331 | buf[2] = priv->alarm_hour < 0 || (priv->irqen & RTC_UF) ? | |
332 | 0x80 : bin2bcd(priv->alarm_hour) & 0x3F; | |
333 | buf[3] = priv->alarm_mday < 0 || (priv->irqen & RTC_UF) ? | |
334 | 0x80 : bin2bcd(priv->alarm_mday) & 0x7F; | |
335 | ||
336 | res = regmap_bulk_write(priv->map, DS1343_ALM0_SEC_REG, buf, 4); | |
337 | if (res) | |
338 | return res; | |
339 | ||
340 | if (priv->irqen) { | |
341 | control |= DS1343_A0IE; | |
342 | res = regmap_write(priv->map, DS1343_CONTROL_REG, control); | |
343 | } | |
344 | ||
345 | return res; | |
346 | } | |
347 | ||
348 | static int ds1343_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) | |
349 | { | |
350 | struct ds1343_priv *priv = dev_get_drvdata(dev); | |
1d6316f5 RG |
351 | int res = 0; |
352 | unsigned int stat; | |
353 | ||
10b06b87 | 354 | if (priv->irq <= 0) |
1d6316f5 RG |
355 | return -EINVAL; |
356 | ||
357 | mutex_lock(&priv->mutex); | |
358 | ||
359 | res = regmap_read(priv->map, DS1343_STATUS_REG, &stat); | |
360 | if (res) | |
361 | goto out; | |
362 | ||
363 | alarm->enabled = !!(priv->irqen & RTC_AF); | |
364 | alarm->pending = !!(stat & DS1343_IRQF0); | |
365 | ||
366 | alarm->time.tm_sec = priv->alarm_sec < 0 ? 0 : priv->alarm_sec; | |
367 | alarm->time.tm_min = priv->alarm_min < 0 ? 0 : priv->alarm_min; | |
368 | alarm->time.tm_hour = priv->alarm_hour < 0 ? 0 : priv->alarm_hour; | |
369 | alarm->time.tm_mday = priv->alarm_mday < 0 ? 0 : priv->alarm_mday; | |
370 | ||
1d6316f5 RG |
371 | out: |
372 | mutex_unlock(&priv->mutex); | |
373 | return res; | |
374 | } | |
375 | ||
376 | static int ds1343_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) | |
377 | { | |
378 | struct ds1343_priv *priv = dev_get_drvdata(dev); | |
1d6316f5 RG |
379 | int res = 0; |
380 | ||
10b06b87 | 381 | if (priv->irq <= 0) |
1d6316f5 RG |
382 | return -EINVAL; |
383 | ||
384 | mutex_lock(&priv->mutex); | |
385 | ||
386 | priv->alarm_sec = alarm->time.tm_sec; | |
387 | priv->alarm_min = alarm->time.tm_min; | |
388 | priv->alarm_hour = alarm->time.tm_hour; | |
389 | priv->alarm_mday = alarm->time.tm_mday; | |
390 | ||
391 | if (alarm->enabled) | |
392 | priv->irqen |= RTC_AF; | |
393 | ||
394 | res = ds1343_update_alarm(dev); | |
395 | ||
396 | mutex_unlock(&priv->mutex); | |
397 | ||
398 | return res; | |
399 | } | |
400 | ||
401 | static int ds1343_alarm_irq_enable(struct device *dev, unsigned int enabled) | |
402 | { | |
403 | struct ds1343_priv *priv = dev_get_drvdata(dev); | |
1d6316f5 RG |
404 | int res = 0; |
405 | ||
10b06b87 | 406 | if (priv->irq <= 0) |
1d6316f5 RG |
407 | return -EINVAL; |
408 | ||
409 | mutex_lock(&priv->mutex); | |
410 | ||
411 | if (enabled) | |
412 | priv->irqen |= RTC_AF; | |
413 | else | |
414 | priv->irqen &= ~RTC_AF; | |
415 | ||
416 | res = ds1343_update_alarm(dev); | |
417 | ||
418 | mutex_unlock(&priv->mutex); | |
419 | ||
420 | return res; | |
421 | } | |
422 | ||
423 | static irqreturn_t ds1343_thread(int irq, void *dev_id) | |
424 | { | |
425 | struct ds1343_priv *priv = dev_id; | |
426 | unsigned int stat, control; | |
427 | int res = 0; | |
428 | ||
429 | mutex_lock(&priv->mutex); | |
430 | ||
431 | res = regmap_read(priv->map, DS1343_STATUS_REG, &stat); | |
432 | if (res) | |
433 | goto out; | |
434 | ||
435 | if (stat & DS1343_IRQF0) { | |
436 | stat &= ~DS1343_IRQF0; | |
437 | regmap_write(priv->map, DS1343_STATUS_REG, stat); | |
438 | ||
439 | res = regmap_read(priv->map, DS1343_CONTROL_REG, &control); | |
440 | if (res) | |
441 | goto out; | |
442 | ||
443 | control &= ~DS1343_A0IE; | |
444 | regmap_write(priv->map, DS1343_CONTROL_REG, control); | |
445 | ||
446 | rtc_update_irq(priv->rtc, 1, RTC_AF | RTC_IRQF); | |
447 | } | |
448 | ||
449 | out: | |
450 | mutex_unlock(&priv->mutex); | |
451 | return IRQ_HANDLED; | |
452 | } | |
453 | ||
454 | static const struct rtc_class_ops ds1343_rtc_ops = { | |
455 | .ioctl = ds1343_ioctl, | |
456 | .read_time = ds1343_read_time, | |
457 | .set_time = ds1343_set_time, | |
458 | .read_alarm = ds1343_read_alarm, | |
459 | .set_alarm = ds1343_set_alarm, | |
460 | .alarm_irq_enable = ds1343_alarm_irq_enable, | |
461 | }; | |
462 | ||
463 | static int ds1343_probe(struct spi_device *spi) | |
464 | { | |
465 | struct ds1343_priv *priv; | |
b5086150 AB |
466 | struct regmap_config config = { .reg_bits = 8, .val_bits = 8, |
467 | .write_flag_mask = 0x80, }; | |
1d6316f5 RG |
468 | unsigned int data; |
469 | int res; | |
d7501f70 AB |
470 | struct nvmem_config nvmem_cfg = { |
471 | .name = "ds1343-", | |
472 | .word_size = 1, | |
473 | .stride = 1, | |
474 | .size = DS1343_NVRAM_LEN, | |
475 | .reg_read = ds1343_nvram_read, | |
476 | .reg_write = ds1343_nvram_write, | |
477 | }; | |
1d6316f5 | 478 | |
1d6316f5 RG |
479 | priv = devm_kzalloc(&spi->dev, sizeof(struct ds1343_priv), GFP_KERNEL); |
480 | if (!priv) | |
481 | return -ENOMEM; | |
482 | ||
483 | priv->spi = spi; | |
484 | mutex_init(&priv->mutex); | |
485 | ||
486 | /* RTC DS1347 works in spi mode 3 and | |
487 | * its chip select is active high | |
488 | */ | |
489 | spi->mode = SPI_MODE_3 | SPI_CS_HIGH; | |
490 | spi->bits_per_word = 8; | |
491 | res = spi_setup(spi); | |
492 | if (res) | |
493 | return res; | |
494 | ||
495 | spi_set_drvdata(spi, priv); | |
496 | ||
497 | priv->map = devm_regmap_init_spi(spi, &config); | |
498 | ||
499 | if (IS_ERR(priv->map)) { | |
500 | dev_err(&spi->dev, "spi regmap init failed for rtc ds1343\n"); | |
501 | return PTR_ERR(priv->map); | |
502 | } | |
503 | ||
504 | res = regmap_read(priv->map, DS1343_SECONDS_REG, &data); | |
505 | if (res) | |
506 | return res; | |
507 | ||
508 | regmap_read(priv->map, DS1343_CONTROL_REG, &data); | |
509 | data |= DS1343_INTCN; | |
510 | data &= ~(DS1343_EOSC | DS1343_A1IE | DS1343_A0IE); | |
511 | regmap_write(priv->map, DS1343_CONTROL_REG, data); | |
512 | ||
513 | regmap_read(priv->map, DS1343_STATUS_REG, &data); | |
514 | data &= ~(DS1343_OSF | DS1343_IRQF1 | DS1343_IRQF0); | |
515 | regmap_write(priv->map, DS1343_STATUS_REG, data); | |
516 | ||
1536f6dc AB |
517 | priv->rtc = devm_rtc_allocate_device(&spi->dev); |
518 | if (IS_ERR(priv->rtc)) | |
1d6316f5 | 519 | return PTR_ERR(priv->rtc); |
1536f6dc | 520 | |
d7501f70 | 521 | priv->rtc->nvram_old_abi = true; |
1536f6dc AB |
522 | priv->rtc->ops = &ds1343_rtc_ops; |
523 | ||
524 | res = rtc_register_device(priv->rtc); | |
525 | if (res) | |
526 | return res; | |
1d6316f5 | 527 | |
d7501f70 AB |
528 | nvmem_cfg.priv = priv; |
529 | rtc_nvmem_register(priv->rtc, &nvmem_cfg); | |
530 | ||
10b06b87 RG |
531 | priv->irq = spi->irq; |
532 | ||
533 | if (priv->irq >= 0) { | |
1d6316f5 | 534 | res = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, |
caff0cc4 | 535 | ds1343_thread, IRQF_ONESHOT, |
1d6316f5 RG |
536 | "ds1343", priv); |
537 | if (res) { | |
10b06b87 | 538 | priv->irq = -1; |
1d6316f5 RG |
539 | dev_err(&spi->dev, |
540 | "unable to request irq for rtc ds1343\n"); | |
10b06b87 | 541 | } else { |
caff0cc4 SH |
542 | device_init_wakeup(&spi->dev, true); |
543 | dev_pm_set_wake_irq(&spi->dev, spi->irq); | |
1d6316f5 | 544 | } |
1d6316f5 RG |
545 | } |
546 | ||
547 | res = ds1343_sysfs_register(&spi->dev); | |
548 | if (res) | |
549 | dev_err(&spi->dev, | |
550 | "unable to create sysfs entries for rtc ds1343\n"); | |
551 | ||
552 | return 0; | |
553 | } | |
554 | ||
555 | static int ds1343_remove(struct spi_device *spi) | |
556 | { | |
557 | struct ds1343_priv *priv = spi_get_drvdata(spi); | |
558 | ||
559 | if (spi->irq) { | |
560 | mutex_lock(&priv->mutex); | |
561 | priv->irqen &= ~RTC_AF; | |
562 | mutex_unlock(&priv->mutex); | |
563 | ||
caff0cc4 SH |
564 | dev_pm_clear_wake_irq(&spi->dev); |
565 | device_init_wakeup(&spi->dev, false); | |
1d6316f5 RG |
566 | devm_free_irq(&spi->dev, spi->irq, priv); |
567 | } | |
568 | ||
569 | spi_set_drvdata(spi, NULL); | |
570 | ||
571 | ds1343_sysfs_unregister(&spi->dev); | |
572 | ||
573 | return 0; | |
574 | } | |
575 | ||
576 | #ifdef CONFIG_PM_SLEEP | |
577 | ||
578 | static int ds1343_suspend(struct device *dev) | |
579 | { | |
580 | struct spi_device *spi = to_spi_device(dev); | |
581 | ||
582 | if (spi->irq >= 0 && device_may_wakeup(dev)) | |
583 | enable_irq_wake(spi->irq); | |
584 | ||
585 | return 0; | |
586 | } | |
587 | ||
588 | static int ds1343_resume(struct device *dev) | |
589 | { | |
590 | struct spi_device *spi = to_spi_device(dev); | |
591 | ||
592 | if (spi->irq >= 0 && device_may_wakeup(dev)) | |
593 | disable_irq_wake(spi->irq); | |
594 | ||
595 | return 0; | |
596 | } | |
597 | ||
598 | #endif | |
599 | ||
600 | static SIMPLE_DEV_PM_OPS(ds1343_pm, ds1343_suspend, ds1343_resume); | |
601 | ||
602 | static struct spi_driver ds1343_driver = { | |
603 | .driver = { | |
604 | .name = "ds1343", | |
1d6316f5 RG |
605 | .pm = &ds1343_pm, |
606 | }, | |
607 | .probe = ds1343_probe, | |
608 | .remove = ds1343_remove, | |
609 | .id_table = ds1343_id, | |
610 | }; | |
611 | ||
612 | module_spi_driver(ds1343_driver); | |
613 | ||
614 | MODULE_DESCRIPTION("DS1343 RTC SPI Driver"); | |
571eb883 RG |
615 | MODULE_AUTHOR("Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com>," |
616 | "Ankur Srivastava <sankurece@gmail.com>"); | |
1d6316f5 | 617 | MODULE_LICENSE("GPL v2"); |