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
,
48 m41t00_get_rtc_time(void)
50 s32 sec
, min
, hour
, day
, mon
, year
;
51 s32 sec1
, min1
, hour1
, day1
, mon1
, year1
;
54 sec
= min
= hour
= day
= mon
= year
= 0;
55 sec1
= min1
= hour1
= day1
= mon1
= year1
= 0;
59 if (((sec
= i2c_smbus_read_byte_data(save_client
, 0)) >= 0)
60 && ((min
= i2c_smbus_read_byte_data(save_client
, 1))
62 && ((hour
= i2c_smbus_read_byte_data(save_client
, 2))
64 && ((day
= i2c_smbus_read_byte_data(save_client
, 4))
66 && ((mon
= i2c_smbus_read_byte_data(save_client
, 5))
68 && ((year
= i2c_smbus_read_byte_data(save_client
, 6))
70 && ((sec
== sec1
) && (min
== min1
) && (hour
== hour1
)
71 && (day
== day1
) && (mon
== mon1
)
82 } while (--limit
> 0);
86 dev_warn(&save_client
->dev
,
87 "m41t00: can't read rtc chip\n");
88 sec
= min
= hour
= day
= mon
= year
= 0;
109 return mktime(year
, mon
, day
, hour
, min
, sec
);
113 m41t00_set_tlet(ulong arg
)
116 ulong nowtime
= *(ulong
*)arg
;
119 tm
.tm_year
= (tm
.tm_year
- 1900) % 100;
121 BIN_TO_BCD(tm
.tm_sec
);
122 BIN_TO_BCD(tm
.tm_min
);
123 BIN_TO_BCD(tm
.tm_hour
);
124 BIN_TO_BCD(tm
.tm_mon
);
125 BIN_TO_BCD(tm
.tm_mday
);
126 BIN_TO_BCD(tm
.tm_year
);
129 if ((i2c_smbus_write_byte_data(save_client
, 0, tm
.tm_sec
& 0x7f) < 0)
130 || (i2c_smbus_write_byte_data(save_client
, 1, tm
.tm_min
& 0x7f)
132 || (i2c_smbus_write_byte_data(save_client
, 2, tm
.tm_hour
& 0x7f)
134 || (i2c_smbus_write_byte_data(save_client
, 4, tm
.tm_mday
& 0x7f)
136 || (i2c_smbus_write_byte_data(save_client
, 5, tm
.tm_mon
& 0x7f)
138 || (i2c_smbus_write_byte_data(save_client
, 6, tm
.tm_year
& 0x7f)
141 dev_warn(&save_client
->dev
,"m41t00: can't write to rtc chip\n");
147 static ulong new_time
;
149 DECLARE_TASKLET_DISABLED(m41t00_tasklet
, m41t00_set_tlet
, (ulong
)&new_time
);
152 m41t00_set_rtc_time(ulong nowtime
)
157 tasklet_schedule(&m41t00_tasklet
);
159 m41t00_set_tlet((ulong
)&new_time
);
165 *****************************************************************************
169 *****************************************************************************
172 m41t00_probe(struct i2c_adapter
*adap
, int addr
, int kind
)
174 struct i2c_client
*client
;
177 client
= kmalloc(sizeof(struct i2c_client
), GFP_KERNEL
);
181 memset(client
, 0, sizeof(struct i2c_client
));
182 strncpy(client
->name
, M41T00_DRV_NAME
, I2C_NAME_SIZE
);
183 client
->flags
= I2C_DF_NOTIFY
;
185 client
->adapter
= adap
;
186 client
->driver
= &m41t00_driver
;
188 if ((rc
= i2c_attach_client(client
)) != 0) {
193 save_client
= client
;
198 m41t00_attach(struct i2c_adapter
*adap
)
200 return i2c_probe(adap
, &addr_data
, m41t00_probe
);
204 m41t00_detach(struct i2c_client
*client
)
208 if ((rc
= i2c_detach_client(client
)) == 0) {
210 tasklet_kill(&m41t00_tasklet
);
215 static struct i2c_driver m41t00_driver
= {
216 .owner
= THIS_MODULE
,
217 .name
= M41T00_DRV_NAME
,
218 .id
= I2C_DRIVERID_STM41T00
,
219 .flags
= I2C_DF_NOTIFY
,
220 .attach_adapter
= m41t00_attach
,
221 .detach_client
= m41t00_detach
,
227 return i2c_add_driver(&m41t00_driver
);
233 i2c_del_driver(&m41t00_driver
);
237 module_init(m41t00_init
);
238 module_exit(m41t00_exit
);
240 MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
241 MODULE_DESCRIPTION("ST Microelectronics M41T00 RTC I2C Client Driver");
242 MODULE_LICENSE("GPL");