2 * An rtc/i2c driver for the Dallas DS1672
3 * Copyright 2005-06 Tower Technologies
5 * Author: Alessandro Zummo <a.zummo@towertech.it>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
12 #include <linux/module.h>
13 #include <linux/i2c.h>
14 #include <linux/rtc.h>
16 #define DRV_VERSION "0.3"
18 /* Addresses to scan: none. This chip cannot be detected. */
19 static unsigned short normal_i2c
[] = { I2C_CLIENT_END
};
21 /* Insmod parameters */
26 #define DS1672_REG_CNT_BASE 0
27 #define DS1672_REG_CONTROL 4
28 #define DS1672_REG_TRICKLE 5
30 #define DS1672_REG_CONTROL_EOSC 0x80
33 static int ds1672_probe(struct i2c_adapter
*adapter
, int address
, int kind
);
36 * In the routines that deal directly with the ds1672 hardware, we use
37 * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch
38 * Epoch is initialized as 2000. Time is set to UTC.
40 static int ds1672_get_datetime(struct i2c_client
*client
, struct rtc_time
*tm
)
43 unsigned char addr
= DS1672_REG_CNT_BASE
;
46 struct i2c_msg msgs
[] = {
47 { client
->addr
, 0, 1, &addr
}, /* setup read ptr */
48 { client
->addr
, I2C_M_RD
, 4, buf
}, /* read date */
51 /* read date registers */
52 if ((i2c_transfer(client
->adapter
, &msgs
[0], 2)) != 2) {
53 dev_err(&client
->dev
, "%s: read error\n", __FUNCTION__
);
58 "%s: raw read data - counters=%02x,%02x,%02x,%02x\n",
59 __FUNCTION__
, buf
[0], buf
[1], buf
[2], buf
[3]);
61 time
= (buf
[3] << 24) | (buf
[2] << 16) | (buf
[1] << 8) | buf
[0];
63 rtc_time_to_tm(time
, tm
);
65 dev_dbg(&client
->dev
, "%s: tm is secs=%d, mins=%d, hours=%d, "
66 "mday=%d, mon=%d, year=%d, wday=%d\n",
67 __FUNCTION__
, tm
->tm_sec
, tm
->tm_min
, tm
->tm_hour
,
68 tm
->tm_mday
, tm
->tm_mon
, tm
->tm_year
, tm
->tm_wday
);
73 static int ds1672_set_mmss(struct i2c_client
*client
, unsigned long secs
)
78 buf
[0] = DS1672_REG_CNT_BASE
;
79 buf
[1] = secs
& 0x000000FF;
80 buf
[2] = (secs
& 0x0000FF00) >> 8;
81 buf
[3] = (secs
& 0x00FF0000) >> 16;
82 buf
[4] = (secs
& 0xFF000000) >> 24;
83 buf
[5] = 0; /* set control reg to enable counting */
85 xfer
= i2c_master_send(client
, buf
, 6);
87 dev_err(&client
->dev
, "%s: send: %d\n", __FUNCTION__
, xfer
);
94 static int ds1672_set_datetime(struct i2c_client
*client
, struct rtc_time
*tm
)
99 "%s: secs=%d, mins=%d, hours=%d, "
100 "mday=%d, mon=%d, year=%d, wday=%d\n",
102 tm
->tm_sec
, tm
->tm_min
, tm
->tm_hour
,
103 tm
->tm_mday
, tm
->tm_mon
, tm
->tm_year
, tm
->tm_wday
);
105 rtc_tm_to_time(tm
, &secs
);
107 return ds1672_set_mmss(client
, secs
);
110 static int ds1672_rtc_read_time(struct device
*dev
, struct rtc_time
*tm
)
112 return ds1672_get_datetime(to_i2c_client(dev
), tm
);
115 static int ds1672_rtc_set_time(struct device
*dev
, struct rtc_time
*tm
)
117 return ds1672_set_datetime(to_i2c_client(dev
), tm
);
120 static int ds1672_rtc_set_mmss(struct device
*dev
, unsigned long secs
)
122 return ds1672_set_mmss(to_i2c_client(dev
), secs
);
125 static int ds1672_get_control(struct i2c_client
*client
, u8
*status
)
127 unsigned char addr
= DS1672_REG_CONTROL
;
129 struct i2c_msg msgs
[] = {
130 { client
->addr
, 0, 1, &addr
}, /* setup read ptr */
131 { client
->addr
, I2C_M_RD
, 1, status
}, /* read control */
134 /* read control register */
135 if ((i2c_transfer(client
->adapter
, &msgs
[0], 2)) != 2) {
136 dev_err(&client
->dev
, "%s: read error\n", __FUNCTION__
);
143 /* following are the sysfs callback functions */
144 static ssize_t
show_control(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
146 struct i2c_client
*client
= to_i2c_client(dev
);
150 err
= ds1672_get_control(client
, &control
);
154 return sprintf(buf
, "%s\n", (control
& DS1672_REG_CONTROL_EOSC
)
155 ? "disabled" : "enabled");
157 static DEVICE_ATTR(control
, S_IRUGO
, show_control
, NULL
);
159 static const struct rtc_class_ops ds1672_rtc_ops
= {
160 .read_time
= ds1672_rtc_read_time
,
161 .set_time
= ds1672_rtc_set_time
,
162 .set_mmss
= ds1672_rtc_set_mmss
,
165 static int ds1672_attach(struct i2c_adapter
*adapter
)
167 return i2c_probe(adapter
, &addr_data
, ds1672_probe
);
170 static int ds1672_detach(struct i2c_client
*client
)
173 struct rtc_device
*rtc
= i2c_get_clientdata(client
);
176 rtc_device_unregister(rtc
);
178 if ((err
= i2c_detach_client(client
)))
186 static struct i2c_driver ds1672_driver
= {
190 .id
= I2C_DRIVERID_DS1672
,
191 .attach_adapter
= &ds1672_attach
,
192 .detach_client
= &ds1672_detach
,
195 static int ds1672_probe(struct i2c_adapter
*adapter
, int address
, int kind
)
199 struct i2c_client
*client
;
200 struct rtc_device
*rtc
;
202 dev_dbg(&adapter
->dev
, "%s\n", __FUNCTION__
);
204 if (!i2c_check_functionality(adapter
, I2C_FUNC_I2C
)) {
209 if (!(client
= kzalloc(sizeof(struct i2c_client
), GFP_KERNEL
))) {
215 client
->addr
= address
;
216 client
->driver
= &ds1672_driver
;
217 client
->adapter
= adapter
;
219 strlcpy(client
->name
, ds1672_driver
.driver
.name
, I2C_NAME_SIZE
);
221 /* Inform the i2c layer */
222 if ((err
= i2c_attach_client(client
)))
225 dev_info(&client
->dev
, "chip found, driver version " DRV_VERSION
"\n");
227 rtc
= rtc_device_register(ds1672_driver
.driver
.name
, &client
->dev
,
228 &ds1672_rtc_ops
, THIS_MODULE
);
235 i2c_set_clientdata(client
, rtc
);
237 /* read control register */
238 err
= ds1672_get_control(client
, &control
);
242 if (control
& DS1672_REG_CONTROL_EOSC
)
243 dev_warn(&client
->dev
, "Oscillator not enabled. "
244 "Set time to enable.\n");
246 /* Register sysfs hooks */
247 err
= device_create_file(&client
->dev
, &dev_attr_control
);
254 rtc_device_unregister(rtc
);
257 i2c_detach_client(client
);
266 static int __init
ds1672_init(void)
268 return i2c_add_driver(&ds1672_driver
);
271 static void __exit
ds1672_exit(void)
273 i2c_del_driver(&ds1672_driver
);
276 MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
277 MODULE_DESCRIPTION("Dallas/Maxim DS1672 timekeeper driver");
278 MODULE_LICENSE("GPL");
279 MODULE_VERSION(DRV_VERSION
);
281 module_init(ds1672_init
);
282 module_exit(ds1672_exit
);