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

📄 rtc.c

📁 实时时钟驱动
💻 C
字号:
#ifndef __KERNEL__#define __KERNEL__#endif#ifndef MODULE#define MODULE#endif#include <linux/config.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/module.h>#include <asm/irq.h>   //disable && enable irq#include <asm/uaccess.h>//copy_from_user | to_user#include <linux/ioctl.h>#include <linux/fs.h>       /* everything... */#include <asm/io.h>#include <linux/ioport.h>//ioremap#include <linux/sched.h>//wait_queue#include <linux/wait.h>#include <linux/mm.h>#include <linux/slab.h> //kmalloc#include <linux/interrupt.h>#include <linux/cdev.h>#include <linux/delay.h>#include <linux/time.h>#define DRIVER_VERSION "v1.0"MODULE_LICENSE("Dual BSD/GPL");#define INT8U	unsigned char#define INT16U	unsigned short#define INT32U	unsigned long#define INT32	signed int#define SMBUS_BASE       0x56fffff0volatile unsigned char *smbase_addr = NULL;#define SMBus_CLH		(*((volatile INT8U *) smbase_addr+1))#define SMBus_CLL		(*((volatile INT8U *) smbase_addr))#define SMBus_CON		(*((volatile INT8U *) smbase_addr+2))#define SMBus_CMD		(*((volatile INT8U *) smbase_addr+4))#define SMBus_TXR		(*((volatile INT8U *) smbase_addr+3))#define SMBus_RXR		(*((volatile INT8U *) smbase_addr+3))#define SMBus_STS		(*((volatile INT8U *) smbase_addr+4))void SMBus_Init(INT8U CLH,INT8U CLL);INT8U SMBus_SendByte(INT8U sla, INT8U mData);INT8U SMBus_SendStr(INT8U sla, INT8U suba, INT8U *s, INT8U no);INT8U SMBus_RecvByte(INT8U sla, INT8U *s);INT8U SMBus_RecvStr(INT8U sla, INT8U suba, INT8U *s, INT8U no);INT8U SMBus_SendOneByte(INT8U sla, INT8U suba, INT8U c);#define DS1339				0xd0#define	Seconds_ADDR 		0x00#define Minutes_ADDR		0x01#define Hours_ADDR			0x02#define Day_ADDR			0x03#define Date_ADDR			0x04#define Month_ADDR			0x05#define Year_ADDR			0x06#define Control_ADDR		0x0e#define STATUS_ADDR			0x0f#define Trickle_ADDR		0x10struct RTC_Time{    INT32U Time_LowSecond;    INT32U Time_Second;    INT32U Time_Minutes;    INT32U Time_Hours;    INT32U Time_Day;    INT32U Time_Date;    INT32U Time_Month;    INT32U Time_Year;};int rtc_major = -1;
long pro_time;
long interval_time;

long pro_SMBus_time;
long interval_SMBus_time;

INT8U RTC_SetTime(struct RTC_Time *pTime);void RTC_Init(void);void RTC_GetTime(struct RTC_Time *pTime);INT8U BCD_TO_BIN(INT8U mData);INT32U BIN_TO_BCD(INT32U mData);void SMBus_Init(INT8U CLH,INT8U CLL){    SMBus_CLH = CLH;    SMBus_CLL = CLL;    SMBus_CON = 0xc0;               // 使能SMBus和中断输出}INT8U SMBus_SendByte(INT8U sla, INT8U mData){    INT8U sla_ack;    SMBus_TXR = sla;    SMBus_CMD = 0x90;    while ((SMBus_STS & 0x01) != 0x01);    SMBus_CMD = 0x01;    sla_ack = SMBus_STS & 0x80;    if (sla_ack != 0x00)    {        return 0;    }    SMBus_TXR = mData;    SMBus_CMD = 0x50;    while ((SMBus_STS & 0x01) != 0x01);    SMBus_CMD = 0x01;    sla_ack = SMBus_STS & 0x80;    if (sla_ack != 0x00)    {        return 0;    }    return 1;}INT8U SMBus_SendOneByte(INT8U sla, INT8U suba, INT8U c){    INT8U sla_ack;    SMBus_TXR = sla;    SMBus_CMD = 0x90;    while ((SMBus_STS & 0x01) != 0x01);    SMBus_CMD = 0x01;    sla_ack = SMBus_STS & 0x80;    if (sla_ack != 0x00)    {        return 0;    }    SMBus_TXR = suba;    SMBus_CMD = 0x10;    while ((SMBus_STS & 0x01) != 0x01);    SMBus_CMD = 0x01;    sla_ack = SMBus_STS & 0x80;    if (sla_ack != 0x00)    {        return 0;    }    SMBus_TXR = c;    SMBus_CMD = 0x50;    while ((SMBus_STS & 0x01) != 0x01);    SMBus_CMD = 0x01;    sla_ack = SMBus_STS & 0x80;    if (sla_ack != 0x00)    {        return 0;    }    return 1;}INT8U SMBus_SendStr(INT8U sla, INT8U suba, INT8U *s, INT8U no){    INT8U sla_ack, i;    SMBus_TXR = sla;    SMBus_CMD = 0x90;    while ((SMBus_STS & 0x01) != 0x01);    SMBus_CMD = 0x01;    sla_ack = SMBus_STS & 0x80;    if (sla_ack != 0x00)    {        return 0;    }    SMBus_TXR = suba;    SMBus_CMD = 0x10;    while ((SMBus_STS & 0x01) != 0x01);    SMBus_CMD = 0x01;    sla_ack = SMBus_STS & 0x80;    if (sla_ack != 0x00)    {        return 0;    }    for (i = 0; i < no - 1; i++)    {        SMBus_TXR = *s;        SMBus_CMD = 0x10;        while ((SMBus_STS & 0x01) != 0x01);        SMBus_CMD = 0x01;        sla_ack = SMBus_STS & 0x80;        if (sla_ack != 0x00)        {            return 0;        }        s++;    }    SMBus_TXR = *s;    SMBus_CMD = 0x50;    while ((SMBus_STS & 0x01) != 0x01);    SMBus_CMD = 0x01;    sla_ack = SMBus_STS & 0x80;    if (sla_ack != 0x00)    {        return 0;    }    return 1;}INT8U SMBus_RecvByte(INT8U sla, INT8U *s){    INT8U sla_ack;    SMBus_TXR = sla;    SMBus_CMD = 0x90;    while ((SMBus_STS & 0x01) != 0x01);    SMBus_CMD = 0x01;    sla_ack = SMBus_STS & 0x80;    if (sla_ack != 0x00)    {        return 0;    }    SMBus_CMD = 0x68;    while ((SMBus_STS & 0x01) != 0x01);    SMBus_CMD = 0x01;    *s = SMBus_RXR;    return(1);}INT8U SMBus_RecvStr(INT8U sla, INT8U suba, INT8U *s, INT8U no){    INT8U sla_ack, i;
	pro_SMBus_time = jiffies;
    SMBus_TXR = sla;    SMBus_CMD = 0x90;    while ((SMBus_STS & 0x01) != 0x01);    SMBus_CMD = 0x01;    sla_ack = SMBus_STS & 0x80;    if (sla_ack != 0x00)    {        return 0;    }    SMBus_TXR = suba;    SMBus_CMD = 0x10;    while ((SMBus_STS & 0x01) != 0x01);    SMBus_CMD = 0x01;    sla_ack = SMBus_STS & 0x80;    if (sla_ack != 0x00)    {        return 0; 	 }    SMBus_TXR = sla + 1;    SMBus_CMD = 0x90;    while ((SMBus_STS & 0x01) != 0x01);    SMBus_CMD = 0x01;    sla_ack = SMBus_STS & 0x80;    if (sla_ack != 0x00)    {        return 0;    }    for (i = 0; i < no - 1; i++)    {        SMBus_CMD = 0x20;        while ((SMBus_STS & 0x01) != 0x01);        SMBus_CMD = 0x01;        if (sla_ack != 0x00)        {            return 0;        }        *s = SMBus_RXR;        s++;    }    SMBus_CMD = 0x68;    while ((SMBus_STS & 0x01) != 0x01);    SMBus_CMD = 0x01;    *s = SMBus_RXR;

	interval_SMBus_time = jiffies - pro_SMBus_time;	printk(KERN_ERR "-------interval_SMBus_time = %lu------\n", interval_SMBus_time);
    return(1);}void RTC_Init(void){    SMBus_SendOneByte(DS1339, Control_ADDR, 0x00);    SMBus_SendOneByte(DS1339, Trickle_ADDR, 0x00);}INT8U RTC_SetTime(struct RTC_Time *pTime){	INT8U Ret = 1, SMRet = 1;    SMRet = SMBus_SendOneByte(DS1339, Seconds_ADDR, BIN_TO_BCD(pTime->Time_Second));    Ret &= SMRet;
	if(0 == SMRet)
	{
		printk(KERN_ERR"----pTime->Time_Second return 0----\n");
	}    SMRet = SMBus_SendOneByte(DS1339, Minutes_ADDR, BIN_TO_BCD(pTime->Time_Minutes));    Ret &= SMRet;
	if(0 == SMRet)
	{
		printk(KERN_ERR"---pTime->Time_Minutes return 0----\n");
	}	SMRet = SMBus_SendOneByte(DS1339, Hours_ADDR, BIN_TO_BCD(pTime->Time_Hours));    Ret &= SMRet;
	if(0 == SMRet)
	{
		printk(KERN_ERR"---pTime->Time_Hours return 0----\n");
	}	SMRet = SMBus_SendOneByte(DS1339, Day_ADDR, BIN_TO_BCD(pTime->Time_Day));    Ret &= SMRet;
	if(0 == SMRet)
	{
		printk(KERN_ERR"---pTime->Time_Day return 0----\n");
	}	SMRet = SMBus_SendOneByte(DS1339, Date_ADDR, BIN_TO_BCD(pTime->Time_Date));    Ret &= SMRet;
	if(0 == SMRet)
	{
		printk(KERN_ERR"--pTime->Time_Date return 0----\n");
	}	SMRet = SMBus_SendOneByte(DS1339, Month_ADDR, BIN_TO_BCD(pTime->Time_Month));    Ret &= SMRet;
	if(0 == SMRet)
	{
		printk(KERN_ERR"--pTime->Time_Month return 0----\n");
	}	SMRet = SMBus_SendOneByte(DS1339, Year_ADDR, BIN_TO_BCD(pTime->Time_Year - 2000));	Ret &= SMRet;
	if(0 == SMRet)
	{
		printk(KERN_ERR"---pTime->Time_Year - 2000 return 0----\n");
	}	return Ret;}void RTC_GetTime(struct RTC_Time *pTime){    unsigned char mReadData;    INT8U volatile pTemp=0;
	pro_time = jiffies;   //added by hd
    SMBus_RecvStr(DS1339, Seconds_ADDR, (unsigned char *)&pTemp, 1);    pTime->Time_Second = BCD_TO_BIN(pTemp);    SMBus_RecvStr(DS1339, Minutes_ADDR,(unsigned char *)&pTemp, 1);    pTime->Time_Minutes = BCD_TO_BIN(pTemp);    SMBus_RecvStr(DS1339, Hours_ADDR, &mReadData, 1);    if (mReadData & 0x40)                            //12 hour mode    {        if (mReadData & 0x20)        {            pTime->Time_Hours = (BCD_TO_BIN(mReadData & 0x1F)) + 11;    //PM        }        else        {            pTime->Time_Hours = (BCD_TO_BIN(mReadData & 0x1F)) - 1;     //AM        }    }    else                                            //24 hour format    {        pTime->Time_Hours = (BCD_TO_BIN(mReadData & 0x3F));    }    SMBus_RecvStr(DS1339, Day_ADDR, (unsigned char *)&pTemp, 1);    pTime->Time_Day = BCD_TO_BIN(pTemp);    SMBus_RecvStr(DS1339, Date_ADDR, (unsigned char *)&pTemp, 1);    pTime->Time_Date = BCD_TO_BIN(pTemp);    SMBus_RecvStr(DS1339, Month_ADDR, (unsigned char *)&pTemp, 1);    pTime->Time_Month = BCD_TO_BIN(pTemp);    SMBus_RecvStr(DS1339, Year_ADDR, (unsigned char *)&pTemp, 1);    pTime->Time_Year = BCD_TO_BIN(pTemp);

	interval_time = jiffies - pro_time;               //added by hd
	printk(KERN_ERR "+++++++++++++++++++++interval_time = %lu+++++++++++++++++++++++++++++++++\n", interval_time);}INT8U BCD_TO_BIN(INT8U mData){    return((((mData >> 4) & 0x0F) * 10) + (mData & 0x0F));}INT32U BIN_TO_BCD(INT32U mData){    return(((mData / 10) << 4) | (mData % 10));}int rtc_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long argv){    struct RTC_Time sTime,gTime;	int Retioctl = 1;    printk("KERN IOCTL\n");    if (cmd == 0)           //设置时间,较时    {        copy_from_user(&sTime,(void *)argv,sizeof(struct RTC_Time));	printk(KERN_ERR "+++SET:%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu\n",sTime.Time_Year,sTime.Time_Month,sTime.Time_Date,\						       sTime.Time_Day,sTime.Time_Hours,sTime.Time_Minutes,\						       sTime.Time_Second,sTime.Time_LowSecond);     Retioctl = RTC_SetTime(&sTime);
	 printk(KERN_ERR "+++Retioctl = %d\n+++", Retioctl);    }    if (cmd == 1)           //获得当前时间    {	printk("get time\n");            RTC_GetTime(&gTime);        printk("GET:%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu\n",gTime.Time_Year,gTime.Time_Month,gTime.Time_Date,\			                               gTime.Time_Day,gTime.Time_Hours,gTime.Time_Minutes,\						       gTime.Time_Second,gTime.Time_LowSecond);	copy_to_user((void *)argv,&gTime,sizeof(struct RTC_Time));    }    return Retioctl;   //chang by hd to test syscall}struct file_operations rtc_fops = {    .owner =    THIS_MODULE,    .ioctl =    rtc_ioctl,};static int __init ahbus_init(void){    smbase_addr=(volatile unsigned char *)ioremap_nocache(SMBUS_BASE,5);    rtc_major = register_chrdev(233, "rtc", &rtc_fops);    printk("rtc_major:%d\n",rtc_major);    SMBus_Init(0x01, 0x00);    printk("Hello RTC!\n");    return 0;}static void __exit ahbus_exit(void){    unregister_chrdev(rtc_major, "rtc");    iounmap((void *)smbase_addr);    printk("Bye RTC.\n");}module_init(ahbus_init);module_exit(ahbus_exit);

⌨️ 快捷键说明

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