pt7c4307 驱动

时间:2013-11-03 09:59:37
【文件属性】:
文件名称:pt7c4307 驱动
文件大小:8KB
文件格式:C
更新时间:2013-11-03 09:59:37
pt7c4307 驱动 pt7c4307 驱动 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DRIVER_VERSION "0.01" /* Register map */ /* rtc section */ #define REG_SC 0x00 #define REG_MN 0x01 #define REG_HR 0x02 #define REG_HR_MIL (1<<6) /* 24h/12h mode */ #define REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */ #define REG_DW 0x03 #define REG_DT 0x04 #define REG_MO 0x05 #define REG_YR 0x06 #define RTC_SECTION_LEN 7 /* i2c configuration */ #define I2C_ADDR 0xd0 ///////////////////////////////////////////////////////////// #define DEFAULT_I2C_CLOCKDIV 180//for APB 108MHz static unsigned long rtc_status; static volatile unsigned long rtc_irq_data; static unsigned long rtc_freq = 1; /*FTRTC010 supports only 1Hz clock*/ static struct fasync_struct *rtc_async_queue; static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); extern spinlock_t rtc_lock; MODULE_AUTHOR("GM Corp."); MODULE_LICENSE("GM License"); extern int GM_i2c_xfer(struct i2c_msg *msgs, int num, int clockdiv); /* block read */ static int i2c_read_regs(u8 reg, u8 buf[], unsigned len) { struct i2c_msg msgs[1]; ////////////// buf[0] = reg; msgs[0].addr = I2C_ADDR>>1; msgs[0].flags = 0; msgs[0].len = 1; msgs[0].buf = buf; if (GM_i2c_xfer(msgs, 1, DEFAULT_I2C_CLOCKDIV) != 1) return -1; ////////////// msgs[0].addr = I2C_ADDR>>1; msgs[0].flags = 1; msgs[0].len = len+1; msgs[0].buf = buf; if (GM_i2c_xfer(msgs, 1, DEFAULT_I2C_CLOCKDIV) != 1) return -1; return 0; } /* block write */ static int i2c_set_regs(u8 reg, u8 const buf[], unsigned len) { u8 i2c_buf[7]; struct i2c_msg msgs[1]; i2c_buf[0] = reg; memcpy(&i2c_buf[1], &buf[0], len); msgs[0].addr = I2C_ADDR>>1; msgs[0].flags = 0; msgs[0].len = len+1; msgs[0].buf = i2c_buf; if (GM_i2c_xfer(msgs, 1, DEFAULT_I2C_CLOCKDIV) != 1) return -1; return 0; } static int set_time(struct rtc_time const *tm) { int sr; u8 regs[RTC_SECTION_LEN] = { 0, }; //printk("set_time Date(y/m/d):%d/%d/%d Time(h/m/s):%d/%d/%d\n",tm->tm_year,tm->tm_mon,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec); regs[REG_SC] = BIN2BCD(tm->tm_sec); regs[REG_MN] = BIN2BCD(tm->tm_min); regs[REG_HR] = BIN2BCD(tm->tm_hour); regs[REG_DT] = BIN2BCD(tm->tm_mday); regs[REG_MO] = BIN2BCD(tm->tm_mon + 1); regs[REG_YR] = BIN2BCD(tm->tm_year - 100); regs[REG_DW] = BIN2BCD(tm->tm_wday & 7); /* write RTC registers */ sr = i2c_set_regs(0, regs, RTC_SECTION_LEN); if (sr < 0) { printk("%s: writing RTC section failed\n", __func__); return sr; } return 0; } static int read_time (struct rtc_time *tm) { int sr; u8 regs[RTC_SECTION_LEN] = { 0, }; sr = i2c_read_regs(0, regs, RTC_SECTION_LEN); if (sr < 0) { printk("%s: reading RTC section failed\n", __func__); return sr; } tm->tm_sec = BCD2BIN(regs[REG_SC]); tm->tm_min = BCD2BIN(regs[REG_MN]); { /* HR field has a more complex interpretation */ const u8 _hr = regs[REG_HR]; if ((_hr & REG_HR_MIL) == 0){ /* 24h format */ tm->tm_hour = BCD2BIN(_hr & 0x3f) - 1; // if (tm->tm_hour > 23) // tm->tm_hour = 0; } else { // 12h format tm->tm_hour = BCD2BIN(_hr & 0x1f); if (_hr & REG_HR_PM) /* PM flag set */ tm->tm_hour += 12; } } tm->tm_mday = BCD2BIN(regs[REG_DT]); tm->tm_mon = BCD2BIN(regs[REG_MO]) - 1; /* rtc starts at 1 */ tm->tm_year = BCD2BIN(regs[REG_YR]) + 100; tm->tm_wday = BCD2BIN(regs[REG_DW]); //printk("read_time Date(y/m/d):%d/%d/%d Time(h/m/s):%d/%d/%d\n",tm->tm_year,tm->tm_mon,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec); return 0; } static unsigned AIE_stat=0; /*ijsung: arch-indep function*/ static int rtc_open(struct inode *inode, struct file *file) { if (test_and_set_bit (1, &rtc_status)) return -EBUSY; rtc_irq_data = 0; return 0; } static int rtc_release(struct inode *inode, struct file *file) { rtc_status = 0; return 0; } static int rtc_fasync (int fd, struct file *filp, int on) { return fasync_helper (fd, filp, on, &rtc_async_queue); } static unsigned int rtc_poll(struct file *file, poll_table *wait) { poll_wait (file, &rtc_wait, wait); return (rtc_irq_data) ? 0 : POLLIN | POLLRDNORM; } static loff_t rtc_llseek(struct file *file, loff_t offset, int origin) { return -ESPIPE; } ssize_t rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos) { DECLARE_WAITQUEUE(wait, current); unsigned long data; ssize_t retval; if (count < sizeof(unsigned long)) return -EINVAL; add_wait_queue(&rtc_wait, &wait); set_current_state(TASK_INTERRUPTIBLE); for (;;) { spin_lock_irq (&rtc_lock); data = rtc_irq_data; if (data != 0) { rtc_irq_data = 0; break; } spin_unlock_irq (&rtc_lock); if (file->f_flags & O_NONBLOCK) { retval = -EAGAIN; goto out; } if (signal_pending(current)) { retval = -ERESTARTSYS; goto out; } schedule(); } spin_unlock_irq (&rtc_lock); data -= 0x100; /* the first IRQ wasn't actually missed */ retval = put_user(data, (unsigned long *)buf); if (!retval) retval = sizeof(unsigned long); out: set_current_state(TASK_RUNNING); remove_wait_queue(&rtc_wait, &wait); return retval; } static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct rtc_time tm; switch (cmd) { case RTC_AIE_OFF: printk("Not Support\n"); return 0; case RTC_AIE_ON: printk("Not Support\n"); return 0; case RTC_ALM_READ: printk("Not Support\n"); return 0; case RTC_ALM_SET: printk("Not Support\n"); return 0; case RTC_RD_TIME: read_time(&tm); break; case RTC_SET_TIME: { if (!capable(CAP_SYS_TIME)) return -EACCES; if (copy_from_user (&tm, (struct rtc_time*)arg, sizeof (tm))) return -EFAULT; set_time(&tm); } return 0; case RTC_IRQP_READ: return put_user(rtc_freq, (unsigned long *)arg); case RTC_IRQP_SET: if (arg != 1) return -EINVAL; return 0; case RTC_EPOCH_READ: return put_user (1970, (unsigned long *)arg); default: return -EINVAL; } return copy_to_user ((void *)arg, &tm, sizeof (tm)) ? -EFAULT : 0; } static struct file_operations rtc_fops = { owner: THIS_MODULE, llseek: rtc_llseek, read: rtc_read, poll: rtc_poll, ioctl: rtc_ioctl, open: rtc_open, release: rtc_release, fasync: rtc_fasync, }; static struct miscdevice ftrtc010rtc_miscdev = { RTC_MINOR, "rtc", &rtc_fops }; static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { char *p = page; int len; struct rtc_time tm; read_time(&tm); //printk("RTC ... %d\n",xtime.tv_sec); p += sprintf(p, "rtc_time\t: %02d:%02d:%02d\n" "rtc_date\t: %04d-%02d-%02d\n" "rtc_epoch\t: %04d\n", tm.tm_hour + 1, tm.tm_min, tm.tm_sec, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 2000); // read_alarm(&tm); // p += sprintf(p, "alrm_time\t: %2dth day of week day\n" // "alrm_date\t: N/A for Platform\n", // tm.tm_wday); p += sprintf(p, "alrm_time\t: Not Support\n" "alrm_date\t: Not Support\n"); p += sprintf(p, "alarm_IRQ\t: %s\n", AIE_stat ? "yes" : "no" ); len = (p - page) - off; if (len < 0) len = 0; *eof = (len <= count) ? 1 : 0; *start = page + off; return len; } static int __init rtc_init(void) { #if 0 volatile unsigned char buf[0]; buf[0] = 0x13;//output clock printk("clock adjustment\n"); i2c_set_regs(7, buf, 1); buf[0] = 0xA5; i2c_read_regs(7, buf, 1); printk("data = %x\n",buf[0]); #endif misc_register (&ftrtc010rtc_miscdev); create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL); printk("pt7c4307 Real Time Clock driver\n"); return 0; } static void __exit rtc_exit(void) { remove_proc_entry ("driver/rtc", NULL); misc_deregister (&ftrtc010rtc_miscdev); } module_init(rtc_init); module_exit(rtc_exit);

网友评论