s3c6410 RTC driver——读取实时时间信息 <LDD3 & ELDD 学习笔记>

s3c6410 RTC driver——读取实时时间信息

开发环境:Ubuntu 14.0

开发板内核版本:Linux 3.0

The Real Time Clock (RTC) unit can be operated by the backup battery when the system power is off. The data include the time by second, minute, hour, date, day, month, and year. The RTC unit works with an external
32.768 KHz crystal and can perform the alarm function.

下面是RTC相关的18个寄存器

s

在头文件中的定义

在mach/map.h里面

自己定义一个header file 方便使用(一层封装的思想)

EOF_rtc.h

/**************************************************
code writer :	EOF
code date   :	2014.08.26
e-mail	    :	[email protected]

code purpose:
	This header file is used for ...

	It's convenient to use this MACRO but not
address number directly.

**************************************************/
#ifndef _EOF_RTC_H
#define _EOF_RTC_H

#include <mach/map.h> /* for 'S3C64XX_PA_RTC' */

#define RTC_CON		(S3C64XX_PA_RTC + 0x40)

#define RTC_SECOND_REG	(S3C64XX_PA_RTC + 0x70)
#define RTC_MINUTE_REG	(S3C64XX_PA_RTC + 0x74)
#define RTC_HOUR_REG	(S3C64XX_PA_RTC + 0x78)
#define RTC_DAY_REG	(S3C64XX_PA_RTC + 0x80)
#define RTC_MONTH_REG	(S3C64XX_PA_RTC + 0x84)
#define RTC_YEAR_REG	(S3C64XX_PA_RTC + 0x88)

/*
** second minute hour day month and year.
** There are six messages waited to be read.
*/
#define MESSAGE		6

#define DEVICE_NAME	"rtc_time"
/*
**	create four device for fun, demo for one driver but drive different devices
*/
#define DEVICE_NUM	1
#define PORT_NUM	36
#define RTC_PORT_BASE	S3C64XX_PA_RTC

#define RTC_MAJOR	0 /*by dynamical */

/*
**	It's fantastic to use a structure to abstract a device!
*/
struct rtc_dev
{
	struct cdev cdev;
	struct mutex mutex;

	/*
	** used for storing time message
	*/
	int buf[1024];
};

#endif

rtc_time.c

/************************************************************
code writer :	EOF
code date   :	2014.08.26
e-mail	    :	[email protected]
code file   :	rtc_time.c

code purpose:

	This is code is for RTC-driver in s3c6410-ARM.

#BUG!
	I am sorry about there is a bug waited to be fixed up.

	When we print out the "day-message", we can't get the
right one.It always print out digital number '1'.I don't know
what happens...

	If you could fix it up, please touch me by e-mail.
Thank you.

************************************************************/

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>

#include <linux/cdev.h>		/* for 'struct cdev'*/
#include <linux/kdev_t.h>	/* for 'MAJOR MINOR' */
#include <linux/fs.h>
#include <linux/kernel.h>	/* for 'printk()' */
#include <linux/slab.h>		/* for 'kmalloc()'*/
#include <linux/types.h>	/* for 'ssize_t'*/
#include <linux/proc_fs.h>
#include <asm/io.h>		/* for 'inl & outl'*/
#include <asm/uaccess.h>	/* for 'copy_to_user'*/
#include <linux/ioport.h>	/* for 'request_region()' 'ioremap()' */

#include <linux/device.h>	/* for 'struct class'*/

#include "EOF_rtc.h"

//#define DEBUG

unsigned int rtc_major	=	RTC_MAJOR;
unsigned int rtc_minor	=	0;

unsigned long t_msg_addr[MESSAGE] =
{
	RTC_SECOND_REG,
	RTC_MINUTE_REG,
	RTC_HOUR_REG,
	RTC_DAY_REG,
	RTC_MONTH_REG,
	RTC_YEAR_REG
};

module_param(rtc_major,int,S_IRUGO);
module_param(rtc_minor,int,S_IRUGO);
module_param(t_msg_addr,unsigned long,S_IRUGO);

MODULE_AUTHOR("EOF");
MODULE_LICENSE("Dual BSD/GPL");

/* allocated in 'void rtc_init(void)' */
struct rtc_dev* rtc_devices;
struct class* rtc_class;

static int rtc_proc_show(char* buf,char** start,off_t offset,int count,int* eof,void* data)
{

#ifdef DEBUG
	printk(KERN_ALERT "calling rtc_proc_show...\n");
#endif
	struct rtc_dev* dev = rtc_devices;
	int device_num = 0;
	int length = 0;
	int temp = 0;
	int foo  = 0;

	if(mutex_lock_interruptible(&dev->mutex))
	{
		return -ERESTARTSYS;
	}

	for(device_num = 0;device_num < DEVICE_NUM;device_num++)
	{
		length += sprintf(buf+length,"### rtc%d ###\n",device_num);

		for(temp = 0; temp < MESSAGE;temp++)
		{
			foo = readl(ioremap(t_msg_addr[temp],sizeof(int)));
			length += sprintf(buf+length," temp: %d time: %d\n",temp, ((foo & 0xF0)>>4)*10 + (foo & 0x0F) );
		}
	}

	*eof = 1;
	mutex_unlock(&dev->mutex);

	return 0;
}

static void rtc_create_proc(void)
{
	struct proc_dir_entry * entry;

	entry	= create_proc_read_entry("rtc_reader",0,NULL,rtc_proc_show,NULL);

	if(!entry)
	{
		printk(KERN_ALERT "line:%d 'proc_create_read_entry()' failed!\n",__LINE__);
	}
}

static void rtc_remove_proc(void)
{
	remove_proc_entry("rtc_reader",NULL);
}

ssize_t rtc_read(struct file* filp,char __user* buf,const size_t count,loff_t* f_pos)
{
#ifdef DEBUG
	printk(KERN_ALERT "rtc_read ing... using ioremap...");
#endif
	struct rtc_dev* dev = filp->private_data;
	int temp  = 0;
	int ret	  = 0;

	if(mutex_lock_interruptible(&dev->mutex))
	{
		return -ERESTARTSYS;
	}
	else
	{
#ifdef DEBUG
		printk(KERN_ALERT "Lock in rtc_read!\n");
#endif
	}

	for(temp = 0; temp < MESSAGE;temp++)
	{
		/*
		** Hey,penguins...Attention! Do not use the physic address directly.
		** You shoult remap it into virtual addres by 'ioremap()'.
		*/
		//dev->buf[temp] = inl(t_msg_addr[temp]);
		dev->buf[temp] = readl(ioremap(t_msg_addr[temp],sizeof(int)));
#ifdef DEBUG
		printk(KERN_ALERT "dev->buf[%d] : %d\n",temp,dev->buf[temp]);
#endif
	}	

	if((ret = copy_to_user(buf,dev->buf,count)))
	{
		printk(KERN_ALERT "copy_to_user failed!\n");
		temp = temp - ret;
		goto out_read;
	}

out_read:
	mutex_unlock(&dev->mutex);
#ifdef DEBUG
		printk(KERN_ALERT "Lock released rtc_read!\n");
#endif

	return temp;
}

ssize_t rtc_write(struct file* filp,const char __user* buf,size_t count,loff_t* f_ops)
{
#ifdef DEBUG
	printk(KERN_ALERT "writing rtc ...\n");
#endif
	struct rtc_dev* dev = filp->private_data;
	int ret = 0;
	int temp = 0;

	if(mutex_lock_interruptible(&dev->mutex))
	{
		return -ERESTARTSYS;
	}

	if((ret = copy_from_user(dev->buf,buf,sizeof(*(dev->buf)) * MESSAGE)))
	{
		temp = temp - ret;
		goto out_write;
	}

	for(temp = 0; temp < MESSAGE;temp++)
	{
		outl(dev->buf[temp],(ioremap(t_msg_addr[temp],sizeof(int))) );
	}	

out_write:
	mutex_unlock(&dev->mutex);

	return 0;
}

int rtc_open(struct inode* inode,struct file* filp)
{
#ifdef DEBUG
	printk(KERN_ALERT "rtc_open ing...!\n");
#endif
	struct rtc_dev* dev;

	dev = container_of(inode->i_cdev,struct rtc_dev,cdev);

	filp->private_data = dev;

	return 0;
}

int rtc_release(struct inode * inode, struct file* filp)
{
#ifdef DEBUG
	printk(KERN_ALERT "rtc Released!\n");
#endif
	return 0;
}

struct file_operations rtc_fops =
{
	.owner	=	THIS_MODULE,
	.read	=	rtc_read,
	/*
	** It's dangerous and unnecessory to write something into RTC's register, the company which created your 'RTC' have finished 'write-work'.Generally, you shouldn't change it.
	** But I also implement a method that how to write message
	** into RTC's register.
	*/
	.write	=	rtc_write,
	.open	=	rtc_open,
	.release=	rtc_release,
};

static void rtc_setup_cdev(struct rtc_dev* dev,int indev)
{
	int err = 0;
	int dev_num = MKDEV(rtc_major,rtc_minor + indev);

	cdev_init(&dev->cdev,&rtc_fops);
	dev->cdev.owner	=	THIS_MODULE;
	dev->cdev.ops	=	&rtc_fops;
	err =  cdev_add(&dev->cdev,dev_num,1);

	if(err)
	{
		printk(KERN_ALERT "Error in adding rtc%d, err value:%d\n",indev,err);
	}
	else
	{
#ifdef DEBUG
		printk(KERN_ALERT "rtc_%d setted!\n",indev);
#endif
	}
}

void rtc_clean(void)
{
	int temp = 0;
	dev_t	dev_num = 0;

	dev_num = MKDEV(rtc_major,rtc_minor);

	if(rtc_devices)
	{
		for(temp = 0;temp > DEVICE_NUM;temp++)
		{
			cdev_del(&rtc_devices[temp].cdev);

			device_destroy(rtc_class,MKDEV(MAJOR(dev_num),temp));
#ifdef DEBUG
			printk(KERN_ALERT "rtc%d!\n",temp);
#endif
		}

		kfree(rtc_devices);
	}

	rtc_remove_proc();

	unregister_chrdev_region(dev_num,DEVICE_NUM);

	release_region(RTC_PORT_BASE,PORT_NUM);

}

int rtc_init(void)
{

	/* get our needed resource */
	if(!request_region(RTC_PORT_BASE,PORT_NUM,DEVICE_NAME))
	{
		printk(KERN_ALERT "rtc: can't request address:%p\n",(void*)RTC_PORT_BASE);

		return -ENODEV;
	}

	int ret = 0;
	int temp = 0;
	dev_t	dev_num = 0;

	ret = alloc_chrdev_region(&dev_num,rtc_minor,DEVICE_NUM,DEVICE_NAME);

	rtc_major = MAJOR(dev_num);

	rtc_class = class_create(THIS_MODULE,DEVICE_NAME);

	if(ret < 0)
	{
		printk(KERN_ALERT "rtc: can't get major %d\n",rtc_major);

		return ret;
	}

	/* allocate the device -- we can't have them static, as the number
	* can be specified at load time
 	*/
	rtc_devices = kmalloc(DEVICE_NUM*sizeof(struct rtc_dev),GFP_KERNEL);

	if(!rtc_devices)
	{
		ret = -ENOMEM;
		goto fail;
	}

	memset(rtc_devices,0,DEVICE_NUM * sizeof(struct rtc_dev));

	/* Initialize the device */
	for(temp = 0;temp < DEVICE_NUM;temp++)
	{
		mutex_init(&rtc_devices[temp].mutex);
		rtc_setup_cdev(&rtc_devices[temp],temp);

		device_create(rtc_class,NULL,(dev_num + temp),NULL,"rtc_%d",temp);
	}

	rtc_create_proc();

#ifdef DEBUG
	printk(KERN_ALERT "rtc registed!\n");
#endif

	return 0;

fail:
	rtc_clean();
	return 0;
}

module_init(rtc_init);
module_exit(rtc_clean);

测试程序

/*********************************************************************
code writer : EOF
code date : 2014.08.16
code file : rtc_test.c
e-mail	  : [email protected]

code purpose:
	This is a demo for user how to use RTC device driver.

	You should know that data store in RTC register as BCD-code.
If you want to represent it as deciminal, we could transform two-bits
BCD-code into deciminal number by this way:

	Deciminal number = ((BCD-code&0xF0)>>4)*10+(BCD-code)&0x0F;

	If there is something wrong with my code,
please touch me by e-mail. Thank you.

*********************************************************************/

#include <stdio.h>
#include <fcntl.h>

int main()
{
	int buf[10];

	char output[BUFSIZ] = {0,};

	int fd = 0;
	int counter = 0;

	if((fd = open("/dev/rtc_0",O_RDONLY)) < 0)
	{
		printf("open failed!\n");
		return 0;
	}

	if(read(fd,buf,sizeof(buf)) <= 0)
	{
		printf("read failed\n");
		goto failed;
	}

	counter += sprintf(output+counter,"Time now: ");

	counter += sprintf(output+counter,"Year: 20%d ", ((buf[5]&0xF0)>>4)*10 + (buf[5]&0x0F));
	counter += sprintf(output+counter,"month: %d ",  ((buf[4]&0xF0)>>4)*10 + (buf[4]&0x0F));
	counter += sprintf(output+counter,"day: %d ",    ((buf[3]&0xF0)>>4)*10 + (buf[3]&0x0F));
	counter += sprintf(output+counter,"hour: %d ",   ((buf[2]&0xF0)>>4)*10 + (buf[2]&0x0F));
	counter += sprintf(output+counter,"minute: %d ", ((buf[1]&0xF0)>>4)*10 + (buf[1]&0x0F));
	counter += sprintf(output+counter,"second: %d\n",((buf[0]&0xF0)>>4)*10 + (buf[0]&0x0F));

	printf("%s\n",output);

failed:
	close(fd);

	return 0;
}

和rtc_time.c里面注释说的一样,我遇到了一个BUG,目前还不知道怎么搞定他,如果高手路过恳请指导修正

很明显有一个有错的地方,今天是8月27日,但是他怎么都是print 8.1...

这里是date输出的结果和我直接debug打印结果(BCD玛)的对比

day对应的是dev->bug[3],这里BCD码是1....

时间: 2024-08-24 06:58:19

s3c6410 RTC driver——读取实时时间信息 <LDD3 & ELDD 学习笔记>的相关文章

vxworks for x86读取bios时间的解决方法

系统时间与bsp有关,在vzworks for x86系列的目标没有直接读取RTC(实时时钟控制器)的函数,用time.h中的函数读到的始终是 00:00:00, Jan. 1 1970. 所以在x86系列的机器中,我们可以从bios中读取当前的时钟.用sysInByte(),sysOutByte(),在70,和71端口读取或写bios里的时间. 首先要分析bios的内容,找出秒,分,时,天,月,年的存放地址. 他们分别是: 0x00,0x02,0x04,0x07,0x08,0x09 然后从71

STM32F4学习笔记10——RTC实时时钟

RTC实时时钟 实时时钟 (RTC) 是一个独立的 BCD 定时器/计数器.RTC 提供一个日历时钟.两个可编程 闹钟中断,以及一个具有中断功能的周期性可编程唤醒标志.RTC 还包含用于管理低功耗模 式的自动唤醒单元. 两个 32 位寄存器包含二进码十进数格式 (BCD) 的秒.分钟.小时(12 或 24 小时制).星 期几.日期.月份和年份.此外,还可提供二进制格式的亚秒值. 系统可以自动将月份的天数补偿为 28.29(闰年).30 和 31 天.并且还可以进行夏令时 补偿. 其它 32 位寄

【android基础】读取系统联系人信息和添加一条联系人信息到通讯录

一,读取系统联系人信息 I,准备工作 同样,要读取系统联系人的数据库文件,首先要确定主机名和匹配规则. 我们将联系人的数据库文件导出来查看时,有下面几点需要知道: 1)联系人的数据,比如name,number,email都存储在data表的data1列. 2)区分不同联系人的列为raw_contact_id,它对应于raw_contacts表中的contact_id列 3)区分联系人数据类型的列位于mimetype列,其中1表示emial,5表示电话,7表示姓名. II,思路 读取联系人的信息,

(转)java读取数据库表信息,子段

import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.HashMap; import java.util.List; /*** * 2014-07-21日: * oracle数据

fstat - 读取文件相关信息

#fstat读取到的信息 ["dev"]=> int(16777220) ["ino"]=> int(66880002) ["mode"]=> int(33188) ["nlink"]=> int(1) ["uid"]=> int(501) ["gid"]=> int(0) ["rdev"]=> int(0) //文件大小(单

智能公交电子站牌为你报告实时交通信息,让出行更方便

近几年,城市公交大力推进信息化.电子化建设,如构建无人售票系统,实行IC卡收费.随着经济的发展,人民生活水平的提高,人民对公共交通出行的要求也越来越高,乘客关注的不仅仅是能否顺利出行,而是更多地关心公交车对于到站时间.车辆运行状况等信息的实时发布,以便乘客能够更好地满足自身出行需求.公交电子站牌的出现很好地解决了这些问题. "智能手机电子站牌"是基本智能手机开发,配套智能公交电子站牌服务器,实际在乘客还未到站台或无电子站牌的站台,乘客可通过手机实时查看某线路车辆距站名距离及车辆数,更合

linux 下查看文件的完整时间信息及三种时间属性

一.linux下查看文件的完整时间信息 1.Linux 下查看文件时,ls –l 缺省是不显示秒的: # ls -l /etc/ total 0 -rw-r--r--.  1 root   root         16 Jan  5 09:43 adjtime -rw-r--r--.  1 root   root       1518 Jun  7  2013 aliases 2.要显示秒(实际更精确),可以用 –full-time 参数: # ls -l /etc/ --full-time

【XML配置文件读取】使用jdom读取XML配置文件信息

在项目中我们经常需要将配置信息写在配置文件中,而XML配置文件是常用的格式. 下面将介绍如何通过jdom来读取xml配置文件信息. 配置文件信息 <?xml version="1.0" encoding="UTF-8"?> <config> <base-config> <stringValue>Hello world</stringValue> <integerValue>8</integ

获取当天时间信息

(now)函数可以很方便的返回当前时间信息,比如年,月等,返回结果存放在list中,使用十分方便.举例如下: > (now) (2015 1 24 14 7 42 393413 24 6 480 0) 注意,这里获得是GMT+0时区,如果想要获得中国时区,需要在第一个参数中指定以分钟为单位的整数.中国是GMT+8,所以应该如下调用: > (now (* 8 60)) (2015 1 24 22 9 9 707743 24 6 480 0)