xref: /openbmc/linux/drivers/rtc/rtc-ds1374.c (revision a1e58bbd)
1 /*
2  * RTC client/driver for the Maxim/Dallas DS1374 Real-Time Clock over I2C
3  *
4  * Based on code by Randy Vinson <rvinson@mvista.com>,
5  * which was based on the m41t00.c by Mark Greer <mgreer@mvista.com>.
6  *
7  * Copyright (C) 2006-2007 Freescale Semiconductor
8  *
9  * 2005 (c) MontaVista Software, Inc. This file is licensed under
10  * the terms of the GNU General Public License version 2. This program
11  * is licensed "as is" without any warranty of any kind, whether express
12  * or implied.
13  */
14 /*
15  * It would be more efficient to use i2c msgs/i2c_transfer directly but, as
16  * recommened in .../Documentation/i2c/writing-clients section
17  * "Sending and receiving", using SMBus level communication is preferred.
18  */
19 
20 #include <linux/kernel.h>
21 #include <linux/module.h>
22 #include <linux/interrupt.h>
23 #include <linux/i2c.h>
24 #include <linux/rtc.h>
25 #include <linux/bcd.h>
26 #include <linux/workqueue.h>
27 
28 #define DS1374_REG_TOD0		0x00 /* Time of Day */
29 #define DS1374_REG_TOD1		0x01
30 #define DS1374_REG_TOD2		0x02
31 #define DS1374_REG_TOD3		0x03
32 #define DS1374_REG_WDALM0	0x04 /* Watchdog/Alarm */
33 #define DS1374_REG_WDALM1	0x05
34 #define DS1374_REG_WDALM2	0x06
35 #define DS1374_REG_CR		0x07 /* Control */
36 #define DS1374_REG_CR_AIE	0x01 /* Alarm Int. Enable */
37 #define DS1374_REG_CR_WDALM	0x20 /* 1=Watchdog, 0=Alarm */
38 #define DS1374_REG_CR_WACE	0x40 /* WD/Alarm counter enable */
39 #define DS1374_REG_SR		0x08 /* Status */
40 #define DS1374_REG_SR_OSF	0x80 /* Oscillator Stop Flag */
41 #define DS1374_REG_SR_AF	0x01 /* Alarm Flag */
42 #define DS1374_REG_TCR		0x09 /* Trickle Charge */
43 
44 struct ds1374 {
45 	struct i2c_client *client;
46 	struct rtc_device *rtc;
47 	struct work_struct work;
48 
49 	/* The mutex protects alarm operations, and prevents a race
50 	 * between the enable_irq() in the workqueue and the free_irq()
51 	 * in the remove function.
52 	 */
53 	struct mutex mutex;
54 	int exiting;
55 };
56 
57 static struct i2c_driver ds1374_driver;
58 
59 static int ds1374_read_rtc(struct i2c_client *client, u32 *time,
60                            int reg, int nbytes)
61 {
62 	u8 buf[4];
63 	int ret;
64 	int i;
65 
66 	if (nbytes > 4) {
67 		WARN_ON(1);
68 		return -EINVAL;
69 	}
70 
71 	ret = i2c_smbus_read_i2c_block_data(client, reg, nbytes, buf);
72 
73 	if (ret < 0)
74 		return ret;
75 	if (ret < nbytes)
76 		return -EIO;
77 
78 	for (i = nbytes - 1, *time = 0; i >= 0; i--)
79 		*time = (*time << 8) | buf[i];
80 
81 	return 0;
82 }
83 
84 static int ds1374_write_rtc(struct i2c_client *client, u32 time,
85                             int reg, int nbytes)
86 {
87 	u8 buf[4];
88 	int i;
89 
90 	if (nbytes > 4) {
91 		WARN_ON(1);
92 		return -EINVAL;
93 	}
94 
95 	for (i = 0; i < nbytes; i++) {
96 		buf[i] = time & 0xff;
97 		time >>= 8;
98 	}
99 
100 	return i2c_smbus_write_i2c_block_data(client, reg, nbytes, buf);
101 }
102 
103 static int ds1374_check_rtc_status(struct i2c_client *client)
104 {
105 	int ret = 0;
106 	int control, stat;
107 
108 	stat = i2c_smbus_read_byte_data(client, DS1374_REG_SR);
109 	if (stat < 0)
110 		return stat;
111 
112 	if (stat & DS1374_REG_SR_OSF)
113 		dev_warn(&client->dev,
114 		         "oscillator discontinuity flagged, "
115 		         "time unreliable\n");
116 
117 	stat &= ~(DS1374_REG_SR_OSF | DS1374_REG_SR_AF);
118 
119 	ret = i2c_smbus_write_byte_data(client, DS1374_REG_SR, stat);
120 	if (ret < 0)
121 		return ret;
122 
123 	/* If the alarm is pending, clear it before requesting
124 	 * the interrupt, so an interrupt event isn't reported
125 	 * before everything is initialized.
126 	 */
127 
128 	control = i2c_smbus_read_byte_data(client, DS1374_REG_CR);
129 	if (control < 0)
130 		return control;
131 
132 	control &= ~(DS1374_REG_CR_WACE | DS1374_REG_CR_AIE);
133 	return i2c_smbus_write_byte_data(client, DS1374_REG_CR, control);
134 }
135 
136 static int ds1374_read_time(struct device *dev, struct rtc_time *time)
137 {
138 	struct i2c_client *client = to_i2c_client(dev);
139 	u32 itime;
140 	int ret;
141 
142 	ret = ds1374_read_rtc(client, &itime, DS1374_REG_TOD0, 4);
143 	if (!ret)
144 		rtc_time_to_tm(itime, time);
145 
146 	return ret;
147 }
148 
149 static int ds1374_set_time(struct device *dev, struct rtc_time *time)
150 {
151 	struct i2c_client *client = to_i2c_client(dev);
152 	unsigned long itime;
153 
154 	rtc_tm_to_time(time, &itime);
155 	return ds1374_write_rtc(client, itime, DS1374_REG_TOD0, 4);
156 }
157 
158 /* The ds1374 has a decrementer for an alarm, rather than a comparator.
159  * If the time of day is changed, then the alarm will need to be
160  * reset.
161  */
162 static int ds1374_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
163 {
164 	struct i2c_client *client = to_i2c_client(dev);
165 	struct ds1374 *ds1374 = i2c_get_clientdata(client);
166 	u32 now, cur_alarm;
167 	int cr, sr;
168 	int ret = 0;
169 
170 	if (client->irq < 0)
171 		return -EINVAL;
172 
173 	mutex_lock(&ds1374->mutex);
174 
175 	cr = ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR);
176 	if (ret < 0)
177 		goto out;
178 
179 	sr = ret = i2c_smbus_read_byte_data(client, DS1374_REG_SR);
180 	if (ret < 0)
181 		goto out;
182 
183 	ret = ds1374_read_rtc(client, &now, DS1374_REG_TOD0, 4);
184 	if (ret)
185 		goto out;
186 
187 	ret = ds1374_read_rtc(client, &cur_alarm, DS1374_REG_WDALM0, 3);
188 	if (ret)
189 		goto out;
190 
191 	rtc_time_to_tm(now + cur_alarm, &alarm->time);
192 	alarm->enabled = !!(cr & DS1374_REG_CR_WACE);
193 	alarm->pending = !!(sr & DS1374_REG_SR_AF);
194 
195 out:
196 	mutex_unlock(&ds1374->mutex);
197 	return ret;
198 }
199 
200 static int ds1374_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
201 {
202 	struct i2c_client *client = to_i2c_client(dev);
203 	struct ds1374 *ds1374 = i2c_get_clientdata(client);
204 	struct rtc_time now;
205 	unsigned long new_alarm, itime;
206 	int cr;
207 	int ret = 0;
208 
209 	if (client->irq < 0)
210 		return -EINVAL;
211 
212 	ret = ds1374_read_time(dev, &now);
213 	if (ret < 0)
214 		return ret;
215 
216 	rtc_tm_to_time(&alarm->time, &new_alarm);
217 	rtc_tm_to_time(&now, &itime);
218 
219 	new_alarm -= itime;
220 
221 	/* This can happen due to races, in addition to dates that are
222 	 * truly in the past.  To avoid requiring the caller to check for
223 	 * races, dates in the past are assumed to be in the recent past
224 	 * (i.e. not something that we'd rather the caller know about via
225 	 * an error), and the alarm is set to go off as soon as possible.
226 	 */
227 	if (new_alarm <= 0)
228 		new_alarm = 1;
229 
230 	mutex_lock(&ds1374->mutex);
231 
232 	ret = cr = i2c_smbus_read_byte_data(client, DS1374_REG_CR);
233 	if (ret < 0)
234 		goto out;
235 
236 	/* Disable any existing alarm before setting the new one
237 	 * (or lack thereof). */
238 	cr &= ~DS1374_REG_CR_WACE;
239 
240 	ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, cr);
241 	if (ret < 0)
242 		goto out;
243 
244 	ret = ds1374_write_rtc(client, new_alarm, DS1374_REG_WDALM0, 3);
245 	if (ret)
246 		goto out;
247 
248 	if (alarm->enabled) {
249 		cr |= DS1374_REG_CR_WACE | DS1374_REG_CR_AIE;
250 		cr &= ~DS1374_REG_CR_WDALM;
251 
252 		ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, cr);
253 	}
254 
255 out:
256 	mutex_unlock(&ds1374->mutex);
257 	return ret;
258 }
259 
260 static irqreturn_t ds1374_irq(int irq, void *dev_id)
261 {
262 	struct i2c_client *client = dev_id;
263 	struct ds1374 *ds1374 = i2c_get_clientdata(client);
264 
265 	disable_irq_nosync(irq);
266 	schedule_work(&ds1374->work);
267 	return IRQ_HANDLED;
268 }
269 
270 static void ds1374_work(struct work_struct *work)
271 {
272 	struct ds1374 *ds1374 = container_of(work, struct ds1374, work);
273 	struct i2c_client *client = ds1374->client;
274 	int stat, control;
275 
276 	mutex_lock(&ds1374->mutex);
277 
278 	stat = i2c_smbus_read_byte_data(client, DS1374_REG_SR);
279 	if (stat < 0)
280 		return;
281 
282 	if (stat & DS1374_REG_SR_AF) {
283 		stat &= ~DS1374_REG_SR_AF;
284 		i2c_smbus_write_byte_data(client, DS1374_REG_SR, stat);
285 
286 		control = i2c_smbus_read_byte_data(client, DS1374_REG_CR);
287 		if (control < 0)
288 			goto out;
289 
290 		control &= ~(DS1374_REG_CR_WACE | DS1374_REG_CR_AIE);
291 		i2c_smbus_write_byte_data(client, DS1374_REG_CR, control);
292 
293 		/* rtc_update_irq() assumes that it is called
294 		 * from IRQ-disabled context.
295 		 */
296 		local_irq_disable();
297 		rtc_update_irq(ds1374->rtc, 1, RTC_AF | RTC_IRQF);
298 		local_irq_enable();
299 	}
300 
301 out:
302 	if (!ds1374->exiting)
303 		enable_irq(client->irq);
304 
305 	mutex_unlock(&ds1374->mutex);
306 }
307 
308 static int ds1374_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
309 {
310 	struct i2c_client *client = to_i2c_client(dev);
311 	struct ds1374 *ds1374 = i2c_get_clientdata(client);
312 	int ret = -ENOIOCTLCMD;
313 
314 	mutex_lock(&ds1374->mutex);
315 
316 	switch (cmd) {
317 	case RTC_AIE_OFF:
318 		ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR);
319 		if (ret < 0)
320 			goto out;
321 
322 		ret &= ~DS1374_REG_CR_WACE;
323 
324 		ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret);
325 		if (ret < 0)
326 			goto out;
327 
328 		break;
329 
330 	case RTC_AIE_ON:
331 		ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR);
332 		if (ret < 0)
333 			goto out;
334 
335 		ret |= DS1374_REG_CR_WACE | DS1374_REG_CR_AIE;
336 		ret &= ~DS1374_REG_CR_WDALM;
337 
338 		ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret);
339 		if (ret < 0)
340 			goto out;
341 
342 		break;
343 	}
344 
345 out:
346 	mutex_unlock(&ds1374->mutex);
347 	return ret;
348 }
349 
350 static const struct rtc_class_ops ds1374_rtc_ops = {
351 	.read_time = ds1374_read_time,
352 	.set_time = ds1374_set_time,
353 	.read_alarm = ds1374_read_alarm,
354 	.set_alarm = ds1374_set_alarm,
355 	.ioctl = ds1374_ioctl,
356 };
357 
358 static int ds1374_probe(struct i2c_client *client)
359 {
360 	struct ds1374 *ds1374;
361 	int ret;
362 
363 	ds1374 = kzalloc(sizeof(struct ds1374), GFP_KERNEL);
364 	if (!ds1374)
365 		return -ENOMEM;
366 
367 	ds1374->client = client;
368 	i2c_set_clientdata(client, ds1374);
369 
370 	INIT_WORK(&ds1374->work, ds1374_work);
371 	mutex_init(&ds1374->mutex);
372 
373 	ret = ds1374_check_rtc_status(client);
374 	if (ret)
375 		goto out_free;
376 
377 	if (client->irq >= 0) {
378 		ret = request_irq(client->irq, ds1374_irq, 0,
379 		                  "ds1374", client);
380 		if (ret) {
381 			dev_err(&client->dev, "unable to request IRQ\n");
382 			goto out_free;
383 		}
384 	}
385 
386 	ds1374->rtc = rtc_device_register(client->name, &client->dev,
387 	                                  &ds1374_rtc_ops, THIS_MODULE);
388 	if (IS_ERR(ds1374->rtc)) {
389 		ret = PTR_ERR(ds1374->rtc);
390 		dev_err(&client->dev, "unable to register the class device\n");
391 		goto out_irq;
392 	}
393 
394 	return 0;
395 
396 out_irq:
397 	if (client->irq >= 0)
398 		free_irq(client->irq, client);
399 
400 out_free:
401 	i2c_set_clientdata(client, NULL);
402 	kfree(ds1374);
403 	return ret;
404 }
405 
406 static int __devexit ds1374_remove(struct i2c_client *client)
407 {
408 	struct ds1374 *ds1374 = i2c_get_clientdata(client);
409 
410 	if (client->irq >= 0) {
411 		mutex_lock(&ds1374->mutex);
412 		ds1374->exiting = 1;
413 		mutex_unlock(&ds1374->mutex);
414 
415 		free_irq(client->irq, client);
416 		flush_scheduled_work();
417 	}
418 
419 	rtc_device_unregister(ds1374->rtc);
420 	i2c_set_clientdata(client, NULL);
421 	kfree(ds1374);
422 	return 0;
423 }
424 
425 static struct i2c_driver ds1374_driver = {
426 	.driver = {
427 		.name = "rtc-ds1374",
428 		.owner = THIS_MODULE,
429 	},
430 	.probe = ds1374_probe,
431 	.remove = __devexit_p(ds1374_remove),
432 };
433 
434 static int __init ds1374_init(void)
435 {
436 	return i2c_add_driver(&ds1374_driver);
437 }
438 
439 static void __exit ds1374_exit(void)
440 {
441 	i2c_del_driver(&ds1374_driver);
442 }
443 
444 module_init(ds1374_init);
445 module_exit(ds1374_exit);
446 
447 MODULE_AUTHOR("Scott Wood <scottwood@freescale.com>");
448 MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC Driver");
449 MODULE_LICENSE("GPL");
450