/*********************************************************************************
mini2440 rtc时钟设备驱动开发源代码(宋宝华框架)
********************************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
//使用宋宝华推荐的普通字符设备框架
#include <linux/fcntl.h>
#include <linux/cdev.h>
#include <linux/version.h>
#include <linux/vmalloc.h>
#include <linux/ctype.h>
#include <linux/pagemap.h>
#include <linux/device.h>
#include <asm/io.h>
//#include <asm/arch/regs-gpio.h> //2.6.12
#include <mach/regs-gpio.h> // 2.6.32
static void __iomem *rtc_base;
static void __iomem *alm_base;
static void __iomem *bcd_base;
#define rRTCCON (*(volatile unsigned long *)(rtc_base + 0x00))
#define rTICNT (*(volatile unsigned long *)(rtc_base + 0x04))
#define rRTCALM (*(volatile unsigned long *)(rtc_base + 0x0a))
#define rALMSEC (*(volatile unsigned long *)(alm_base + 0x00))
#define rALMMIN (*(volatile unsigned long *)(alm_base + 0x04))
#define rALMHOUR (*(volatile unsigned long *)(alm_base + 0x08))
#define rALMDATE (*(volatile unsigned long *)(alm_base + 0x0c))
#define rALMMON (*(volatile unsigned long *)(alm_base + 0x10))
#define rALMYEAR (*(volatile unsigned long *)(alm_base + 0x14))
#define rBCDSEC (*(volatile unsigned long *)(bcd_base + 0x00))
#define rBCDMIN (*(volatile unsigned long *)(bcd_base + 0x04))
#define rBCDHOUR (*(volatile unsigned long *)(bcd_base + 0x08))
#define rBCDDATE (*(volatile unsigned long *)(bcd_base + 0xc))
#define rBCDDAY (*(volatile unsigned long *)(bcd_base + 0x10))
#define rBCDMON (*(volatile unsigned long *)(bcd_base + 0x14))
#define rBCDYEAR (*(volatile unsigned long *)(bcd_base + 0x18))
#define LEDOFF 0
#define LEDON 1
//#define rtc_MAJOR 235 //静态分配
#define rtc_MAJOR 0 //动态分配
#define rtc_MINOR 0
int devmajor = rtc_MAJOR;
int devminor = rtc_MINOR;
dev_t dev = 0;
//设备结构
//设备结构
struct rtc_dev
{
struct cdev cdev; /* Char device structure*/
};
struct TIME_RTC
{
int year;
int mon;
int day; //周
int date;
int hour;
int min;
int sec;
};
struct rtc_dev *rtc_devices;
struct class *my_class; //my_class
int rtc_open(struct inode *inode, struct file *filp)
{ /*
rRTCCON = (1<<0);
rTICNT = (1<<7)|(12<<0);
rRTCALM = 0X3F;
return 0;*/
rRTCCON = (0x0<<3)|(0x0<<2)|(0x0<<1)|(0x1<<0);
//rTICNT = (0x1<<7)|(12<<0); //闹钟
//rRTCALM = (0x1<<6)|(0x1<<5)|(0x1<<4)|(0x1<<3)|(0x1<<2)|(0x1<<1)|(0x1<<0);
return 0;
}
int rtc_release(struct inode *inode, struct file *filp)
{
return 0;
}
int rtc_ioctl(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg)
{
return 0;
}
//也可以使用rtc_write来替代rtc_ioctl
ssize_t rtc_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
struct TIME_RTC set_time;
int len = sizeof(struct TIME_RTC);
/*用户空间->内核空间*/ /*失败返回没有被拷贝的字节数,成功0*/
if (copy_from_user(&set_time, buf, len))
{
printk(" copy_to_user error\n");
return -EFAULT;
}
rBCDHOUR = ((set_time.hour/10)<<4)|(set_time.hour%10);
rBCDMIN = ((set_time.min/10)<<4)|(set_time.min%10);
rBCDSEC= (set_time.sec/10)<<4|(set_time.sec%10);
rBCDYEAR = (set_time.year/10)<<4|(set_time.year%10);
rBCDMON = (set_time.mon/10)<<4|(set_time.mon%10);
rBCDDATE = (set_time.date/10)<<4|(set_time.date%10);
rBCDDAY = set_time.day;
/*
if(set_time.day>7) //设置闹钟
{
rALMHOUR = ((set_time.hour/10)<<4)|(set_time.hour%10);
rALMMIN = ((set_time.min/10)<<4)|(set_time.min%10);
rALMSEC= (set_time.sec/10)<<4|(set_time.sec%10);
rALMYEAR = (set_time.year/10)<<4|(set_time.year%10);
rALMMON = (set_time.mon/10)<<4|(set_time.mon%10);
rALMDATE = (set_time.date/10)<<4|(set_time.date%10);
}
else
{ //设定时间
rBCDHOUR = ((set_time.hour/10)<<4)|(set_time.hour%10);
rBCDMIN = ((set_time.min/10)<<4)|(set_time.min%10);
rBCDSEC= (set_time.sec/10)<<4|(set_time.sec%10);
rBCDYEAR = (set_time.year/10)<<4|(set_time.year%10);
rBCDMON = (set_time.mon/10)<<4|(set_time.mon%10);
rBCDDATE = (set_time.date/10)<<4|(set_time.date%10);
rBCDDAY = set_time.day;
}
*/
return 0;
}
ssize_t rtc_read(struct file *filp,char __user *buf,size_t size,loff_t *offp)
{
struct TIME_RTC rtc_time;
int len=sizeof(struct TIME_RTC);
rtc_time.year = rBCDYEAR;
rtc_time.year = (rtc_time.year>>4)*10+(rtc_time.year & 0xf);
rtc_time.mon = rBCDMON;
rtc_time.mon = (rtc_time.mon>>4)*10+(rtc_time.mon & 0xf);
rtc_time.date = rBCDDATE;
rtc_time.date = (rtc_time.date>>4)*10 + (rtc_time.date & 0xf);
rtc_time.day = rBCDDAY;
rtc_time.hour = rBCDHOUR;
rtc_time.hour = (rtc_time.hour>>4)*10+(rtc_time.hour & 0xf);
rtc_time.min = rBCDMIN;
rtc_time.min = (rtc_time.min>>4)*10 + (rtc_time.min & 0xf);
rtc_time.sec = rBCDSEC;
rtc_time.sec =(rtc_time.sec>>4)*10 + (rtc_time.sec & 0xf);
/*内核空间->用户空间*/
if (copy_to_user(buf, &rtc_time, len)) //从指针当前位置开始读故+p
{
printk("copy_to_user error\n");
return - EFAULT; /* Bad address 错误的地址*/
}
return 0;
}
struct file_operations rtc_fops = {
.owner = THIS_MODULE,
.ioctl = rtc_ioctl,
.open = rtc_open,
.write = rtc_write,
.read = rtc_read,
.release=rtc_release,
};
/*******************************************************
MODULE ROUTINE
*******************************************************/
//卸载
void rtc_cleanup_module(void)
{
//dev_t devno = MKDEV(rtc_MAJOR, rtc_MINOR);
iounmap(rtc_base);
iounmap(alm_base);
iounmap(bcd_base);
if (rtc_devices)
{
cdev_del(&rtc_devices->cdev);//5 从系统中移除一个字符设备
kfree(rtc_devices);
}
device_destroy(my_class, MKDEV(devmajor, 0)); //delete device node under /dev
class_destroy(my_class); //delete class created by us
unregister_chrdev_region(dev,1);// 6 释放设备编号
}
//挂载
int rtc_init_module(void)
{
int result;
if(devmajor)
{
dev = MKDEV(devmajor, devminor); // 1 获得设备号
result = register_chrdev_region(dev, 1, "rtc_driver"); // 2 分配设备编号
}
else
{
result = alloc_chrdev_region(&dev, devminor, 1, "rtc_driver");
// //2 动态分配设备编号
devmajor = MAJOR(dev);
}
if (result < 0)
{
printk(KERN_WARNING "scull: can't get major %d\n", devmajor);
return result;
}
printk(KERN_WARNING "led get major: %d\n", devmajor);
rtc_devices = kmalloc(sizeof(struct rtc_dev), GFP_KERNEL);//分配内存给本设备结构体
if (!rtc_devices)
{
result = -ENOMEM;
goto fail;
}
memset(rtc_devices, 0, sizeof(struct rtc_dev));
cdev_init(&rtc_devices->cdev, &rtc_fops);//(1) // 字符设备的注册,即将结构嵌入到自己的设备中
rtc_devices->cdev.owner = THIS_MODULE;
rtc_devices->cdev.ops = &rtc_fops; //(2)
result = cdev_add (&rtc_devices->cdev, dev, 1);// 4 把本设备放内核中
if(result)
{
printk(KERN_NOTICE "Error %d adding rtc\n", result);
goto fail;
}
//创建节点方法2 使用函数自动创建 方法1是手动创建#mknod /dev/test c 235 0
// 下面方法2.6.32支持。2.6.18 2.6.12不支持
/* create your own class under /sysfs 2.6.32*/
my_class = class_create(THIS_MODULE, "my_class");
if(IS_ERR(my_class))
{
printk("Err: failed in creating class.\n");
return -1;
}
/* register your own device in sysfs, and this will cause udev to create corresponding device node */
device_create( my_class, NULL, MKDEV(devmajor, 0), NULL, "rtc_driver");
rtc_base = (volatile unsigned *)ioremap((volatile unsigned *)0x57000040,12);
alm_base = (volatile unsigned *)ioremap((volatile unsigned *)0x57000054,24);
bcd_base = (volatile unsigned *)ioremap((volatile unsigned *)0x57000070,28);
return 0;
fail:
rtc_cleanup_module(); //注销
return result;
}
module_init(rtc_init_module); //注册
module_exit(rtc_cleanup_module); //注销
MODULE_AUTHOR("hui");
MODULE_LICENSE("GPL");
/*********************************************************************************
/*********************************************************************************
应用程序测试代码
********************************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MYRTC "/dev/rtc_driver"
void Delay_MS( unsigned int time) //50 ns
{
unsigned int i,j;
for ( i=0; i<time; i++)
{
for(j=0;j<30000;j++)
{
}
}
}
struct TIME_RTC
{
unsigned int year;
unsigned int mon;
unsigned int day; //周
unsigned int date;
unsigned int hour;
unsigned int min;
unsigned int sec;
}TIME_RTC;
int main(void)
{
int fd,i=0;
int cmd;
int status;
struct TIME_RTC rtc_time;
printf("the struct TIME_RTC len is: %d\n",sizeof(struct TIME_RTC));
fd = open(MYRTC,O_RDWR,0666);
if (fd < 0)
{
perror("open device rtc_driver error\n");
exit(1);
}
printf("open /dev/rtc_driver success!\n");
int year,mon,date,day,hour,min,sec;
read(fd,&rtc_time,sizeof(struct TIME_RTC));
printf("************000000***************\n");
printf("**date:%d - %d -%d\n",rtc_time.year,rtc_time.mon,rtc_time.date);
printf("**workday:%d\n",rtc_time.day);
printf("**time:%d : %d : %d\n",rtc_time.hour,rtc_time.min,rtc_time.sec);
printf("***************************\n");
printf("please input the date and time that you will set!!\n");
printf("please input year: ");
scanf("%d",&rtc_time.year);
printf("please input mon: ");
scanf("%d",&rtc_time.mon);
printf("please input date: ");
scanf("%d",&rtc_time.date);
printf("please input day: ");
scanf("%d",&rtc_time.day);
printf("please input hour: ");
scanf("%d",&rtc_time.hour);
printf("please input min: ");
scanf("%d",&rtc_time.min);
printf("please input sec: ");
scanf("%d",&rtc_time.sec);
write(fd,&rtc_time,sizeof(struct TIME_RTC));
sleep(5);
read(fd,&rtc_time,sizeof(struct TIME_RTC));
printf("the time is :\n");
printf("***************************\n");
printf("**date:%d - %d -%d\n",rtc_time.year,rtc_time.mon,rtc_time.date);
printf("**workday:%d\n",rtc_time.day);
printf("**time:%d : %d : %d\n",rtc_time.hour,rtc_time.min,rtc_time.sec);
printf("***************************\n");
close(fd);
return 0;
}