Commit | Line | Data |
---|---|---|
fca1dd03 | 1 | /* |
f903129b | 2 | * RTC driver for Maxim MAX77686 and MAX77802 |
fca1dd03 JL |
3 | * |
4 | * Copyright (C) 2012 Samsung Electronics Co.Ltd | |
5 | * | |
6 | * based on rtc-max8997.c | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify it | |
9 | * under the terms of the GNU General Public License as published by the | |
10 | * Free Software Foundation; either version 2 of the License, or (at your | |
11 | * option) any later version. | |
12 | * | |
13 | */ | |
14 | ||
15 | #include <linux/slab.h> | |
16 | #include <linux/rtc.h> | |
17 | #include <linux/delay.h> | |
18 | #include <linux/mutex.h> | |
19 | #include <linux/module.h> | |
20 | #include <linux/platform_device.h> | |
21 | #include <linux/mfd/max77686-private.h> | |
22 | #include <linux/irqdomain.h> | |
23 | #include <linux/regmap.h> | |
24 | ||
25 | /* RTC Control Register */ | |
26 | #define BCD_EN_SHIFT 0 | |
0b4f8b08 | 27 | #define BCD_EN_MASK BIT(BCD_EN_SHIFT) |
fca1dd03 | 28 | #define MODEL24_SHIFT 1 |
0b4f8b08 | 29 | #define MODEL24_MASK BIT(MODEL24_SHIFT) |
fca1dd03 JL |
30 | /* RTC Update Register1 */ |
31 | #define RTC_UDR_SHIFT 0 | |
0b4f8b08 | 32 | #define RTC_UDR_MASK BIT(RTC_UDR_SHIFT) |
fca1dd03 | 33 | #define RTC_RBUDR_SHIFT 4 |
0b4f8b08 | 34 | #define RTC_RBUDR_MASK BIT(RTC_RBUDR_SHIFT) |
fca1dd03 JL |
35 | /* RTC Hour register */ |
36 | #define HOUR_PM_SHIFT 6 | |
0b4f8b08 | 37 | #define HOUR_PM_MASK BIT(HOUR_PM_SHIFT) |
fca1dd03 JL |
38 | /* RTC Alarm Enable */ |
39 | #define ALARM_ENABLE_SHIFT 7 | |
0b4f8b08 | 40 | #define ALARM_ENABLE_MASK BIT(ALARM_ENABLE_SHIFT) |
fca1dd03 | 41 | |
f903129b JMC |
42 | #define REG_RTC_NONE 0xdeadbeef |
43 | ||
44 | /* | |
45 | * MAX77802 has separate register (RTCAE1) for alarm enable instead | |
46 | * using 1 bit from registers RTC{SEC,MIN,HOUR,DAY,MONTH,YEAR,DATE} | |
47 | * as in done in MAX77686. | |
48 | */ | |
49 | #define MAX77802_ALARM_ENABLE_VALUE 0x77 | |
50 | ||
fca1dd03 JL |
51 | enum { |
52 | RTC_SEC = 0, | |
53 | RTC_MIN, | |
54 | RTC_HOUR, | |
55 | RTC_WEEKDAY, | |
56 | RTC_MONTH, | |
57 | RTC_YEAR, | |
58 | RTC_DATE, | |
59 | RTC_NR_TIME | |
60 | }; | |
61 | ||
01ea01b3 JMC |
62 | struct max77686_rtc_driver_data { |
63 | /* Minimum usecs needed for a RTC update */ | |
64 | unsigned long delay; | |
65 | /* Mask used to read RTC registers value */ | |
66 | u8 mask; | |
90a5698a JMC |
67 | /* Registers offset to I2C addresses map */ |
68 | const unsigned int *map; | |
f903129b JMC |
69 | /* Has a separate alarm enable register? */ |
70 | bool alarm_enable_reg; | |
71 | /* Has a separate I2C regmap for the RTC? */ | |
72 | bool separate_i2c_addr; | |
01ea01b3 JMC |
73 | }; |
74 | ||
fca1dd03 JL |
75 | struct max77686_rtc_info { |
76 | struct device *dev; | |
77 | struct max77686_dev *max77686; | |
78 | struct i2c_client *rtc; | |
79 | struct rtc_device *rtc_dev; | |
80 | struct mutex lock; | |
81 | ||
82 | struct regmap *regmap; | |
83 | ||
01ea01b3 JMC |
84 | const struct max77686_rtc_driver_data *drv_data; |
85 | ||
fca1dd03 JL |
86 | int virq; |
87 | int rtc_24hr_mode; | |
88 | }; | |
89 | ||
90 | enum MAX77686_RTC_OP { | |
91 | MAX77686_RTC_WRITE, | |
92 | MAX77686_RTC_READ, | |
93 | }; | |
94 | ||
90a5698a JMC |
95 | /* These are not registers but just offsets that are mapped to addresses */ |
96 | enum max77686_rtc_reg_offset { | |
97 | REG_RTC_CONTROLM = 0, | |
98 | REG_RTC_CONTROL, | |
99 | REG_RTC_UPDATE0, | |
100 | REG_WTSR_SMPL_CNTL, | |
101 | REG_RTC_SEC, | |
102 | REG_RTC_MIN, | |
103 | REG_RTC_HOUR, | |
104 | REG_RTC_WEEKDAY, | |
105 | REG_RTC_MONTH, | |
106 | REG_RTC_YEAR, | |
107 | REG_RTC_DATE, | |
108 | REG_ALARM1_SEC, | |
109 | REG_ALARM1_MIN, | |
110 | REG_ALARM1_HOUR, | |
111 | REG_ALARM1_WEEKDAY, | |
112 | REG_ALARM1_MONTH, | |
113 | REG_ALARM1_YEAR, | |
114 | REG_ALARM1_DATE, | |
115 | REG_ALARM2_SEC, | |
116 | REG_ALARM2_MIN, | |
117 | REG_ALARM2_HOUR, | |
118 | REG_ALARM2_WEEKDAY, | |
119 | REG_ALARM2_MONTH, | |
120 | REG_ALARM2_YEAR, | |
121 | REG_ALARM2_DATE, | |
f903129b | 122 | REG_RTC_AE1, |
90a5698a JMC |
123 | REG_RTC_END, |
124 | }; | |
125 | ||
126 | /* Maps RTC registers offset to the MAX77686 register addresses */ | |
127 | static const unsigned int max77686_map[REG_RTC_END] = { | |
128 | [REG_RTC_CONTROLM] = MAX77686_RTC_CONTROLM, | |
129 | [REG_RTC_CONTROL] = MAX77686_RTC_CONTROL, | |
130 | [REG_RTC_UPDATE0] = MAX77686_RTC_UPDATE0, | |
131 | [REG_WTSR_SMPL_CNTL] = MAX77686_WTSR_SMPL_CNTL, | |
132 | [REG_RTC_SEC] = MAX77686_RTC_SEC, | |
133 | [REG_RTC_MIN] = MAX77686_RTC_MIN, | |
134 | [REG_RTC_HOUR] = MAX77686_RTC_HOUR, | |
135 | [REG_RTC_WEEKDAY] = MAX77686_RTC_WEEKDAY, | |
136 | [REG_RTC_MONTH] = MAX77686_RTC_MONTH, | |
137 | [REG_RTC_YEAR] = MAX77686_RTC_YEAR, | |
138 | [REG_RTC_DATE] = MAX77686_RTC_DATE, | |
139 | [REG_ALARM1_SEC] = MAX77686_ALARM1_SEC, | |
140 | [REG_ALARM1_MIN] = MAX77686_ALARM1_MIN, | |
141 | [REG_ALARM1_HOUR] = MAX77686_ALARM1_HOUR, | |
142 | [REG_ALARM1_WEEKDAY] = MAX77686_ALARM1_WEEKDAY, | |
143 | [REG_ALARM1_MONTH] = MAX77686_ALARM1_MONTH, | |
144 | [REG_ALARM1_YEAR] = MAX77686_ALARM1_YEAR, | |
145 | [REG_ALARM1_DATE] = MAX77686_ALARM1_DATE, | |
146 | [REG_ALARM2_SEC] = MAX77686_ALARM2_SEC, | |
147 | [REG_ALARM2_MIN] = MAX77686_ALARM2_MIN, | |
148 | [REG_ALARM2_HOUR] = MAX77686_ALARM2_HOUR, | |
149 | [REG_ALARM2_WEEKDAY] = MAX77686_ALARM2_WEEKDAY, | |
150 | [REG_ALARM2_MONTH] = MAX77686_ALARM2_MONTH, | |
151 | [REG_ALARM2_YEAR] = MAX77686_ALARM2_YEAR, | |
152 | [REG_ALARM2_DATE] = MAX77686_ALARM2_DATE, | |
f903129b | 153 | [REG_RTC_AE1] = REG_RTC_NONE, |
90a5698a JMC |
154 | }; |
155 | ||
01ea01b3 JMC |
156 | static const struct max77686_rtc_driver_data max77686_drv_data = { |
157 | .delay = 16000, | |
158 | .mask = 0x7f, | |
90a5698a | 159 | .map = max77686_map, |
f903129b JMC |
160 | .alarm_enable_reg = false, |
161 | .separate_i2c_addr = true, | |
162 | }; | |
163 | ||
164 | static const unsigned int max77802_map[REG_RTC_END] = { | |
165 | [REG_RTC_CONTROLM] = MAX77802_RTC_CONTROLM, | |
166 | [REG_RTC_CONTROL] = MAX77802_RTC_CONTROL, | |
167 | [REG_RTC_UPDATE0] = MAX77802_RTC_UPDATE0, | |
168 | [REG_WTSR_SMPL_CNTL] = MAX77802_WTSR_SMPL_CNTL, | |
169 | [REG_RTC_SEC] = MAX77802_RTC_SEC, | |
170 | [REG_RTC_MIN] = MAX77802_RTC_MIN, | |
171 | [REG_RTC_HOUR] = MAX77802_RTC_HOUR, | |
172 | [REG_RTC_WEEKDAY] = MAX77802_RTC_WEEKDAY, | |
173 | [REG_RTC_MONTH] = MAX77802_RTC_MONTH, | |
174 | [REG_RTC_YEAR] = MAX77802_RTC_YEAR, | |
175 | [REG_RTC_DATE] = MAX77802_RTC_DATE, | |
176 | [REG_ALARM1_SEC] = MAX77802_ALARM1_SEC, | |
177 | [REG_ALARM1_MIN] = MAX77802_ALARM1_MIN, | |
178 | [REG_ALARM1_HOUR] = MAX77802_ALARM1_HOUR, | |
179 | [REG_ALARM1_WEEKDAY] = MAX77802_ALARM1_WEEKDAY, | |
180 | [REG_ALARM1_MONTH] = MAX77802_ALARM1_MONTH, | |
181 | [REG_ALARM1_YEAR] = MAX77802_ALARM1_YEAR, | |
182 | [REG_ALARM1_DATE] = MAX77802_ALARM1_DATE, | |
183 | [REG_ALARM2_SEC] = MAX77802_ALARM2_SEC, | |
184 | [REG_ALARM2_MIN] = MAX77802_ALARM2_MIN, | |
185 | [REG_ALARM2_HOUR] = MAX77802_ALARM2_HOUR, | |
186 | [REG_ALARM2_WEEKDAY] = MAX77802_ALARM2_WEEKDAY, | |
187 | [REG_ALARM2_MONTH] = MAX77802_ALARM2_MONTH, | |
188 | [REG_ALARM2_YEAR] = MAX77802_ALARM2_YEAR, | |
189 | [REG_ALARM2_DATE] = MAX77802_ALARM2_DATE, | |
190 | [REG_RTC_AE1] = MAX77802_RTC_AE1, | |
191 | }; | |
192 | ||
193 | static const struct max77686_rtc_driver_data max77802_drv_data = { | |
194 | .delay = 200, | |
195 | .mask = 0xff, | |
196 | .map = max77802_map, | |
197 | .alarm_enable_reg = true, | |
198 | .separate_i2c_addr = false, | |
01ea01b3 JMC |
199 | }; |
200 | ||
fca1dd03 | 201 | static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm, |
01ea01b3 | 202 | struct max77686_rtc_info *info) |
fca1dd03 | 203 | { |
01ea01b3 JMC |
204 | u8 mask = info->drv_data->mask; |
205 | ||
206 | tm->tm_sec = data[RTC_SEC] & mask; | |
207 | tm->tm_min = data[RTC_MIN] & mask; | |
0b4f8b08 | 208 | if (info->rtc_24hr_mode) { |
fca1dd03 | 209 | tm->tm_hour = data[RTC_HOUR] & 0x1f; |
0b4f8b08 | 210 | } else { |
fca1dd03 JL |
211 | tm->tm_hour = data[RTC_HOUR] & 0x0f; |
212 | if (data[RTC_HOUR] & HOUR_PM_MASK) | |
213 | tm->tm_hour += 12; | |
214 | } | |
215 | ||
a20cd88e | 216 | /* Only a single bit is set in data[], so fls() would be equivalent */ |
01ea01b3 | 217 | tm->tm_wday = ffs(data[RTC_WEEKDAY] & mask) - 1; |
fca1dd03 JL |
218 | tm->tm_mday = data[RTC_DATE] & 0x1f; |
219 | tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; | |
f903129b | 220 | tm->tm_year = data[RTC_YEAR] & mask; |
fca1dd03 JL |
221 | tm->tm_yday = 0; |
222 | tm->tm_isdst = 0; | |
f903129b JMC |
223 | |
224 | /* | |
225 | * MAX77686 uses 1 bit from sec/min/hour/etc RTC registers and the | |
226 | * year values are just 0..99 so add 100 to support up to 2099. | |
227 | */ | |
228 | if (!info->drv_data->alarm_enable_reg) | |
229 | tm->tm_year += 100; | |
fca1dd03 JL |
230 | } |
231 | ||
f903129b JMC |
232 | static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data, |
233 | struct max77686_rtc_info *info) | |
fca1dd03 JL |
234 | { |
235 | data[RTC_SEC] = tm->tm_sec; | |
236 | data[RTC_MIN] = tm->tm_min; | |
237 | data[RTC_HOUR] = tm->tm_hour; | |
238 | data[RTC_WEEKDAY] = 1 << tm->tm_wday; | |
239 | data[RTC_DATE] = tm->tm_mday; | |
240 | data[RTC_MONTH] = tm->tm_mon + 1; | |
f903129b JMC |
241 | |
242 | if (info->drv_data->alarm_enable_reg) { | |
243 | data[RTC_YEAR] = tm->tm_year; | |
244 | return 0; | |
245 | } | |
246 | ||
cdf5f4ac | 247 | data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0; |
fca1dd03 JL |
248 | |
249 | if (tm->tm_year < 100) { | |
1e5813bd | 250 | dev_err(info->dev, "RTC cannot handle the year %d.\n", |
a737e835 | 251 | 1900 + tm->tm_year); |
fca1dd03 JL |
252 | return -EINVAL; |
253 | } | |
f903129b | 254 | |
fca1dd03 JL |
255 | return 0; |
256 | } | |
257 | ||
258 | static int max77686_rtc_update(struct max77686_rtc_info *info, | |
0b4f8b08 | 259 | enum MAX77686_RTC_OP op) |
fca1dd03 JL |
260 | { |
261 | int ret; | |
262 | unsigned int data; | |
01ea01b3 | 263 | unsigned long delay = info->drv_data->delay; |
fca1dd03 JL |
264 | |
265 | if (op == MAX77686_RTC_WRITE) | |
266 | data = 1 << RTC_UDR_SHIFT; | |
267 | else | |
268 | data = 1 << RTC_RBUDR_SHIFT; | |
269 | ||
270 | ret = regmap_update_bits(info->max77686->rtc_regmap, | |
90a5698a JMC |
271 | info->drv_data->map[REG_RTC_UPDATE0], |
272 | data, data); | |
fca1dd03 | 273 | if (ret < 0) |
bf035f42 KK |
274 | dev_err(info->dev, "Fail to write update reg(ret=%d, data=0x%x)\n", |
275 | ret, data); | |
fca1dd03 | 276 | else { |
01ea01b3 JMC |
277 | /* Minimum delay required before RTC update. */ |
278 | usleep_range(delay, delay * 2); | |
fca1dd03 JL |
279 | } |
280 | ||
281 | return ret; | |
282 | } | |
283 | ||
284 | static int max77686_rtc_read_time(struct device *dev, struct rtc_time *tm) | |
285 | { | |
286 | struct max77686_rtc_info *info = dev_get_drvdata(dev); | |
287 | u8 data[RTC_NR_TIME]; | |
288 | int ret; | |
289 | ||
290 | mutex_lock(&info->lock); | |
291 | ||
292 | ret = max77686_rtc_update(info, MAX77686_RTC_READ); | |
293 | if (ret < 0) | |
294 | goto out; | |
295 | ||
296 | ret = regmap_bulk_read(info->max77686->rtc_regmap, | |
90a5698a JMC |
297 | info->drv_data->map[REG_RTC_SEC], |
298 | data, ARRAY_SIZE(data)); | |
fca1dd03 | 299 | if (ret < 0) { |
bf035f42 | 300 | dev_err(info->dev, "Fail to read time reg(%d)\n", ret); |
fca1dd03 JL |
301 | goto out; |
302 | } | |
303 | ||
01ea01b3 | 304 | max77686_rtc_data_to_tm(data, tm, info); |
fca1dd03 JL |
305 | |
306 | ret = rtc_valid_tm(tm); | |
307 | ||
308 | out: | |
309 | mutex_unlock(&info->lock); | |
310 | return ret; | |
311 | } | |
312 | ||
313 | static int max77686_rtc_set_time(struct device *dev, struct rtc_time *tm) | |
314 | { | |
315 | struct max77686_rtc_info *info = dev_get_drvdata(dev); | |
316 | u8 data[RTC_NR_TIME]; | |
317 | int ret; | |
318 | ||
f903129b | 319 | ret = max77686_rtc_tm_to_data(tm, data, info); |
fca1dd03 JL |
320 | if (ret < 0) |
321 | return ret; | |
322 | ||
323 | mutex_lock(&info->lock); | |
324 | ||
325 | ret = regmap_bulk_write(info->max77686->rtc_regmap, | |
90a5698a JMC |
326 | info->drv_data->map[REG_RTC_SEC], |
327 | data, ARRAY_SIZE(data)); | |
fca1dd03 | 328 | if (ret < 0) { |
bf035f42 | 329 | dev_err(info->dev, "Fail to write time reg(%d)\n", ret); |
fca1dd03 JL |
330 | goto out; |
331 | } | |
332 | ||
333 | ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); | |
334 | ||
335 | out: | |
336 | mutex_unlock(&info->lock); | |
337 | return ret; | |
338 | } | |
339 | ||
340 | static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |
341 | { | |
342 | struct max77686_rtc_info *info = dev_get_drvdata(dev); | |
343 | u8 data[RTC_NR_TIME]; | |
344 | unsigned int val; | |
90a5698a | 345 | const unsigned int *map = info->drv_data->map; |
fca1dd03 JL |
346 | int i, ret; |
347 | ||
348 | mutex_lock(&info->lock); | |
349 | ||
350 | ret = max77686_rtc_update(info, MAX77686_RTC_READ); | |
351 | if (ret < 0) | |
352 | goto out; | |
353 | ||
354 | ret = regmap_bulk_read(info->max77686->rtc_regmap, | |
90a5698a | 355 | map[REG_ALARM1_SEC], data, ARRAY_SIZE(data)); |
fca1dd03 | 356 | if (ret < 0) { |
bf035f42 | 357 | dev_err(info->dev, "Fail to read alarm reg(%d)\n", ret); |
fca1dd03 JL |
358 | goto out; |
359 | } | |
360 | ||
01ea01b3 | 361 | max77686_rtc_data_to_tm(data, &alrm->time, info); |
fca1dd03 JL |
362 | |
363 | alrm->enabled = 0; | |
f903129b JMC |
364 | |
365 | if (info->drv_data->alarm_enable_reg) { | |
366 | if (map[REG_RTC_AE1] == REG_RTC_NONE) { | |
367 | ret = -EINVAL; | |
368 | dev_err(info->dev, | |
369 | "alarm enable register not set(%d)\n", ret); | |
370 | goto out; | |
371 | } | |
372 | ||
69be249a | 373 | ret = regmap_read(info->max77686->rtc_regmap, |
f903129b JMC |
374 | map[REG_RTC_AE1], &val); |
375 | if (ret < 0) { | |
376 | dev_err(info->dev, | |
377 | "fail to read alarm enable(%d)\n", ret); | |
378 | goto out; | |
379 | } | |
380 | ||
381 | if (val) | |
fca1dd03 | 382 | alrm->enabled = 1; |
f903129b JMC |
383 | } else { |
384 | for (i = 0; i < ARRAY_SIZE(data); i++) { | |
385 | if (data[i] & ALARM_ENABLE_MASK) { | |
386 | alrm->enabled = 1; | |
387 | break; | |
388 | } | |
fca1dd03 JL |
389 | } |
390 | } | |
391 | ||
392 | alrm->pending = 0; | |
1748cbf7 | 393 | ret = regmap_read(info->max77686->regmap, MAX77686_REG_STATUS2, &val); |
fca1dd03 | 394 | if (ret < 0) { |
bf035f42 | 395 | dev_err(info->dev, "Fail to read status2 reg(%d)\n", ret); |
fca1dd03 JL |
396 | goto out; |
397 | } | |
398 | ||
399 | if (val & (1 << 4)) /* RTCA1 */ | |
400 | alrm->pending = 1; | |
401 | ||
402 | out: | |
403 | mutex_unlock(&info->lock); | |
7cdffeb5 | 404 | return ret; |
fca1dd03 JL |
405 | } |
406 | ||
407 | static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info) | |
408 | { | |
409 | u8 data[RTC_NR_TIME]; | |
410 | int ret, i; | |
411 | struct rtc_time tm; | |
90a5698a | 412 | const unsigned int *map = info->drv_data->map; |
fca1dd03 JL |
413 | |
414 | if (!mutex_is_locked(&info->lock)) | |
415 | dev_warn(info->dev, "%s: should have mutex locked\n", __func__); | |
416 | ||
417 | ret = max77686_rtc_update(info, MAX77686_RTC_READ); | |
418 | if (ret < 0) | |
419 | goto out; | |
420 | ||
f903129b JMC |
421 | if (info->drv_data->alarm_enable_reg) { |
422 | if (map[REG_RTC_AE1] == REG_RTC_NONE) { | |
423 | ret = -EINVAL; | |
424 | dev_err(info->dev, | |
425 | "alarm enable register not set(%d)\n", ret); | |
426 | goto out; | |
427 | } | |
428 | ||
69be249a LD |
429 | ret = regmap_write(info->max77686->rtc_regmap, |
430 | map[REG_RTC_AE1], 0); | |
f903129b JMC |
431 | } else { |
432 | ret = regmap_bulk_read(info->max77686->rtc_regmap, | |
433 | map[REG_ALARM1_SEC], data, | |
434 | ARRAY_SIZE(data)); | |
435 | if (ret < 0) { | |
bf035f42 | 436 | dev_err(info->dev, "Fail to read alarm reg(%d)\n", ret); |
f903129b JMC |
437 | goto out; |
438 | } | |
fca1dd03 | 439 | |
f903129b | 440 | max77686_rtc_data_to_tm(data, &tm, info); |
fca1dd03 | 441 | |
f903129b JMC |
442 | for (i = 0; i < ARRAY_SIZE(data); i++) |
443 | data[i] &= ~ALARM_ENABLE_MASK; | |
444 | ||
445 | ret = regmap_bulk_write(info->max77686->rtc_regmap, | |
446 | map[REG_ALARM1_SEC], data, | |
447 | ARRAY_SIZE(data)); | |
448 | } | |
fca1dd03 | 449 | |
fca1dd03 | 450 | if (ret < 0) { |
bf035f42 | 451 | dev_err(info->dev, "Fail to write alarm reg(%d)\n", ret); |
fca1dd03 JL |
452 | goto out; |
453 | } | |
454 | ||
455 | ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); | |
456 | out: | |
457 | return ret; | |
458 | } | |
459 | ||
460 | static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) | |
461 | { | |
462 | u8 data[RTC_NR_TIME]; | |
463 | int ret; | |
464 | struct rtc_time tm; | |
90a5698a | 465 | const unsigned int *map = info->drv_data->map; |
fca1dd03 JL |
466 | |
467 | if (!mutex_is_locked(&info->lock)) | |
468 | dev_warn(info->dev, "%s: should have mutex locked\n", __func__); | |
469 | ||
470 | ret = max77686_rtc_update(info, MAX77686_RTC_READ); | |
471 | if (ret < 0) | |
472 | goto out; | |
473 | ||
f903129b | 474 | if (info->drv_data->alarm_enable_reg) { |
69be249a | 475 | ret = regmap_write(info->max77686->rtc_regmap, map[REG_RTC_AE1], |
f903129b JMC |
476 | MAX77802_ALARM_ENABLE_VALUE); |
477 | } else { | |
478 | ret = regmap_bulk_read(info->max77686->rtc_regmap, | |
479 | map[REG_ALARM1_SEC], data, | |
480 | ARRAY_SIZE(data)); | |
481 | if (ret < 0) { | |
bf035f42 | 482 | dev_err(info->dev, "Fail to read alarm reg(%d)\n", ret); |
f903129b JMC |
483 | goto out; |
484 | } | |
fca1dd03 | 485 | |
f903129b JMC |
486 | max77686_rtc_data_to_tm(data, &tm, info); |
487 | ||
488 | data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT); | |
489 | data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT); | |
490 | data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT); | |
491 | data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK; | |
492 | if (data[RTC_MONTH] & 0xf) | |
493 | data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT); | |
494 | if (data[RTC_YEAR] & info->drv_data->mask) | |
495 | data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT); | |
496 | if (data[RTC_DATE] & 0x1f) | |
497 | data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT); | |
498 | ||
499 | ret = regmap_bulk_write(info->max77686->rtc_regmap, | |
500 | map[REG_ALARM1_SEC], data, | |
501 | ARRAY_SIZE(data)); | |
502 | } | |
fca1dd03 | 503 | |
fca1dd03 | 504 | if (ret < 0) { |
bf035f42 | 505 | dev_err(info->dev, "Fail to write alarm reg(%d)\n", ret); |
fca1dd03 JL |
506 | goto out; |
507 | } | |
508 | ||
509 | ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); | |
510 | out: | |
511 | return ret; | |
512 | } | |
513 | ||
514 | static int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |
515 | { | |
516 | struct max77686_rtc_info *info = dev_get_drvdata(dev); | |
517 | u8 data[RTC_NR_TIME]; | |
518 | int ret; | |
519 | ||
f903129b | 520 | ret = max77686_rtc_tm_to_data(&alrm->time, data, info); |
fca1dd03 JL |
521 | if (ret < 0) |
522 | return ret; | |
523 | ||
524 | mutex_lock(&info->lock); | |
525 | ||
526 | ret = max77686_rtc_stop_alarm(info); | |
527 | if (ret < 0) | |
528 | goto out; | |
529 | ||
530 | ret = regmap_bulk_write(info->max77686->rtc_regmap, | |
90a5698a JMC |
531 | info->drv_data->map[REG_ALARM1_SEC], |
532 | data, ARRAY_SIZE(data)); | |
fca1dd03 JL |
533 | |
534 | if (ret < 0) { | |
bf035f42 | 535 | dev_err(info->dev, "Fail to write alarm reg(%d)\n", ret); |
fca1dd03 JL |
536 | goto out; |
537 | } | |
538 | ||
539 | ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); | |
540 | if (ret < 0) | |
541 | goto out; | |
542 | ||
543 | if (alrm->enabled) | |
544 | ret = max77686_rtc_start_alarm(info); | |
545 | out: | |
546 | mutex_unlock(&info->lock); | |
547 | return ret; | |
548 | } | |
549 | ||
550 | static int max77686_rtc_alarm_irq_enable(struct device *dev, | |
0b4f8b08 | 551 | unsigned int enabled) |
fca1dd03 JL |
552 | { |
553 | struct max77686_rtc_info *info = dev_get_drvdata(dev); | |
554 | int ret; | |
555 | ||
556 | mutex_lock(&info->lock); | |
557 | if (enabled) | |
558 | ret = max77686_rtc_start_alarm(info); | |
559 | else | |
560 | ret = max77686_rtc_stop_alarm(info); | |
561 | mutex_unlock(&info->lock); | |
562 | ||
563 | return ret; | |
564 | } | |
565 | ||
566 | static irqreturn_t max77686_rtc_alarm_irq(int irq, void *data) | |
567 | { | |
568 | struct max77686_rtc_info *info = data; | |
569 | ||
bf035f42 | 570 | dev_dbg(info->dev, "RTC alarm IRQ: %d\n", irq); |
fca1dd03 JL |
571 | |
572 | rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF); | |
573 | ||
574 | return IRQ_HANDLED; | |
575 | } | |
576 | ||
577 | static const struct rtc_class_ops max77686_rtc_ops = { | |
578 | .read_time = max77686_rtc_read_time, | |
579 | .set_time = max77686_rtc_set_time, | |
580 | .read_alarm = max77686_rtc_read_alarm, | |
581 | .set_alarm = max77686_rtc_set_alarm, | |
582 | .alarm_irq_enable = max77686_rtc_alarm_irq_enable, | |
583 | }; | |
584 | ||
fca1dd03 JL |
585 | static int max77686_rtc_init_reg(struct max77686_rtc_info *info) |
586 | { | |
587 | u8 data[2]; | |
588 | int ret; | |
589 | ||
590 | /* Set RTC control register : Binary mode, 24hour mdoe */ | |
591 | data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); | |
592 | data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); | |
593 | ||
594 | info->rtc_24hr_mode = 1; | |
595 | ||
862f9453 | 596 | ret = regmap_bulk_write(info->max77686->rtc_regmap, |
90a5698a JMC |
597 | info->drv_data->map[REG_RTC_CONTROLM], |
598 | data, ARRAY_SIZE(data)); | |
fca1dd03 | 599 | if (ret < 0) { |
bf035f42 | 600 | dev_err(info->dev, "Fail to write controlm reg(%d)\n", ret); |
fca1dd03 JL |
601 | return ret; |
602 | } | |
603 | ||
604 | ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); | |
605 | return ret; | |
606 | } | |
607 | ||
fca1dd03 JL |
608 | static int max77686_rtc_probe(struct platform_device *pdev) |
609 | { | |
610 | struct max77686_dev *max77686 = dev_get_drvdata(pdev->dev.parent); | |
611 | struct max77686_rtc_info *info; | |
01ea01b3 | 612 | const struct platform_device_id *id = platform_get_device_id(pdev); |
6f1c1e71 | 613 | int ret; |
fca1dd03 | 614 | |
0f64f853 | 615 | info = devm_kzalloc(&pdev->dev, sizeof(struct max77686_rtc_info), |
0b4f8b08 | 616 | GFP_KERNEL); |
fca1dd03 JL |
617 | if (!info) |
618 | return -ENOMEM; | |
619 | ||
620 | mutex_init(&info->lock); | |
621 | info->dev = &pdev->dev; | |
622 | info->max77686 = max77686; | |
623 | info->rtc = max77686->rtc; | |
01ea01b3 JMC |
624 | info->drv_data = (const struct max77686_rtc_driver_data *) |
625 | id->driver_data; | |
6f1c1e71 | 626 | |
f903129b JMC |
627 | if (!info->drv_data->separate_i2c_addr) |
628 | info->max77686->rtc_regmap = info->max77686->regmap; | |
629 | ||
fca1dd03 JL |
630 | platform_set_drvdata(pdev, info); |
631 | ||
632 | ret = max77686_rtc_init_reg(info); | |
633 | ||
634 | if (ret < 0) { | |
635 | dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret); | |
636 | goto err_rtc; | |
637 | } | |
638 | ||
fca1dd03 JL |
639 | device_init_wakeup(&pdev->dev, 1); |
640 | ||
f903129b | 641 | info->rtc_dev = devm_rtc_device_register(&pdev->dev, id->name, |
f56950ec | 642 | &max77686_rtc_ops, THIS_MODULE); |
fca1dd03 JL |
643 | |
644 | if (IS_ERR(info->rtc_dev)) { | |
fca1dd03 JL |
645 | ret = PTR_ERR(info->rtc_dev); |
646 | dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); | |
647 | if (ret == 0) | |
648 | ret = -EINVAL; | |
649 | goto err_rtc; | |
650 | } | |
6f1c1e71 | 651 | |
1745d6d3 JMC |
652 | if (!max77686->rtc_irq_data) { |
653 | ret = -EINVAL; | |
bf035f42 | 654 | dev_err(&pdev->dev, "No RTC regmap IRQ chip\n"); |
1745d6d3 JMC |
655 | goto err_rtc; |
656 | } | |
657 | ||
6f1c1e71 JMC |
658 | info->virq = regmap_irq_get_virq(max77686->rtc_irq_data, |
659 | MAX77686_RTCIRQ_RTCA1); | |
fb166ba1 | 660 | if (info->virq <= 0) { |
ad819039 | 661 | ret = -ENXIO; |
fca1dd03 | 662 | goto err_rtc; |
ad819039 | 663 | } |
fca1dd03 | 664 | |
6f1c1e71 | 665 | ret = devm_request_threaded_irq(&pdev->dev, info->virq, NULL, |
0b4f8b08 LD |
666 | max77686_rtc_alarm_irq, 0, |
667 | "rtc-alarm1", info); | |
ad819039 | 668 | if (ret < 0) |
fca1dd03 JL |
669 | dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", |
670 | info->virq, ret); | |
fca1dd03 | 671 | |
fca1dd03 | 672 | err_rtc: |
fca1dd03 JL |
673 | return ret; |
674 | } | |
675 | ||
e7f7fc73 DA |
676 | #ifdef CONFIG_PM_SLEEP |
677 | static int max77686_rtc_suspend(struct device *dev) | |
678 | { | |
679 | if (device_may_wakeup(dev)) { | |
680 | struct max77686_rtc_info *info = dev_get_drvdata(dev); | |
681 | ||
682 | return enable_irq_wake(info->virq); | |
683 | } | |
684 | ||
685 | return 0; | |
686 | } | |
687 | ||
688 | static int max77686_rtc_resume(struct device *dev) | |
689 | { | |
690 | if (device_may_wakeup(dev)) { | |
691 | struct max77686_rtc_info *info = dev_get_drvdata(dev); | |
692 | ||
693 | return disable_irq_wake(info->virq); | |
694 | } | |
695 | ||
696 | return 0; | |
697 | } | |
698 | #endif | |
699 | ||
700 | static SIMPLE_DEV_PM_OPS(max77686_rtc_pm_ops, | |
701 | max77686_rtc_suspend, max77686_rtc_resume); | |
702 | ||
fca1dd03 | 703 | static const struct platform_device_id rtc_id[] = { |
01ea01b3 | 704 | { "max77686-rtc", .driver_data = (kernel_ulong_t)&max77686_drv_data, }, |
f903129b | 705 | { "max77802-rtc", .driver_data = (kernel_ulong_t)&max77802_drv_data, }, |
fca1dd03 JL |
706 | {}, |
707 | }; | |
2d0cca0d | 708 | MODULE_DEVICE_TABLE(platform, rtc_id); |
fca1dd03 JL |
709 | |
710 | static struct platform_driver max77686_rtc_driver = { | |
711 | .driver = { | |
712 | .name = "max77686-rtc", | |
e7f7fc73 | 713 | .pm = &max77686_rtc_pm_ops, |
fca1dd03 JL |
714 | }, |
715 | .probe = max77686_rtc_probe, | |
fca1dd03 JL |
716 | .id_table = rtc_id, |
717 | }; | |
718 | ||
0c58ff58 | 719 | module_platform_driver(max77686_rtc_driver); |
fca1dd03 JL |
720 | |
721 | MODULE_DESCRIPTION("Maxim MAX77686 RTC driver"); | |
f5b1d3c5 | 722 | MODULE_AUTHOR("Chiwoong Byun <woong.byun@samsung.com>"); |
fca1dd03 | 723 | MODULE_LICENSE("GPL"); |