⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcf8593-rtc.c

📁 pcf8593实时时钟的驱动实例 Real Time Clock interface for Linux on CPE with FTRTC010
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	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 + -