2 * drivers/i2c/chips/m41t11.c
4 * I2C client driver for the ST M41T11 Real Time Clock chip.
6 * (C) Copyright (C) 2006, Greg Ungerer <gerg@snapgear.com>
10 * This driver is very much a hybrid RTC and I2C driver. It has interfaces
11 * into both sub-systems (well the RTC is really a misc device). Ultimately
12 * I want to be able to use hwclock "as is" on the RTC. But the hardware is
13 * a true I2c device...
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/miscdevice.h>
20 #include <linux/i2c.h>
21 #include <linux/bcd.h>
22 #include <linux/rtc.h>
23 #include <asm/uaccess.h>
25 #define M41T11_DRV_NAME "m41t11"
28 * Size of RTC region. 64 bytes total, the first 10 are the RTC.
30 #define M41T11_MSIZE 0x3f
33 * M41T11 register offsets.
35 #define M41T11_SEC 0x00 /* Address of second register */
36 #define M41T11_MIN 0x01 /* Address of minute register */
37 #define M41T11_HOUR 0x02 /* Address of hour register */
38 #define M41T11_WDAY 0x03 /* Address of day of week register */
39 #define M41T11_MDAY 0x04 /* Address of day of month register */
40 #define M41T11_MON 0x05 /* Address of month register */
41 #define M41T11_YEAR 0x06 /* Address of year register */
42 #define M41T11_FTOUT 0x07 /* Address of control register */
44 static DECLARE_MUTEX(m41t11_mutex
);
47 * We keep a copy of the client device found, since we are really only
48 * need one device for the real misc device interface.
50 static struct i2c_client
*client
;
52 #define m41t11_readbyte(a) i2c_smbus_read_byte_data(client, a)
53 #define m41t11_writebyte(a,v) i2c_smbus_write_byte_data(client, a, v);
56 *****************************************************************************
58 * RTC Driver Interface
60 *****************************************************************************
63 static ssize_t
m41t11_read(struct file
*fp
, char __user
*buf
, size_t count
, loff_t
*ptr
)
67 if (fp
->f_pos
>= M41T11_MSIZE
)
70 if (count
> (M41T11_MSIZE
- fp
->f_pos
))
71 count
= M41T11_MSIZE
- fp
->f_pos
;
74 for (total
= 0; (total
< count
); total
++)
75 put_user(m41t11_readbyte(fp
->f_pos
+ total
), buf
++);
82 static ssize_t
m41t11_write(struct file
*fp
, const char __user
*buf
, size_t count
, loff_t
*ptr
)
87 if (fp
->f_pos
>= M41T11_MSIZE
)
90 if (count
> (M41T11_MSIZE
- fp
->f_pos
))
91 count
= M41T11_MSIZE
- fp
->f_pos
;
94 for (total
= 0; (total
< count
); total
++, buf
++) {
96 m41t11_writebyte((fp
->f_pos
+ total
), val
);
105 * Do some consistency checks on the time. On first power up the
106 * RTC may contain completely bogus junk, this will clean it up.
107 * Just for good measure we do this when writing to the RTC as well.
109 static void m41t11_validatetime(struct rtc_time
*rtime
)
111 if ((rtime
->tm_year
< 70) || (rtime
->tm_year
>= 200))
113 if ((rtime
->tm_mon
< 0) || (rtime
->tm_mon
>= 12))
115 if ((rtime
->tm_mday
< 1) || (rtime
->tm_mday
> 31))
117 if ((rtime
->tm_wday
< 0) || (rtime
->tm_wday
>= 7))
119 if ((rtime
->tm_hour
< 0) || (rtime
->tm_hour
>= 24))
121 if ((rtime
->tm_min
< 0) || (rtime
->tm_min
>= 60))
123 if ((rtime
->tm_sec
< 0) || (rtime
->tm_sec
>= 60))
127 static void m41t11_readtime(struct rtc_time
*rtime
)
130 memset(rtime
, 0, sizeof(*rtime
));
131 rtime
->tm_year
= BCD2BIN(m41t11_readbyte(M41T11_YEAR
)) +
132 ((m41t11_readbyte(M41T11_HOUR
) & 0x40) ? 100 : 0);
133 rtime
->tm_mon
= BCD2BIN(m41t11_readbyte(M41T11_MON
& 0x1f)) - 1;
134 rtime
->tm_mday
= BCD2BIN(m41t11_readbyte(M41T11_MDAY
& 0x3f));
135 rtime
->tm_wday
= BCD2BIN(m41t11_readbyte(M41T11_WDAY
) & 0x7) - 1;
136 rtime
->tm_hour
= BCD2BIN(m41t11_readbyte(M41T11_HOUR
) & 0x3f);
137 rtime
->tm_min
= BCD2BIN(m41t11_readbyte(M41T11_MIN
) & 0x7f);
138 rtime
->tm_sec
= BCD2BIN(m41t11_readbyte(M41T11_SEC
) & 0x7f);
142 static void m41t11_settime(struct rtc_time
*rtime
)
145 m41t11_writebyte(M41T11_YEAR
, BIN2BCD(rtime
->tm_year
));
146 m41t11_writebyte(M41T11_MON
, BIN2BCD(rtime
->tm_mon
+1));
147 m41t11_writebyte(M41T11_MDAY
, BIN2BCD(rtime
->tm_mday
));
148 m41t11_writebyte(M41T11_WDAY
, BIN2BCD(rtime
->tm_wday
+1));
149 m41t11_writebyte(M41T11_HOUR
, BIN2BCD(rtime
->tm_hour
) |
150 ((rtime
->tm_year
> 99) ? 0xc0 : 0x80));
151 m41t11_writebyte(M41T11_MIN
, BIN2BCD(rtime
->tm_min
));
152 m41t11_writebyte(M41T11_SEC
, BIN2BCD(rtime
->tm_sec
));
153 m41t11_writebyte(M41T11_FTOUT
, 0x90);
157 static int m41t11_ioctl(struct inode
*inode
, struct file
*file
, unsigned int cmd
, unsigned long arg
)
159 struct rtc_time rtime
;
164 m41t11_readtime(&rtime
);
165 m41t11_validatetime(&rtime
);
166 if (copy_to_user((void __user
*) arg
, &rtime
, sizeof(rtime
)))
171 if (!capable(CAP_SYS_TIME
))
173 m41t11_validatetime(&rtime
);
174 if (copy_from_user(&rtime
, (void __user
*) arg
, sizeof(rtime
)))
176 m41t11_settime(&rtime
);
187 *****************************************************************************
189 * I2C Driver Interface
191 *****************************************************************************
194 static unsigned short ignore
[] = { I2C_CLIENT_END
};
195 static unsigned short normal_addr
[] = { 0x68, I2C_CLIENT_END
};
197 static struct i2c_client_address_data addr_data
= {
198 .normal_i2c
= normal_addr
,
203 static struct i2c_driver m41t11_i2cdrv
;
205 static int m41t11_probe(struct i2c_adapter
*adap
, int addr
, int kind
)
207 struct i2c_client
*c
;
211 c
= kzalloc(sizeof(struct i2c_client
), GFP_KERNEL
);
215 strncpy(c
->name
, M41T11_DRV_NAME
, I2C_NAME_SIZE
);
218 c
->driver
= &m41t11_i2cdrv
;
220 if ((rc
= i2c_attach_client(c
)) != 0) {
227 /* Start the oscillator if needed */
228 val
= m41t11_readbyte(M41T11_SEC
);
230 m41t11_writebyte(M41T11_SEC
, val
& 0x7f);
235 static int m41t11_attach(struct i2c_adapter
*adap
)
237 return i2c_probe(adap
, &addr_data
, m41t11_probe
);
240 static int m41t11_detach(struct i2c_client
*c
)
244 if ((rc
= i2c_detach_client(c
)) < 0)
251 *****************************************************************************
255 *****************************************************************************
258 static struct i2c_driver m41t11_i2cdrv
= {
260 .name
= M41T11_DRV_NAME
,
262 .id
= I2C_DRIVERID_STM41T00
,
263 .attach_adapter
= m41t11_attach
,
264 .detach_client
= m41t11_detach
,
267 static struct file_operations m41t11_fops
= {
268 .owner
= THIS_MODULE
,
270 .write
= m41t11_write
,
271 .ioctl
= m41t11_ioctl
,
274 static struct miscdevice m41t11_miscdrv
= {
277 .fops
= &m41t11_fops
,
280 static int __init
m41t11_init(void)
284 if ((rc
= i2c_add_driver(&m41t11_i2cdrv
)) < 0)
286 if ((rc
= misc_register(&m41t11_miscdrv
)) < 0) {
287 i2c_del_driver(&m41t11_i2cdrv
);
291 printk("M41T11: RTC I2C driver registered\n");
295 static void __exit
m41t11_exit(void)
297 misc_deregister(&m41t11_miscdrv
);
298 i2c_del_driver(&m41t11_i2cdrv
);
302 module_init(m41t11_init
);
303 module_exit(m41t11_exit
);
305 MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
306 MODULE_DESCRIPTION("ST Microelectronics M41T11 RTC I2C Client Driver");
307 MODULE_LICENSE("GPL");