MOXA linux-2.6.x / linux-2.6.19-uc1 from UC-7110-LX-BOOTLOADER-1.9_VERSION-4.2.tgz
[linux-2.6.19-moxart.git] / drivers / char / m41t11m6.c
blobf5db9661e1e82f8bce7906d41c501cbc2a7c5b85
1 /*****************************************************************************/
3 /*
4 * m41t11m6.c -- driver for M41T11M6 Real Time Clock.
6 * (C) Copyright 2004-2005, Greg Ungerer <gerg@snapgear.com>
7 */
9 /*****************************************************************************/
11 #include <linux/types.h>
12 #include <linux/miscdevice.h>
13 #include <linux/init.h>
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/fs.h>
17 #include <linux/mm.h>
18 #include <linux/wait.h>
19 #include <linux/delay.h>
20 #include <linux/rtc.h>
21 #include <asm/hardware.h>
22 #include <asm/uaccess.h>
23 #include <asm/semaphore.h>
25 /*****************************************************************************/
28 * Size of RTC region. 64 bytes total, the first 10 are the RTC.
30 #define M41T11M6_MSIZE 0x3f
32 /*****************************************************************************/
35 * M41T11M6 defines.
37 #define M41T11M6_ADDR 0xd0 /* IIC address of M41T11M6 device */
38 #define M41T11M6_RD 1 /* Read bit command */
39 #define M41T11M6_WR 0 /* Write bit command */
41 #define M41T11M6_SEC 0x00 /* Address of second register */
42 #define M41T11M6_MIN 0x01 /* Address of minute register */
43 #define M41T11M6_HOUR 0x02 /* Address of hour register */
44 #define M41T11M6_WDAY 0x03 /* Address of day of week register */
45 #define M41T11M6_MDAY 0x04 /* Address of day of month register */
46 #define M41T11M6_MON 0x05 /* Address of month register */
47 #define M41T11M6_YEAR 0x06 /* Address of year register */
48 #define M41T11M6_FTOUT 0x07 /* Address of control register */
50 /*****************************************************************************/
51 #ifdef CONFIG_MACH_IPD
52 /*****************************************************************************/
54 #include <asm/io.h>
57 * On the EP9312/IPD, the clock in on EGIO[1] and the data is on EGPIO[3]
59 #define SDA 0x8
60 #define SCL 0x2
61 #define IN 0
62 #define OUT 1
64 static void gpio_line_config(int line, int dir)
66 unsigned long flags;
68 save_flags(flags); cli();
69 if (dir == OUT)
70 outl(inl(GPIO_PADDR) | line, GPIO_PADDR); /* data is output */
71 else
72 outl(inl(GPIO_PADDR) & ~line, GPIO_PADDR); /* data is input */
73 restore_flags(flags);
76 static void gpio_line_set(int line, int val)
78 unsigned long flags;
80 save_flags(flags); cli();
81 if (val)
82 outl(inl(GPIO_PADR) | line, GPIO_PADR);
83 else
84 outl(inl(GPIO_PADR) & ~line, GPIO_PADR);
85 restore_flags(flags);
88 static inline void gpio_line_get(int line, int *val)
90 *val = (inl(GPIO_PADR) & line) ? 1 : 0;
93 /*****************************************************************************/
94 #elif defined(CONFIG_MACH_CM41xx) || defined(CONFIG_MACH_CM4008)
95 /*****************************************************************************/
97 #include <asm/io.h>
100 * GPIO lines 6, 7 and 8 are used for the RTC.
102 #define SDAT 6 /* SDA transmit */
103 #define SDAR 7 /* SDA receiver */
104 #define SCL 8 /* SCL - clock */
105 #define SDA SDAR
107 #define IN 0
108 #define OUT 1
110 #define SDAT_B (1 << SDAT)
111 #define SDAR_B (1 << SDAR)
112 #define SCL_B (1 << SCL)
114 static volatile unsigned int *gpdatap = (volatile unsigned int *) (IO_ADDRESS(KS8695_IO_BASE) + KS8695_GPIO_DATA);
115 static volatile unsigned int *gpmodep = (volatile unsigned int *) (IO_ADDRESS(KS8695_IO_BASE) + KS8695_GPIO_MODE);
117 static inline void gpio_line_config(int line, int dir)
119 if (line == SDA) {
120 if (dir == IN)
121 *gpdatap |= SDAT_B;
123 if (line == SCL) {
124 /* We do normal initialization for all GPIO bits here */
125 *gpmodep |= SCL_B | SDAT_B;
126 *gpmodep &= ~SDAR_B;
130 static inline void gpio_line_set(int line, int val)
132 if (line == SCL) {
133 if (val)
134 *gpdatap |= SCL_B;
135 else
136 *gpdatap &= ~SCL_B;
137 } else {
138 if (val)
139 *gpdatap |= SDAT_B;
140 else
141 *gpdatap &= ~SDAT_B;
145 static inline void gpio_line_get(int line, int *val)
147 *val = (*gpdatap & SDAR_B) ? 1 : 0;
150 /*****************************************************************************/
151 #else
152 /*****************************************************************************/
155 * The IIC lines to the M41T11M6 are GPIO lines from the IXP4xx.
156 * The clock line is on GPIO12, and the data line on GPIO11.
158 #define SDA 11
159 #define SCL 12
160 #define IN IXP4XX_GPIO_IN
161 #define OUT IXP4XX_GPIO_OUT
163 /*****************************************************************************/
164 #endif
165 /*****************************************************************************/
167 static void gpio_line_config_slow(u8 line, u32 style)
169 gpio_line_config(line, style);
170 udelay(10);
173 static void gpio_line_set_slow(u8 line, int value)
175 gpio_line_set(line, value);
176 udelay(10);
179 static void gpio_line_get_slow(u8 line, int *value)
181 gpio_line_get(line, value);
182 udelay(10);
185 /*****************************************************************************/
187 void m41t11m6_readack(void)
189 unsigned int ack;
191 gpio_line_config_slow(SDA, IN);
192 gpio_line_set_slow(SCL, 1);
193 gpio_line_get_slow(SDA, &ack);
194 gpio_line_set_slow(SCL, 0);
195 gpio_line_config_slow(SDA, OUT);
198 void m41t11m6_writeack(void)
200 gpio_line_set_slow(SDA, 0);
201 gpio_line_set_slow(SCL, 1);
202 gpio_line_set_slow(SCL, 0);
205 void m41t11m6_sendbits(unsigned int val)
207 int i;
209 gpio_line_set_slow(SCL, 0);
210 for (i = 7; (i >= 0); i--) {
211 gpio_line_set_slow(SDA, ((val >> i) & 0x1));
212 gpio_line_set_slow(SCL, 1);
213 gpio_line_set_slow(SCL, 0);
217 unsigned int m41t11m6_recvbits(void)
219 unsigned int val, bit;
220 int i;
222 gpio_line_set_slow(SCL, 0);
223 gpio_line_config_slow(SDA, IN);
224 for (i = 0, val = 0; (i < 8); i++) {
225 gpio_line_set_slow(SCL, 1);
226 gpio_line_get_slow(SDA, &bit);
227 val = (val << 1) | bit;
228 gpio_line_set_slow(SCL, 0);
231 gpio_line_config_slow(SDA, OUT);
232 return val;
235 /*****************************************************************************/
236 DECLARE_MUTEX(m41t11m6_sem);
239 * The read byte sequenece is actually a write sequence followed
240 * by the read sequenece. The first write is to set the register
241 * address, and is a complete cycle itself.
243 unsigned int m41t11m6_readbyte(unsigned int addr)
245 unsigned int val;
247 down(&m41t11m6_sem);
248 #if 0
249 printk("m41t11m6_readbyte(addr=%x)\n", addr);
250 #endif
252 /* Send start signal */
253 gpio_line_set_slow(SCL, 1);
254 gpio_line_set_slow(SDA, 1);
255 gpio_line_set_slow(SDA, 0);
257 /* Send M41T11M6 device address byte, and write command for addr */
258 m41t11m6_sendbits(M41T11M6_ADDR | M41T11M6_WR);
259 m41t11m6_readack();
260 m41t11m6_sendbits(addr);
261 m41t11m6_readack();
263 /* Now send sequence to read bytes, starting with start signal */
264 gpio_line_set_slow(SDA, 1);
265 gpio_line_set_slow(SCL, 1);
266 gpio_line_set_slow(SDA, 1);
267 gpio_line_set_slow(SDA, 0);
269 /* Send M41T11M6 device address byte, and read command for addr */
270 m41t11m6_sendbits(M41T11M6_ADDR | M41T11M6_RD);
271 m41t11m6_writeack();
272 val = m41t11m6_recvbits();
274 /* Send stop signal */
275 gpio_line_set_slow(SDA, 0);
276 gpio_line_set_slow(SCL, 1);
277 gpio_line_set_slow(SDA, 1);
279 up(&m41t11m6_sem);
281 return val;
284 void m41t11m6_writebyte(unsigned int addr, unsigned int val)
286 down(&m41t11m6_sem);
287 #if 0
288 printk("m41t11m6_writebyte(addr=%x)\n", addr);
289 #endif
291 /* Send start signal */
292 gpio_line_set_slow(SCL, 1);
293 gpio_line_set_slow(SDA, 1);
294 gpio_line_set_slow(SDA, 0);
296 /* Send M41T11M6 device address byte, and write command */
297 m41t11m6_sendbits(M41T11M6_ADDR | M41T11M6_WR);
298 m41t11m6_readack();
300 /* Send word address and data to write */
301 m41t11m6_sendbits(addr);
302 m41t11m6_readack();
303 m41t11m6_sendbits(val);
304 m41t11m6_readack();
306 /* Send stop signal */
307 gpio_line_set_slow(SDA, 0);
308 gpio_line_set_slow(SCL, 1);
309 gpio_line_set_slow(SDA, 1);
311 up(&m41t11m6_sem);
314 /*****************************************************************************/
316 void m41t11m6_setup(void)
318 down(&m41t11m6_sem);
320 /* Initially set the IIC lines to be outputs from the IXP4xx */
321 gpio_line_config(SCL, OUT);
322 gpio_line_config(SDA, OUT);
324 /* Set IIC bus into idle mode */
325 gpio_line_set(SCL, 1);
326 gpio_line_set(SDA, 1);
328 up(&m41t11m6_sem);
331 /*****************************************************************************/
333 int bcd2bin(int val)
335 return ((((val & 0xf0) >> 4) * 10) + (val & 0xf));
338 int bin2bcd(int val)
340 val &= 0xff;
341 return (((val / 10) << 4) + (val % 10));
344 /*****************************************************************************/
346 static ssize_t m41t11m6_read(struct file *fp, char __user *buf, size_t count, loff_t *ptr)
348 int total;
350 #if 0
351 printk("m41t11m6_read(buf=%x,count=%d)\n", (int) buf, count);
352 #endif
354 if (fp->f_pos >= M41T11M6_MSIZE)
355 return 0;
357 if (count > (M41T11M6_MSIZE - fp->f_pos))
358 count = M41T11M6_MSIZE - fp->f_pos;
360 for (total = 0; (total < count); total++)
361 put_user(m41t11m6_readbyte(fp->f_pos + total), buf++);
363 fp->f_pos += total;
364 return total;
367 /*****************************************************************************/
369 static ssize_t m41t11m6_write(struct file *fp, const char __user *buf, size_t count, loff_t *ptr)
371 int total;
372 char val;
374 #if 0
375 printk("m41t11m6_write(buf=%x,count=%d)\n", (int) buf, count);
376 #endif
378 if (fp->f_pos >= M41T11M6_MSIZE)
379 return 0;
381 if (count > (M41T11M6_MSIZE - fp->f_pos))
382 count = M41T11M6_MSIZE - fp->f_pos;
384 for (total = 0; (total < count); total++, buf++) {
385 get_user(val,buf);
386 m41t11m6_writebyte((fp->f_pos + total), val);
389 fp->f_pos += total;
390 return total;
393 /*****************************************************************************/
396 * Do some consistency checks on the time. On first power up the
397 * RTC may contain completely bogus junk, this will clean it up.
398 * Just for good measure we do this when writing to the RTC as well.
401 static void m41t11m6_validatetime(struct rtc_time *rtime)
403 if ((rtime->tm_year < 70) || (rtime->tm_year >= 200))
404 rtime->tm_year = 70;
405 if ((rtime->tm_mon < 0) || (rtime->tm_mon >= 12))
406 rtime->tm_mon = 0;
407 if ((rtime->tm_mday < 1) || (rtime->tm_mday > 31))
408 rtime->tm_mday = 1;
409 if ((rtime->tm_wday < 0) || (rtime->tm_wday >= 7))
410 rtime->tm_wday = 0;
411 if ((rtime->tm_hour < 0) || (rtime->tm_hour >= 24))
412 rtime->tm_hour = 0;
413 if ((rtime->tm_min < 0) || (rtime->tm_min >= 60))
414 rtime->tm_min = 0;
415 if ((rtime->tm_sec < 0) || (rtime->tm_sec >= 60))
416 rtime->tm_sec = 0;
419 /*****************************************************************************/
421 static void m41t11m6_readtime(struct rtc_time *rtime)
423 memset(rtime, 0, sizeof(*rtime));
424 rtime->tm_year = bcd2bin(m41t11m6_readbyte(M41T11M6_YEAR)) +
425 ((m41t11m6_readbyte(M41T11M6_HOUR) & 0x40) ? 100 : 0);
426 rtime->tm_mon = bcd2bin(m41t11m6_readbyte(M41T11M6_MON & 0x1f)) - 1;
427 rtime->tm_mday = bcd2bin(m41t11m6_readbyte(M41T11M6_MDAY & 0x3f));
428 rtime->tm_wday = bcd2bin(m41t11m6_readbyte(M41T11M6_WDAY) & 0x7) - 1;
429 rtime->tm_hour = bcd2bin(m41t11m6_readbyte(M41T11M6_HOUR) & 0x3f);
430 rtime->tm_min = bcd2bin(m41t11m6_readbyte(M41T11M6_MIN) & 0x7f);
431 rtime->tm_sec = bcd2bin(m41t11m6_readbyte(M41T11M6_SEC) & 0x7f);
434 /*****************************************************************************/
436 static void m41t11m6_settime(struct rtc_time *rtime)
438 m41t11m6_writebyte(M41T11M6_YEAR, bin2bcd(rtime->tm_year));
439 m41t11m6_writebyte(M41T11M6_MON, bin2bcd(rtime->tm_mon+1));
440 m41t11m6_writebyte(M41T11M6_MDAY, bin2bcd(rtime->tm_mday));
441 m41t11m6_writebyte(M41T11M6_WDAY, bin2bcd(rtime->tm_wday+1));
442 m41t11m6_writebyte(M41T11M6_HOUR, bin2bcd(rtime->tm_hour) |
443 ((rtime->tm_year > 99) ? 0xc0 : 0x80));
444 m41t11m6_writebyte(M41T11M6_MIN, bin2bcd(rtime->tm_min));
445 m41t11m6_writebyte(M41T11M6_SEC, bin2bcd(rtime->tm_sec));
446 m41t11m6_writebyte(M41T11M6_FTOUT, 0x90);
449 /*****************************************************************************/
451 static int m41t11m6_ioctl(struct inode *inode, struct file *file, unsigned cmd, unsigned long arg)
453 struct rtc_time rtime;
455 #if 0
456 printk("m41t11m6_ioctl(cmd=%x,arg=%x)\n", cmd, arg);
457 #endif
459 switch (cmd) {
461 case RTC_RD_TIME:
462 m41t11m6_readtime(&rtime);
463 m41t11m6_validatetime(&rtime);
464 if (copy_to_user((void __user *) arg, &rtime, sizeof(rtime)))
465 return -EFAULT;
466 break;
468 case RTC_SET_TIME:
469 if (!capable(CAP_SYS_TIME))
470 return -EACCES;
471 m41t11m6_validatetime(&rtime);
472 if (copy_from_user(&rtime, (void __user *) arg, sizeof(rtime)))
473 return -EFAULT;
474 m41t11m6_settime(&rtime);
475 break;
477 default:
478 return -EINVAL;
481 return 0;
484 /*****************************************************************************/
487 * Exported file operations structure for driver...
489 static struct file_operations m41t11m6_fops =
491 .owner = THIS_MODULE,
492 .read = m41t11m6_read,
493 .write = m41t11m6_write,
494 .ioctl = m41t11m6_ioctl,
497 static struct miscdevice m41t11m6_dev =
499 RTC_MINOR,
500 "rtc",
501 &m41t11m6_fops
504 /*****************************************************************************/
506 static int __init m41t11m6_init(void)
508 m41t11m6_setup();
509 misc_register(&m41t11m6_dev);
510 printk ("M41T11M6: Real Time Clock driver\n");
511 return 0;
514 static void __exit m41t11m6_exit(void)
516 misc_deregister(&m41t11m6_dev);
519 /*****************************************************************************/
521 module_init(m41t11m6_init);
522 module_exit(m41t11m6_exit);
524 MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
525 MODULE_LICENSE("GPL");
527 /*****************************************************************************/