📄 pcf8593-rtc.c
字号:
return ret; get_date_exit_error: return ret; }#if 0static void get_time(unsigned char *buf){ int i=0; I2C_WR(I2C_DR, 0x67); I2C_WR(I2C_CR, (I2C_ENABLE | I2C_TBEN | I2C_START)); i2c_wait_ack(); for(i = 0; i < 2; i++) { I2C_WR(I2C_CR, (I2C_ENABLE | I2C_TBEN)); i2c_check_ready(); buf[i] = Read_Endian(I2C_RD(I2C_DR)); //printk(" RTC %dth data = %x\n",i,buf[i]); } I2C_WR(I2C_CR, (I2C_ENABLE | I2C_TBEN | I2C_STOP | I2C_ACKNAK)); i2c_check_ready(); buf[i] = Read_Endian(I2C_RD(I2C_DR)); //printk(" RTC %dth data = %x\n",i,buf[i]);} #endifstatic int set_date(unsigned char *buf){ int ret=-1,data_tmp; unsigned char data=0; down(&pcf8593lock); if(pcf8593_stop()<0) goto set_date_error_exit; if(I2C_Write(PCF8593_WRITE_ADDR,0x02,buf[0])<0)//seconds goto set_date_error_exit; if(I2C_Write(PCF8593_WRITE_ADDR,0x03,buf[1])<0)//minutes goto set_date_error_exit; data_tmp=I2C_Read(PCF8593_READ_ADDR,0x04)&0xc0;//hour if(data_tmp==-1) goto set_date_error_exit; data=(unsigned char)data_tmp; data=data|buf[2]; if(I2C_Write(PCF8593_WRITE_ADDR,0x04,data)<0)//hour goto set_date_error_exit; data=(buf[5]<<6)|buf[3]; if(I2C_Write(PCF8593_WRITE_ADDR,0x05,data)<0)//year/date goto set_date_error_exit; data=(buf[6]<<5)|buf[4]; if(I2C_Write(PCF8593_WRITE_ADDR,0x06,data)<0)//week/month goto set_date_error_exit; //start 8593 if(pcf8593_start()<0) goto set_date_error_exit; up(&pcf8593lock); ret=0; return ret; set_date_error_exit: up(&pcf8593lock); return ret;}#if 0static void time_set_rtc(void){ unsigned char buf[7]; unsigned long current_time = xtime.tv_sec; buf[0] = current_time / 3600; buf[1] = current_time / 60; buf[2] = current_time % 60; set_time(buf);}#endif#if 0static void set_32kE(void){ I2C_WR(I2C_DR, 0x62); I2C_WR(I2C_CR, (I2C_ENABLE | I2C_TBEN | I2C_START)); i2c_wait_ack(); I2C_WR(I2C_DR, 0x10); I2C_WR(I2C_CR, (I2C_ENABLE | I2C_TBEN | I2C_STOP)); i2c_wait_ack(); }#endif#if 0static void set_time(unsigned char *buf){ int i=0; I2C_WR(I2C_DR, 0x66); I2C_WR(I2C_CR, (I2C_ENABLE | I2C_TBEN | I2C_START)); i2c_wait_ack(); for(i = 0; i < 2; i++) { I2C_WR(I2C_DR, Write_Endian(buf[i])); I2C_WR(I2C_CR, (I2C_ENABLE | I2C_TBEN)); /* wait for ack */ i2c_wait_ack(); } I2C_WR(I2C_DR, Write_Endian(buf[i])); I2C_WR(I2C_CR, (I2C_ENABLE | I2C_TBEN | I2C_STOP)); i2c_wait_ack(); }static int Write_Alarm_Endian(unsigned char data){ short i=0,tmp=0,tmp_1=0; tmp_1 = ((data / 10) << 4) | (data % 10); for(i = 0; i < 8; i++) tmp |= ((tmp_1 >> i) & 0x1) << (7-i); return tmp; }static int Read_Alarm_Endian(unsigned char data){ short i=0,tmp=0,tmp_1=0; data &= 0xFE;//disable enable bit for(i = 0; i < 8; i++) tmp |= ((data >> i) & 0x1) << (7-i); tmp_1 = ((tmp / 10) << 4) | (tmp % 10); return tmp_1; }#endif#if 0static void set_alarm_time(unsigned char *buf,unsigned char w_enable,unsigned char h_enable,unsigned char m_enable){ unsigned char i=0,flag[3]; flag[0]=w_enable; flag[1]=h_enable; flag[2]=m_enable; i2c_write(0x62,0x4); I2C_WR(I2C_DR, 0x68); I2C_WR(I2C_CR, (I2C_ENABLE | I2C_TBEN | I2C_START)); i2c_wait_ack(); for(i = 0; i < 2; i++) { //printk("I2C_WR %d,%x,%x\n",buf[i],Alarm_Endian(buf[i]),Alarm_Endian(buf[i]) + flag[i]); I2C_WR(I2C_DR, Write_Alarm_Endian(buf[i]) + flag[i]); I2C_WR(I2C_CR, (I2C_ENABLE | I2C_TBEN)); /* wait for ack */ i2c_wait_ack(); } //printk("I2C_WR %d,%x,%x\n",buf[i],Alarm_Endian(buf[i]),Alarm_Endian(buf[i]) + flag[i]); I2C_WR(I2C_DR, Write_Alarm_Endian(buf[i]) + flag[i]); I2C_WR(I2C_CR, (I2C_ENABLE | I2C_TBEN | I2C_STOP)); i2c_wait_ack(); }#endif#if 0static void get_alarm_time(unsigned char *buf){ int i=0,dd; I2C_WR(I2C_DR, 0x69); I2C_WR(I2C_CR, (I2C_ENABLE | I2C_TBEN | I2C_START)); i2c_wait_ack(); #if 0 for(i = 0; i < 2; i++) { I2C_WR(I2C_CR, (I2C_ENABLE | I2C_TBEN)); i2c_check_ready(); dd = I2C_RD(I2C_DR); printk("ttt %x\n",dd); buf[i] = Read_Alarm_Endian(dd); }#endif I2C_WR(I2C_CR, (I2C_ENABLE | I2C_TBEN | I2C_STOP | I2C_ACKNAK)); i2c_check_ready(); dd = I2C_RD(I2C_DR); //printk("ttt %x\n",dd); buf[i] = Read_Alarm_Endian(dd);}#endif/* * Converts seconds since 1970-01-01 00:00:00 to Gregorian date. *//*The function modified by hyyeah--9.3.2007 */static int decodetime (struct rtc_time *tval){ unsigned char buf[7]; unsigned short year=0; unsigned char year_pcf8593=0; down(&pcf8593lock); if(get_date(buf)<0){ up(&pcf8593lock); return -1; } up(&pcf8593lock); tval->tm_sec = BCD_TO_BIN(buf[0]); tval->tm_min = BCD_TO_BIN(buf[1]); tval->tm_hour = BCD_TO_BIN(buf[2]); tval->tm_mday = BCD_TO_BIN(buf[3]); tval->tm_mon = BCD_TO_BIN(buf[4]); /* In pcf8593 month range:1~12, but in struct tm or rtc_tm, range: 0~11. Note by hyyeah--8.31.2007 */ tval->tm_mon--; /* Year and wday fields are not BCD code,so don't need transform. * Get tm_year field of struct time_rtc. * Added by hyyeah--9.3.2007. */ if(get_year(&year,&year_pcf8593)<0) return -1; if(year_pcf8593!=buf[5]){ //year_change=1; printk("Warning, the year[%d] has gone !!\n",year); if(set_year(++year,buf[5])<0) return -1; } //printk("get_current_year :%d\n",get_current_year()); //if(year_change){ //year_cnt++; //year_change=0; //}// tval->tm_year=year+year_cnt-1900; tval->tm_year=year-1900; tval->tm_wday = buf[6]; #ifdef PCF8593_DEBUG printk("Date(y/m/d):%d/%d/%d,week:%d, Time(h/m/s):%d/%d/%d\n", tval->tm_year,tval->tm_mon,tval->tm_mday,tval->tm_wday,tval->tm_hour, tval->tm_min,tval->tm_sec);#endif return 0;}//static unsigned AIE_stat=0;//static unsigned saved_second=0; /* workaround for A320C *//*ijsung:currently only support alarm*/#if 0static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs){ /* wake up waiting process */ wake_up_interruptible(&rtc_wait); kill_fasync (&rtc_async_queue, SIGIO, POLL_IN);}#endifstatic int rtc_open(struct inode *inode, struct file *file){#if 0//ch by ljn if (test_and_set_bit (1, &rtc_status)) return -EBUSY; rtc_irq_data = 0; return 0;#else if(pcf8593_checkstatus()>=0) return 0; else return -EBUSY;#endif}static int rtc_release(struct inode *inode, struct file *file){#if 0//del by ljn unsigned char buf[7]; spin_lock_irq (&rtc_lock); set_alarm_time(buf,0,0,0); spin_unlock_irq (&rtc_lock); rtc_status = 0;#endif return 0;}static int rtc_fasync (int fd, struct file *filp, int on){#if 0 return fasync_helper (fd, filp, on, &rtc_async_queue);#else return 0;#endif}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){#if 0//del by ljn 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;#endifreturn 0;}static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct rtc_time tm; switch (cmd) { case RTC_8593_INIT: if(pcf8593_init()) { printk("RTC_8593_INIT okl!\n\r"); return 0; } else { printk("RTC_8593_INIT failedl!\n\r"); return -1; } case RTC_RD_TIME: if(decodetime(&tm)<0) return -1; break; case RTC_SET_TIME: { unsigned char buf[7]; if (copy_from_user (&tm, (struct rtc_time*)arg, sizeof (tm))) return -EFAULT; /* Added by hyyeah--8.28.2007 */ //tm.tm_year += 1900; if (tm.tm_year < 1970 || (unsigned)tm.tm_mon >=12 || tm.tm_mday < 1 || tm.tm_mday > (days_in_mo[tm.tm_mon] + (tm.tm_mon == 1 && is_leap(tm.tm_year))) || (unsigned)tm.tm_hour >= 24 || (unsigned)tm.tm_min >= 60 || (unsigned)tm.tm_sec >= 60) return -EINVAL; /* In pcf8593 month range:1~12, but in struct tm or rtc_tm, range: 0~11. Added by hyyeah--8.31.2007 */ tm.tm_mon++; buf[0] = BIN_TO_BCD(tm.tm_sec); buf[1] = BIN_TO_BCD(tm.tm_min); buf[2] = BIN_TO_BCD(tm.tm_hour)&0x3f; buf[3] = BIN_TO_BCD(tm.tm_mday)&0x3f; buf[4] = BIN_TO_BCD(tm.tm_mon)&0x1f; /* Added by hyyeah-8.28.2007 */ buf[5] = tm.tm_year&0x3; if(set_year((unsigned short)tm.tm_year,buf[5])<0) return -1; buf[6] = tm.tm_wday&0x7; if(set_date(buf)<0) return -1; return 0; } #if 0 case RTC_AIE_OFF: spin_lock_irq(&rtc_lock); //AIE_stat=0; //set_alarm_time(buf,0,0,0); spin_unlock_irq(&rtc_lock); return 0; case RTC_AIE_ON: spin_lock_irq(&rtc_lock); //get_alarm_time(buf); //set_alarm_time(buf,1,1,1); //rtc_irq_data = 0; spin_unlock_irq(&rtc_lock); return 0; case RTC_ALM_READ: { decodetime(&tm); } break; case RTC_ALM_SET: if (copy_from_user (&tm2, (struct rtc_time*)arg, sizeof (tm2))) return -EFAULT; buf[0]=tm2.tm_wday; buf[1]=tm2.tm_hour; buf[2]=tm2.tm_min; set_alarm_time(buf,1,1,1); 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);#endif 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};#if 0static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ unsigned alarm_time; unsigned char buf[7]; char *p = page; int len; struct rtc_time tm; decodetime(&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, tm.tm_min, tm.tm_sec, tm.tm_year + 2000, tm.tm_mon, tm.tm_mday, 2000); get_alarm_time(buf);// p += sprintf(p, "alrm_time\t: %2dth day of week day\n"// "alrm_date\t: N/A for FIC8120\n",// tm.tm_wday); p += sprintf(p, "alrm_time\t: Not be Set\n" "alrm_date\t: Not be Set\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;}#endifstatic int __init pcf8593rtc_init(void){ int ret; if((ret=misc_register (&ftrtc010rtc_miscdev))<0) { printk("Can't register rtc device:PCF8593!\n"); return ret; }#if 0//del by ljn create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL); cpe_int_set_irq(IRQ_RTCALARM, EDGE, H_ACTIVE); ret = request_irq (IRQ_RTCALARM, rtc_interrupt, SA_INTERRUPT, "rtc Alrm", NULL); if (ret) { printk(KERN_ERR "rtc: IRQ %d already in use.\n", 17); goto IRQ_RTCAlrm_failed; }#endif#if 0 if(pcf8593_start()<0) { printk("Real Time Clock driver init failed!\n"); }#endif init_MUTEX(&pcf8593lock); /* Added by hyyeah for test--8.27.2007 *///if(pcf8593_init()<0) //printk("Real Time Clock driver init failed!\n"); #ifdef DEBUG_KERNEL_BOOT_MSG printk("Real time clock pcf8593 driver init ok!\n"); #else printk(BOOT_SYM);#endif //set_rtc = time_set_rtc; return 0;#if 0IRQ_RTCAlrm_failed: remove_proc_entry ("driver/rtc", NULL); misc_deregister (&ftrtc010rtc_miscdev); return ret;#endif }static void __exit pcf8593rtc_exit(void){ /* Masked by hyyeah--8.24.2007 */ //remove_proc_entry ("driver/rtc", NULL); misc_deregister (&ftrtc010rtc_miscdev);}module_init(pcf8593rtc_init);module_exit(pcf8593rtc_exit);MODULE_AUTHOR("I-Jui Sung <ijsung@faraday-tech.com>");MODULE_DESCRIPTION("CPE FTRTC010 Realtime Clock Driver (RTC)");MODULE_LICENSE("GPL");EXPORT_NO_SYMBOLS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -