xref: /openbmc/linux/drivers/rtc/rtc-ds3232.c (revision b595076a)
1 /*
2  * RTC client/driver for the Maxim/Dallas DS3232 Real-Time Clock over I2C
3  *
4  * Copyright (C) 2009-2010 Freescale Semiconductor.
5  * Author: Jack Lan <jack.lan@freescale.com>
6  *
7  * This program is free software; you can redistribute  it and/or modify it
8  * under  the terms of  the GNU General  Public License as published by the
9  * Free Software Foundation;  either version 2 of the  License, or (at your
10  * option) any later version.
11  */
12 /*
13  * It would be more efficient to use i2c msgs/i2c_transfer directly but, as
14  * recommened in .../Documentation/i2c/writing-clients section
15  * "Sending and receiving", using SMBus level communication is preferred.
16  */
17 
18 #include <linux/kernel.h>
19 #include <linux/module.h>
20 #include <linux/interrupt.h>
21 #include <linux/i2c.h>
22 #include <linux/rtc.h>
23 #include <linux/bcd.h>
24 #include <linux/workqueue.h>
25 #include <linux/slab.h>
26 
27 #define DS3232_REG_SECONDS	0x00
28 #define DS3232_REG_MINUTES	0x01
29 #define DS3232_REG_HOURS	0x02
30 #define DS3232_REG_AMPM		0x02
31 #define DS3232_REG_DAY		0x03
32 #define DS3232_REG_DATE		0x04
33 #define DS3232_REG_MONTH	0x05
34 #define DS3232_REG_CENTURY	0x05
35 #define DS3232_REG_YEAR		0x06
36 #define DS3232_REG_ALARM1         0x07	/* Alarm 1 BASE */
37 #define DS3232_REG_ALARM2         0x0B	/* Alarm 2 BASE */
38 #define DS3232_REG_CR		0x0E	/* Control register */
39 #	define DS3232_REG_CR_nEOSC        0x80
40 #       define DS3232_REG_CR_INTCN        0x04
41 #       define DS3232_REG_CR_A2IE        0x02
42 #       define DS3232_REG_CR_A1IE        0x01
43 
44 #define DS3232_REG_SR	0x0F	/* control/status register */
45 #	define DS3232_REG_SR_OSF   0x80
46 #       define DS3232_REG_SR_BSY   0x04
47 #       define DS3232_REG_SR_A2F   0x02
48 #       define DS3232_REG_SR_A1F   0x01
49 
50 struct ds3232 {
51 	struct i2c_client *client;
52 	struct rtc_device *rtc;
53 	struct work_struct work;
54 
55 	/* The mutex protects alarm operations, and prevents a race
56 	 * between the enable_irq() in the workqueue and the free_irq()
57 	 * in the remove function.
58 	 */
59 	struct mutex mutex;
60 	int exiting;
61 };
62 
63 static struct i2c_driver ds3232_driver;
64 
65 static int ds3232_check_rtc_status(struct i2c_client *client)
66 {
67 	int ret = 0;
68 	int control, stat;
69 
70 	stat = i2c_smbus_read_byte_data(client, DS3232_REG_SR);
71 	if (stat < 0)
72 		return stat;
73 
74 	if (stat & DS3232_REG_SR_OSF)
75 		dev_warn(&client->dev,
76 				"oscillator discontinuity flagged, "
77 				"time unreliable\n");
78 
79 	stat &= ~(DS3232_REG_SR_OSF | DS3232_REG_SR_A1F | DS3232_REG_SR_A2F);
80 
81 	ret = i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat);
82 	if (ret < 0)
83 		return ret;
84 
85 	/* If the alarm is pending, clear it before requesting
86 	 * the interrupt, so an interrupt event isn't reported
87 	 * before everything is initialized.
88 	 */
89 
90 	control = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
91 	if (control < 0)
92 		return control;
93 
94 	control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE);
95 	control |= DS3232_REG_CR_INTCN;
96 
97 	return i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
98 }
99 
100 static int ds3232_read_time(struct device *dev, struct rtc_time *time)
101 {
102 	struct i2c_client *client = to_i2c_client(dev);
103 	int ret;
104 	u8 buf[7];
105 	unsigned int year, month, day, hour, minute, second;
106 	unsigned int week, twelve_hr, am_pm;
107 	unsigned int century, add_century = 0;
108 
109 	ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_SECONDS, 7, buf);
110 
111 	if (ret < 0)
112 		return ret;
113 	if (ret < 7)
114 		return -EIO;
115 
116 	second = buf[0];
117 	minute = buf[1];
118 	hour = buf[2];
119 	week = buf[3];
120 	day = buf[4];
121 	month = buf[5];
122 	year = buf[6];
123 
124 	/* Extract additional information for AM/PM and century */
125 
126 	twelve_hr = hour & 0x40;
127 	am_pm = hour & 0x20;
128 	century = month & 0x80;
129 
130 	/* Write to rtc_time structure */
131 
132 	time->tm_sec = bcd2bin(second);
133 	time->tm_min = bcd2bin(minute);
134 	if (twelve_hr) {
135 		/* Convert to 24 hr */
136 		if (am_pm)
137 			time->tm_hour = bcd2bin(hour & 0x1F) + 12;
138 		else
139 			time->tm_hour = bcd2bin(hour & 0x1F);
140 	} else {
141 		time->tm_hour = bcd2bin(hour);
142 	}
143 
144 	time->tm_wday = bcd2bin(week);
145 	time->tm_mday = bcd2bin(day);
146 	time->tm_mon = bcd2bin(month & 0x7F);
147 	if (century)
148 		add_century = 100;
149 
150 	time->tm_year = bcd2bin(year) + add_century;
151 
152 	return rtc_valid_tm(time);
153 }
154 
155 static int ds3232_set_time(struct device *dev, struct rtc_time *time)
156 {
157 	struct i2c_client *client = to_i2c_client(dev);
158 	u8 buf[7];
159 
160 	/* Extract time from rtc_time and load into ds3232*/
161 
162 	buf[0] = bin2bcd(time->tm_sec);
163 	buf[1] = bin2bcd(time->tm_min);
164 	buf[2] = bin2bcd(time->tm_hour);
165 	buf[3] = bin2bcd(time->tm_wday); /* Day of the week */
166 	buf[4] = bin2bcd(time->tm_mday); /* Date */
167 	buf[5] = bin2bcd(time->tm_mon);
168 	if (time->tm_year >= 100) {
169 		buf[5] |= 0x80;
170 		buf[6] = bin2bcd(time->tm_year - 100);
171 	} else {
172 		buf[6] = bin2bcd(time->tm_year);
173 	}
174 
175 	return i2c_smbus_write_i2c_block_data(client,
176 					      DS3232_REG_SECONDS, 7, buf);
177 }
178 
179 /*
180  * DS3232 has two alarm, we only use alarm1
181  * According to linux specification, only support one-shot alarm
182  * no periodic alarm mode
183  */
184 static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
185 {
186 	struct i2c_client *client = to_i2c_client(dev);
187 	struct ds3232 *ds3232 = i2c_get_clientdata(client);
188 	int control, stat;
189 	int ret;
190 	u8 buf[4];
191 
192 	mutex_lock(&ds3232->mutex);
193 
194 	ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR);
195 	if (ret < 0)
196 		goto out;
197 	stat = ret;
198 	ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
199 	if (ret < 0)
200 		goto out;
201 	control = ret;
202 	ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf);
203 	if (ret < 0)
204 		goto out;
205 
206 	alarm->time.tm_sec = bcd2bin(buf[0] & 0x7F);
207 	alarm->time.tm_min = bcd2bin(buf[1] & 0x7F);
208 	alarm->time.tm_hour = bcd2bin(buf[2] & 0x7F);
209 	alarm->time.tm_mday = bcd2bin(buf[3] & 0x7F);
210 
211 	alarm->time.tm_mon = -1;
212 	alarm->time.tm_year = -1;
213 	alarm->time.tm_wday = -1;
214 	alarm->time.tm_yday = -1;
215 	alarm->time.tm_isdst = -1;
216 
217 	alarm->enabled = !!(control & DS3232_REG_CR_A1IE);
218 	alarm->pending = !!(stat & DS3232_REG_SR_A1F);
219 
220 	ret = 0;
221 out:
222 	mutex_unlock(&ds3232->mutex);
223 	return ret;
224 }
225 
226 /*
227  * linux rtc-module does not support wday alarm
228  * and only 24h time mode supported indeed
229  */
230 static int ds3232_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
231 {
232 	struct i2c_client *client = to_i2c_client(dev);
233 	struct ds3232 *ds3232 = i2c_get_clientdata(client);
234 	int control, stat;
235 	int ret;
236 	u8 buf[4];
237 
238 	if (client->irq <= 0)
239 		return -EINVAL;
240 
241 	mutex_lock(&ds3232->mutex);
242 
243 	buf[0] = bin2bcd(alarm->time.tm_sec);
244 	buf[1] = bin2bcd(alarm->time.tm_min);
245 	buf[2] = bin2bcd(alarm->time.tm_hour);
246 	buf[3] = bin2bcd(alarm->time.tm_mday);
247 
248 	/* clear alarm interrupt enable bit */
249 	ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
250 	if (ret < 0)
251 		goto out;
252 	control = ret;
253 	control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE);
254 	ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
255 	if (ret < 0)
256 		goto out;
257 
258 	/* clear any pending alarm flag */
259 	ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR);
260 	if (ret < 0)
261 		goto out;
262 	stat = ret;
263 	stat &= ~(DS3232_REG_SR_A1F | DS3232_REG_SR_A2F);
264 	ret = i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat);
265 	if (ret < 0)
266 		goto out;
267 
268 	ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf);
269 
270 	if (alarm->enabled) {
271 		control |= DS3232_REG_CR_A1IE;
272 		ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
273 	}
274 out:
275 	mutex_unlock(&ds3232->mutex);
276 	return ret;
277 }
278 
279 static void ds3232_update_alarm(struct i2c_client *client)
280 {
281 	struct ds3232 *ds3232 = i2c_get_clientdata(client);
282 	int control;
283 	int ret;
284 	u8 buf[4];
285 
286 	mutex_lock(&ds3232->mutex);
287 
288 	ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf);
289 	if (ret < 0)
290 		goto unlock;
291 
292 	buf[0] = bcd2bin(buf[0]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
293 								0x80 : buf[0];
294 	buf[1] = bcd2bin(buf[1]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
295 								0x80 : buf[1];
296 	buf[2] = bcd2bin(buf[2]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
297 								0x80 : buf[2];
298 	buf[3] = bcd2bin(buf[3]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
299 								0x80 : buf[3];
300 
301 	ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf);
302 	if (ret < 0)
303 		goto unlock;
304 
305 	control = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
306 	if (control < 0)
307 		goto unlock;
308 
309 	if (ds3232->rtc->irq_data & (RTC_AF | RTC_UF))
310 		/* enable alarm1 interrupt */
311 		control |= DS3232_REG_CR_A1IE;
312 	else
313 		/* disable alarm1 interrupt */
314 		control &= ~(DS3232_REG_CR_A1IE);
315 	i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
316 
317 unlock:
318 	mutex_unlock(&ds3232->mutex);
319 }
320 
321 static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled)
322 {
323 	struct i2c_client *client = to_i2c_client(dev);
324 	struct ds3232 *ds3232 = i2c_get_clientdata(client);
325 
326 	if (client->irq <= 0)
327 		return -EINVAL;
328 
329 	if (enabled)
330 		ds3232->rtc->irq_data |= RTC_AF;
331 	else
332 		ds3232->rtc->irq_data &= ~RTC_AF;
333 
334 	ds3232_update_alarm(client);
335 	return 0;
336 }
337 
338 static int ds3232_update_irq_enable(struct device *dev, unsigned int enabled)
339 {
340 	struct i2c_client *client = to_i2c_client(dev);
341 	struct ds3232 *ds3232 = i2c_get_clientdata(client);
342 
343 	if (client->irq <= 0)
344 		return -EINVAL;
345 
346 	if (enabled)
347 		ds3232->rtc->irq_data |= RTC_UF;
348 	else
349 		ds3232->rtc->irq_data &= ~RTC_UF;
350 
351 	ds3232_update_alarm(client);
352 	return 0;
353 }
354 
355 static irqreturn_t ds3232_irq(int irq, void *dev_id)
356 {
357 	struct i2c_client *client = dev_id;
358 	struct ds3232 *ds3232 = i2c_get_clientdata(client);
359 
360 	disable_irq_nosync(irq);
361 	schedule_work(&ds3232->work);
362 	return IRQ_HANDLED;
363 }
364 
365 static void ds3232_work(struct work_struct *work)
366 {
367 	struct ds3232 *ds3232 = container_of(work, struct ds3232, work);
368 	struct i2c_client *client = ds3232->client;
369 	int stat, control;
370 
371 	mutex_lock(&ds3232->mutex);
372 
373 	stat = i2c_smbus_read_byte_data(client, DS3232_REG_SR);
374 	if (stat < 0)
375 		goto unlock;
376 
377 	if (stat & DS3232_REG_SR_A1F) {
378 		control = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
379 		if (control < 0)
380 			goto out;
381 		/* disable alarm1 interrupt */
382 		control &= ~(DS3232_REG_CR_A1IE);
383 		i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
384 
385 		/* clear the alarm pend flag */
386 		stat &= ~DS3232_REG_SR_A1F;
387 		i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat);
388 
389 		rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF);
390 	}
391 
392 out:
393 	if (!ds3232->exiting)
394 		enable_irq(client->irq);
395 unlock:
396 	mutex_unlock(&ds3232->mutex);
397 }
398 
399 static const struct rtc_class_ops ds3232_rtc_ops = {
400 	.read_time = ds3232_read_time,
401 	.set_time = ds3232_set_time,
402 	.read_alarm = ds3232_read_alarm,
403 	.set_alarm = ds3232_set_alarm,
404 	.alarm_irq_enable = ds3232_alarm_irq_enable,
405 	.update_irq_enable = ds3232_update_irq_enable,
406 };
407 
408 static int __devinit ds3232_probe(struct i2c_client *client,
409 		const struct i2c_device_id *id)
410 {
411 	struct ds3232 *ds3232;
412 	int ret;
413 
414 	ds3232 = kzalloc(sizeof(struct ds3232), GFP_KERNEL);
415 	if (!ds3232)
416 		return -ENOMEM;
417 
418 	ds3232->client = client;
419 	i2c_set_clientdata(client, ds3232);
420 
421 	INIT_WORK(&ds3232->work, ds3232_work);
422 	mutex_init(&ds3232->mutex);
423 
424 	ret = ds3232_check_rtc_status(client);
425 	if (ret)
426 		goto out_free;
427 
428 	ds3232->rtc = rtc_device_register(client->name, &client->dev,
429 					  &ds3232_rtc_ops, THIS_MODULE);
430 	if (IS_ERR(ds3232->rtc)) {
431 		ret = PTR_ERR(ds3232->rtc);
432 		dev_err(&client->dev, "unable to register the class device\n");
433 		goto out_irq;
434 	}
435 
436 	if (client->irq >= 0) {
437 		ret = request_irq(client->irq, ds3232_irq, 0,
438 				 "ds3232", client);
439 		if (ret) {
440 			dev_err(&client->dev, "unable to request IRQ\n");
441 			goto out_free;
442 		}
443 	}
444 
445 	return 0;
446 
447 out_irq:
448 	if (client->irq >= 0)
449 		free_irq(client->irq, client);
450 
451 out_free:
452 	kfree(ds3232);
453 	return ret;
454 }
455 
456 static int __devexit ds3232_remove(struct i2c_client *client)
457 {
458 	struct ds3232 *ds3232 = i2c_get_clientdata(client);
459 
460 	if (client->irq >= 0) {
461 		mutex_lock(&ds3232->mutex);
462 		ds3232->exiting = 1;
463 		mutex_unlock(&ds3232->mutex);
464 
465 		free_irq(client->irq, client);
466 		flush_scheduled_work();
467 	}
468 
469 	rtc_device_unregister(ds3232->rtc);
470 	kfree(ds3232);
471 	return 0;
472 }
473 
474 static const struct i2c_device_id ds3232_id[] = {
475 	{ "ds3232", 0 },
476 	{ }
477 };
478 MODULE_DEVICE_TABLE(i2c, ds3232_id);
479 
480 static struct i2c_driver ds3232_driver = {
481 	.driver = {
482 		.name = "rtc-ds3232",
483 		.owner = THIS_MODULE,
484 	},
485 	.probe = ds3232_probe,
486 	.remove = __devexit_p(ds3232_remove),
487 	.id_table = ds3232_id,
488 };
489 
490 static int __init ds3232_init(void)
491 {
492 	return i2c_add_driver(&ds3232_driver);
493 }
494 
495 static void __exit ds3232_exit(void)
496 {
497 	i2c_del_driver(&ds3232_driver);
498 }
499 
500 module_init(ds3232_init);
501 module_exit(ds3232_exit);
502 
503 MODULE_AUTHOR("Srikanth Srinivasan <srikanth.srinivasan@freescale.com>");
504 MODULE_DESCRIPTION("Maxim/Dallas DS3232 RTC Driver");
505 MODULE_LICENSE("GPL");
506