?? i2c_ds1337.c
字號:
/******************************************************************************** File name : ds1337.c** ** Description :** ds1337(Real Time clock) ** Usage :** DS1337 Device Driver file for iMX21 Platform** ** License : ** This program is free software; you can redistribute it and/or modify** it under the terms of the GNU General Public License version 2 as** published by the Free Software Foundation** Note: tm_year: from 2000;*******************************************************************************/#include <linux/kernel.h>#include <linux/module.h>#include <linux/compatmac.h>#include <linux/hdreg.h>#include <linux/vmalloc.h>#include <linux/fs.h>#include <linux/module.h>#include <linux/blkpg.h>#include <linux/i2c.h>#include <linux/i2c-algo-bit.h>#include <linux/i2c-id.h>#include <linux/slab.h>#include <asm/io.h>#include <linux/mm.h>#include <linux/wrapper.h>#include <asm/dma.h>#include <linux/miscdevice.h>#include <asm/arch/mx2.h>#include <linux/rtc.h>#include <linux/init.h>#define UINT8 unsigned char#define SINT32 int#define IIC_ADDR 0xd0#define SCL (1 << 27)#define SDA (1 << 18)#define DS1337_NAME "ds1337"#define DS1337_VERSION "version 0.1"#define DS1337_MAJOR 251#define RTC_SEC 0x00#define RTC_MIN 0x01#define RTC_HOUR 0x02#define RTC_DAY 0x03#define RTC_DATE 0x04#define RTC_MONTH 0x05#define RTC_YEAR 0x06#define RTC_CTRL 0x0e#define RTC_STATUS 0x0fstatic unsigned char days_in_mo[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};void delay500ns(){ int i; for(i=0;i<100;i++);}void delay1us(){ delay500ns(); delay500ns();}void delay2us(){ delay1us(); delay1us();}void delay5us(){ delay2us(); delay2us(); delay1us();}void delay8us(){ delay5us(); delay2us(); delay1us();}void delay10us(){ delay5us(); delay5us();}SINT32 set_sda_input(){ /* * PE3 : SDA * PE4 : SCL */ _reg_GPIO_DDIR(GPIOC) &= ~SDA; return 0;}SINT32 set_sda_output(){ /* * PE3 : SDA * PE4 : SCL */ _reg_GPIO_DDIR(GPIOC) |= SDA; return 0;}SINT32 set_sda_value(UINT8 flag){ /* * PE3 : SDA * PE4 : SCL */ if(flag) _reg_GPIO_DR(GPIOC) |= SDA; else _reg_GPIO_DR(GPIOC) &= ~SDA; return 0;}SINT32 set_scl_high(){ /* * PE3 : SDA * PE4 : SCL */ _reg_GPIO_DR(GPIOB) |= SCL; return 0;}SINT32 set_scl_low(){ /* * PA15 : SDA * PA16 : SCL */ _reg_GPIO_DR(GPIOB) &= ~SCL; return 0;}/* Read sda status */UINT8 get_sda_value(){ if(_reg_GPIO_SSR(GPIOC) & SDA) return 0x01; else return 0x00;}/* SCCB write */ void sccb_write(UINT8 reg, UINT8 data){ int i; UINT8 addr; addr = IIC_ADDR; set_sda_value(1); set_scl_high(); delay10us(); set_sda_value(0); // Issue start command /* Send ID address */ for(i=0;i<8;i++) { delay10us(); set_scl_low(); // First clock start delay500ns(); set_sda_value((addr >> (7-i)) & 0x01); delay10us(); set_scl_high(); } delay10us(); set_scl_low(); // The Ninth clock start delay1us(); set_sda_input(); delay8us(); set_scl_high(); // Dont't care bit delay10us(); set_scl_low(); delay2us(); set_sda_output(); /* Send sub address */ for(i=0;i<8;i++) { delay500ns(); set_sda_value((reg >> (7-i)) & 0x01); delay10us(); set_scl_high(); delay10us(); set_scl_low(); } delay1us(); set_sda_input(); delay8us(); set_scl_high(); // Dont't care bit delay10us(); set_scl_low(); delay2us(); set_sda_output(); /* Send sub address */ for(i=0;i<8;i++) { delay500ns(); set_sda_value((data >> (7-i)) & 0x01); delay10us(); set_scl_high(); delay10us(); set_scl_low(); } delay1us(); set_sda_input(); delay8us(); set_scl_high(); // Dont't care bit delay10us(); set_scl_low(); delay2us(); set_sda_output(); set_sda_value(0); delay10us(); set_scl_high(); delay10us(); set_sda_value(1); // Stop return;}/* SCCB read */ void sccb_read(UINT8 reg, UINT8 *data){ int i; UINT8 addr, ret; ret = 0; *data = 0; /* 2-phases write */ addr = IIC_ADDR; set_sda_value(1); set_scl_high(); delay10us(); set_sda_value(0); // Issue start command /* Send ID address */ for(i=0;i<8;i++) { delay10us(); set_scl_low(); // First clock start delay500ns(); set_sda_value((addr >> (7-i)) & 0x01); delay10us(); set_scl_high(); } delay10us(); set_scl_low(); // The Ninth clock start delay1us(); set_sda_input(); delay8us(); set_scl_high(); // Dont't care bit delay10us(); set_scl_low(); delay2us(); set_sda_output(); /* Send sub address */ for(i=0;i<8;i++) { delay500ns(); set_sda_value((reg >> (7-i)) & 0x01); delay10us(); set_scl_high(); delay10us(); set_scl_low(); } delay1us(); set_sda_input(); delay8us(); set_scl_high(); // Dont't care bit delay10us(); set_scl_low(); delay2us(); set_sda_output(); set_sda_value(0); delay10us(); set_scl_high(); delay10us(); set_sda_value(1); // Stop 2-phases write /****************************************************************/ /* 2-phases read */ addr = IIC_ADDR + 1; set_sda_value(1); set_scl_high(); delay10us(); set_sda_value(0); // Issue start command /* Send ID address */ for(i=0;i<8;i++) { delay10us(); set_scl_low(); // First clock start delay500ns(); set_sda_value((addr >> (7-i)) & 0x01); delay10us(); set_scl_high(); } delay10us(); set_scl_low(); // The Ninth clock start delay1us(); set_sda_input(); delay8us(); set_scl_high(); // Dont't care bit delay10us(); for(i=0;i<8;i++) { set_scl_low(); delay10us(); set_scl_high(); delay5us(); ret = get_sda_value(); *data |= (ret << (7-i)); delay5us(); } set_scl_low(); // The Ninth clock start delay1us(); set_sda_output(); delay500ns(); set_sda_value(1); delay8us(); set_scl_high(); // Dont't care bit delay10us(); set_scl_low(); delay5us(); set_sda_value(0); delay10us(); set_scl_high(); delay10us(); set_sda_value(1); // Stop 2-phases write}/* Initialize SCCB signal, simulation SCCB timing by GPIO */SINT32 sccb_init(){ /* * PA15 : SDA * PA16 : SCL */ _reg_GPIO_GIUS(GPIOC) |= SDA; _reg_GPIO_GIUS(GPIOB) |= SCL; _reg_GPIO_OCR2(GPIOB) |= 0x00C00000; _reg_GPIO_OCR2(GPIOC) |= 0x30; _reg_GPIO_DDIR(GPIOC) |= SDA; _reg_GPIO_DDIR(GPIOB) |= SCL; set_sda_value(1); set_scl_high(); return 0;} ///////////////////////////////////////////////////////////////////////////Read Regstatic unsigned char RtcReadReg(unsigned char addr){ unsigned char data; sccb_read(addr, &data); return data;}//Write Regstatic void RtcWriteReg(unsigned char addr,unsigned char data){ sccb_write(addr, data);}static unsigned char bin2int(unsigned char data){ return ((data&0x0f)+((data&0xf0)>>4)*10);}static unsigned char int2bin(unsigned char data){ return ((data%10)+((data/10)*16));}static void ds1337_rtc_init(void){ int ii = 0; int jj = 0; sccb_init(); //init i2c while(0){ set_scl_high(); set_sda_value(1);printk("in loop,high\n"); delay10us(); set_scl_low(); set_sda_value(0);printk("in loop,low\n"); delay10us(); jj++; }// for(ii = 0; ii <= 0x0f; ii++){ //init ds1337 register all zero// RtcWriteReg(ii, 0x0);// }}static int ds1337_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct rtc_time wtime; struct rtc_time rtc_tm; unsigned char mon, mday, hrs, min, sec, leap_yr; unsigned int yrs;// printk("cmd = %d\n", cmd); switch (cmd) { case RTC_RD_TIME:///Read Date { wtime.tm_sec = bin2int(RtcReadReg(RTC_SEC)); wtime.tm_min = bin2int(RtcReadReg(RTC_MIN)); wtime.tm_hour = bin2int(RtcReadReg(RTC_HOUR)); wtime.tm_mday = bin2int(RtcReadReg(RTC_DATE)); wtime.tm_mon = bin2int(RtcReadReg(RTC_MONTH)); wtime.tm_year = bin2int(RtcReadReg(RTC_YEAR)); //from 970/* printk("1 read: year = %d\n", wtime.tm_year); printk("1 read: mon = %d\n", wtime.tm_mon); printk("1 read: mday = %d\n", wtime.tm_mday); printk("1 read: hour = %d\n", wtime.tm_hour); printk("1 read: min = %d\n", wtime.tm_min); printk("1 read: sec = %d\n", wtime.tm_sec); */ break; } case RTC_SET_TIME:///Set Date { if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) return -EFAULT; yrs = rtc_tm.tm_year + 2000; mon = rtc_tm.tm_mon; mday = rtc_tm.tm_mday; hrs = rtc_tm.tm_hour; min = rtc_tm.tm_min; sec = rtc_tm.tm_sec; if (yrs < 2000) return -EINVAL; leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); if ((mon > 12) || (mday == 0)) return -EINVAL; if (mday > (days_in_mo[mon] + ((mon == 2) && leap_yr))) return -EINVAL; if ((hrs >= 24) || (min >= 60) || (sec >= 60)) return -EINVAL; RtcWriteReg(RTC_YEAR, int2bin(rtc_tm.tm_year)); RtcWriteReg(RTC_MONTH, int2bin(rtc_tm.tm_mon)); RtcWriteReg(RTC_DATE, int2bin(rtc_tm.tm_mday)); RtcWriteReg(RTC_HOUR, int2bin(rtc_tm.tm_hour)); RtcWriteReg(RTC_MIN, int2bin(rtc_tm.tm_min)); RtcWriteReg(RTC_SEC, int2bin(rtc_tm.tm_sec)); return 0; } default: return -EINVAL; } return copy_to_user((void *)arg, &wtime, sizeof(struct rtc_time)) ? -EFAULT : 0;}static int ds1337_open(struct inode *minode, struct file *mfile){// printk("ds1337 open\n"); MOD_INC_USE_COUNT; return 0;}static int ds1337_release(struct inode *minode, struct file *mfile){ MOD_DEC_USE_COUNT; return 0;}static struct file_operations device_fops = { owner: THIS_MODULE, open: ds1337_open, release: ds1337_release, ioctl: ds1337_ioctl,};static devfs_handle_t g_devfs_handle;static int g_rtc_major;static __init int ds1337_init(void){ int result; /* register our character device */ result = devfs_register_chrdev(0, "ds1337", &device_fops); if ( result < 0 ) { printk("ds1337 driver: Unable to register driver\n"); return -ENODEV; } g_devfs_handle = devfs_register(NULL, "ds1337", DEVFS_FL_DEFAULT, result, 0, S_IFCHR | S_IRUSR | S_IWUSR, &device_fops, NULL); printk("make node for ds1337 with 'mknod ds1337 c %d 0'\n", result); g_rtc_major = result; ds1337_rtc_init(); //register_chrdev(DS1337_MAJOR, DS1337_NAME, &device_fops); //printk("%s %s initialized.\n", DS1337_NAME, DS1337_VERSION); return 0;}static __exit void ds1337_exit(void){ if(g_rtc_major>0) { devfs_unregister_chrdev(g_rtc_major, DS1337_NAME); devfs_unregister(g_devfs_handle); }// unregister_chrdev(DS1337_MAJOR, DS1337_NAME);// printk("%s unregisterd.\n", DS1337_NAME);}module_init(ds1337_init);module_exit(ds1337_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("pyl");/*vim:ts=4*/
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -