Root/drivers/rtc/rtc-ds3232.c

1/*
2 * RTC client/driver for the Maxim/Dallas DS3232 Real-Time Clock over I2C
3 *
4 * Copyright (C) 2009-2011 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
50struct 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
63static struct i2c_driver ds3232_driver;
64
65static 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
100static 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    /* Day of the week in linux range is 0~6 while 1~7 in RTC chip */
145    time->tm_wday = bcd2bin(week) - 1;
146    time->tm_mday = bcd2bin(day);
147    /* linux tm_mon range:0~11, while month range is 1~12 in RTC chip */
148    time->tm_mon = bcd2bin(month & 0x7F) - 1;
149    if (century)
150        add_century = 100;
151
152    time->tm_year = bcd2bin(year) + add_century;
153
154    return rtc_valid_tm(time);
155}
156
157static int ds3232_set_time(struct device *dev, struct rtc_time *time)
158{
159    struct i2c_client *client = to_i2c_client(dev);
160    u8 buf[7];
161
162    /* Extract time from rtc_time and load into ds3232*/
163
164    buf[0] = bin2bcd(time->tm_sec);
165    buf[1] = bin2bcd(time->tm_min);
166    buf[2] = bin2bcd(time->tm_hour);
167    /* Day of the week in linux range is 0~6 while 1~7 in RTC chip */
168    buf[3] = bin2bcd(time->tm_wday + 1);
169    buf[4] = bin2bcd(time->tm_mday); /* Date */
170    /* linux tm_mon range:0~11, while month range is 1~12 in RTC chip */
171    buf[5] = bin2bcd(time->tm_mon + 1);
172    if (time->tm_year >= 100) {
173        buf[5] |= 0x80;
174        buf[6] = bin2bcd(time->tm_year - 100);
175    } else {
176        buf[6] = bin2bcd(time->tm_year);
177    }
178
179    return i2c_smbus_write_i2c_block_data(client,
180                          DS3232_REG_SECONDS, 7, buf);
181}
182
183/*
184 * DS3232 has two alarm, we only use alarm1
185 * According to linux specification, only support one-shot alarm
186 * no periodic alarm mode
187 */
188static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
189{
190    struct i2c_client *client = to_i2c_client(dev);
191    struct ds3232 *ds3232 = i2c_get_clientdata(client);
192    int control, stat;
193    int ret;
194    u8 buf[4];
195
196    mutex_lock(&ds3232->mutex);
197
198    ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR);
199    if (ret < 0)
200        goto out;
201    stat = ret;
202    ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
203    if (ret < 0)
204        goto out;
205    control = ret;
206    ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf);
207    if (ret < 0)
208        goto out;
209
210    alarm->time.tm_sec = bcd2bin(buf[0] & 0x7F);
211    alarm->time.tm_min = bcd2bin(buf[1] & 0x7F);
212    alarm->time.tm_hour = bcd2bin(buf[2] & 0x7F);
213    alarm->time.tm_mday = bcd2bin(buf[3] & 0x7F);
214
215    alarm->time.tm_mon = -1;
216    alarm->time.tm_year = -1;
217    alarm->time.tm_wday = -1;
218    alarm->time.tm_yday = -1;
219    alarm->time.tm_isdst = -1;
220
221    alarm->enabled = !!(control & DS3232_REG_CR_A1IE);
222    alarm->pending = !!(stat & DS3232_REG_SR_A1F);
223
224    ret = 0;
225out:
226    mutex_unlock(&ds3232->mutex);
227    return ret;
228}
229
230/*
231 * linux rtc-module does not support wday alarm
232 * and only 24h time mode supported indeed
233 */
234static int ds3232_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
235{
236    struct i2c_client *client = to_i2c_client(dev);
237    struct ds3232 *ds3232 = i2c_get_clientdata(client);
238    int control, stat;
239    int ret;
240    u8 buf[4];
241
242    if (client->irq <= 0)
243        return -EINVAL;
244
245    mutex_lock(&ds3232->mutex);
246
247    buf[0] = bin2bcd(alarm->time.tm_sec);
248    buf[1] = bin2bcd(alarm->time.tm_min);
249    buf[2] = bin2bcd(alarm->time.tm_hour);
250    buf[3] = bin2bcd(alarm->time.tm_mday);
251
252    /* clear alarm interrupt enable bit */
253    ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
254    if (ret < 0)
255        goto out;
256    control = ret;
257    control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE);
258    ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
259    if (ret < 0)
260        goto out;
261
262    /* clear any pending alarm flag */
263    ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR);
264    if (ret < 0)
265        goto out;
266    stat = ret;
267    stat &= ~(DS3232_REG_SR_A1F | DS3232_REG_SR_A2F);
268    ret = i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat);
269    if (ret < 0)
270        goto out;
271
272    ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf);
273
274    if (alarm->enabled) {
275        control |= DS3232_REG_CR_A1IE;
276        ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
277    }
278out:
279    mutex_unlock(&ds3232->mutex);
280    return ret;
281}
282
283static void ds3232_update_alarm(struct i2c_client *client)
284{
285    struct ds3232 *ds3232 = i2c_get_clientdata(client);
286    int control;
287    int ret;
288    u8 buf[4];
289
290    mutex_lock(&ds3232->mutex);
291
292    ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf);
293    if (ret < 0)
294        goto unlock;
295
296    buf[0] = bcd2bin(buf[0]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
297                                0x80 : buf[0];
298    buf[1] = bcd2bin(buf[1]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
299                                0x80 : buf[1];
300    buf[2] = bcd2bin(buf[2]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
301                                0x80 : buf[2];
302    buf[3] = bcd2bin(buf[3]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
303                                0x80 : buf[3];
304
305    ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf);
306    if (ret < 0)
307        goto unlock;
308
309    control = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
310    if (control < 0)
311        goto unlock;
312
313    if (ds3232->rtc->irq_data & (RTC_AF | RTC_UF))
314        /* enable alarm1 interrupt */
315        control |= DS3232_REG_CR_A1IE;
316    else
317        /* disable alarm1 interrupt */
318        control &= ~(DS3232_REG_CR_A1IE);
319    i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
320
321unlock:
322    mutex_unlock(&ds3232->mutex);
323}
324
325static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled)
326{
327    struct i2c_client *client = to_i2c_client(dev);
328    struct ds3232 *ds3232 = i2c_get_clientdata(client);
329
330    if (client->irq <= 0)
331        return -EINVAL;
332
333    if (enabled)
334        ds3232->rtc->irq_data |= RTC_AF;
335    else
336        ds3232->rtc->irq_data &= ~RTC_AF;
337
338    ds3232_update_alarm(client);
339    return 0;
340}
341
342static irqreturn_t ds3232_irq(int irq, void *dev_id)
343{
344    struct i2c_client *client = dev_id;
345    struct ds3232 *ds3232 = i2c_get_clientdata(client);
346
347    disable_irq_nosync(irq);
348    schedule_work(&ds3232->work);
349    return IRQ_HANDLED;
350}
351
352static void ds3232_work(struct work_struct *work)
353{
354    struct ds3232 *ds3232 = container_of(work, struct ds3232, work);
355    struct i2c_client *client = ds3232->client;
356    int stat, control;
357
358    mutex_lock(&ds3232->mutex);
359
360    stat = i2c_smbus_read_byte_data(client, DS3232_REG_SR);
361    if (stat < 0)
362        goto unlock;
363
364    if (stat & DS3232_REG_SR_A1F) {
365        control = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
366        if (control < 0)
367            goto out;
368        /* disable alarm1 interrupt */
369        control &= ~(DS3232_REG_CR_A1IE);
370        i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
371
372        /* clear the alarm pend flag */
373        stat &= ~DS3232_REG_SR_A1F;
374        i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat);
375
376        rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF);
377    }
378
379out:
380    if (!ds3232->exiting)
381        enable_irq(client->irq);
382unlock:
383    mutex_unlock(&ds3232->mutex);
384}
385
386static const struct rtc_class_ops ds3232_rtc_ops = {
387    .read_time = ds3232_read_time,
388    .set_time = ds3232_set_time,
389    .read_alarm = ds3232_read_alarm,
390    .set_alarm = ds3232_set_alarm,
391    .alarm_irq_enable = ds3232_alarm_irq_enable,
392};
393
394static int __devinit ds3232_probe(struct i2c_client *client,
395        const struct i2c_device_id *id)
396{
397    struct ds3232 *ds3232;
398    int ret;
399
400    ds3232 = kzalloc(sizeof(struct ds3232), GFP_KERNEL);
401    if (!ds3232)
402        return -ENOMEM;
403
404    ds3232->client = client;
405    i2c_set_clientdata(client, ds3232);
406
407    INIT_WORK(&ds3232->work, ds3232_work);
408    mutex_init(&ds3232->mutex);
409
410    ret = ds3232_check_rtc_status(client);
411    if (ret)
412        goto out_free;
413
414    ds3232->rtc = rtc_device_register(client->name, &client->dev,
415                      &ds3232_rtc_ops, THIS_MODULE);
416    if (IS_ERR(ds3232->rtc)) {
417        ret = PTR_ERR(ds3232->rtc);
418        dev_err(&client->dev, "unable to register the class device\n");
419        goto out_irq;
420    }
421
422    if (client->irq >= 0) {
423        ret = request_irq(client->irq, ds3232_irq, 0,
424                 "ds3232", client);
425        if (ret) {
426            dev_err(&client->dev, "unable to request IRQ\n");
427            goto out_free;
428        }
429    }
430
431    return 0;
432
433out_irq:
434    if (client->irq >= 0)
435        free_irq(client->irq, client);
436
437out_free:
438    kfree(ds3232);
439    return ret;
440}
441
442static int __devexit ds3232_remove(struct i2c_client *client)
443{
444    struct ds3232 *ds3232 = i2c_get_clientdata(client);
445
446    if (client->irq >= 0) {
447        mutex_lock(&ds3232->mutex);
448        ds3232->exiting = 1;
449        mutex_unlock(&ds3232->mutex);
450
451        free_irq(client->irq, client);
452        cancel_work_sync(&ds3232->work);
453    }
454
455    rtc_device_unregister(ds3232->rtc);
456    kfree(ds3232);
457    return 0;
458}
459
460static const struct i2c_device_id ds3232_id[] = {
461    { "ds3232", 0 },
462    { }
463};
464MODULE_DEVICE_TABLE(i2c, ds3232_id);
465
466static struct i2c_driver ds3232_driver = {
467    .driver = {
468        .name = "rtc-ds3232",
469        .owner = THIS_MODULE,
470    },
471    .probe = ds3232_probe,
472    .remove = __devexit_p(ds3232_remove),
473    .id_table = ds3232_id,
474};
475
476module_i2c_driver(ds3232_driver);
477
478MODULE_AUTHOR("Srikanth Srinivasan <srikanth.srinivasan@freescale.com>");
479MODULE_DESCRIPTION("Maxim/Dallas DS3232 RTC Driver");
480MODULE_LICENSE("GPL");
481

Archive Download this file



interactive