linux2.4 GPIO模擬實現I2C數據傳輸-DS1302

1。我們要實現通過GPIO讀寫 DS1302的寄存器數據;

2。首先我們需要了解下DS1302的工作方式,它提供SCL、DATA、RST三個信號,然後可以參考其時序圖進行數據的讀寫;

3。我們現在就是要通過GPIO來模擬整個讀寫的時序;

4。下面的代碼是linux2.4下的,當然只能適合我的CPU,應該不同的CPU的GPIO寄存器地址都不一樣,如果你使用需要修改;

頭文件主要定義了DS1302的操作地址、及tm時間結構等;

/* $Id: rtc.h,v 1.3 2001/03/21 09:56:31 magnusmn Exp $ */


#ifndef DS1302_H
#define DS1302_H


#include <linux/config.h>
#include <linux/ioctl.h>


/* Dallas DS1302 clock/calendar register numbers */
/*
#define RTC_SECONDS 0
#define RTC_MINUTES 1
#define RTC_HOURS 2
#define RTC_DAY_OF_MONTH 3
#define RTC_MONTH 4
#define RTC_WEEKDAY 5
#define RTC_YEAR 6
#define RTC_CONTROL 7
*/


#define RTC_SECONDS 0x80
#define RTC_MINUTES 0x82
#define RTC_HOURS   0x84
#define RTC_DAY_OF_MONTH 0x86
#define RTC_MONTH   0x88
#define RTC_WEEKDAY 0x8a
#define RTC_YEAR    0x8c
#define RTC_CONTROL 0x8e
#define RTC_TRICKLECHARGER 0x90
/* Bits in CONTROL register */
#define RTC_CONTROL_WRITEPROTECT 0x80
//#define RTC_TRICKLECHARGER 8
/* Bits in TRICKLECHARGER register TCS TCS TCS TCS DS DS RS RS */
#define   RTC_TCR_PATTERN 0xA0 /* 1010xxxx */
#define   RTC_TCR_1DIOD 0x04 /* xxxx01xx */
#define   RTC_TCR_2DIOD 0x08 /* xxxx10xx */
#define   RTC_TCR_DISABLED 0x00 /* xxxxxx00 Disabled */
#define   RTC_TCR_2KOHM 0x01      /* xxxxxx01 2KOhm */
#define   RTC_TCR_4KOHM 0x02      /* xxxxxx10 4kOhm */
#define   RTC_TCR_8KOHM 0x03      /* xxxxxx11 8kOhm */


#ifdef CONFIG_ETRAX_DS1302
#define CMOS_READ(x) ds1302_readreg(x)
#define CMOS_WRITE(val,reg) ds1302_writereg(reg,val)
#define RTC_INIT() ds1302_init()
#else
/* no RTC configured so we shouldn't try to access any */
#define CMOS_READ(x) 42
#define CMOS_WRITE(x,y)
#define RTC_INIT() (-1)
#endif


/* conversions to and from the stupid RTC internal format */


#define BCD_TO_BIN(x) x = (((x & 0xf0) >> 3) * 5 + (x & 0xf))
#define BIN_TO_BCD(x) x = (x % 10) | ((x / 10) << 4) 


/*
 * The struct used to pass data via the following ioctl. Similar to the
 * struct tm in <time.h>, but it needs to be here so that the kernel 
 * source is self contained, allowing cross-compiles, etc. etc.
 */


struct rtc_time {
	int tm_sec;
	int tm_min;
	int tm_hour;
	int tm_mday;
	int tm_mon;
	int tm_year;
	int tm_wday;
	int tm_yday;
	int tm_isdst;
};


#define RTC_MAJOR_NR  230
/*
 * ioctl calls that are permitted to the /dev/rtc interface
 */


#define RTC_RD_TIME	_IOR('p', 0x09, struct rtc_time) /* Read RTC time   */
#define RTC_SET_TIME	_IOW('p', 0x0a, struct rtc_time) /* Set RTC time    */
#define RTC_SET_CHARGE  _IOW('p', 0x0b, int) /* Set CHARGE mode    */


//#define RTC_RD_TIME	66
//#define RTC_SET_TIME	77
//#define RTC_SET_CHARGE  88


#endif





實現文件

/*!***************************************************************************
*!
*! FILE NAME  : ds1302.c
*!
*! DESCRIPTION: Implements an interface for the DS1302 RTC through Etrax I/O
*!
*! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status
*! ---------------------------------------------------------------------------
*!
*! (C) Copyright 1999, 2000, 2001  Axis Communications AB, LUND, SWEDEN
*!
*! $Id: ds1302.c,v 1.11 2001/06/14 12:35:52 jonashg Exp $
*!
*!***************************************************************************/
/*
#include <linux/config.h>


#include <linux/fs.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/blkdev.h>
#include <asm/uaccess.h>
#include <asm/system.h>
//#include <asm/svinto.h>
#include <asm/io.h>*/
#include <linux/fs.h>
#include <linux/iobuf.h>
//#include <linux/major.h>   
#include <linux/blkdev.h>
#include <linux/capability.h>
#include <linux/smp_lock.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/module.h>




//#include <asm/rtc.h>
//#include <linux/rtc.h>
#include "ds1302n.h"


static int init_module(void);
static void cleanup_module(void);
static int  ds1302_open(struct inode*, struct file *);
static int  ds1302_close(struct inode*, struct file *);
static int  rtc_ioctl(struct inode*inode,struct file *flip,unsigned int cmd,unsigned long arg);
static void ds1302_release(struct inode*inode, struct file *filp);




#define GPIO_MODE_OUTOFF 0x00
#define GPIO_MODE_INOFF  0x04
#define GPIO_MODE_DIROFF 0x08
#define GPIO_MODE_PULLENOFF  0x18
#define GPIO_MODE_PULLTYOFF  0x1C




#define DS1302_RST  0x0001
#define DS1302_SCL  0x0002
#define DS1302_SDA  0x0004


#define INN  0
#define OUTT 1




//#define RTC_MAJOR_NR 121 /* local major, change later */


static const char ds1302_name[] = "ds1302";


/* The DS1302 might be connected to different bits on different products. 
 * It has three signals - SDA, SCL and RST. RST and SCL are always outputs,
 * but SDA can have a selected direction.
 * For now, only PORT_PB is hardcoded.
 */


/* The RST bit may be on either the Generic Port or Port PB. */
/*
#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
#define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_G_DATA,  port_g_data_shadow,  CONFIG_ETRAX_DS1302_RSTBIT, x)
#define TK_RST_DIR(x)
#else
//#define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x)
//#define TK_RST_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR,  port_pb_dir_shadow,  CONFIG_ETRAX_DS1302_RSTBIT, x)
#define TK_RST_OUT(x)   write_gpio_bit(GPIO_MODE_OUT | DS1302_RST,x)
#define TK_RST_DIR(x)
#endif




//#define TK_SDA_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SDABIT, x)
#define TK_SDA_OUT(x)   write_gpio_bit(GPIO_MODE_OUT | DS1302_SDA,x)
//#define TK_SCL_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SCLBIT, x)
#define TK_SCL_OUT(x)   write_gpio_bit(GPIO_MODE_OUT | DS1302_SCL,x)


//#define TK_SDA_IN()   ((*R_PORT_PB_READ >> CONFIG_ETRAX_DS1302_SDABIT) & 1)
#define TK_SDA_IN()     read_gpio_bit(DS1302_SDA)


//#define TK_SDA_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR,  port_pb_dir_shadow,  CONFIG_ETRAX_DS1302_SDABIT, x)
//#define TK_SDA_DIR(x)   (if(x==1) set_gpio_ctrl(GPIO_MODE_OUT | DS1302_SDA); else set_gpio_ctrl(GPIO_MODE_IN | DS1302_SDA); )
#define TK_SDA_DIR(x) set_gpio_ctrl(x | DS1302_SDA)
//#define TK_SCL_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR,  port_pb_dir_shadow,  CONFIG_ETRAX_DS1302_SCLBIT, x)
#define TK_SCL_DIR(x)*/
/* 1 is out, 0 is in */


void TK_SDA_OUT(char x)
{
	int tmp;
	tmp = *(volatile int*)(CPE_GPIO_VA_BASE + GPIO_MODE_OUTOFF);
	*(volatile int*)(CPE_GPIO_VA_BASE + GPIO_MODE_OUTOFF) = (tmp & ~(1<<DS1302_SDA)) | x<<DS1302_SDA;
}


char TK_SDA_IN(void)
{
	return ((*(volatile int*)(CPE_GPIO_VA_BASE + GPIO_MODE_INOFF)>>DS1302_SDA)&1) ;
}


void TK_SCL_OUT(char x)
{
	int tmp;
	tmp = *(volatile int*)(CPE_GPIO_VA_BASE + GPIO_MODE_OUTOFF);
	*(volatile int*)(CPE_GPIO_VA_BASE + GPIO_MODE_OUTOFF) = ((tmp & ~(1<<DS1302_SCL)) | x<<DS1302_SCL);
}
void TK_RST_OUT(char x)
{
	int tmp;
	tmp = *(volatile int*)(CPE_GPIO_VA_BASE + GPIO_MODE_OUTOFF);
	*(volatile int*)(CPE_GPIO_VA_BASE + GPIO_MODE_OUTOFF) = ((tmp & ~(1<<DS1302_RST)) | x<<DS1302_RST);
}


void TK_SDA_DIR(char dir)
{
	if(dir==1)
	{
		int tmp;
		tmp = *(volatile int*)(CPE_GPIO_VA_BASE + GPIO_MODE_DIROFF);
		*(volatile int*)(CPE_GPIO_VA_BASE + GPIO_MODE_DIROFF) = (tmp | 1<<DS1302_SDA);
	}
	else if(dir==0)
	{
		int tmp;
		tmp = *(volatile int*)(CPE_GPIO_VA_BASE + GPIO_MODE_DIROFF);
		*(volatile int*)(CPE_GPIO_VA_BASE + GPIO_MODE_DIROFF) = (tmp & ~(1<<DS1302_SDA));
	}
	else;
}
void TK_SCL_DIR(char dir)
{
	if(dir==1)
	{
		int tmp;
		tmp = *(volatile int*)(CPE_GPIO_VA_BASE + GPIO_MODE_DIROFF);
		*(volatile int*)(CPE_GPIO_VA_BASE + GPIO_MODE_DIROFF) = (tmp | 1<<DS1302_SCL);
	}
	else if(dir==0)
	{
		int tmp;
		tmp = *(volatile int*)(CPE_GPIO_VA_BASE + GPIO_MODE_DIROFF);
		*(volatile int*)(CPE_GPIO_VA_BASE + GPIO_MODE_DIROFF) = (tmp & ~(1<<DS1302_SCL));
	}
	else;
}
void TK_RST_DIR(char dir)
{
	if(dir==1)
	{
		int tmp;
		tmp = *(volatile int*)(CPE_GPIO_VA_BASE + GPIO_MODE_DIROFF);
		*(volatile int*)(CPE_GPIO_VA_BASE + GPIO_MODE_DIROFF) = (tmp | 1<<DS1302_RST);
	}
	else if(dir==0)
	{
		int tmp;
		tmp = *(volatile int*)(CPE_GPIO_VA_BASE + GPIO_MODE_DIROFF);
		*(volatile int*)(CPE_GPIO_VA_BASE + GPIO_MODE_DIROFF) = (tmp & ~(1<<DS1302_RST));
	}
	else;
}


/* Set the pin enable pulled. */
static void setpullenable(char x, char value)
{
	int tmp;
	tmp = *(volatile int *)(CPE_GPIO_VA_BASE + GPIO_MODE_PULLENOFF);
	*(volatile int *)(CPE_GPIO_VA_BASE + GPIO_MODE_PULLENOFF) = ((tmp & ~(1<<x)) | (value<<x));
}


/* Set the pin pull type, pull low or pull high */
static void setpulltype(char x, char value)
{
	int tmp;
	tmp = *(volatile int*)(CPE_GPIO_VA_BASE + GPIO_MODE_PULLTYOFF);
	*(volatile int*)(CPE_GPIO_VA_BASE + GPIO_MODE_PULLTYOFF) = ((tmp & ~(1<<x)) | (value<<x));
}


/*
 * The reason for tempudelay and not udelay is that loops_per_usec
 * (used in udelay) is not set when functions here are called from time.c 
 */


static void tempudelay(int usecs) 
{
	volatile int loops;


	for(loops = usecs * 12; loops > 0; loops--)
		/* nothing */;	
}




/* Send 8 bits. */
static void
out_byte(unsigned char x) 
{
	int i;
	//TK_SDA_DIR(1);
	TK_SDA_DIR(OUTT);
	for (i = 8; i--;) {
		/* The chip latches incoming bits on the rising edge of SCL. */
		TK_SCL_OUT(0);
		TK_SDA_OUT(x & 1);
		tempudelay(1);
		TK_SCL_OUT(1);
		tempudelay(1);
		x >>= 1;
	}
	//TK_SDA_DIR(0);
	TK_SDA_DIR(INN);
}


static unsigned char
in_byte(void) 
{
	unsigned char x = 0;
	int i;


	/* Read byte. Bits come LSB first, on the falling edge of SCL.
	 * Assume SDA is in input direction already.
	 */
	//TK_SDA_DIR(0);
    TK_SDA_DIR(INN);
	for (i = 8; i--;) {
		TK_SCL_OUT(0);
		tempudelay(1);
		x >>= 1;
		x |= (TK_SDA_IN() << 7);
		TK_SCL_OUT(1);
		tempudelay(1);
	}


	return x;
}


/* Prepares for a transaction by de-activating RST (active-low). */


static void
start(void) 
{
	TK_SCL_OUT(0);
	tempudelay(1);
	TK_RST_OUT(0);
	tempudelay(5);
	TK_RST_OUT(1);	
}


/* Ends a transaction by taking RST active again. */


static void
stop(void) 
{
	tempudelay(2);
	TK_RST_OUT(0);
}


/* Enable writing. */


static void
ds1302_wenable(void) 
{
	start(); 	
	out_byte(0x8e); /* Write control register  */
	out_byte(0x00); /* Disable write protect bit 7 = 0 */
	stop();
}


static void
ds1302_osc_enable(void)
{
	char tmp;
	start();
	out_byte(0x81);
	tmp=in_byte();
	stop();
	if((tmp&0x80)==0x00);
	else
	{
		start(); 
		out_byte(0x80);
		out_byte(0x00);
		stop();
	}
}


/* Disable writing. */


static void
ds1302_wdisable(void) 
{
	start();
	out_byte(0x8e); /* Write control register  */
	out_byte(0x80); /* Disable write protect bit 7 = 0 */
	stop();
}


/* Probe for the chip by writing something to its RAM and try reading it back. */


#define MAGIC_PATTERN 0x42


static int
ds1302_probe(void) 
{
	int retval, res; 


	TK_RST_DIR(1);
	TK_SCL_DIR(1);
	//TK_SDA_DIR(0);
	TK_SDA_DIR(INN);
	ds1302_osc_enable();
	ds1302_writereg(RTC_TRICKLECHARGER, 0x00);//disable the trickle charger
	/* Try to talk to timekeeper. */
	ds1302_wenable();  
	start();
	out_byte(0xc0); /* write RAM byte 0 */	
	out_byte(MAGIC_PATTERN); /* write something magic */
	start();
	out_byte(0xc1); /* read RAM byte 0 */


	if((res = in_byte()) == MAGIC_PATTERN) {
		char buf[100];
		stop();
		ds1302_wdisable();
		printk("%s: RTC found.\n", ds1302_name);
		/*
		printk("%s: SDA, SCL, RST on PB%i, PB%i, %s%i\n",
		       ds1302_name,
		       CONFIG_ETRAX_DS1302_SDABIT,
		       CONFIG_ETRAX_DS1302_SCLBIT,
#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
		       "GENIO",
#else
		       "PB",
#endif
		       CONFIG_ETRAX_DS1302_RSTBIT);*/
    get_rtc_status(buf);
    printk(buf);
		retval = 1;
	} else {
		stop();
		printk("%s: RTC not found.\n", ds1302_name);
		retval = 0;
	}


	return retval;
}




/* Read a byte from the selected register in the DS1302. */


static unsigned char
ds1302_readreg(int reg) 
{
	unsigned char x;


	start();
	//out_byte(0x81 | (reg << 1)); /* read register */
	out_byte(reg|0x01);
	x = in_byte();
	stop();


	return x;
}


/* Write a byte to the selected register. */


static void
ds1302_writereg( unsigned char val,int reg) 
{
	ds1302_wenable();
	start();
	//out_byte(0x80 | (reg << 1)); /* write register */
	out_byte(reg&0xfe);
	out_byte(val);
	stop();
	ds1302_wdisable();
}


static void
get_rtc_time(struct rtc_time *rtc_tm) 
{
	unsigned long flags;


	save_flags(flags);
	cli();
	/*
	rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
	rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
	rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
	rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
	rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
	rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
  */


	rtc_tm->tm_sec= ds1302_readreg(RTC_SECONDS);
	rtc_tm->tm_min = ds1302_readreg(RTC_MINUTES);
	rtc_tm->tm_hour = ds1302_readreg(RTC_HOURS);
	rtc_tm->tm_mday = ds1302_readreg(RTC_DAY_OF_MONTH);
	rtc_tm->tm_mon = ds1302_readreg(RTC_MONTH);
	rtc_tm->tm_year = ds1302_readreg(RTC_YEAR);
	rtc_tm->tm_wday = ds1302_readreg(RTC_WEEKDAY);


	restore_flags(flags);
	
	BCD_TO_BIN(rtc_tm->tm_sec);
	BCD_TO_BIN(rtc_tm->tm_min);
	BCD_TO_BIN(rtc_tm->tm_hour);
	BCD_TO_BIN(rtc_tm->tm_mday);
	BCD_TO_BIN(rtc_tm->tm_mon);
	BCD_TO_BIN(rtc_tm->tm_year);
	BCD_TO_BIN(rtc_tm->tm_wday);


	/*
	 * Account for differences between how the RTC uses the values
	 * and how they are defined in a struct rtc_time;
	 */
  rtc_tm->tm_wday-=1;
	if (rtc_tm->tm_year <= 69)
		rtc_tm->tm_year += 100;


	rtc_tm->tm_mon--;
}


static unsigned char days_in_mo[] = 
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};


/* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date). */


static int
rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
	  unsigned long arg) 
{
        unsigned long flags;


	switch(cmd) {
		case RTC_RD_TIME:	/* read the time/date from RTC	*/
		{
			struct rtc_time rtc_tm;
						
			get_rtc_time(&rtc_tm);						
			if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time)))
				return -EFAULT;	
			return 0;
		}


		case RTC_SET_TIME:	/* set the RTC */
		{
			struct rtc_time rtc_tm;
			unsigned char mon, day, hrs, min, sec, leap_yr,wday;
			unsigned char save_control, save_freq_select;
			unsigned int yrs;
			if (!capable(CAP_SYS_TIME))
			{
				printk("capable failed.\n");
				return -EPERM;
			}
			if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)))
			{
				printk("copy_from_user failed.\n");
				return -EFAULT;    	
			}
			yrs = rtc_tm.tm_year + 1900;
			mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
			day = rtc_tm.tm_mday;
			hrs = rtc_tm.tm_hour;
			min = rtc_tm.tm_min;
			sec = rtc_tm.tm_sec;
			wday= rtc_tm.tm_wday+1;
			
			
			
			if ((yrs < 1970) || (yrs > 2069))
				return -EINVAL;


			leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));


			if ((mon > 12) || (day == 0))
				return -EINVAL;


			if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
				return -EINVAL;
			
			if ((hrs >= 24) || (min >= 60) || (sec >= 60))
				return -EINVAL;
      
      if(wday>7)
        return -EINVAL;
      
			if (yrs >= 2000)
				yrs -= 2000;	/* RTC (0, 1, ... 69) */
			else
				yrs -= 1900;	/* RTC (70, 71, ... 99) */


      
			BIN_TO_BCD(sec);
			BIN_TO_BCD(min);
			BIN_TO_BCD(hrs);
			BIN_TO_BCD(day);
			BIN_TO_BCD(mon);
			BIN_TO_BCD(yrs);
			BIN_TO_BCD(wday);






			save_flags(flags);
			cli();
			/*
			CMOS_WRITE(yrs, RTC_YEAR);
			CMOS_WRITE(mon, RTC_MONTH);
			CMOS_WRITE(day, RTC_DAY_OF_MONTH);
			CMOS_WRITE(hrs, RTC_HOURS);
			CMOS_WRITE(min, RTC_MINUTES);
			CMOS_WRITE(sec, RTC_SECONDS);
			*/
			ds1302_writereg(yrs, RTC_YEAR);
			ds1302_writereg(mon, RTC_MONTH);
			ds1302_writereg(day, RTC_DAY_OF_MONTH);
			ds1302_writereg(hrs, RTC_HOURS);
			ds1302_writereg(min, RTC_MINUTES);
			ds1302_writereg(sec, RTC_SECONDS);
			ds1302_writereg(wday, RTC_WEEKDAY);
			
			restore_flags(flags);


			/* Notice that at this point, the RTC is updated but
			 * the kernel is still running with the old time.
			 * You need to set that separately with settimeofday
			 * or adjtimex.
			 */
			return 0;
		}


		case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */
		{
			int tcs_val;                        
			unsigned char save_control, save_freq_select;


			if (!capable(CAP_SYS_TIME))
				return -EPERM;
			
			if(copy_from_user(&tcs_val, (int*)arg, sizeof(int)))
				return -EFAULT;


			//tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F);
			tcs_val &= 0x0F;                              // disable  the trickle charger
			ds1302_writereg(RTC_TRICKLECHARGER, tcs_val);
			return 0;
		}                
		default:
			return -ENOIOCTLCMD;
	}
}


static int
get_rtc_status(char *buf) 
{
	char *p;
	struct rtc_time tm;


	p = buf;


	get_rtc_time(&tm);


	/*
	 * There is no way to tell if the luser has the RTC set for local
	 * time or for Universal Standard Time (GMT). Probably local though.
	 */


	p += sprintf(p,
		"rtc_time\t: %02d:%02d:%02d\n"
		"rtc_date\t: %04d-%02d-%02d\n",
		tm.tm_hour, tm.tm_min, tm.tm_sec,
		tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);


	return  p - buf;
}




/* The various file operations we support. */


static struct file_operations rtc_fops = {
        owner:          THIS_MODULE,
        ioctl:          rtc_ioctl,	
        open:           ds1302_open,
        release:        ds1302_release,
}; 


/* Just probe for the RTC and register the device to handle the ioctl needed. */


static int 
init_module(void) 
{ 
	int ret;
	setpullenable(DS1302_SCL, 1);
	setpullenable(DS1302_RST, 1);
	setpulltype(DS1302_SCL, 1);
	setpulltype(DS1302_RST, 1);
	if (!ds1302_probe()) {
//#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
		/*
		 * The only way to set g27 to output is to enable ATA.
		 *
		 * Make sure that R_GEN_CONFIG is setup correct.
		 */
    	//	genconfig_shadow = ((genconfig_shadow &
				    // ~IO_MASK(R_GEN_CONFIG, ata))
				  // | 
				   //(IO_STATE(R_GEN_CONFIG, ata, select)));    
    	//	*R_GEN_CONFIG = genconfig_shadow;
    		//if (!ds1302_probe())
      			//return -1;
//#else
     	printk("probe fail....\n");
      return -1;
//#endif
  	}
  
	if (ret=register_chrdev(RTC_MAJOR_NR, ds1302_name, &rtc_fops)) {
		printk(KERN_INFO "%s: unable to get major %d for rtc\n", 
		       ds1302_name, RTC_MAJOR_NR);
		return -1;
	}
	
	return 0;
}


static void cleanup_module(void)
{
	unregister_chrdev(RTC_MAJOR_NR, ds1302_name);
}


static void ds1302_release(struct inode*inode, struct file *filp)
{ 
	return;
}




static int ds1302_open(struct inode*inode, struct file *filp)
{
	return 0;
}


static int  ds1302_close(struct inode*inode, struct file *filp)
{ 
	return 0;
}


//module_init(ds1302_init); //用戶加載該驅動時執行insmod gpio_driv.o就會自動調用gpio_init函數,它是驅動
//的入口點,相當於應用程序的main函數。
//module_exit(ds1302_release); //用戶卸載該驅動rmmod gpio_driv時執行
驅動編譯完成後,我們接好硬件就可以測試下
測試代碼如下:

#include "ds1302n.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>


#define DEVICE_FILE "/dev/ds1302"


int main(int argc, char** argv)
{
	int fds1302, ret;
	struct rtc_time rtc_tm;
	
	fds1302 = open(DEVICE_FILE, 0);
	if(fds1302 < 0)
	{
		printf("Can't Open device file: %s\n", DEVICE_FILE);
		exit(-1);
	}
	ret = ioctl(fds1302, RTC_RD_TIME, &rtc_tm);
	if(ret == 0)
	{
		printf("Time: %04d-%02d-%02d %02d:%02d:%02d\n", rtc_tm.tm_year+1900, rtc_tm.tm_mon+1,
rtc_tm.tm_mday, rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
	}
	memset(&rtc_tm, 0, sizeof(struct rtc_time));
	rtc_tm.tm_year = 2013 - 1900;
	rtc_tm.tm_mon = 5 - 1;
	rtc_tm.tm_mday = 10;
	rtc_tm.tm_hour = 14;
	rtc_tm.tm_min = 18;
	rtc_tm.tm_sec = 59;	
 	ret = ioctl(fds1302, RTC_SET_TIME, &rtc_tm);	
	if(ret != 0)
		printf("ioctl failed.\n");
	return 0;	
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章