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

📄 ds2786_battery.c

📁 锂电池电量检测芯片ds2786驱动程序(参照linux/driver/power/ds2760_battery.c).在linux-2.6.24内核测试通过.
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <linux/module.h>#include <linux/param.h>#include <linux/jiffies.h>#include <linux/workqueue.h>#include <linux/pm.h>#include <linux/platform_device.h>#include <linux/power_supply.h>#include <linux/i2c.h>#include <linux/device.h>#include <linux/delay.h>#include <linux/mutex.h>#include <linux/interrupt.h>#include <asm/io.h>#include <asm/arch/regs-irq.h>#include <asm/plat-s3c24xx/irq.h>#include <asm/hardware.h>#include "ds2786_battery.h"#define DBG(format, arg...) do { \printk(KERN_ALERT"%s: " format "\n" , __FUNCTION__ , ## arg); \} while (0)#ifdef DEBUG#define dprintk (format,arg...) printk(format,arg...)#else#define DBG(format, arg...) do {} while (0)#define dprintk(format,arg...) do {} while (0)#endifstruct ds2786_device_info {	struct device *dev;	/* DS2760 data, valid after calling ds2786_battery_read_status() */	unsigned long update_time;	/* jiffies when data read */	char raw[DS2786_DATA_SIZE];	/* raw DS2786 data */	int voltage_raw;		/* units of 1.22 mV */	int voltage_uV;			/* units of µV */	int current_raw;		/* units of 0.625 mA */	int current_uA;			/* units of µA */	int accum_current_uAh;		/* units of µAh */	int temp_raw;			/* units of 0.125 °C */	int temp_C;			/* units of 0.1 °C */	int rated_capacity;		/* units of µAh */	int rem_capacity;		/* percentage */	int full_active_uAh;		/* units of µAh */	int empty_uAh;			/* units of µAh */	int life_sec;			/* units of seconds */	int charge_status;		/* POWER_SUPPLY_STATUS_* */	int full_counter;	struct power_supply bat;	struct i2c_client *client;	struct i2c_driver	ds2786_driver;	struct workqueue_struct *monitor_wqueue;	struct delayed_work monitor_work;};static unsigned int cache_time = 1000;module_param(cache_time, uint, 0644);MODULE_PARM_DESC(cache_time, "cache time in milliseconds");//i2c partstatic unsigned short normal_i2c[] = { 0x36, I2C_CLIENT_END };static struct i2c_client_address_data addr_data = {	.normal_i2c	= normal_i2c,	.probe		= &normal_i2c[1],	.ignore		= &normal_i2c[1], 	};struct ds2786_device_info *di;static int ds2786_attach_adapter(struct i2c_adapter *adapter);static int ds2786_detect(struct i2c_adapter *adapter, int address, int kind);static int ds2786_detach_client(struct i2c_client *client);int i2c_ds2786_write(struct i2c_client *client,char *buf ,int count){	int ret=0;		struct i2c_adapter *adap=client->adapter;	struct i2c_msg msg;	if (client->adapter->algo->master_xfer)	{		msg.addr   = client->addr;		msg.flags = client->flags & I2C_M_TEN;		msg.len = count;		msg.buf = buf;				dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n",count);				mutex_lock_nested(&adap->bus_lock, adap->level);		msg.len=count+1;		ret = adap->algo->master_xfer(adap,&msg,1);		mutex_unlock(&adap->bus_lock);				return (ret==count )? count : -EBUSY;	}	dev_err(&client->adapter->dev, "I2C level transfers not supported\n");	return -ENOSYS;}int i2c_ds2786_read(struct i2c_client *client, char *buf ,int pos,int count){	struct i2c_adapter *adap=client->adapter;	struct i2c_msg msg[2];	int ret;	char addr=pos;	//return count;		if (client->adapter->algo->master_xfer)	{		msg[0].addr   = client->addr;		msg[0].flags = client->flags & I2C_M_TEN;		msg[0].len = 1;		msg[0].buf = &addr;				msg[1].addr   = client->addr;		msg[1].flags = client->flags & I2C_M_TEN;		msg[1].flags |= I2C_M_RD;		msg[1].len = count;		msg[1].buf = buf;				dev_dbg(&client->adapter->dev, "master_recv: reading %d bytes.\n",count);				mutex_lock_nested(&adap->bus_lock, adap->level);		ret = adap->algo->master_xfer(adap,msg,2);		mutex_unlock(&adap->bus_lock);				dev_dbg(&client->adapter->dev, "master_recv: return:%d (count:%d, addr:0x%02x)\n",				ret, count, client->addr);		return (ret == 2 )? count : ret;	}	dev_err(&client->adapter->dev, "I2C level transfers not supported\n");	return -ENOSYS;}static int ds2786_attach_adapter(struct i2c_adapter *adapter){	DBG("\n");	printk(KERN_ALERT"%s: \n" , __FUNCTION__ );	return i2c_probe(adapter, &addr_data, ds2786_detect);}/* This function is called by i2c_probe */static int ds2786_detect(struct i2c_adapter *adapter, int address, int kind){	int err = 0;	DBG("\n");	printk(KERN_ALERT"%s: \n" , __FUNCTION__ );	if (!(di->client= kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) 	{		err = -ENOMEM;		goto exit;	}		i2c_set_clientdata(di->client,di->client);	di->client->addr = address;	di->client->adapter = adapter;	di->client->driver = &di->ds2786_driver;	di->client->flags = 0;	/* Fill in the remaining client fields */	strlcpy(di->client->name, "ds2786", strlen("ds2786")+1);	/* Detect the ds2786.*/	err=i2c_ds2786_read(di->client,di->raw,0,1);	printk(KERN_ALERT"err:%d\n",err);	if (err<0)		goto exit_kfree;		/* Tell the I2C layer a new client has arrived */	if ((err = i2c_attach_client(di->client)))		goto exit_kfree;	return 0;exit_kfree:	kfree(di->client);exit:	return err;}static int ds2786_detach_client (struct i2c_client *client){	int err;	err = i2c_detach_client(client);	if (err)		return err;		kfree(i2c_get_clientdata(client));		return 0;}//end of i2c part//end of apm partstatic int ds2786_battery_read_status(struct ds2786_device_info *di){	int ret, start, count;	if (di->update_time && time_before(jiffies, di->update_time +					   msecs_to_jiffies(cache_time)))		return 0;	DBG("\n");	/* The first time we read the entire contents of SRAM/EEPROM,	 * but after that we just read the interesting bits that change. */	 //return -1;	if (di->update_time == 0)	{		start = 0;		count = DS2786_DATA_SIZE;		dprintk(KERN_ALERT"first\n");	}	else	{		start = DS2786_RELATIVE_CAP;		count = DS2786_LEARNED_CAPACITY- start + 1;	}		count=DS2786_DATA_SIZE-start+1;	ret = i2c_ds2786_read(di->client, di->raw + start, start, count);	if (ret != count)	{		dev_warn(di->dev, "call to i2c_ds2786_read failed\n");		return 1;	}	di->update_time = jiffies;	/* DS2786 reports voltage in signed units of 1.22mV, but the battery class	 * reports in units of uV, so convert by multiplying by 1220. */	di->voltage_raw =  (((signed char)di->raw[DS2786_VOLTAGE_MSB]) << 5)|			  (di->raw[DS2786_VOLTAGE_LSB] >> 3);	di->voltage_uV = di->voltage_raw * 1220;	if (di->voltage_uV<1000*1000)	{		di->rem_capacity =-1;		di->life_sec = -1;		return -1;	}		dprintk(KERN_ALERT"di->voltage_uV=%d\n",di->voltage_uV);	/* DS2786 reports current in signed units of 2.5mA, but the battery	 * class reports in units of µA, so convert by multiplying by 2500. */	di->current_raw =	    (((signed char)di->raw[DS2786_CURRENT_MSB]) << 4) |			  (di->raw[DS2786_CURRENT_LSB] >> 4);	di->current_uA = di->current_raw * 2500;	dprintk(KERN_ALERT"di->current_uA=%d\n",di->current_uA);	/* DS2760 reports temperature in signed units of 0.125°C, but the	 * battery class reports in units of 1/10 °C, so we convert by	 * multiplying by .125 * 10 = 1.25. */	di->temp_raw = (((signed char)di->raw[DS2786_AUX1_TEMP_MSB]) << 3)			 |(di->raw[DS2786_AUX1_TEMP_LSB] >> 5);	di->temp_C = di->temp_raw + (di->temp_raw / 4);	dprintk(KERN_ALERT"di->temp_C=%d\n",di->temp_C);		/*cap=1/(reg_val*0.78125*Rsns) Rsns=0.01*/	i2c_ds2786_read(di->client,di->raw+DS2786_INITIAL_CAP,DS2786_INITIAL_CAP,1);	//di->rated_capacity = 128*1000000L/(long)di->raw[DS2786_INITIAL_CAP];	dprintk(KERN_ALERT"di->raw[DS2786_INITIAL_CAP]=%d\n",(int)di->raw[DS2786_INITIAL_CAP]);	dprintk(KERN_ALERT"di->rated_capacity=%d\n",di->rated_capacity);		if (!di->raw[DS2786_LEARNED_CAPACITY])		di->full_active_uAh = di->rated_capacity;	else	 	di->full_active_uAh=128*1000000L/di->raw[DS2786_LEARNED_CAPACITY];	dprintk(KERN_ALERT"di->full_active_uAh=%d\n",di->full_active_uAh);		di->empty_uAh = (di->full_active_uAh/100)*5;//(5%)	//printk(KERN_ALERT"di->empty_uAh=%d\n",di->empty_uAh);		di->rem_capacity = di->raw[DS2786_RELATIVE_CAP]/2;	//printk(KERN_ALERT"di->rem_capacity=%d\n",di->rem_capacity);		di->accum_current_uAh =-((di->raw[DS2786_RELATIVE_CAP]-di->raw[DS2786_LAST_OCV_RELATIVE_CAP]))		/2*di->full_active_uAh;	dprintk(KERN_ALERT"di->accum_current_uAh=%d\n",di->accum_current_uAh);	dprintk(KERN_ALERT"DS2786_LAST_OCV_RELATIVE_CAP=%d\n",di->raw[DS2786_LAST_OCV_RELATIVE_CAP]);	dprintk(KERN_ALERT"DS2786_RELATIVE_CAP=%d\n",di->raw[DS2786_RELATIVE_CAP]);		if (di->current_uA<-10*1000) {		di->life_sec = -((((di->full_active_uAh*di->rem_capacity)/100 - di->empty_uAh)) 			/ di->current_uA)*3600L;		//di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;		}	else if (di->current_uA>10*1000)  {//charge		di->life_sec = -((((long int)di->full_active_uAh*(long int)(200-di->raw[DS2786_RELATIVE_CAP]))/100)					/di->current_uA)*1800L;		//di->charge_status = POWER_SUPPLY_STATUS_CHARGING;		}	else		di->life_sec = 0;	dprintk(KERN_ALERT"di->life_sec=%d\n",di->life_sec);	return 0;}static void ds2786_battery_update_status(struct ds2786_device_info *dx){	int old_charge_status = di->charge_status;	DBG("\n");	ds2786_battery_read_status(di);	if (di->rem_capacity<0)	{		di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING;		if (di->charge_status != old_charge_status)			power_supply_changed(&di->bat);		return;	}	if (di->charge_status == POWER_SUPPLY_STATUS_UNKNOWN)		di->full_counter = 0;			if (di->current_uA > 10*1000)	{		di->charge_status = POWER_SUPPLY_STATUS_CHARGING;		di->full_counter = 0;	}	else if(di->current_uA < -10*1000)	{		di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;

⌨️ 快捷键说明

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