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

📄 ds12885.c

📁 Ep9315 arm ds12885 ep9315 ds12885时间芯片驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
	case RTC_EPOCH_SET:	/* Set the epoch.	*/	{		/* 		 * There were no RTC clocks before 1900.		 */		if (arg < 1900)			return -EINVAL;		if (!capable(CAP_SYS_TIME))			return -EACCES;		epoch = arg;		return 0;	}	default:		return -ENOTTY;	}	return copy_to_user((void __user *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;}static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,		     unsigned long arg){	return rtc_do_ioctl(cmd, arg, 0);}/* *	We enforce only one user at a time here with the open/close. *	Also clear the previous interrupt data on an open, and clean *	up things on a close. *//* We use rtc_lock to protect against concurrent opens. So the BKL is not * needed here. Or anywhere else in this driver. */static int rtc_open(struct inode *inode, struct file *file){	spin_lock_irq (&rtc_lock);	if(rtc_status & RTC_IS_OPEN)		goto out_busy;	rtc_status |= RTC_IS_OPEN;	rtc_irq_data = 0;	spin_unlock_irq (&rtc_lock);	return 0;out_busy:	spin_unlock_irq (&rtc_lock);	return -EBUSY;}static int rtc_release(struct inode *inode, struct file *file){	spin_lock_irq (&rtc_lock);	rtc_irq_data = 0;	rtc_status &= ~RTC_IS_OPEN;	spin_unlock_irq (&rtc_lock);	return 0;}/* *	The various file operations we support. */static struct file_operations rtc12885_fops = {	.owner		= THIS_MODULE,	.llseek		= no_llseek,	.read		= rtc_read,	.ioctl		= rtc_ioctl,	.open		= rtc_open,	.release	= rtc_release,};#if 0static void rtc_dropped_irq(unsigned long data){	unsigned long freq;	spin_lock_irq (&rtc_lock);	/* Just in case someone disabled the timer from behind our back... */	if (rtc_status & RTC_TIMER_ON)//		mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);	rtc_irq_data += ((rtc_freq/HZ)<<8);	rtc_irq_data &= ~0xff;	rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);	/* restart */	freq = rtc_freq;	spin_unlock_irq(&rtc_lock);	printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", freq);	/* Now we have new data */	wake_up_interruptible(&rtc_wait);	kill_fasync (&rtc_async_queue, SIGIO, POLL_IN);}#endif/* *	Info exported via "/proc/driver/rtc". */static int rtc_proc_output (char *buf){#define YN(bit) ((ctrl & bit) ? "yes" : "no")#define NY(bit) ((ctrl & bit) ? "no" : "yes")	char *p;	struct rtc_time tm;	unsigned char batt, ctrl;	unsigned long freq;	spin_lock_irq(&rtc_lock);	batt = CMOS_READ(RTC_VALID) & RTC_VRT;	ctrl = CMOS_READ(RTC_CONTROL);	freq = rtc_freq;	spin_unlock_irq(&rtc_lock);	p = buf;	rtc_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"	 	     "rtc_epoch\t: %04lu\n",		     tm.tm_hour, tm.tm_min, tm.tm_sec,		     tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch);	get_rtc_alm_time(&tm);	/*	 * We implicitly assume 24hr mode here. Alarm values >= 0xc0 will	 * match any value for that particular field. Values that are	 * greater than a valid time, but less than 0xc0 shouldn't appear.	 */	p += sprintf(p, "alarm\t\t: ");	if (tm.tm_hour <= 24)		p += sprintf(p, "%02d:", tm.tm_hour);	else		p += sprintf(p, "**:");	if (tm.tm_min <= 59)		p += sprintf(p, "%02d:", tm.tm_min);	else		p += sprintf(p, "**:");	if (tm.tm_sec <= 59)		p += sprintf(p, "%02d\n", tm.tm_sec);	else		p += sprintf(p, "**\n");	p += sprintf(p,		     "DST_enable\t: %s\n"		     "BCD\t\t: %s\n"		     "24hr\t\t: %s\n"		     "square_wave\t: %s\n"		     "alarm_IRQ\t: %s\n"		     "update_IRQ\t: %s\n"		     "periodic_IRQ\t: %s\n"		     "periodic_freq\t: %ld\n"		     "batt_status\t: %s\n",		     YN(RTC_DST_EN),		     NY(RTC_DM_BINARY),		     YN(RTC_24H),		     YN(RTC_SQWE),		     YN(RTC_AIE),		     YN(RTC_UIE),		     YN(RTC_PIE),		     freq,		     batt ? "okay" : "dead");	return  p - buf;#undef YN#undef NY}static int rtc_read_proc(char *page, char **start, off_t off,                         int count, int *eof, void *data){        int len = rtc_proc_output (page);        if (len <= off+count) *eof = 1;        *start = page + off;        len -= off;        if (len>count) len = count;        if (len<0) len = 0;        return len;}void rtc_get_rtc_time(struct rtc_time *rtc_tm){	unsigned long uip_watchdog = jiffies;	unsigned char ctrl;	/*	 * read RTC once any update in progress is done. The update	 * can take just over 2ms. We wait 10 to 20ms. There is no need to	 * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.	 * If you need to know *exactly* when a second has started, enable	 * periodic update complete interrupts, (via ioctl) and then 	 * immediately read /dev/rtc which will block until you get the IRQ.	 * Once the read clears, read the RTC time (again via ioctl). Easy.	 */	if (rtc_is_updating() != 0)		while (jiffies - uip_watchdog < 2*HZ/100) {			barrier();			cpu_relax();		}	/*	 * Only the values that we read from the RTC are set. We leave	 * tm_wday, tm_yday and tm_isdst untouched. Even though the	 * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated	 * by the RTC when initially set to a non-zero value.	 */	spin_lock_irq(&rtc_lock);	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);	ctrl = CMOS_READ(RTC_CONTROL);	spin_unlock_irq(&rtc_lock);	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)	{		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);	}	/*	 * Account for differences between how the RTC uses the values	 * and how they are defined in a struct rtc_time;	 */	if ((rtc_tm->tm_year += (epoch - 1900)) <= 69)		rtc_tm->tm_year += 100;	rtc_tm->tm_mon--;}static void get_rtc_alm_time(struct rtc_time *alm_tm){	unsigned char ctrl;	/*	 * Only the values that we read from the RTC are set. That	 * means only tm_hour, tm_min, and tm_sec.	 */	spin_lock_irq(&rtc_lock);	alm_tm->tm_sec = CMOS_READ(RTC_SECONDS_ALARM);	alm_tm->tm_min = CMOS_READ(RTC_MINUTES_ALARM);	alm_tm->tm_hour = CMOS_READ(RTC_HOURS_ALARM);	ctrl = CMOS_READ(RTC_CONTROL);	spin_unlock_irq(&rtc_lock);	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)	{		BCD_TO_BIN(alm_tm->tm_sec);		BCD_TO_BIN(alm_tm->tm_min);		BCD_TO_BIN(alm_tm->tm_hour);	}}static void mask_rtc_irq_bit(unsigned char bit){	unsigned char val;	spin_lock_irq(&rtc_lock);	val = CMOS_READ(RTC_CONTROL);	val &=  ~bit;	CMOS_WRITE(val, RTC_CONTROL);	CMOS_READ(RTC_INTR_FLAGS);	rtc_irq_data = 0;	spin_unlock_irq(&rtc_lock);}static void set_rtc_irq_bit(unsigned char bit){	unsigned char val;	spin_lock_irq(&rtc_lock);	val = CMOS_READ(RTC_CONTROL);	val |= bit;	CMOS_WRITE(val, RTC_CONTROL);	CMOS_READ(RTC_INTR_FLAGS);	rtc_irq_data = 0;	spin_unlock_irq(&rtc_lock);}static int  __init test_set_ds12885(void){#define RTC_INIT			0xA5	unsigned char rtc_state,temp=0;	spin_lock_irq(&rtc_lock);		CMOS_WRITE(0xAA, 0xE);	CMOS_WRITE(0x55, 0x31);	temp=CMOS_READ(0xE);	if(temp!=0xAA){		printk(KERN_ALERT "Not found DS12885!\n");		spin_unlock_irq(&rtc_lock);		return 1;	}	temp=CMOS_READ(0x31);	if(temp!=0x55){		printk(KERN_ALERT "Not found DS12885!\n");		spin_unlock_irq(&rtc_lock);		return 1;	}	if(!(CMOS_READ(RTC_VALID) & RTC_VRT)){		printk(KERN_ALERT "DS12885's battery error!\n");		printk(KERN_INFO "Ds12885 init...\n");		goto init_rtc;		}	rtc_state=CMOS_READ(0xF);	if(rtc_state!=RTC_INIT	){		printk(KERN_INFO "Ds12885 init...\n");		CMOS_WRITE(RTC_INIT, 0xF);		goto init_rtc;	}	printk(KERN_INFO "Test DS12885 OK!\n");	spin_unlock_irq(&rtc_lock);	return 0;init_rtc:		CMOS_WRITE(0x1A,RTC_CONTROL);	CMOS_WRITE(0x2F,RTC_FREQ_SELECT);	spin_unlock_irq(&rtc_lock);	return 0;#undef RTC_INIT}int __initds12885_init(void){	dev_t dev_Num = 0;	int result=0;	/*	*Initialize periodic freq. to CMOS reset default, which is 2Hz.and test chip.	*/	if (test_set_ds12885()){		printk(KERN_INFO "test ds12885 failed!\n");		goto error_test;	}	dev_Num = MKDEV(DS12885_MAJOR, DS12885_MINOR);			result = register_chrdev_region(dev_Num, 1, "DS12885-RTC");	if (result < 0) {				printk(KERN_WARNING "ds12885 can't get major %d\n", DS12885_MAJOR);				goto error_region;	}		if (!request_mem_region(RTC_PORT(RTC_DATA), 2, "ds12885")) {		printk(KERN_ERR "ds12885: I/O port %d is not free.\n", RTC_PORT (RTC_DATA));		goto error_mem;	}	cdev_init(&rtc12885_dev.cdev, &rtc12885_fops);		rtc12885_dev.cdev.owner = THIS_MODULE;	rtc12885_dev.cdev.ops = &rtc12885_fops;		result = cdev_add (&rtc12885_dev.cdev, dev_Num, 1);		if (result)	{		printk(KERN_NOTICE "ds12885 Can not add cdev!\n");		goto error_dev;	}	if (!create_proc_read_entry ("driver/rtc-ds12885", 0, NULL, rtc_read_proc, NULL)) 		goto error_proc;	sysctl_header = register_sysctl_table(dev_root, 0);	outl((inl(GPIO_AINTEN) & (~DS12885_IRQ_POART)), GPIO_AINTEN);		//disable EGPIO 0 as an interrupt pin	outl((inl(GPIO_PADDR) & (~DS12885_IRQ_POART)), GPIO_PADDR);		//set EGPIO 0 as an input pin	outl((inl(GPIO_AINTTYPE1) | DS12885_IRQ_POART), GPIO_AINTTYPE1);		//set EGPIO 0 to edge sensitive	outl((inl(GPIO_AINTTYPE2) & (~DS12885_IRQ_POART)), GPIO_AINTTYPE2);	//set EGPIO 0 interrupt is falling edge	outl((inl(GPIO_ADB) | DS12885_IRQ_POART), GPIO_ADB);				//set EGPIO 0 debounce register	if (request_irq(ds12885_irq, ds12885_interrupt, SA_INTERRUPT|SA_SHIRQ, "ds12885", &rtc12885_dev)) {				printk(KERN_ERR "ds12885: cannot register IRQ %d\n", ds12885_irq);		goto error_irq;	}	else{		outl((inl(GPIO_AINTEN) | DS12885_IRQ_POART), GPIO_AINTEN);		}#ifdef CONFIG_DEVFS_FS	devfs_mk_cdev(dev_Num, S_IFCHR|S_IRUGO|S_IWUGO, "rtc");#endif		//#ifdef CONFIG_DEVFS_FS	printk(KERN_INFO "ds12885 Real Time Clock Driver init OK!\n");	return 0;	error_irq:	remove_proc_entry ("driver/rtc-ds12885", NULL);	error_proc:	cdev_del(&rtc12885_dev.cdev);//	result=-ENOMEM;error_dev:		//	result=	release_mem_region(RTC_PORT(RTC_DATA), 2);	error_mem:	unregister_chrdev_region(dev_Num, 1);//	result = -EIO	error_region:	goto init_failed;error_test:	//	result=		init_failed:		return -EIO;}	static void __exitds12885_exit(void){#ifdef CONFIG_DEVFS_FS	devfs_remove("rtc");#endif		//#ifdef CONFIG_DEVFS_FS	outl((inl(GPIO_AINTEN) & (~DS12885_IRQ_POART)), GPIO_AINTEN);	free_irq (ds12885_irq, &rtc12885_dev);	cdev_del(&rtc12885_dev.cdev);       unregister_chrdev_region(MKDEV(DS12885_MAJOR, DS12885_MINOR), 1);	release_mem_region (RTC_PORT (RTC_DATA), 2);	cleanup_sysctl();//	unregister_sysctl_table(sysctl_header);	remove_proc_entry ("driver/rtc-ds12885", NULL);}module_init(ds12885_init);module_exit(ds12885_exit);MODULE_AUTHOR("LiTao");MODULE_LICENSE("GPL");MODULE_DESCRIPTION("DS12885 RTC Driver");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -