电量计驱动代码

外部电量计驱动代码,直接上代码了,懒,不做细节分析。。。。。

/*
 * Fuelgauge battery driver
 *
 * This package 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.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#define pr_fmt(fmt)	"[hy4145] %s: " fmt, __func__
#include <linux/module.h>
#include <linux/param.h>
#include <linux/jiffies.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/gpio/consumer.h>


#define sh_info	pr_info
#define sh_dbg	pr_debug
#define sh_err	pr_err
#define sh_log	pr_err


#define	INVALID_REG_ADDR	0xFF
#define SHFS_UPDATE_KEY		0x8F91

#define SH_FG_I2C_DEV_ADDR    (0x0b >> 1)
#define hy4145_ADDR 0x0b

#define FG_FLAGS_FD				BIT(4)
#define	FG_FLAGS_FC				BIT(5)
#define	FG_FLAGS_DSG				BIT(6)
#define FG_FLAGS_RCA				BIT(9)


#define DEBUG_INFO 0

#if DEBUG_INFO
	#define debug(fmt,x...) printk("[hy4145]:-------------->%s(), line = %d " fmt,__FUNCTION__, __LINE__, ##x);
#else
	#define debug(fmt, x...)
#endif


struct sh_fg_chip* sh;	

int charge_temp_value = 1000;
int charge_vlot_value = 0;
static int value_temp = 0;

enum sh_fg_device {
	HY4145,
};

static const unsigned char *device2str[] = {
	"hy4145",
};


struct sh_fg_chip {
	struct device *dev;
	struct i2c_client *client;
	struct mutex update_lock;
	struct mutex irq_complete;
	bool resume_completed;
	u8 chip;

	struct power_supply *fg_psy;
	struct power_supply_desc fg_psy_d;

};


static int standard_command(struct i2c_client *client,unsigned char addr, unsigned char* buf)
{
	int ret = i2c_master_send(client, &addr, 1);
	if (ret < 0){
		pr_err("i2c_master_send error ret=%d\n", ret);
		return -1;
	}

	ret = i2c_master_recv(client, buf, 2);
	if (ret < 0){
		pr_err("i2c_master_recv error ret=%d\n", ret);
		return -1;
	}
	return 0;
}

static int get_prop_status(struct sh_fg_chip *sh)
{
	unsigned char buf[2];

	standard_command(sh->client,0x00,buf);
	return buf[1]<<8|buf[0];
}

static int get_prop_flags(struct sh_fg_chip *sh)
{
	unsigned char buf[2];

	standard_command(sh->client,0x0a,buf);
	return buf[1]<<8|buf[0];
}

static int get_prop_present(struct sh_fg_chip *sh){
	unsigned char buf[2];
	standard_command(sh->client,0x0a,buf);
	// BAT_DET
	if (buf[1] & (1<<3))
		return 1;
	else
		return 0;
}

static int get_prop_temp(struct sh_fg_chip *sh)
{
	unsigned char buf[2];

	standard_command(sh->client,0x06,buf);
	return buf[1]<<8|buf[0];
}

static int get_prop_averge_volt(struct sh_fg_chip *sh)
{
	unsigned char buf[2];

	standard_command(sh->client,0x08,buf);
	return buf[1]<<8|buf[0];
}

static int get_prop_full_volt(struct sh_fg_chip *sh)
{
	unsigned char buf[2];

	standard_command(sh->client,0x76,buf);
	return buf[1]<<8|buf[0];
}

static int get_prop_averge_current(struct sh_fg_chip *sh)
{
	unsigned char buf[2];

	standard_command(sh->client,0x30,buf);
	return buf[1]<<8|buf[0];
}

static int get_prop_full_design(struct sh_fg_chip *sh)
{
	unsigned char buf[2];

	standard_command(sh->client,0x12,buf);
	return buf[1]<<8|buf[0];
}

static int get_prop_cycle_count(struct sh_fg_chip *sh)
{
	unsigned char buf[2];

	standard_command(sh->client,0x2a,buf);
	return buf[1]<<8|buf[0];
}

static int get_prop_health(struct sh_fg_chip *sh)
{
	unsigned char buf[2];

	standard_command(sh->client,0x2e,buf);
	return buf[1]<<8|buf[0];
}

static int get_prop_capacity(struct sh_fg_chip *sh)
{
	unsigned char buf[2];

	standard_command(sh->client,0x0e,buf);
	return buf[1]<<8|buf[0];
}

static int get_prop_capacity_level(struct sh_fg_chip *sh)
{
	unsigned char buf[2];

	standard_command(sh->client,0x2c,buf);
	return buf[1]<<8|buf[0];
}




void  update_info(struct sh_fg_chip *sh)
{
	printk("==rrd== update_info:status=0x%x \n", get_prop_status(sh));
	printk("==rrd== update_info:flags=0x%x \n",get_prop_flags(sh));
	printk("==rrd== update_info:present=%d \n",get_prop_present(sh));
	printk("==rrd== update_info:voltage=%d \n",get_prop_averge_volt(sh));
	printk("==rrd== update_info:current=%d \n", get_prop_averge_current(sh));
	printk("==rrd== update_info:health=%d \n", get_prop_health(sh));
	printk("==rrd== update_info:capacity=%d \n", get_prop_capacity(sh));
	printk("==rrd== update_info:level=%d \n", get_prop_capacity_level(sh));
	printk("==rrd== update_info:temp=%d \n", get_prop_temp(sh));
	printk("==rrd== update_info:counter=%d \n", get_prop_cycle_count(sh));
	printk("==rrd== update_info:full=%d \n", get_prop_full_volt(sh));
	printk("==rrd== update_info:design=%d \n", get_prop_full_design(sh));
	printk("==rrd== update_info:count=%d\n", get_prop_cycle_count(sh));

}



static enum power_supply_property fg_props[] = {
	POWER_SUPPLY_PROP_STATUS,
	POWER_SUPPLY_PROP_PRESENT,
	POWER_SUPPLY_PROP_VOLTAGE_NOW,
	POWER_SUPPLY_PROP_CURRENT_NOW,
	POWER_SUPPLY_PROP_HEALTH,/*implement it in battery power_supply*/
	POWER_SUPPLY_PROP_CAPACITY,
	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
	POWER_SUPPLY_PROP_TEMP,
	POWER_SUPPLY_PROP_CHARGE_COUNTER,
	POWER_SUPPLY_PROP_CHARGE_FULL,
	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
	POWER_SUPPLY_PROP_CYCLE_COUNT,
	POWER_SUPPLY_PROP_TECHNOLOGY,
	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,

	POWER_SUPPLY_PROP_VOLTAGE_AVG,
	POWER_SUPPLY_PROP_VOLTAGE_OCV,

	POWER_SUPPLY_PROP_CURRENT_AVG,
	POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,

	POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
};

static int fg_get_property(struct power_supply *psy,
			enum power_supply_property psp,
			union power_supply_propval *val)
{
	struct sh_fg_chip *sh = power_supply_get_drvdata(psy);

	mutex_lock(&sh->update_lock);

	switch (psp) {
	case POWER_SUPPLY_PROP_STATUS:
		val->intval = get_prop_status(sh);
		break;

	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
		val->intval = get_prop_averge_volt(sh);

		charge_vlot_value = val->intval;

		printk("hy4145 %s %d value=%d \n",__func__,__LINE__,val->intval);
	
		break;
	case POWER_SUPPLY_PROP_PRESENT:
		val->intval = 1;
		break;
	case POWER_SUPPLY_PROP_CURRENT_NOW:
	case POWER_SUPPLY_PROP_CURRENT_AVG:
		val->intval = get_prop_averge_current(sh);
		debug("hy4145 %s %d value=%d \n",__func__,__LINE__,val->intval);
		break;

	case POWER_SUPPLY_PROP_CAPACITY:
		val->intval = get_prop_capacity_level(sh);
		debug("hy4145 %s %d value=%d \n",__func__,__LINE__,val->intval);
		break;

	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
		val->intval = get_prop_capacity_level(sh);
		debug("hy4145 %s %d value=%d \n",__func__,__LINE__,val->intval);
		break;

	case POWER_SUPPLY_PROP_TEMP:
	if(value_temp>20){
		val->intval = value_temp;
	}else{
		val->intval = get_prop_temp(sh);
		charge_temp_value = val->intval;
	}
		debug("hy4145 %s %d value=%d \n",__func__,__LINE__,val->intval);
		break;

	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:

		//debug("hy4145 %s %d value=%d \n",__func__,__LINE__,val->intval);
		break;

	case POWER_SUPPLY_PROP_HEALTH:
		val->intval = POWER_SUPPLY_HEALTH_GOOD;
		break;

	case POWER_SUPPLY_PROP_CHARGE_FULL:
		val->intval = get_prop_full_volt(sh);
		break;

	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
		val->intval = get_prop_full_design(sh);
		break;

	case POWER_SUPPLY_PROP_CYCLE_COUNT:
		val->intval = get_prop_cycle_count(sh);
		break;

	case POWER_SUPPLY_PROP_TECHNOLOGY:
		val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO;
		break;

	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
		
		val->intval = 870000;
		break;


	case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
		val->intval = 6600*1000;
		break;

	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
		val->intval = 1;
		break;
	
	case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
		val->intval = 60 * 4 * 60 ;
		break;

	default:
		mutex_unlock(&sh->update_lock);
		return -EINVAL;
	}

	mutex_unlock(&sh->update_lock);

	return 0;
}

static int fg_set_property(struct power_supply *psy,
			       enum power_supply_property prop,
			       const union power_supply_propval *val)
{
	struct sh_fg_chip *sh = power_supply_get_drvdata(psy);

	mutex_lock(&sh->update_lock);

	switch (prop) {
	case POWER_SUPPLY_PROP_TEMP:
		break;
	case POWER_SUPPLY_PROP_CAPACITY:
		break;
	default:
		mutex_unlock(&sh->update_lock);
		return -EINVAL;
	}

	mutex_unlock(&sh->update_lock);

	return 0;
}


static int fg_prop_is_writeable(struct power_supply *psy,
				       enum power_supply_property prop)
{
	int ret;

	switch (prop) {
	case POWER_SUPPLY_PROP_TEMP:
	case POWER_SUPPLY_PROP_CAPACITY:
	// case POWER_SUPPLY_PROP_UPDATE_NOW:
		ret = 1;
		break;
	default:
		ret = 0;
		break;
	}
	return ret;
}



static int fg_psy_register(struct sh_fg_chip *sh)
{
	struct power_supply_config fg_psy_cfg = {};

	sh->fg_psy_d.name = "hy4145-fgu";
	sh->fg_psy_d.type = POWER_SUPPLY_TYPE_BATTERY;
	sh->fg_psy_d.properties = fg_props;
	sh->fg_psy_d.num_properties = ARRAY_SIZE(fg_props);
	sh->fg_psy_d.get_property = fg_get_property;
	sh->fg_psy_d.set_property = fg_set_property;
	sh->fg_psy_d.property_is_writeable = fg_prop_is_writeable;

	fg_psy_cfg.drv_data = sh;
	fg_psy_cfg.num_supplicants = 0;
	sh->fg_psy = devm_power_supply_register(sh->dev,
						&sh->fg_psy_d,
						&fg_psy_cfg);
	if (IS_ERR(sh->fg_psy)) {
		pr_err("Failed to register fg_psy");
		return PTR_ERR(sh->fg_psy);
	}
	return 0;
}





static ssize_t fg_attr_show_Rtest(struct device *dev,
				struct device_attribute *attr, char *buf)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct sh_fg_chip *sh = i2c_get_clientdata(client);

	mutex_lock(&sh->update_lock);
	update_info(sh);	
	mutex_unlock(&sh->update_lock);

	return 0;
}

static ssize_t fg_attr_store_Rtest(struct device *dev, struct device_attribute *attr,
             const char *buf, size_t count)
{
	char *end;
	value_temp = simple_strtoul(buf, &end, 10);
    debug("%s:%d: Entry %s value= %d", __FILE__, __LINE__, __func__, value_temp);

    return count;
}




//static DEVICE_ATTR(Qmax, S_IRUGO, fg_attr_show_Qmax, NULL);
static DEVICE_ATTR(Rtest, 0664, fg_attr_show_Rtest, fg_attr_store_Rtest);

static struct attribute *fg_attributes[] = {
//	&dev_attr_RaTable.attr,
//	&dev_attr_Qmax.attr,
	&dev_attr_Rtest.attr,

	NULL,
};

static const struct attribute_group fg_attr_group = {
	.attrs = fg_attributes,
};




static inline bool is_device_suspended(struct sh_fg_chip *sh)
{
	return !sh->resume_completed;
}


static int sh_fg_probe(struct i2c_client *client,
				const struct i2c_device_id *id)
{

	int ret;
	sh = devm_kzalloc(&client->dev, sizeof(*sh), GFP_KERNEL);
	if (sh == NULL) {
		return -ENOMEM; 
	}

	if (!sh)
		return -ENOMEM;

	sh->dev = &client->dev;
	sh->client = client;
	sh->chip = id->driver_data;


	i2c_set_clientdata(client, sh);

	mutex_init(&sh->update_lock);
	mutex_init(&sh->irq_complete);

	sh->resume_completed = true;

	device_init_wakeup(sh->dev, 1);


	fg_psy_register(sh);

	ret = sysfs_create_group(&sh->dev->kobj, &fg_attr_group);
	if (ret)
		pr_err("Failed to register sysfs, err:%d\n", ret);


	sh_log("sh fuel gauge probe successfully, %s\n",
			device2str[sh->chip]);

	return 0;
}




static s32 sh_fg_remove(struct i2c_client* client)
{
	//struct sh_fg_chip* sh = i2c_get_clientdata(client);
	debug("hy4145_remove %s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
				  
	return 0;

}

static void sh_fg_shutdown(struct i2c_client *client)
{
	pr_info("sh fuel gauge driver shutdown!\n");
}

static const struct of_device_id sh_fg_match_table[] = {
    {
	.compatible = "sh,hy4145",
    },
    {},
};
MODULE_DEVICE_TABLE(of, sh_fg_match_table);

static const struct i2c_device_id sh_fg_id[] = {
    {"hy4145", HY4145},
    {},
};
MODULE_DEVICE_TABLE(i2c, sh_fg_id);



static struct i2c_driver sh_fg_driver = {
	.driver	= {
		.name   = "hy4145",
		.owner  = THIS_MODULE,
		.of_match_table = sh_fg_match_table,
		//.pm     = &sh_fg_pm_ops,
	},
	.id_table       = sh_fg_id,

	.probe          = sh_fg_probe,
	.remove		= sh_fg_remove,
	.shutdown	= sh_fg_shutdown,

};
static int __init sh_fg_driver_init(void)
{
	u8 ret;
    ret= i2c_add_driver(&sh_fg_driver);
	pr_err("i2c_drivr_init,return=%d\n",ret);
	return ret;
}


static void __exit sh_fg_driver_exit(void)
{
    i2c_del_driver(&sh_fg_driver);
} 

module_init(sh_fg_driver_init);
module_exit(sh_fg_driver_exit);

EXPORT_SYMBOL(charge_vlot_value);
MODULE_DESCRIPTION("SH HY4145 Driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("ruidong.ren@163.com");


  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值