1 | // SPDX-License-Identifier: GPL-2.0-or-later |
---|---|
2 | /* |
3 | * Intersil ISL1208 rtc class driver |
4 | * |
5 | * Copyright 2005,2006 Hebert Valerio Riedel <hvr@gnu.org> |
6 | */ |
7 | |
8 | #include <linux/bcd.h> |
9 | #include <linux/clk.h> |
10 | #include <linux/delay.h> |
11 | #include <linux/i2c.h> |
12 | #include <linux/module.h> |
13 | #include <linux/of.h> |
14 | #include <linux/of_irq.h> |
15 | #include <linux/rtc.h> |
16 | |
17 | /* Register map */ |
18 | /* rtc section */ |
19 | #define ISL1208_REG_SC 0x00 |
20 | #define ISL1208_REG_MN 0x01 |
21 | #define ISL1208_REG_HR 0x02 |
22 | #define ISL1208_REG_HR_MIL (1<<7) /* 24h/12h mode */ |
23 | #define ISL1208_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */ |
24 | #define ISL1208_REG_DT 0x03 |
25 | #define ISL1208_REG_MO 0x04 |
26 | #define ISL1208_REG_YR 0x05 |
27 | #define ISL1208_REG_DW 0x06 |
28 | #define ISL1208_RTC_SECTION_LEN 7 |
29 | |
30 | /* control/status section */ |
31 | #define ISL1208_REG_SR 0x07 |
32 | #define ISL1208_REG_SR_ARST (1<<7) /* auto reset */ |
33 | #define ISL1208_REG_SR_XTOSCB (1<<6) /* crystal oscillator */ |
34 | #define ISL1208_REG_SR_WRTC (1<<4) /* write rtc */ |
35 | #define ISL1208_REG_SR_EVT (1<<3) /* event */ |
36 | #define ISL1208_REG_SR_ALM (1<<2) /* alarm */ |
37 | #define ISL1208_REG_SR_BAT (1<<1) /* battery */ |
38 | #define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */ |
39 | #define ISL1208_REG_INT 0x08 |
40 | #define ISL1208_REG_INT_ALME (1<<6) /* alarm enable */ |
41 | #define ISL1208_REG_INT_IM (1<<7) /* interrupt/alarm mode */ |
42 | #define ISL1219_REG_EV 0x09 |
43 | #define ISL1219_REG_EV_EVEN (1<<4) /* event detection enable */ |
44 | #define ISL1219_REG_EV_EVIENB (1<<7) /* event in pull-up disable */ |
45 | #define ISL1208_REG_ATR 0x0a |
46 | #define ISL1208_REG_DTR 0x0b |
47 | |
48 | /* alarm section */ |
49 | #define ISL1208_REG_SCA 0x0c |
50 | #define ISL1208_REG_MNA 0x0d |
51 | #define ISL1208_REG_HRA 0x0e |
52 | #define ISL1208_REG_DTA 0x0f |
53 | #define ISL1208_REG_MOA 0x10 |
54 | #define ISL1208_REG_DWA 0x11 |
55 | #define ISL1208_ALARM_SECTION_LEN 6 |
56 | |
57 | /* user section */ |
58 | #define ISL1208_REG_USR1 0x12 |
59 | #define ISL1208_REG_USR2 0x13 |
60 | #define ISL1208_USR_SECTION_LEN 2 |
61 | |
62 | /* event section */ |
63 | #define ISL1219_REG_SCT 0x14 |
64 | #define ISL1219_REG_MNT 0x15 |
65 | #define ISL1219_REG_HRT 0x16 |
66 | #define ISL1219_REG_DTT 0x17 |
67 | #define ISL1219_REG_MOT 0x18 |
68 | #define ISL1219_REG_YRT 0x19 |
69 | #define ISL1219_EVT_SECTION_LEN 6 |
70 | |
71 | static struct i2c_driver isl1208_driver; |
72 | |
73 | /* Chip capabilities table */ |
74 | struct isl1208_config { |
75 | unsigned int nvmem_length; |
76 | unsigned has_tamper:1; |
77 | unsigned has_timestamp:1; |
78 | unsigned has_inverted_osc_bit:1; |
79 | }; |
80 | |
81 | static const struct isl1208_config config_isl1208 = { |
82 | .nvmem_length = 2, |
83 | .has_tamper = false, |
84 | .has_timestamp = false |
85 | }; |
86 | |
87 | static const struct isl1208_config config_isl1209 = { |
88 | .nvmem_length = 2, |
89 | .has_tamper = true, |
90 | .has_timestamp = false |
91 | }; |
92 | |
93 | static const struct isl1208_config config_isl1218 = { |
94 | .nvmem_length = 8, |
95 | .has_tamper = false, |
96 | .has_timestamp = false |
97 | }; |
98 | |
99 | static const struct isl1208_config config_isl1219 = { |
100 | .nvmem_length = 2, |
101 | .has_tamper = true, |
102 | .has_timestamp = true |
103 | }; |
104 | |
105 | static const struct isl1208_config config_raa215300_a0 = { |
106 | .nvmem_length = 2, |
107 | .has_tamper = false, |
108 | .has_timestamp = false, |
109 | .has_inverted_osc_bit = true |
110 | }; |
111 | |
112 | static const struct i2c_device_id isl1208_id[] = { |
113 | { "isl1208", .driver_data = (kernel_ulong_t)&config_isl1208 }, |
114 | { "isl1209", .driver_data = (kernel_ulong_t)&config_isl1209 }, |
115 | { "isl1218", .driver_data = (kernel_ulong_t)&config_isl1218 }, |
116 | { "isl1219", .driver_data = (kernel_ulong_t)&config_isl1219 }, |
117 | { "raa215300_a0", .driver_data = (kernel_ulong_t)&config_raa215300_a0 }, |
118 | { } |
119 | }; |
120 | MODULE_DEVICE_TABLE(i2c, isl1208_id); |
121 | |
122 | static const __maybe_unused struct of_device_id isl1208_of_match[] = { |
123 | { .compatible = "isil,isl1208", .data = &config_isl1208 }, |
124 | { .compatible = "isil,isl1209", .data = &config_isl1209 }, |
125 | { .compatible = "isil,isl1218", .data = &config_isl1218 }, |
126 | { .compatible = "isil,isl1219", .data = &config_isl1219 }, |
127 | { } |
128 | }; |
129 | MODULE_DEVICE_TABLE(of, isl1208_of_match); |
130 | |
131 | /* Device state */ |
132 | struct isl1208_state { |
133 | struct nvmem_config nvmem_config; |
134 | struct rtc_device *rtc; |
135 | const struct isl1208_config *config; |
136 | }; |
137 | |
138 | /* block read */ |
139 | static int |
140 | isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], |
141 | unsigned len) |
142 | { |
143 | int ret; |
144 | |
145 | WARN_ON(reg > ISL1219_REG_YRT); |
146 | WARN_ON(reg + len > ISL1219_REG_YRT + 1); |
147 | |
148 | ret = i2c_smbus_read_i2c_block_data(client, command: reg, length: len, values: buf); |
149 | return (ret < 0) ? ret : 0; |
150 | } |
151 | |
152 | /* block write */ |
153 | static int |
154 | isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], |
155 | unsigned len) |
156 | { |
157 | int ret; |
158 | |
159 | WARN_ON(reg > ISL1219_REG_YRT); |
160 | WARN_ON(reg + len > ISL1219_REG_YRT + 1); |
161 | |
162 | ret = i2c_smbus_write_i2c_block_data(client, command: reg, length: len, values: buf); |
163 | return (ret < 0) ? ret : 0; |
164 | } |
165 | |
166 | /* simple check to see whether we have a isl1208 */ |
167 | static int |
168 | isl1208_i2c_validate_client(struct i2c_client *client) |
169 | { |
170 | u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, }; |
171 | u8 zero_mask[ISL1208_RTC_SECTION_LEN] = { |
172 | 0x80, 0x80, 0x40, 0xc0, 0xe0, 0x00, 0xf8 |
173 | }; |
174 | int i; |
175 | int ret; |
176 | |
177 | ret = isl1208_i2c_read_regs(client, reg: 0, buf: regs, ISL1208_RTC_SECTION_LEN); |
178 | if (ret < 0) |
179 | return ret; |
180 | |
181 | for (i = 0; i < ISL1208_RTC_SECTION_LEN; ++i) { |
182 | if (regs[i] & zero_mask[i]) /* check if bits are cleared */ |
183 | return -ENODEV; |
184 | } |
185 | |
186 | return 0; |
187 | } |
188 | |
189 | static int isl1208_set_xtoscb(struct i2c_client *client, int sr, int xtosb_val) |
190 | { |
191 | /* Do nothing if bit is already set to desired value */ |
192 | if (!!(sr & ISL1208_REG_SR_XTOSCB) == xtosb_val) |
193 | return 0; |
194 | |
195 | if (xtosb_val) |
196 | sr |= ISL1208_REG_SR_XTOSCB; |
197 | else |
198 | sr &= ~ISL1208_REG_SR_XTOSCB; |
199 | |
200 | return i2c_smbus_write_byte_data(client, ISL1208_REG_SR, value: sr); |
201 | } |
202 | |
203 | static int |
204 | isl1208_i2c_get_sr(struct i2c_client *client) |
205 | { |
206 | return i2c_smbus_read_byte_data(client, ISL1208_REG_SR); |
207 | } |
208 | |
209 | static int |
210 | isl1208_i2c_get_atr(struct i2c_client *client) |
211 | { |
212 | int atr = i2c_smbus_read_byte_data(client, ISL1208_REG_ATR); |
213 | if (atr < 0) |
214 | return atr; |
215 | |
216 | /* The 6bit value in the ATR register controls the load |
217 | * capacitance C_load * in steps of 0.25pF |
218 | * |
219 | * bit (1<<5) of the ATR register is inverted |
220 | * |
221 | * C_load(ATR=0x20) = 4.50pF |
222 | * C_load(ATR=0x00) = 12.50pF |
223 | * C_load(ATR=0x1f) = 20.25pF |
224 | * |
225 | */ |
226 | |
227 | atr &= 0x3f; /* mask out lsb */ |
228 | atr ^= 1 << 5; /* invert 6th bit */ |
229 | atr += 2 * 9; /* add offset of 4.5pF; unit[atr] = 0.25pF */ |
230 | |
231 | return atr; |
232 | } |
233 | |
234 | /* returns adjustment value + 100 */ |
235 | static int |
236 | isl1208_i2c_get_dtr(struct i2c_client *client) |
237 | { |
238 | int dtr = i2c_smbus_read_byte_data(client, ISL1208_REG_DTR); |
239 | if (dtr < 0) |
240 | return -EIO; |
241 | |
242 | /* dtr encodes adjustments of {-60,-40,-20,0,20,40,60} ppm */ |
243 | dtr = ((dtr & 0x3) * 20) * (dtr & (1 << 2) ? -1 : 1); |
244 | |
245 | return dtr + 100; |
246 | } |
247 | |
248 | static int |
249 | isl1208_i2c_get_usr(struct i2c_client *client) |
250 | { |
251 | u8 buf[ISL1208_USR_SECTION_LEN] = { 0, }; |
252 | int ret; |
253 | |
254 | ret = isl1208_i2c_read_regs(client, ISL1208_REG_USR1, buf, |
255 | ISL1208_USR_SECTION_LEN); |
256 | if (ret < 0) |
257 | return ret; |
258 | |
259 | return (buf[1] << 8) | buf[0]; |
260 | } |
261 | |
262 | static int |
263 | isl1208_i2c_set_usr(struct i2c_client *client, u16 usr) |
264 | { |
265 | u8 buf[ISL1208_USR_SECTION_LEN]; |
266 | |
267 | buf[0] = usr & 0xff; |
268 | buf[1] = (usr >> 8) & 0xff; |
269 | |
270 | return isl1208_i2c_set_regs(client, ISL1208_REG_USR1, buf, |
271 | ISL1208_USR_SECTION_LEN); |
272 | } |
273 | |
274 | static int |
275 | isl1208_rtc_toggle_alarm(struct i2c_client *client, int enable) |
276 | { |
277 | int icr = i2c_smbus_read_byte_data(client, ISL1208_REG_INT); |
278 | |
279 | if (icr < 0) { |
280 | dev_err(&client->dev, "%s: reading INT failed\n", __func__); |
281 | return icr; |
282 | } |
283 | |
284 | if (enable) |
285 | icr |= ISL1208_REG_INT_ALME | ISL1208_REG_INT_IM; |
286 | else |
287 | icr &= ~(ISL1208_REG_INT_ALME | ISL1208_REG_INT_IM); |
288 | |
289 | icr = i2c_smbus_write_byte_data(client, ISL1208_REG_INT, value: icr); |
290 | if (icr < 0) { |
291 | dev_err(&client->dev, "%s: writing INT failed\n", __func__); |
292 | return icr; |
293 | } |
294 | |
295 | return 0; |
296 | } |
297 | |
298 | static int |
299 | isl1208_rtc_proc(struct device *dev, struct seq_file *seq) |
300 | { |
301 | struct i2c_client *const client = to_i2c_client(dev); |
302 | int sr, dtr, atr, usr; |
303 | |
304 | sr = isl1208_i2c_get_sr(client); |
305 | if (sr < 0) { |
306 | dev_err(&client->dev, "%s: reading SR failed\n", __func__); |
307 | return sr; |
308 | } |
309 | |
310 | seq_printf(m: seq, fmt: "status_reg\t:%s%s%s%s%s%s (0x%.2x)\n", |
311 | (sr & ISL1208_REG_SR_RTCF) ? " RTCF": "", |
312 | (sr & ISL1208_REG_SR_BAT) ? " BAT": "", |
313 | (sr & ISL1208_REG_SR_ALM) ? " ALM": "", |
314 | (sr & ISL1208_REG_SR_WRTC) ? " WRTC": "", |
315 | (sr & ISL1208_REG_SR_XTOSCB) ? " XTOSCB": "", |
316 | (sr & ISL1208_REG_SR_ARST) ? " ARST": "", sr); |
317 | |
318 | seq_printf(m: seq, fmt: "batt_status\t: %s\n", |
319 | (sr & ISL1208_REG_SR_RTCF) ? "bad": "okay"); |
320 | |
321 | dtr = isl1208_i2c_get_dtr(client); |
322 | if (dtr >= 0) |
323 | seq_printf(m: seq, fmt: "digital_trim\t: %d ppm\n", dtr - 100); |
324 | |
325 | atr = isl1208_i2c_get_atr(client); |
326 | if (atr >= 0) |
327 | seq_printf(m: seq, fmt: "analog_trim\t: %d.%.2d pF\n", |
328 | atr >> 2, (atr & 0x3) * 25); |
329 | |
330 | usr = isl1208_i2c_get_usr(client); |
331 | if (usr >= 0) |
332 | seq_printf(m: seq, fmt: "user_data\t: 0x%.4x\n", usr); |
333 | |
334 | return 0; |
335 | } |
336 | |
337 | static int |
338 | isl1208_i2c_read_time(struct i2c_client *client, struct rtc_time *tm) |
339 | { |
340 | int sr; |
341 | u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, }; |
342 | |
343 | sr = isl1208_i2c_get_sr(client); |
344 | if (sr < 0) { |
345 | dev_err(&client->dev, "%s: reading SR failed\n", __func__); |
346 | return -EIO; |
347 | } |
348 | |
349 | sr = isl1208_i2c_read_regs(client, reg: 0, buf: regs, ISL1208_RTC_SECTION_LEN); |
350 | if (sr < 0) { |
351 | dev_err(&client->dev, "%s: reading RTC section failed\n", |
352 | __func__); |
353 | return sr; |
354 | } |
355 | |
356 | tm->tm_sec = bcd2bin(regs[ISL1208_REG_SC]); |
357 | tm->tm_min = bcd2bin(regs[ISL1208_REG_MN]); |
358 | |
359 | /* HR field has a more complex interpretation */ |
360 | { |
361 | const u8 _hr = regs[ISL1208_REG_HR]; |
362 | if (_hr & ISL1208_REG_HR_MIL) /* 24h format */ |
363 | tm->tm_hour = bcd2bin(_hr & 0x3f); |
364 | else { |
365 | /* 12h format */ |
366 | tm->tm_hour = bcd2bin(_hr & 0x1f); |
367 | if (_hr & ISL1208_REG_HR_PM) /* PM flag set */ |
368 | tm->tm_hour += 12; |
369 | } |
370 | } |
371 | |
372 | tm->tm_mday = bcd2bin(regs[ISL1208_REG_DT]); |
373 | tm->tm_mon = bcd2bin(regs[ISL1208_REG_MO]) - 1; /* rtc starts at 1 */ |
374 | tm->tm_year = bcd2bin(regs[ISL1208_REG_YR]) + 100; |
375 | tm->tm_wday = bcd2bin(regs[ISL1208_REG_DW]); |
376 | |
377 | return 0; |
378 | } |
379 | |
380 | static int |
381 | isl1208_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm) |
382 | { |
383 | struct rtc_time *const tm = &alarm->time; |
384 | u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, }; |
385 | int icr, yr, sr = isl1208_i2c_get_sr(client); |
386 | |
387 | if (sr < 0) { |
388 | dev_err(&client->dev, "%s: reading SR failed\n", __func__); |
389 | return sr; |
390 | } |
391 | |
392 | sr = isl1208_i2c_read_regs(client, ISL1208_REG_SCA, buf: regs, |
393 | ISL1208_ALARM_SECTION_LEN); |
394 | if (sr < 0) { |
395 | dev_err(&client->dev, "%s: reading alarm section failed\n", |
396 | __func__); |
397 | return sr; |
398 | } |
399 | |
400 | /* MSB of each alarm register is an enable bit */ |
401 | tm->tm_sec = bcd2bin(regs[ISL1208_REG_SCA - ISL1208_REG_SCA] & 0x7f); |
402 | tm->tm_min = bcd2bin(regs[ISL1208_REG_MNA - ISL1208_REG_SCA] & 0x7f); |
403 | tm->tm_hour = bcd2bin(regs[ISL1208_REG_HRA - ISL1208_REG_SCA] & 0x3f); |
404 | tm->tm_mday = bcd2bin(regs[ISL1208_REG_DTA - ISL1208_REG_SCA] & 0x3f); |
405 | tm->tm_mon = |
406 | bcd2bin(regs[ISL1208_REG_MOA - ISL1208_REG_SCA] & 0x1f) - 1; |
407 | tm->tm_wday = bcd2bin(regs[ISL1208_REG_DWA - ISL1208_REG_SCA] & 0x03); |
408 | |
409 | /* The alarm doesn't store the year so get it from the rtc section */ |
410 | yr = i2c_smbus_read_byte_data(client, ISL1208_REG_YR); |
411 | if (yr < 0) { |
412 | dev_err(&client->dev, "%s: reading RTC YR failed\n", __func__); |
413 | return yr; |
414 | } |
415 | tm->tm_year = bcd2bin(yr) + 100; |
416 | |
417 | icr = i2c_smbus_read_byte_data(client, ISL1208_REG_INT); |
418 | if (icr < 0) { |
419 | dev_err(&client->dev, "%s: reading INT failed\n", __func__); |
420 | return icr; |
421 | } |
422 | alarm->enabled = !!(icr & ISL1208_REG_INT_ALME); |
423 | |
424 | return 0; |
425 | } |
426 | |
427 | static int |
428 | isl1208_i2c_set_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm) |
429 | { |
430 | struct rtc_time *alarm_tm = &alarm->time; |
431 | u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, }; |
432 | const int offs = ISL1208_REG_SCA; |
433 | struct rtc_time rtc_tm; |
434 | int err, enable; |
435 | |
436 | err = isl1208_i2c_read_time(client, tm: &rtc_tm); |
437 | if (err) |
438 | return err; |
439 | |
440 | /* If the alarm time is before the current time disable the alarm */ |
441 | if (!alarm->enabled || rtc_tm_sub(lhs: alarm_tm, rhs: &rtc_tm) <= 0) |
442 | enable = 0x00; |
443 | else |
444 | enable = 0x80; |
445 | |
446 | /* Program the alarm and enable it for each setting */ |
447 | regs[ISL1208_REG_SCA - offs] = bin2bcd(alarm_tm->tm_sec) | enable; |
448 | regs[ISL1208_REG_MNA - offs] = bin2bcd(alarm_tm->tm_min) | enable; |
449 | regs[ISL1208_REG_HRA - offs] = bin2bcd(alarm_tm->tm_hour) | |
450 | ISL1208_REG_HR_MIL | enable; |
451 | |
452 | regs[ISL1208_REG_DTA - offs] = bin2bcd(alarm_tm->tm_mday) | enable; |
453 | regs[ISL1208_REG_MOA - offs] = bin2bcd(alarm_tm->tm_mon + 1) | enable; |
454 | regs[ISL1208_REG_DWA - offs] = bin2bcd(alarm_tm->tm_wday & 7) | enable; |
455 | |
456 | /* write ALARM registers */ |
457 | err = isl1208_i2c_set_regs(client, reg: offs, buf: regs, |
458 | ISL1208_ALARM_SECTION_LEN); |
459 | if (err < 0) { |
460 | dev_err(&client->dev, "%s: writing ALARM section failed\n", |
461 | __func__); |
462 | return err; |
463 | } |
464 | |
465 | err = isl1208_rtc_toggle_alarm(client, enable); |
466 | if (err) |
467 | return err; |
468 | |
469 | return 0; |
470 | } |
471 | |
472 | static int |
473 | isl1208_rtc_read_time(struct device *dev, struct rtc_time *tm) |
474 | { |
475 | return isl1208_i2c_read_time(to_i2c_client(dev), tm); |
476 | } |
477 | |
478 | static int |
479 | isl1208_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm) |
480 | { |
481 | int sr; |
482 | u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, }; |
483 | |
484 | /* The clock has an 8 bit wide bcd-coded register (they never learn) |
485 | * for the year. tm_year is an offset from 1900 and we are interested |
486 | * in the 2000-2099 range, so any value less than 100 is invalid. |
487 | */ |
488 | if (tm->tm_year < 100) |
489 | return -EINVAL; |
490 | |
491 | regs[ISL1208_REG_SC] = bin2bcd(tm->tm_sec); |
492 | regs[ISL1208_REG_MN] = bin2bcd(tm->tm_min); |
493 | regs[ISL1208_REG_HR] = bin2bcd(tm->tm_hour) | ISL1208_REG_HR_MIL; |
494 | |
495 | regs[ISL1208_REG_DT] = bin2bcd(tm->tm_mday); |
496 | regs[ISL1208_REG_MO] = bin2bcd(tm->tm_mon + 1); |
497 | regs[ISL1208_REG_YR] = bin2bcd(tm->tm_year - 100); |
498 | |
499 | regs[ISL1208_REG_DW] = bin2bcd(tm->tm_wday & 7); |
500 | |
501 | sr = isl1208_i2c_get_sr(client); |
502 | if (sr < 0) { |
503 | dev_err(&client->dev, "%s: reading SR failed\n", __func__); |
504 | return sr; |
505 | } |
506 | |
507 | /* set WRTC */ |
508 | sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, |
509 | value: sr | ISL1208_REG_SR_WRTC); |
510 | if (sr < 0) { |
511 | dev_err(&client->dev, "%s: writing SR failed\n", __func__); |
512 | return sr; |
513 | } |
514 | |
515 | /* write RTC registers */ |
516 | sr = isl1208_i2c_set_regs(client, reg: 0, buf: regs, ISL1208_RTC_SECTION_LEN); |
517 | if (sr < 0) { |
518 | dev_err(&client->dev, "%s: writing RTC section failed\n", |
519 | __func__); |
520 | return sr; |
521 | } |
522 | |
523 | /* clear WRTC again */ |
524 | sr = isl1208_i2c_get_sr(client); |
525 | if (sr < 0) { |
526 | dev_err(&client->dev, "%s: reading SR failed\n", __func__); |
527 | return sr; |
528 | } |
529 | sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, |
530 | value: sr & ~ISL1208_REG_SR_WRTC); |
531 | if (sr < 0) { |
532 | dev_err(&client->dev, "%s: writing SR failed\n", __func__); |
533 | return sr; |
534 | } |
535 | |
536 | return 0; |
537 | } |
538 | |
539 | static int |
540 | isl1208_rtc_set_time(struct device *dev, struct rtc_time *tm) |
541 | { |
542 | return isl1208_i2c_set_time(to_i2c_client(dev), tm); |
543 | } |
544 | |
545 | static int |
546 | isl1208_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) |
547 | { |
548 | return isl1208_i2c_read_alarm(to_i2c_client(dev), alarm); |
549 | } |
550 | |
551 | static int |
552 | isl1208_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) |
553 | { |
554 | return isl1208_i2c_set_alarm(to_i2c_client(dev), alarm); |
555 | } |
556 | |
557 | static ssize_t timestamp0_store(struct device *dev, |
558 | struct device_attribute *attr, |
559 | const char *buf, size_t count) |
560 | { |
561 | struct i2c_client *client = to_i2c_client(dev->parent); |
562 | int sr; |
563 | |
564 | sr = isl1208_i2c_get_sr(client); |
565 | if (sr < 0) { |
566 | dev_err(dev, "%s: reading SR failed\n", __func__); |
567 | return sr; |
568 | } |
569 | |
570 | sr &= ~ISL1208_REG_SR_EVT; |
571 | |
572 | sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, value: sr); |
573 | if (sr < 0) |
574 | dev_err(dev, "%s: writing SR failed\n", |
575 | __func__); |
576 | |
577 | return count; |
578 | }; |
579 | |
580 | static ssize_t timestamp0_show(struct device *dev, |
581 | struct device_attribute *attr, char *buf) |
582 | { |
583 | struct i2c_client *client = to_i2c_client(dev->parent); |
584 | u8 regs[ISL1219_EVT_SECTION_LEN] = { 0, }; |
585 | struct rtc_time tm; |
586 | int sr; |
587 | |
588 | sr = isl1208_i2c_get_sr(client); |
589 | if (sr < 0) { |
590 | dev_err(dev, "%s: reading SR failed\n", __func__); |
591 | return sr; |
592 | } |
593 | |
594 | if (!(sr & ISL1208_REG_SR_EVT)) |
595 | return 0; |
596 | |
597 | sr = isl1208_i2c_read_regs(client, ISL1219_REG_SCT, buf: regs, |
598 | ISL1219_EVT_SECTION_LEN); |
599 | if (sr < 0) { |
600 | dev_err(dev, "%s: reading event section failed\n", |
601 | __func__); |
602 | return 0; |
603 | } |
604 | |
605 | /* MSB of each alarm register is an enable bit */ |
606 | tm.tm_sec = bcd2bin(regs[ISL1219_REG_SCT - ISL1219_REG_SCT] & 0x7f); |
607 | tm.tm_min = bcd2bin(regs[ISL1219_REG_MNT - ISL1219_REG_SCT] & 0x7f); |
608 | tm.tm_hour = bcd2bin(regs[ISL1219_REG_HRT - ISL1219_REG_SCT] & 0x3f); |
609 | tm.tm_mday = bcd2bin(regs[ISL1219_REG_DTT - ISL1219_REG_SCT] & 0x3f); |
610 | tm.tm_mon = |
611 | bcd2bin(regs[ISL1219_REG_MOT - ISL1219_REG_SCT] & 0x1f) - 1; |
612 | tm.tm_year = bcd2bin(regs[ISL1219_REG_YRT - ISL1219_REG_SCT]) + 100; |
613 | |
614 | sr = rtc_valid_tm(tm: &tm); |
615 | if (sr) |
616 | return sr; |
617 | |
618 | return sprintf(buf, fmt: "%llu\n", |
619 | (unsigned long long)rtc_tm_to_time64(tm: &tm)); |
620 | }; |
621 | |
622 | static DEVICE_ATTR_RW(timestamp0); |
623 | |
624 | static irqreturn_t |
625 | isl1208_rtc_interrupt(int irq, void *data) |
626 | { |
627 | unsigned long timeout = jiffies + msecs_to_jiffies(m: 1000); |
628 | struct i2c_client *client = data; |
629 | struct isl1208_state *isl1208 = i2c_get_clientdata(client); |
630 | int handled = 0, sr, err; |
631 | |
632 | if (!isl1208->config->has_tamper) { |
633 | /* |
634 | * The INT# output is pulled low 250ms after the alarm is |
635 | * triggered. After the INT# output is pulled low, it is low for |
636 | * at least 250ms, even if the correct action is taken to clear |
637 | * it. It is impossible to clear ALM if it is still active. The |
638 | * host must wait for the RTC to progress past the alarm time |
639 | * plus the 250ms delay before clearing ALM. |
640 | */ |
641 | msleep(msecs: 250); |
642 | } |
643 | |
644 | /* |
645 | * I2C reads get NAK'ed if we read straight away after an interrupt? |
646 | * Using a mdelay/msleep didn't seem to help either, so we work around |
647 | * this by continually trying to read the register for a short time. |
648 | */ |
649 | while (1) { |
650 | sr = isl1208_i2c_get_sr(client); |
651 | if (sr >= 0) |
652 | break; |
653 | |
654 | if (time_after(jiffies, timeout)) { |
655 | dev_err(&client->dev, "%s: reading SR failed\n", |
656 | __func__); |
657 | return sr; |
658 | } |
659 | } |
660 | |
661 | if (sr & ISL1208_REG_SR_ALM) { |
662 | dev_dbg(&client->dev, "alarm!\n"); |
663 | |
664 | rtc_update_irq(rtc: isl1208->rtc, num: 1, RTC_IRQF | RTC_AF); |
665 | |
666 | /* Disable the alarm */ |
667 | err = isl1208_rtc_toggle_alarm(client, enable: 0); |
668 | if (err) |
669 | return err; |
670 | |
671 | fsleep(usecs: 275); |
672 | |
673 | /* Clear the alarm */ |
674 | sr &= ~ISL1208_REG_SR_ALM; |
675 | sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, value: sr); |
676 | if (sr < 0) |
677 | dev_err(&client->dev, "%s: writing SR failed\n", |
678 | __func__); |
679 | else |
680 | handled = 1; |
681 | } |
682 | |
683 | if (isl1208->config->has_tamper && (sr & ISL1208_REG_SR_EVT)) { |
684 | dev_warn(&client->dev, "event detected"); |
685 | handled = 1; |
686 | if (isl1208->config->has_timestamp) |
687 | sysfs_notify(kobj: &isl1208->rtc->dev.kobj, NULL, |
688 | attr: dev_attr_timestamp0.attr.name); |
689 | } |
690 | |
691 | return handled ? IRQ_HANDLED : IRQ_NONE; |
692 | } |
693 | |
694 | static const struct rtc_class_ops isl1208_rtc_ops = { |
695 | .proc = isl1208_rtc_proc, |
696 | .read_time = isl1208_rtc_read_time, |
697 | .set_time = isl1208_rtc_set_time, |
698 | .read_alarm = isl1208_rtc_read_alarm, |
699 | .set_alarm = isl1208_rtc_set_alarm, |
700 | }; |
701 | |
702 | /* sysfs interface */ |
703 | |
704 | static ssize_t |
705 | isl1208_sysfs_show_atrim(struct device *dev, |
706 | struct device_attribute *attr, char *buf) |
707 | { |
708 | int atr = isl1208_i2c_get_atr(to_i2c_client(dev->parent)); |
709 | if (atr < 0) |
710 | return atr; |
711 | |
712 | return sprintf(buf, fmt: "%d.%.2d pF\n", atr >> 2, (atr & 0x3) * 25); |
713 | } |
714 | |
715 | static DEVICE_ATTR(atrim, S_IRUGO, isl1208_sysfs_show_atrim, NULL); |
716 | |
717 | static ssize_t |
718 | isl1208_sysfs_show_dtrim(struct device *dev, |
719 | struct device_attribute *attr, char *buf) |
720 | { |
721 | int dtr = isl1208_i2c_get_dtr(to_i2c_client(dev->parent)); |
722 | if (dtr < 0) |
723 | return dtr; |
724 | |
725 | return sprintf(buf, fmt: "%d ppm\n", dtr - 100); |
726 | } |
727 | |
728 | static DEVICE_ATTR(dtrim, S_IRUGO, isl1208_sysfs_show_dtrim, NULL); |
729 | |
730 | static ssize_t |
731 | isl1208_sysfs_show_usr(struct device *dev, |
732 | struct device_attribute *attr, char *buf) |
733 | { |
734 | int usr = isl1208_i2c_get_usr(to_i2c_client(dev->parent)); |
735 | if (usr < 0) |
736 | return usr; |
737 | |
738 | return sprintf(buf, fmt: "0x%.4x\n", usr); |
739 | } |
740 | |
741 | static ssize_t |
742 | isl1208_sysfs_store_usr(struct device *dev, |
743 | struct device_attribute *attr, |
744 | const char *buf, size_t count) |
745 | { |
746 | int usr = -1; |
747 | |
748 | if (buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X')) { |
749 | if (sscanf(buf, "%x", &usr) != 1) |
750 | return -EINVAL; |
751 | } else { |
752 | if (sscanf(buf, "%d", &usr) != 1) |
753 | return -EINVAL; |
754 | } |
755 | |
756 | if (usr < 0 || usr > 0xffff) |
757 | return -EINVAL; |
758 | |
759 | if (isl1208_i2c_set_usr(to_i2c_client(dev->parent), usr)) |
760 | return -EIO; |
761 | |
762 | return count; |
763 | } |
764 | |
765 | static DEVICE_ATTR(usr, S_IRUGO | S_IWUSR, isl1208_sysfs_show_usr, |
766 | isl1208_sysfs_store_usr); |
767 | |
768 | static struct attribute *isl1208_rtc_attrs[] = { |
769 | &dev_attr_atrim.attr, |
770 | &dev_attr_dtrim.attr, |
771 | &dev_attr_usr.attr, |
772 | NULL |
773 | }; |
774 | |
775 | static const struct attribute_group isl1208_rtc_sysfs_files = { |
776 | .attrs = isl1208_rtc_attrs, |
777 | }; |
778 | |
779 | static struct attribute *isl1219_rtc_attrs[] = { |
780 | &dev_attr_timestamp0.attr, |
781 | NULL |
782 | }; |
783 | |
784 | static const struct attribute_group isl1219_rtc_sysfs_files = { |
785 | .attrs = isl1219_rtc_attrs, |
786 | }; |
787 | |
788 | static int isl1208_nvmem_read(void *priv, unsigned int off, void *buf, |
789 | size_t count) |
790 | { |
791 | struct isl1208_state *isl1208 = priv; |
792 | struct i2c_client *client = to_i2c_client(isl1208->rtc->dev.parent); |
793 | |
794 | /* nvmem sanitizes offset/count for us, but count==0 is possible */ |
795 | if (!count) |
796 | return count; |
797 | |
798 | return isl1208_i2c_read_regs(client, ISL1208_REG_USR1 + off, buf, |
799 | len: count); |
800 | } |
801 | |
802 | static int isl1208_nvmem_write(void *priv, unsigned int off, void *buf, |
803 | size_t count) |
804 | { |
805 | struct isl1208_state *isl1208 = priv; |
806 | struct i2c_client *client = to_i2c_client(isl1208->rtc->dev.parent); |
807 | |
808 | /* nvmem sanitizes off/count for us, but count==0 is possible */ |
809 | if (!count) |
810 | return count; |
811 | |
812 | return isl1208_i2c_set_regs(client, ISL1208_REG_USR1 + off, buf, |
813 | len: count); |
814 | } |
815 | |
816 | static const struct nvmem_config isl1208_nvmem_config = { |
817 | .name = "isl1208_nvram", |
818 | .word_size = 1, |
819 | .stride = 1, |
820 | /* .size from chip specific config */ |
821 | .reg_read = isl1208_nvmem_read, |
822 | .reg_write = isl1208_nvmem_write, |
823 | }; |
824 | |
825 | static int isl1208_setup_irq(struct i2c_client *client, int irq) |
826 | { |
827 | int rc = devm_request_threaded_irq(dev: &client->dev, irq, NULL, |
828 | thread_fn: isl1208_rtc_interrupt, |
829 | IRQF_SHARED | IRQF_ONESHOT, |
830 | devname: isl1208_driver.driver.name, |
831 | dev_id: client); |
832 | if (!rc) { |
833 | device_init_wakeup(dev: &client->dev, enable: true); |
834 | enable_irq_wake(irq); |
835 | } else { |
836 | dev_err(&client->dev, |
837 | "Unable to request irq %d, no alarm support\n", |
838 | irq); |
839 | } |
840 | return rc; |
841 | } |
842 | |
843 | static int |
844 | isl1208_clk_present(struct i2c_client *client, const char *name) |
845 | { |
846 | struct clk *clk; |
847 | |
848 | clk = devm_clk_get_optional(dev: &client->dev, id: name); |
849 | if (IS_ERR(ptr: clk)) |
850 | return PTR_ERR(ptr: clk); |
851 | |
852 | return !!clk; |
853 | } |
854 | |
855 | static int |
856 | isl1208_probe(struct i2c_client *client) |
857 | { |
858 | struct isl1208_state *isl1208; |
859 | int evdet_irq = -1; |
860 | int xtosb_val = 0; |
861 | int rc = 0; |
862 | int sr; |
863 | |
864 | if (!i2c_check_functionality(adap: client->adapter, I2C_FUNC_I2C)) |
865 | return -ENODEV; |
866 | |
867 | if (isl1208_i2c_validate_client(client) < 0) |
868 | return -ENODEV; |
869 | |
870 | /* Allocate driver state, point i2c client data to it */ |
871 | isl1208 = devm_kzalloc(dev: &client->dev, size: sizeof(*isl1208), GFP_KERNEL); |
872 | if (!isl1208) |
873 | return -ENOMEM; |
874 | i2c_set_clientdata(client, data: isl1208); |
875 | |
876 | /* Determine which chip we have */ |
877 | isl1208->config = i2c_get_match_data(client); |
878 | if (!isl1208->config) |
879 | return -ENODEV; |
880 | |
881 | rc = isl1208_clk_present(client, name: "xin"); |
882 | if (rc < 0) |
883 | return rc; |
884 | |
885 | if (!rc) { |
886 | rc = isl1208_clk_present(client, name: "clkin"); |
887 | if (rc < 0) |
888 | return rc; |
889 | |
890 | if (rc) |
891 | xtosb_val = 1; |
892 | } |
893 | |
894 | isl1208->rtc = devm_rtc_allocate_device(dev: &client->dev); |
895 | if (IS_ERR(ptr: isl1208->rtc)) |
896 | return PTR_ERR(ptr: isl1208->rtc); |
897 | |
898 | isl1208->rtc->ops = &isl1208_rtc_ops; |
899 | |
900 | /* Setup nvmem configuration in driver state struct */ |
901 | isl1208->nvmem_config = isl1208_nvmem_config; |
902 | isl1208->nvmem_config.size = isl1208->config->nvmem_length; |
903 | isl1208->nvmem_config.priv = isl1208; |
904 | |
905 | sr = isl1208_i2c_get_sr(client); |
906 | if (sr < 0) { |
907 | dev_err(&client->dev, "reading status failed\n"); |
908 | return sr; |
909 | } |
910 | |
911 | if (isl1208->config->has_inverted_osc_bit) |
912 | xtosb_val = !xtosb_val; |
913 | |
914 | rc = isl1208_set_xtoscb(client, sr, xtosb_val); |
915 | if (rc) |
916 | return rc; |
917 | |
918 | if (sr & ISL1208_REG_SR_RTCF) |
919 | dev_warn(&client->dev, "rtc power failure detected, " |
920 | "please set clock.\n"); |
921 | |
922 | if (isl1208->config->has_tamper) { |
923 | struct device_node *np = client->dev.of_node; |
924 | u32 evienb; |
925 | |
926 | rc = i2c_smbus_read_byte_data(client, ISL1219_REG_EV); |
927 | if (rc < 0) { |
928 | dev_err(&client->dev, "failed to read EV reg\n"); |
929 | return rc; |
930 | } |
931 | rc |= ISL1219_REG_EV_EVEN; |
932 | if (!of_property_read_u32(np, propname: "isil,ev-evienb", out_value: &evienb)) { |
933 | if (evienb) |
934 | rc |= ISL1219_REG_EV_EVIENB; |
935 | else |
936 | rc &= ~ISL1219_REG_EV_EVIENB; |
937 | } |
938 | rc = i2c_smbus_write_byte_data(client, ISL1219_REG_EV, value: rc); |
939 | if (rc < 0) { |
940 | dev_err(&client->dev, "could not enable tamper detection\n"); |
941 | return rc; |
942 | } |
943 | evdet_irq = of_irq_get_byname(dev: np, name: "evdet"); |
944 | } |
945 | if (isl1208->config->has_timestamp) { |
946 | rc = rtc_add_group(rtc: isl1208->rtc, grp: &isl1219_rtc_sysfs_files); |
947 | if (rc) |
948 | return rc; |
949 | } |
950 | |
951 | rc = rtc_add_group(rtc: isl1208->rtc, grp: &isl1208_rtc_sysfs_files); |
952 | if (rc) |
953 | return rc; |
954 | |
955 | if (client->irq > 0) { |
956 | rc = isl1208_setup_irq(client, irq: client->irq); |
957 | if (rc) |
958 | return rc; |
959 | } else { |
960 | clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, addr: isl1208->rtc->features); |
961 | } |
962 | |
963 | if (evdet_irq > 0 && evdet_irq != client->irq) |
964 | rc = isl1208_setup_irq(client, irq: evdet_irq); |
965 | if (rc) |
966 | return rc; |
967 | |
968 | rc = devm_rtc_nvmem_register(rtc: isl1208->rtc, nvmem_config: &isl1208->nvmem_config); |
969 | if (rc) |
970 | return rc; |
971 | |
972 | return devm_rtc_register_device(isl1208->rtc); |
973 | } |
974 | |
975 | static struct i2c_driver isl1208_driver = { |
976 | .driver = { |
977 | .name = "rtc-isl1208", |
978 | .of_match_table = of_match_ptr(isl1208_of_match), |
979 | }, |
980 | .probe = isl1208_probe, |
981 | .id_table = isl1208_id, |
982 | }; |
983 | |
984 | module_i2c_driver(isl1208_driver); |
985 | |
986 | MODULE_AUTHOR("Herbert Valerio Riedel <hvr@gnu.org>"); |
987 | MODULE_DESCRIPTION("Intersil ISL1208 RTC driver"); |
988 | MODULE_LICENSE("GPL"); |
989 |
Definitions
- isl1208_driver
- isl1208_config
- config_isl1208
- config_isl1209
- config_isl1218
- config_isl1219
- config_raa215300_a0
- isl1208_id
- isl1208_of_match
- isl1208_state
- isl1208_i2c_read_regs
- isl1208_i2c_set_regs
- isl1208_i2c_validate_client
- isl1208_set_xtoscb
- isl1208_i2c_get_sr
- isl1208_i2c_get_atr
- isl1208_i2c_get_dtr
- isl1208_i2c_get_usr
- isl1208_i2c_set_usr
- isl1208_rtc_toggle_alarm
- isl1208_rtc_proc
- isl1208_i2c_read_time
- isl1208_i2c_read_alarm
- isl1208_i2c_set_alarm
- isl1208_rtc_read_time
- isl1208_i2c_set_time
- isl1208_rtc_set_time
- isl1208_rtc_read_alarm
- isl1208_rtc_set_alarm
- timestamp0_store
- timestamp0_show
- isl1208_rtc_interrupt
- isl1208_rtc_ops
- isl1208_sysfs_show_atrim
- isl1208_sysfs_show_dtrim
- isl1208_sysfs_show_usr
- isl1208_sysfs_store_usr
- isl1208_rtc_attrs
- isl1208_rtc_sysfs_files
- isl1219_rtc_attrs
- isl1219_rtc_sysfs_files
- isl1208_nvmem_read
- isl1208_nvmem_write
- isl1208_nvmem_config
- isl1208_setup_irq
- isl1208_clk_present
- isl1208_probe
Improve your Profiling and Debugging skills
Find out more