📄 rtc.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 + -