2 * drivers/i2c/chips/m41t00.c
4 * I2C client/driver for the ST M41T00 Real-Time Clock chip.
6 * Author: Mark A. Greer <mgreer@mvista.com>
8 * 2005 (c) MontaVista Software, Inc. This file is licensed under
9 * the terms of the GNU General Public License version 2. This program
10 * is licensed "as is" without any warranty of any kind, whether express
14 * This i2c client/driver wedges between the drivers/char/genrtc.c RTC
15 * interface and the SMBus interface of the i2c subsystem.
16 * It would be more efficient to use i2c msgs/i2c_transfer directly but, as
17 * recommened in .../Documentation/i2c/writing-clients section
18 * "Sending and receiving", using SMBus level communication is preferred.
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/interrupt.h>
24 #include <linux/i2c.h>
25 #include <linux/rtc.h>
26 #include <linux/bcd.h>
31 #define M41T00_DRV_NAME "m41t00"
33 static DECLARE_MUTEX(m41t00_mutex
);
35 static struct i2c_driver m41t00_driver
;
36 static struct i2c_client
*save_client
;
38 static unsigned short ignore
[] = { I2C_CLIENT_END
};
39 static unsigned short normal_addr
[] = { 0x68, I2C_CLIENT_END
};
41 static struct i2c_client_address_data addr_data
= {
42 .normal_i2c
= normal_addr
,
43 .normal_i2c_range
= ignore
,
45 .probe_range
= ignore
,
47 .ignore_range
= ignore
,
52 m41t00_get_rtc_time(void)
54 s32 sec
, min
, hour
, day
, mon
, year
;
55 s32 sec1
, min1
, hour1
, day1
, mon1
, year1
;
58 sec
= min
= hour
= day
= mon
= year
= 0;
59 sec1
= min1
= hour1
= day1
= mon1
= year1
= 0;
63 if (((sec
= i2c_smbus_read_byte_data(save_client
, 0)) >= 0)
64 && ((min
= i2c_smbus_read_byte_data(save_client
, 1))
66 && ((hour
= i2c_smbus_read_byte_data(save_client
, 2))
68 && ((day
= i2c_smbus_read_byte_data(save_client
, 4))
70 && ((mon
= i2c_smbus_read_byte_data(save_client
, 5))
72 && ((year
= i2c_smbus_read_byte_data(save_client
, 6))
74 && ((sec
== sec1
) && (min
== min1
) && (hour
== hour1
)
75 && (day
== day1
) && (mon
== mon1
)
86 } while (--limit
> 0);
90 dev_warn(&save_client
->dev
,
91 "m41t00: can't read rtc chip\n");
92 sec
= min
= hour
= day
= mon
= year
= 0;
113 return mktime(year
, mon
, day
, hour
, min
, sec
);
117 m41t00_set_tlet(ulong arg
)
120 ulong nowtime
= *(ulong
*)arg
;
123 tm
.tm_year
= (tm
.tm_year
- 1900) % 100;
125 BIN_TO_BCD(tm
.tm_sec
);
126 BIN_TO_BCD(tm
.tm_min
);
127 BIN_TO_BCD(tm
.tm_hour
);
128 BIN_TO_BCD(tm
.tm_mon
);
129 BIN_TO_BCD(tm
.tm_mday
);
130 BIN_TO_BCD(tm
.tm_year
);
133 if ((i2c_smbus_write_byte_data(save_client
, 0, tm
.tm_sec
& 0x7f) < 0)
134 || (i2c_smbus_write_byte_data(save_client
, 1, tm
.tm_min
& 0x7f)
136 || (i2c_smbus_write_byte_data(save_client
, 2, tm
.tm_hour
& 0x7f)
138 || (i2c_smbus_write_byte_data(save_client
, 4, tm
.tm_mday
& 0x7f)
140 || (i2c_smbus_write_byte_data(save_client
, 5, tm
.tm_mon
& 0x7f)
142 || (i2c_smbus_write_byte_data(save_client
, 6, tm
.tm_year
& 0x7f)
145 dev_warn(&save_client
->dev
,"m41t00: can't write to rtc chip\n");
153 DECLARE_TASKLET_DISABLED(m41t00_tasklet
, m41t00_set_tlet
, (ulong
)&new_time
);
156 m41t00_set_rtc_time(ulong nowtime
)
161 tasklet_schedule(&m41t00_tasklet
);
163 m41t00_set_tlet((ulong
)&new_time
);
169 *****************************************************************************
173 *****************************************************************************
176 m41t00_probe(struct i2c_adapter
*adap
, int addr
, int kind
)
178 struct i2c_client
*client
;
181 client
= kmalloc(sizeof(struct i2c_client
), GFP_KERNEL
);
185 memset(client
, 0, sizeof(struct i2c_client
));
186 strncpy(client
->name
, M41T00_DRV_NAME
, I2C_NAME_SIZE
);
187 client
->flags
= I2C_DF_NOTIFY
;
189 client
->adapter
= adap
;
190 client
->driver
= &m41t00_driver
;
192 if ((rc
= i2c_attach_client(client
)) != 0) {
197 save_client
= client
;
202 m41t00_attach(struct i2c_adapter
*adap
)
204 return i2c_probe(adap
, &addr_data
, m41t00_probe
);
208 m41t00_detach(struct i2c_client
*client
)
212 if ((rc
= i2c_detach_client(client
)) == 0) {
213 kfree(i2c_get_clientdata(client
));
214 tasklet_kill(&m41t00_tasklet
);
219 static struct i2c_driver m41t00_driver
= {
220 .owner
= THIS_MODULE
,
221 .name
= M41T00_DRV_NAME
,
222 .id
= I2C_DRIVERID_STM41T00
,
223 .flags
= I2C_DF_NOTIFY
,
224 .attach_adapter
= m41t00_attach
,
225 .detach_client
= m41t00_detach
,
231 return i2c_add_driver(&m41t00_driver
);
237 i2c_del_driver(&m41t00_driver
);
241 module_init(m41t00_init
);
242 module_exit(m41t00_exit
);
244 MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
245 MODULE_DESCRIPTION("ST Microelectronics M41T00 RTC I2C Client Driver");
246 MODULE_LICENSE("GPL");