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

📄 ds3231.c

📁 DS3231 RTC的Linux驱动程序
💻 C
字号:
  /*  *  linux/drivers/i2c/chips/ds1337.c  *  *  Copyright (C) 2005 James Chapman <jchapman@katalix.com>  *  *      based on linux/drivers/acorn/char/pcf8583.c  *  Copyright (C) 2000 Russell King  *  * 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.  *  * Driver for Dallas Semiconductor DS1337 and DS1339 real time clock chip  *  *   History:  *      2007/8/11 Port by WenBinWu for PNX8550,add interface for user application;  *      2007/9/12 add source comment by liuym for ds3231 chipset      *      2008/4/24 add read temperature funtion for ds3231 chipset     */ #include <linux/module.h> #include <linux/kernel.h>  #include <linux/init.h> #include <linux/slab.h> #include <linux/i2c.h> #include <linux/string.h> #include <linux/rtc.h>          /* get the user-level API */ #include <linux/bcd.h> #include <linux/list.h> #include <linux/fs.h> #include <linux/miscdevice.h> #include <asm/uaccess.h> #include <linux/ioctl.h> #include <linux/major.h> #include <linux/errno.h> #include "ds3231.h"   /* Device registers */ #define DS3231_REG_SECOND       	0x00 #define DS3231_REG_MINUTE       	0x01 #define DS3231_REG_HOUR         	0x02	/*x [12/24] 2 1 | 8 4 2 1 */ #define DS3231_REG_DAY          	0x03 #define DS3231_REG_DATE         	0x04 #define DS3231_REG_MONTH        	0x05 #define ds3231_REG_YEAR		0x06	 /* 8  4 2 1 | 8 4 2 1 */ #define ds3231_REG_AL1_SECOND	0x07 	/* A1M1 4 2 1 | 8 4 2 1 */ #define ds3231_REG_AL1_MIN		0x08 	/* A1M2 4 2 1 | 8 4 2 1 */ #define ds3231_REG_AL1_HR		0x09 	/* A1M3 [12/24] 2 1 | 8 4 2 1 */ #define ds3231_REG_AL1_DAY		0x0a 	/* A1M4 [DY/DT] 2 1 | 8 4 2 1 */ #define ds3231_REG_AL2_MIN		0x0b 	/* A2M2 4 2 1 | 8 4 2 1 */ #define ds3231_REG_AL2_HR		0x0c 	/* A2M3 [12/24] 2 1 | 8 4 2 1 */ #define ds3231_REG_AL2_DAY		0x0d 	/* A2M4 [DY/DT] 2 1 | 8 4 2 1 */ #define DS3231_REG_CONTROL      	0x0e	/*ESOC x x RS2 RS1 INTCN A2IE A1IE*/ #define DS3231_REG_STATUS      	0x0f	/*OSF X X X X X A1F A2F*/ #define DS3231_REG_TEMP_HI		0x11 #define DS3231_REG_TEMP_LO	0x12 /* Control reg */ #define ds3231_CTRL_A1IE		(1<<0) #define ds3231_CTRL_A2IE		(1<<1) #define ds3231_CTRL_INTCN		(1<<2) #define ds3231_CTRL_RS			(1<<3) #define ds3231_CTRL_EOSC		(1<<7) /* Status reg */ #define ds3231_STATUS_A1F		(1<<0) #define ds3231_STATUS_A2F		(1<<1) #define ds3231_STATUS_OSF		(1<<7) /* CLKOUT frequencies , RS*/ #define ds3231_FD_32768HZ		(0x3) #define ds3231_FD_1024HZ		(0x2) #define ds3231_FD_32			(0x1) #define ds3231_FD_1HZ			(0x0) #define  I2C_SALVEID_DS3231 0xd0 #define I2C_DRIVERID_DS3231 0xf000 #define DEVNAME   "rtc"    /* * Generic i2c probe * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */static unsigned short normal_i2c[] = { I2C_SALVEID_DS3231 >> 1, I2C_CLIENT_END };static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };                                                                                static struct i2c_client_address_data addr_data = {	.normal_i2c		= normal_i2c,	.normal_i2c_range	= normal_i2c_range,	.probe			= probe,	.probe_range		= probe_range,	.ignore			= ignore,	.ignore_range		= ignore_range,	.force			= force};//I2C_CLIENT_INSMOD_1(ds3231);static int ds3231_attach_adapter(struct i2c_adapter *adapter);static int ds3231_detect(struct i2c_adapter *adapter, int address, int kind);static void ds3231_init_client(struct i2c_client *client);static int ds3231_detach_client(struct i2c_client *client);static int ds3231_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);static int ds3231_get_tempture(struct i2c_client *client, int *value);/*2007/9/12, liuym,  file operations for device file register though ds3231_MiscDev, which is defined below*/static struct file_operations   ds3231_fops    =   {    .owner          =   THIS_MODULE,    .read           =   NULL,    .open           =   NULL,    .release        =   NULL,    .ioctl          =   ds3231_ioctl,};/*2007/9/12, liuym,  structure used in dynamically register and unregister device ,search for "misc_register" and "misc_deregister"   */static struct miscdevice ds3231_MiscDev = {     .minor =   MISC_DYNAMIC_MINOR,     .name  =   DEVNAME,     .fops  =   &ds3231_fops}; /*  * I2c Driver struct  */static struct i2c_driver ds3231_driver = { 	   .owner		= THIS_MODULE,	   .id			= I2C_DRIVERID_DS3231,         .name   = "ds3231", 	   .flags = I2C_DF_NOTIFY,         .attach_adapter = ds3231_attach_adapter,         .detach_client  = ds3231_detach_client, }; static int ds3231_attached = 0;static struct i2c_client *ds3231_client; /*  * Client data (each client gets its own)  */ struct ds3231_data {         struct i2c_client client;         struct list_head list; };  /*  * Internal variables  */ //static LIST_HEAD(ds3231_clients); /*DS3231读写函数*/ static inline int ds3231_read(struct i2c_client *client, u8 reg, u8 *value) {         s32 tmp = i2c_smbus_read_byte_data(client, reg);          if (tmp < 0)                 return -EIO;          *value = tmp;         return 0; } static inline int ds3231_write (struct i2c_client *client, u8 reg, u8 value){	return i2c_smbus_write_byte_data(client, reg, value);} /*读取DS3231内部温度传感器转换编码值*/static int ds3231_get_tempture(struct i2c_client *client, int *value){	int i;	int err;	u8 buf[2];	int flag;	int t1;	int t2;		err = ds3231_read(client, DS3231_REG_TEMP_HI, &buf[0]);	if (err) return err;	err = ds3231_read(client, DS3231_REG_TEMP_LO, &buf[1]);	if (err) return err;	/*温度编码值占2个字节,第一个字节的第1位是符号位,第二字节的只有第1,2位是有效位。*/	flag=buf[0] & 0x80;	t1=buf[0] & 0xef;	t2=buf[1] & 0xc0;	t1=(t1<<2) | (t2 >> 6);		if (flag>0)		t1 =  t1 * (-1);		*value = t1;	return 0;	} /*  * DS3231时间获取函数  */ static int ds3231_get_datetime(struct i2c_client *client, struct rtc_time *dt) {         u8 buf[7];         u8 val; 	   int err = 0;	            if (!dt) {                 dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__);                 return -EINVAL;         }	  u8 i = 0;	  dev_dbg(&client->dev, "%s: RTC not running!\n", __FUNCTION__);	  /* 读取寄存器的值*/	  for (i=0; i<7; i++)	  {		  err = ds3231_read(client, i, &buf[i]);		  if (err != 0)			break;	  }         dev_dbg(&client->dev, "%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n",                 __FUNCTION__, err, buf[0], buf[1], buf[2], buf[3],                 buf[4], buf[5], buf[6]);          if (err == 0) {                 dt->tm_sec = BCD2BIN(buf[0]);                 dt->tm_min = BCD2BIN(buf[1]);                 val = buf[2] & 0x3f;		//RTC 模式是24小时制                 dt->tm_hour = BCD2BIN(val);                 dt->tm_wday = BCD2BIN(buf[3]) - 1;//RTC星期表示为1-7;需转换成0-6                 dt->tm_mday = BCD2BIN(buf[4]);                 val = buf[5] & 0x7f;                 dt->tm_mon = BCD2BIN(val) - 1;//RTC月份表示为1-12;需转换成0-11                 dt->tm_year = BCD2BIN(buf[6]);                 if (buf[5] & 0x80)                         dt->tm_year += 100;                  dev_dbg(&client->dev, "%s: secs=%d, mins=%d, "                         "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",                         __FUNCTION__, dt->tm_sec, dt->tm_min,                         dt->tm_hour, dt->tm_mday,                         dt->tm_mon, dt->tm_year, dt->tm_wday);                 return 0;         }          dev_err(&client->dev, "error reading data! %d\n", err);         return -EIO; }    /*  * DS3231时间设置函数  */ static int ds3231_set_datetime(struct i2c_client *client, struct rtc_time *dt) {         u8 buf[7];         u8 val;         u8 i = 0;          if (!dt) {                 dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__);                 return -EINVAL;         }          dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "                 "mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__,                 dt->tm_sec, dt->tm_min, dt->tm_hour,                 dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday);         buf[0] = BIN2BCD(dt->tm_sec);         buf[1] = BIN2BCD(dt->tm_min);         buf[2] = BIN2BCD(dt->tm_hour);         buf[3] = BIN2BCD(dt->tm_wday + 1);         buf[4] = BIN2BCD(dt->tm_mday);         buf[5] = BIN2BCD(dt->tm_mon + 1);         val = dt->tm_year;         if (val >= 100) {                 val -= 100;                 buf[5] |= (1 << 7);         }         buf[6] = BIN2BCD(val);	   for (i=0; i<7; i++)	   {                ds3231_write(client, i, buf[i]);	   } 	   return 0; }/*	ds3231命令接口,应用层的ioctl调用将首先进入该函数*/ static int ds3231_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){	struct rtc_time rtc_tm;	int val;	switch (cmd) {	 /*读取RTC时间*/	case RTC_RD_TIME:		memset(&rtc_tm, 0, sizeof (struct rtc_time));		if (ds3231_get_datetime(ds3231_client, &rtc_tm))			return -EFAULT;		if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time)))			return -EFAULT;	       break;	 /*设置RTC时间*/ 	case RTC_SET_TIME:	       if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)))	     	return -EFAULT;	         if (ds3231_set_datetime(ds3231_client, &rtc_tm))	         	return -EFAULT;	     break;	case RTC_TEMP_READ:		if (ds3231_get_tempture(ds3231_client, &val))			return -EFAULT;		if (copy_to_user((int*)arg, &val, sizeof(int)))			return -EFAULT;		break;	case RTC_ALM_READ:	case RTC_ALM_SET:			    break;	default:	         return -EINVAL;	 }	return 0;} static int ds3231_attach_adapter(struct i2c_adapter *adapter) {         return i2c_probe(adapter, &addr_data, ds3231_detect); }  /*  * DS3231检测程序,如果测试成功,将会注册这个设备   */  static int ds3231_i2c_id = 0; static int ds3231_detect(struct i2c_adapter *adapter, int address, int kind) {         int err = 0;	   if (ds3231_attached == 1) goto exit;         if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))                 goto exit;          if (!(ds3231_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {                 err = -ENOMEM;                 goto exit;         }	   memset(ds3231_client, 0, sizeof(struct i2c_client));         ds3231_client->addr = address;         ds3231_client->adapter = adapter;         ds3231_client->driver = &ds3231_driver;         ds3231_client->flags = I2C_CLIENT_ALLOW_USE;         ds3231_client->id = ds3231_i2c_id++; 	   snprintf(ds3231_client->name, sizeof(ds3231_client->name) - 1,		"ds3231-%d", ds3231_client->id);         /* Tell the I2C layer a new client has arrived */         if ((err = i2c_attach_client(ds3231_client)))                 goto exit_free;         /* Initialize the DS3231 chip */         ds3231_init_client(ds3231_client);          /* Register a misc device called "ds3231". */    	  if ((err = misc_register( &ds3231_MiscDev )))		  	goto exit_free;         ds3231_attached = 1;	   /*only support one device*/         return 0;  exit_free:         kfree(ds3231_client); exit:         return err; }   /* 	ds3231芯片初始化函数,在探测到到芯片后,调用该函数 */ static void ds3231_init_client(struct i2c_client *client) {         u8 status = 0, control = 0;         u8 val;         int err;         err = ds3231_read(client, DS3231_REG_STATUS, &status);         err = ds3231_read(client, DS3231_REG_CONTROL,&control);          if ((status & 0x80) || (control & 0x80)) {                 /* RTC 没有运行,复位RTC */		    u8 i = 0; 		    printk("RTC not running!\n");                 dev_dbg(&client->dev, "%s: RTC not running!\n", __FUNCTION__);                  /* 将 STATUS ,CONTROL 设置为0 */		   for (i=14; i<16; i++)		   {                    ds3231_write(client, i, 0);		   }         } else {                 /* DS3231运行中,要保证运行在24小时模式 */		    printk("RTC running!\n");                  err = ds3231_read(client, DS3231_REG_HOUR, &val);                 if ((val & (1 << 6)))                         ds3231_write(client, DS3231_REG_HOUR,                                                   val & 0x3f);         } }   static int ds3231_detach_client(struct i2c_client *client) {         int err;         if ((err = i2c_detach_client(client)))                 return err;          if (misc_deregister(&ds3231_MiscDev)!=0)         {            printk(KERN_INFO "ds3231: could not misc_deregister the device\n");         }         kfree(client);                  return 0; }   /*加载模块(insmod)的入口*/ static int __init ds3231_init(void) {         return i2c_add_driver(&ds3231_driver); }   /*卸载模块(rmmod)的入口*/ static void __exit ds3231_exit(void) {         i2c_del_driver(&ds3231_driver); }   MODULE_AUTHOR("James Chapman <jchapman@katalix.com>"); MODULE_DESCRIPTION("DS3231 RTC driver"); MODULE_LICENSE("GPL");   module_init(ds3231_init); module_exit(ds3231_exit); 

⌨️ 快捷键说明

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