diff options
Diffstat (limited to 'drivers/rtc/rtc-pcf8563.c')
-rw-r--r-- | drivers/rtc/rtc-pcf8563.c | 231 |
1 files changed, 201 insertions, 30 deletions
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 63b558c48196..5a197d9dc7e7 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c | |||
@@ -26,6 +26,8 @@ | |||
26 | 26 | ||
27 | #define PCF8563_REG_ST1 0x00 /* status */ | 27 | #define PCF8563_REG_ST1 0x00 /* status */ |
28 | #define PCF8563_REG_ST2 0x01 | 28 | #define PCF8563_REG_ST2 0x01 |
29 | #define PCF8563_BIT_AIE (1 << 1) | ||
30 | #define PCF8563_BIT_AF (1 << 3) | ||
29 | 31 | ||
30 | #define PCF8563_REG_SC 0x02 /* datetime */ | 32 | #define PCF8563_REG_SC 0x02 /* datetime */ |
31 | #define PCF8563_REG_MN 0x03 | 33 | #define PCF8563_REG_MN 0x03 |
@@ -36,9 +38,6 @@ | |||
36 | #define PCF8563_REG_YR 0x08 | 38 | #define PCF8563_REG_YR 0x08 |
37 | 39 | ||
38 | #define PCF8563_REG_AMN 0x09 /* alarm */ | 40 | #define PCF8563_REG_AMN 0x09 /* alarm */ |
39 | #define PCF8563_REG_AHR 0x0A | ||
40 | #define PCF8563_REG_ADM 0x0B | ||
41 | #define PCF8563_REG_ADW 0x0C | ||
42 | 41 | ||
43 | #define PCF8563_REG_CLKO 0x0D /* clock out */ | 42 | #define PCF8563_REG_CLKO 0x0D /* clock out */ |
44 | #define PCF8563_REG_TMRC 0x0E /* timer control */ | 43 | #define PCF8563_REG_TMRC 0x0E /* timer control */ |
@@ -67,37 +66,133 @@ struct pcf8563 { | |||
67 | */ | 66 | */ |
68 | int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */ | 67 | int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */ |
69 | int voltage_low; /* incicates if a low_voltage was detected */ | 68 | int voltage_low; /* incicates if a low_voltage was detected */ |
69 | |||
70 | struct i2c_client *client; | ||
70 | }; | 71 | }; |
71 | 72 | ||
72 | /* | 73 | static int pcf8563_read_block_data(struct i2c_client *client, unsigned char reg, |
73 | * In the routines that deal directly with the pcf8563 hardware, we use | 74 | unsigned char length, unsigned char *buf) |
74 | * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. | ||
75 | */ | ||
76 | static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) | ||
77 | { | 75 | { |
78 | struct pcf8563 *pcf8563 = i2c_get_clientdata(client); | ||
79 | unsigned char buf[13] = { PCF8563_REG_ST1 }; | ||
80 | |||
81 | struct i2c_msg msgs[] = { | 76 | struct i2c_msg msgs[] = { |
82 | {/* setup read ptr */ | 77 | {/* setup read ptr */ |
83 | .addr = client->addr, | 78 | .addr = client->addr, |
84 | .len = 1, | 79 | .len = 1, |
85 | .buf = buf | 80 | .buf = ®, |
86 | }, | 81 | }, |
87 | {/* read status + date */ | 82 | { |
88 | .addr = client->addr, | 83 | .addr = client->addr, |
89 | .flags = I2C_M_RD, | 84 | .flags = I2C_M_RD, |
90 | .len = 13, | 85 | .len = length, |
91 | .buf = buf | 86 | .buf = buf |
92 | }, | 87 | }, |
93 | }; | 88 | }; |
94 | 89 | ||
95 | /* read registers */ | ||
96 | if ((i2c_transfer(client->adapter, msgs, 2)) != 2) { | 90 | if ((i2c_transfer(client->adapter, msgs, 2)) != 2) { |
97 | dev_err(&client->dev, "%s: read error\n", __func__); | 91 | dev_err(&client->dev, "%s: read error\n", __func__); |
98 | return -EIO; | 92 | return -EIO; |
99 | } | 93 | } |
100 | 94 | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static int pcf8563_write_block_data(struct i2c_client *client, | ||
99 | unsigned char reg, unsigned char length, | ||
100 | unsigned char *buf) | ||
101 | { | ||
102 | int i, err; | ||
103 | |||
104 | for (i = 0; i < length; i++) { | ||
105 | unsigned char data[2] = { reg + i, buf[i] }; | ||
106 | |||
107 | err = i2c_master_send(client, data, sizeof(data)); | ||
108 | if (err != sizeof(data)) { | ||
109 | dev_err(&client->dev, | ||
110 | "%s: err=%d addr=%02x, data=%02x\n", | ||
111 | __func__, err, data[0], data[1]); | ||
112 | return -EIO; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static int pcf8563_set_alarm_mode(struct i2c_client *client, bool on) | ||
120 | { | ||
121 | unsigned char buf[2]; | ||
122 | int err; | ||
123 | |||
124 | err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, buf + 1); | ||
125 | if (err < 0) | ||
126 | return err; | ||
127 | |||
128 | if (on) | ||
129 | buf[1] |= PCF8563_BIT_AIE; | ||
130 | else | ||
131 | buf[1] &= ~PCF8563_BIT_AIE; | ||
132 | |||
133 | buf[1] &= ~PCF8563_BIT_AF; | ||
134 | buf[0] = PCF8563_REG_ST2; | ||
135 | |||
136 | err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, buf + 1); | ||
137 | if (err < 0) { | ||
138 | dev_err(&client->dev, "%s: write error\n", __func__); | ||
139 | return -EIO; | ||
140 | } | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static int pcf8563_get_alarm_mode(struct i2c_client *client, unsigned char *en, | ||
146 | unsigned char *pen) | ||
147 | { | ||
148 | unsigned char buf; | ||
149 | int err; | ||
150 | |||
151 | err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, &buf); | ||
152 | if (err) | ||
153 | return err; | ||
154 | |||
155 | if (en) | ||
156 | *en = !!(buf & PCF8563_BIT_AIE); | ||
157 | if (pen) | ||
158 | *pen = !!(buf & PCF8563_BIT_AF); | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static irqreturn_t pcf8563_irq(int irq, void *dev_id) | ||
164 | { | ||
165 | struct pcf8563 *pcf8563 = i2c_get_clientdata(dev_id); | ||
166 | int err; | ||
167 | char pending; | ||
168 | |||
169 | err = pcf8563_get_alarm_mode(pcf8563->client, NULL, &pending); | ||
170 | if (err < 0) | ||
171 | return err; | ||
172 | |||
173 | if (pending) { | ||
174 | rtc_update_irq(pcf8563->rtc, 1, RTC_IRQF | RTC_AF); | ||
175 | pcf8563_set_alarm_mode(pcf8563->client, 1); | ||
176 | return IRQ_HANDLED; | ||
177 | } | ||
178 | |||
179 | return IRQ_NONE; | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * In the routines that deal directly with the pcf8563 hardware, we use | ||
184 | * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. | ||
185 | */ | ||
186 | static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) | ||
187 | { | ||
188 | struct pcf8563 *pcf8563 = i2c_get_clientdata(client); | ||
189 | unsigned char buf[9]; | ||
190 | int err; | ||
191 | |||
192 | err = pcf8563_read_block_data(client, PCF8563_REG_ST1, 9, buf); | ||
193 | if (err) | ||
194 | return err; | ||
195 | |||
101 | if (buf[PCF8563_REG_SC] & PCF8563_SC_LV) { | 196 | if (buf[PCF8563_REG_SC] & PCF8563_SC_LV) { |
102 | pcf8563->voltage_low = 1; | 197 | pcf8563->voltage_low = 1; |
103 | dev_info(&client->dev, | 198 | dev_info(&client->dev, |
@@ -144,7 +239,7 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) | |||
144 | static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) | 239 | static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) |
145 | { | 240 | { |
146 | struct pcf8563 *pcf8563 = i2c_get_clientdata(client); | 241 | struct pcf8563 *pcf8563 = i2c_get_clientdata(client); |
147 | int i, err; | 242 | int err; |
148 | unsigned char buf[9]; | 243 | unsigned char buf[9]; |
149 | 244 | ||
150 | dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " | 245 | dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " |
@@ -170,19 +265,10 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) | |||
170 | 265 | ||
171 | buf[PCF8563_REG_DW] = tm->tm_wday & 0x07; | 266 | buf[PCF8563_REG_DW] = tm->tm_wday & 0x07; |
172 | 267 | ||
173 | /* write register's data */ | 268 | err = pcf8563_write_block_data(client, PCF8563_REG_SC, |
174 | for (i = 0; i < 7; i++) { | 269 | 9 - PCF8563_REG_SC, buf + PCF8563_REG_SC); |
175 | unsigned char data[2] = { PCF8563_REG_SC + i, | 270 | if (err) |
176 | buf[PCF8563_REG_SC + i] }; | 271 | return err; |
177 | |||
178 | err = i2c_master_send(client, data, sizeof(data)); | ||
179 | if (err != sizeof(data)) { | ||
180 | dev_err(&client->dev, | ||
181 | "%s: err=%d addr=%02x, data=%02x\n", | ||
182 | __func__, err, data[0], data[1]); | ||
183 | return -EIO; | ||
184 | } | ||
185 | } | ||
186 | 272 | ||
187 | return 0; | 273 | return 0; |
188 | } | 274 | } |
@@ -235,16 +321,83 @@ static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
235 | return pcf8563_set_datetime(to_i2c_client(dev), tm); | 321 | return pcf8563_set_datetime(to_i2c_client(dev), tm); |
236 | } | 322 | } |
237 | 323 | ||
324 | static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm) | ||
325 | { | ||
326 | struct i2c_client *client = to_i2c_client(dev); | ||
327 | unsigned char buf[4]; | ||
328 | int err; | ||
329 | |||
330 | err = pcf8563_read_block_data(client, PCF8563_REG_AMN, 4, buf); | ||
331 | if (err) | ||
332 | return err; | ||
333 | |||
334 | dev_dbg(&client->dev, | ||
335 | "%s: raw data is min=%02x, hr=%02x, mday=%02x, wday=%02x\n", | ||
336 | __func__, buf[0], buf[1], buf[2], buf[3]); | ||
337 | |||
338 | tm->time.tm_min = bcd2bin(buf[0] & 0x7F); | ||
339 | tm->time.tm_hour = bcd2bin(buf[1] & 0x7F); | ||
340 | tm->time.tm_mday = bcd2bin(buf[2] & 0x1F); | ||
341 | tm->time.tm_wday = bcd2bin(buf[3] & 0x7); | ||
342 | tm->time.tm_mon = -1; | ||
343 | tm->time.tm_year = -1; | ||
344 | tm->time.tm_yday = -1; | ||
345 | tm->time.tm_isdst = -1; | ||
346 | |||
347 | err = pcf8563_get_alarm_mode(client, &tm->enabled, &tm->pending); | ||
348 | if (err < 0) | ||
349 | return err; | ||
350 | |||
351 | dev_dbg(&client->dev, "%s: tm is mins=%d, hours=%d, mday=%d, wday=%d," | ||
352 | " enabled=%d, pending=%d\n", __func__, tm->time.tm_min, | ||
353 | tm->time.tm_hour, tm->time.tm_mday, tm->time.tm_wday, | ||
354 | tm->enabled, tm->pending); | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) | ||
360 | { | ||
361 | struct i2c_client *client = to_i2c_client(dev); | ||
362 | unsigned char buf[4]; | ||
363 | int err; | ||
364 | |||
365 | dev_dbg(dev, "%s, min=%d hour=%d wday=%d mday=%d " | ||
366 | "enabled=%d pending=%d\n", __func__, | ||
367 | tm->time.tm_min, tm->time.tm_hour, tm->time.tm_wday, | ||
368 | tm->time.tm_mday, tm->enabled, tm->pending); | ||
369 | |||
370 | buf[0] = bin2bcd(tm->time.tm_min); | ||
371 | buf[1] = bin2bcd(tm->time.tm_hour); | ||
372 | buf[2] = bin2bcd(tm->time.tm_mday); | ||
373 | buf[3] = tm->time.tm_wday & 0x07; | ||
374 | |||
375 | err = pcf8563_write_block_data(client, PCF8563_REG_AMN, 4, buf); | ||
376 | if (err) | ||
377 | return err; | ||
378 | |||
379 | return pcf8563_set_alarm_mode(client, 1); | ||
380 | } | ||
381 | |||
382 | static int pcf8563_irq_enable(struct device *dev, unsigned int enabled) | ||
383 | { | ||
384 | return pcf8563_set_alarm_mode(to_i2c_client(dev), !!enabled); | ||
385 | } | ||
386 | |||
238 | static const struct rtc_class_ops pcf8563_rtc_ops = { | 387 | static const struct rtc_class_ops pcf8563_rtc_ops = { |
239 | .ioctl = pcf8563_rtc_ioctl, | 388 | .ioctl = pcf8563_rtc_ioctl, |
240 | .read_time = pcf8563_rtc_read_time, | 389 | .read_time = pcf8563_rtc_read_time, |
241 | .set_time = pcf8563_rtc_set_time, | 390 | .set_time = pcf8563_rtc_set_time, |
391 | .read_alarm = pcf8563_rtc_read_alarm, | ||
392 | .set_alarm = pcf8563_rtc_set_alarm, | ||
393 | .alarm_irq_enable = pcf8563_irq_enable, | ||
242 | }; | 394 | }; |
243 | 395 | ||
244 | static int pcf8563_probe(struct i2c_client *client, | 396 | static int pcf8563_probe(struct i2c_client *client, |
245 | const struct i2c_device_id *id) | 397 | const struct i2c_device_id *id) |
246 | { | 398 | { |
247 | struct pcf8563 *pcf8563; | 399 | struct pcf8563 *pcf8563; |
400 | int err; | ||
248 | 401 | ||
249 | dev_dbg(&client->dev, "%s\n", __func__); | 402 | dev_dbg(&client->dev, "%s\n", __func__); |
250 | 403 | ||
@@ -259,12 +412,30 @@ static int pcf8563_probe(struct i2c_client *client, | |||
259 | dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); | 412 | dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); |
260 | 413 | ||
261 | i2c_set_clientdata(client, pcf8563); | 414 | i2c_set_clientdata(client, pcf8563); |
415 | pcf8563->client = client; | ||
416 | device_set_wakeup_capable(&client->dev, 1); | ||
262 | 417 | ||
263 | pcf8563->rtc = devm_rtc_device_register(&client->dev, | 418 | pcf8563->rtc = devm_rtc_device_register(&client->dev, |
264 | pcf8563_driver.driver.name, | 419 | pcf8563_driver.driver.name, |
265 | &pcf8563_rtc_ops, THIS_MODULE); | 420 | &pcf8563_rtc_ops, THIS_MODULE); |
266 | 421 | ||
267 | return PTR_ERR_OR_ZERO(pcf8563->rtc); | 422 | if (IS_ERR(pcf8563->rtc)) |
423 | return PTR_ERR(pcf8563->rtc); | ||
424 | |||
425 | if (client->irq > 0) { | ||
426 | err = devm_request_threaded_irq(&client->dev, client->irq, | ||
427 | NULL, pcf8563_irq, | ||
428 | IRQF_SHARED|IRQF_ONESHOT|IRQF_TRIGGER_FALLING, | ||
429 | pcf8563->rtc->name, client); | ||
430 | if (err) { | ||
431 | dev_err(&client->dev, "unable to request IRQ %d\n", | ||
432 | client->irq); | ||
433 | return err; | ||
434 | } | ||
435 | |||
436 | } | ||
437 | |||
438 | return 0; | ||
268 | } | 439 | } |
269 | 440 | ||
270 | static const struct i2c_device_id pcf8563_id[] = { | 441 | static const struct i2c_device_id pcf8563_id[] = { |