📄 pcf8593-rtc.c
字号:
/* * Real Time Clock interface for Linux on CPE with FTRTC010 * * Based on sa1100-rtc.c by Nils Faerber * * Based on rtc.c by Paul Gortmaker * Date/time conversion routines taken from arch/arm/kernel/time.c * by Linus Torvalds and Russel King * and the GNU C Library * ( ... I love the GPL ... just take what you need! ;) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * 0.01 2004-11-17 I-Jui Sung <ijsung@faraday-tech.com> * - initial release */#include <linux/module.h>#include <linux/fs.h>#include <linux/miscdevice.h>#include <linux/string.h>#include <linux/init.h>#include <linux/poll.h>#include <linux/proc_fs.h>#include <linux/ioport.h>#include <asm/bitops.h>#include <asm/hardware.h>#include <asm/irq.h>#include <asm/io.h>#include <linux/rtc.h>#include <linux/delay.h>#include <asm/arch/cpe/cpe.h>#include <asm/arch/cpe_int.h>#include "pcf8593.h"#include <linux/i2c.h>#include <linux/i2c-dev.h>#include <linux/i2c-algo-bit.h>#include <linux/i2c-algo-faraday.h>#include<sys_boot_msg.h>#include <linux/time.h>#include <asm/arch/cpe/fic8120.h>#include <asm/io.h>#include <asm/system.h>#define DRIVER_VERSION "0.01"//#define PCF8593_DEBUG/* Added by hyyeah--8.28.2007 *///static int year_cnt=0;//static int year_current=2007;//static int year_change=0;//static int year_pcf8593=0;//static int set_pcf8593=0;#if 0#define I2C_ADDR CPE_I2C_VA_BASE/* I2C Register Offset Definition */#define I2C_CR 0x00 /* I2C Control Register */#define I2C_SR 0x04 /* I2C Status Register */#define I2C_CDR 0x08 /* I2C Clock Divided Register */#define I2C_DR 0x0C /* I2C Data Register */#define I2C_SAR 0x10 /* I2C Slave Address Register */#define I2C_TGSR 0x14 /* I2C Setup/Hold Time & Glitch Setting Reg. */#define I2C_MBR 0x18 /* I2C Bus Monitor Reg. */#define I2C_VERSION 0x30 /* I2C Version Reg. */#define I2C_FEATURE 0x34 /* I2C Feature Reg. *//* I2C Control Register Bit Definition */#define I2C_ALIEN 0x2000 /* Arbitration lose */#define I2C_SAMIEN 0x1000 /* slave address match */#define I2C_STOPIEN 0x800 /* stop condition */#define I2C_BERRIEN 0x400 /* non ACK response */#define I2C_DRIEN 0x200 /* data receive */#define I2C_DTIEN 0x100 /* data transmit */#define I2C_TBEN 0x80 /* transfer byte enable */#define I2C_ACKNAK 0x40 /* ack sent */#define I2C_STOP 0x20 /* stop */#define I2C_START 0x10 /* start */#define I2C_GCEN 0x8 /* general call */#define I2C_SCLEN 0x4 /* enable clock */#define I2C_I2CEN 0x2 /* enable I2C */#define I2C_I2CRST 0x1 /* reset I2C */#define I2C_ENABLE (I2C_ALIEN|I2C_SAMIEN|I2C_STOPIEN|I2C_BERRIEN|I2C_DRIEN|I2C_DTIEN|I2C_SCLEN|I2C_I2CEN)#if 0#define I2C_ENABLE (I2C_ALIEN | I2C_SAMIEN | I2C_STOPIEN | \ I2C_BERRIEN | I2C_DRIEN | I2C_DTIEN | \ I2C_SCLEN | I2C_I2CEN)#endif/* I2C Status Register Bit Definition */#define I2C_SR_START 0x800#define I2C_SR_AL 0x400#define I2C_SR_GC 0x200#define I2C_SR_SAM 0x100#define I2C_SR_STOP 0x080#define I2C_SR_BERR 0x040#define I2C_SR_DR 0x020#define I2C_SR_DT 0x010#define I2C_SR_BB 0x008#define I2C_SR_I2CB 0x004#define I2C_SR_ACK 0x002#define I2C_SR_RW 0x001#define I2C_WR(reg, val) (*(volatile unsigned int *)((I2C_ADDR)+(reg)) = (unsigned int)(val))#define I2C_RD(reg) (*(volatile unsigned int *)((I2C_ADDR)+(reg)))#define I2C_GSR_Value 0x00#define I2C_TSR_Value 0x20#define I2C_CDR_Value 0x50#endif//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;extern int (*set_rtc)(void);extern int faraday_i2c_read(unsigned int i_dev_addr,unsigned int i_dev_offset,unsigned char *buf,unsigned int size,int clockdiv);extern int faraday_i2c_write(unsigned int i_dev_addr,unsigned int i_dev_offset,unsigned char *buf,unsigned int size,int clockdiv);int I2C_Write (unsigned int address, unsigned int index, unsigned char value);int I2C_Read(unsigned int address, unsigned int index);struct semaphore pcf8593lock;//static const unsigned char days_in_mo[] = //month:0~11 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};#define is_leap(year) \ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))/* Added by hyyeah 8.29.2007 */ static void get_local_time (unsigned long t, struct rtc_time *tval){ long days, month, year, rem; days = t / 86400; rem = t % 86400; tval->tm_hour = rem / 3600; rem %= 3600; tval->tm_min = rem / 60; tval->tm_sec = rem % 60; tval->tm_wday = (4 + days) % 7;#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) year = 1970 + days / 365; days -= ((year - 1970) * 365 + LEAPS_THRU_END_OF (year - 1) - LEAPS_THRU_END_OF (1970 - 1)); if (days < 0) { year -= 1; days += 365 + is_leap(year); } tval->tm_year = year - 1900; tval->tm_yday = days + 1; month = 0; if (days >= 31) { days -= 31; month++; if (days >= (28 + is_leap(year))) { days -= (28 + is_leap(year)); month++; while (days >= days_in_mo[month]) { days -= days_in_mo[month]; month++; } } } tval->tm_mon = month; tval->tm_mday = days + 1; tval->tm_isdst=0; }static int get_current_year(void){ struct timeval tv; struct rtc_time tval; do_gettimeofday(&tv); get_local_time(tv.tv_sec, &tval); return (int)tval.tm_year; }static void get_current_time(struct rtc_time * tval){ struct timeval tv; do_gettimeofday(&tv); get_local_time(tv.tv_sec,tval);}static int set_year(unsigned short year,unsigned char pcf8593_year){ int ret=-1; unsigned char year_lo,year_hi; unsigned short pcf8593_year_tmp=0; if(year>16383){ printk("Warning,the year %d is overload !!\n",year); return ret; } pcf8593_year&=0x03; pcf8593_year_tmp|=pcf8593_year; pcf8593_year_tmp<<=14; year|=pcf8593_year_tmp; year_lo=year&0x00ff; year_hi=(year&0xff00)>>8; //printk("%s,The year_lo is %02x\n",__FUNCTION__,year_lo); //printk("%s,The year_hi is %02x\n",__FUNCTION__,year_hi); down(&pcf8593lock); /*Save the LSB 8 bits */ if(I2C_Write(PCF8593_WRITE_ADDR,0x0e,year_lo)<0) goto exit_error; /* Save the MSB 8 bits */ if(I2C_Write(PCF8593_WRITE_ADDR,0x0f,year_hi)<0) goto exit_error; up(&pcf8593lock); ret=0; return ret; exit_error: up(&pcf8593lock); return ret; }static int get_year(unsigned short *year, unsigned char *pcf8593_year){ unsigned short year_tmp=0; unsigned char year_lo,year_hi; int ret=-1,year_lo_tmp,year_hi_tmp; down(&pcf8593lock); year_lo_tmp=I2C_Read(PCF8593_READ_ADDR,0x0e); if(year_lo_tmp==-1) goto get_year_ret_error; year_hi_tmp=I2C_Read(PCF8593_READ_ADDR,0x0f); if(year_hi_tmp==-1) goto get_year_ret_error; up(&pcf8593lock); year_lo=(unsigned char)year_lo_tmp; year_hi=(unsigned char)year_hi_tmp; //printk("%s,The year_lo is %02x\n",__FUNCTION__,year_lo); //printk("%s,The year_hi is %02x\n",__FUNCTION__,year_hi); year_tmp|=year_hi; *pcf8593_year=(unsigned char)(year_tmp>>6); year_tmp<<=8; year_tmp|=year_lo; year_tmp&=0x3fff; *year=year_tmp; //printk("the pcf8593_year is %d\n",*pcf8593_year); //printk("the year is %d\n",*year); ret=0; return ret;get_year_ret_error: up(&pcf8593lock); return ret; }/* End add */#if 0 //del by ljn static inti2c_wait_ack (void){ volatile unsigned int status=0,count=0;; while (!(status&0x10)) { mdelay(1); status=I2C_RD (I2C_SR); count++; if(count>0x100) { printk ("I2C wait ack time out\n"); return 1; } } return 0;}static inti2c_check_ready (void){ volatile unsigned int status=0,count=0;; while (!(status&0x20)) { mdelay(1); status=I2C_RD (I2C_SR); count++; if(count>0x100) { printk ("I2C check ready time out\n"); return 1; } } return 0;}static voidi2c_write(unsigned char cmd, unsigned char data){ /* start the transaction and output 7-bit addrss and R/W bit */ I2C_WR(I2C_DR, cmd); I2C_WR(I2C_CR, (I2C_ENABLE | I2C_TBEN | I2C_START)); /* wait for ack */ i2c_wait_ack(); I2C_WR(I2C_DR, data); I2C_WR(I2C_CR, (I2C_ENABLE | I2C_TBEN)); /* wait for ack */ i2c_wait_ack(); I2C_WR(I2C_CR, (I2C_ENABLE | I2C_TBEN | I2C_STOP)); i2c_wait_ack();}static int Write_Endian(unsigned char data){ short i=0,tmp=0,tmp_1=0; tmp_1 = ((data / 10) << 4) | (data % 10); //printk("input = %d,mid = %d,%d,out = 0x%x\n",data,data / 10,data % 10,tmp_1); for(i = 0; i < 8; i++) tmp |= ((tmp_1 >> i) & 0x1) << (7-i); //printk("dd1 = %x\n",tmp); return tmp; }static int Read_Endian(unsigned char data){ short i=0,tmp=0; for(i = 0; i < 8; i++) tmp |= ((data >> i) & 0x1) << (7-i); return ((tmp >> 4) * 10 + (tmp & 0xF));}static int checkstatus(void){ unsigned char data; short i=0,tmp=0; I2C_WR(I2C_DR, 0x61); I2C_WR(I2C_CR, (I2C_ENABLE | I2C_TBEN | I2C_START)); /* wait for ack */ i2c_wait_ack(); I2C_WR(I2C_CR, (I2C_ENABLE | I2C_TBEN | I2C_STOP | I2C_ACKNAK)); i2c_check_ready(); data = I2C_RD(I2C_DR); for(i = 0; i < 8; i++) tmp |= ((data >> i) & 0x1) << (7-i); if((tmp == 0x80) || (tmp == 0x40)) return 1; else return 0;}#endifint I2C_Read(unsigned int address, unsigned int index){ int ret; unsigned char val; ret = faraday_i2c_read(address, index, &val, 1, 0); if(ret < 0 ){ printk(" I2C read fail: addr=%x, offset=%x\n",address, index); return -1; } //if ((index == 0x12) && (val=='0x80')){ //if ((val == 0x80)){ // printk("reset all register by OV7640...\n"); //mdelay(1000); // mdelay(5); //} return val;}// --------------------------------------------------------------------// return// -1 ==> failure// 1 ==> success// --------------------------------------------------------------------int I2C_Write (unsigned int address, unsigned int index, unsigned char value){ int ret; ret = faraday_i2c_write(address,index,&value,1,0); if(ret < 0 ){ printk(" I2C write fail: addr=%x, offset=%x\n",address, index); return -1; } udelay(1000); return ret;}static int pcf8593_checkstatus(void){ unsigned char value=0; int value_tmp; value_tmp=I2C_Read(PCF8593_READ_ADDR,0x0); if(value_tmp==-1) return -1; value=(unsigned char)value_tmp; if(value&0x80) { #ifdef PCF8593_DEBUG printk("PCF8593 is stopped\n"); #endif return 0;//8593 is stopped } else if((value&0x80)==0) { #ifdef PCF8593_DEBUG printk("PCF8593 is runing\n"); #endif return 1;//8593 is running } else return -1;}static int pcf8593_start(void){ unsigned char value=0; int value_tmp; if(pcf8593_checkstatus()==1) return 1;//is running value_tmp=I2C_Read(PCF8593_READ_ADDR,0x0); if(value_tmp==-1) return -1; value=(unsigned char)value_tmp; value&=0x7f; if(I2C_Write(PCF8593_WRITE_ADDR,0x0,value)) { #ifdef PCF8593_DEBUG printk("Start pcf8593 \n"); #endif return 1; } else return -1;}static int pcf8593_stop(void){ unsigned char value=0; int value_tmp; if(pcf8593_checkstatus()==0) return 1;//is stopped value_tmp=I2C_Read(PCF8593_READ_ADDR,0x0); if(value_tmp==-1) return -1; value=(unsigned char)value_tmp; value|=0x80; if(I2C_Write(PCF8593_WRITE_ADDR,0x0,value)) { #ifdef PCF8593_DEBUG printk("Stop pcf8593 \n"); #endif return 1; } else return -1;}static int pcf8593_init(void){ unsigned char value=0; int value_tmp; down(&pcf8593lock); if(pcf8593_stop()<0) goto pcf8593_init_error_exit;//stop error //set mode value_tmp=I2C_Read(PCF8593_READ_ADDR,0x0); if(value_tmp==-1) goto pcf8593_init_error_exit; value=(unsigned char)value_tmp; #ifdef PCF8593_DEBUG printk("PCF8593 default ctrl/status:0x%2x\n",value); #endif value=0x80;//see pcf8593 datasheet if(I2C_Write(PCF8593_WRITE_ADDR,0x0,value)<0) { #ifdef PCF8593_DEBUG printk("PCF8593 init ctrl/status reg failed\n"); #endif goto pcf8593_init_error_exit; } //set am or pm value_tmp=I2C_Read(PCF8593_READ_ADDR,0x4); if(value_tmp==-1) goto pcf8593_init_error_exit; value=(unsigned char)value_tmp; #ifdef PCF8593_DEBUG printk("PCF8593 default hour reg:%2x\n",value); #endif value&=0x3f;//see pcf8593 datasheet,set 24h mode if(I2C_Write(PCF8593_WRITE_ADDR,0x4,value)<0) { #ifdef PCF8593_DEBUG printk("PCF8593 init hour reg failed\n"); #endif goto pcf8593_init_error_exit; } //start 8593 if(pcf8593_start()<0) { #ifdef PCF8593_DEBUG printk("PCF8593 init failed\n"); #endif goto pcf8593_init_error_exit; } up(&pcf8593lock); return 1;pcf8593_init_error_exit: up(&pcf8593lock); return -1; }static int get_date(unsigned char *buf){ unsigned char date=0; int ret=-1,buf_tmp; buf_tmp=I2C_Read(PCF8593_READ_ADDR,0x02);//seconds if(buf_tmp==-1) goto get_date_exit_error; buf[0]=(unsigned char)buf_tmp; //printk("sec is %2x\n",buf[0]); buf_tmp=I2C_Read(PCF8593_READ_ADDR,0x03);//minutes if(buf_tmp==-1) goto get_date_exit_error; buf[1]=(unsigned char)buf_tmp; //printk("min is %2x\n",buf[1]); buf_tmp=I2C_Read(PCF8593_READ_ADDR,0x04);//hour if(buf_tmp==-1) goto get_date_exit_error; buf[2]=(unsigned char)buf_tmp; //printk("hour is %2x\n",buf[2]); buf[2]&=0x3f; buf_tmp=I2C_Read(PCF8593_READ_ADDR,0x05); if(buf_tmp==-1) goto get_date_exit_error; date=(unsigned char)buf_tmp; //printk("year/date is %2x\n",date); buf[3]=date&0x3f;//date buf[5]=(date>>6)&0x3;//year buf_tmp=I2C_Read(PCF8593_READ_ADDR,0x06); if(buf_tmp==-1) goto get_date_exit_error; date=(unsigned char)buf_tmp; //printk(" month/weekdays is %2x\n",date); buf[4]=date&0x1f;//month buf[6]=(date>>5)&0x7;//week day ret=0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -