RK3568 Android11.0.1 电池充放电管理

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、power_supply子系统介绍
  • 二、power_supply更新状态
  • 总结


前言

  现在有部分机器用途于便携式设备,所以在硬件上改用了电池供电。battery管理是power_supply的重要组成部分。本章节介绍的电池充放电管理在硬件上引用了充电小板,通过ad转换读取电池电压值,模拟当前电池剩余的电量,从而实现电池冲放电管理。重点介绍一下power_supply子系统管理电池显示。


一、power_supply子系统介绍

        power_supply子系统是kernel用来管理所有与电池有关的设备,包括充电放电,电池安全情况等等信息。话不多说,直接从宏观到微观的深入了解。

        (1) 查看电池的注册信息

rk3399_all:/ # ls -al /sys/class/power_supply
total 0
drwxr-xr-x  2 root root 0 2013-01-18 17:17 .
drwxr-xr-x 77 root root 0 2013-01-18 17:17 ..
lrwxrwxrwx  1 root root 0 2013-01-18 17:17 test_ac -> ../../devices/virtual/power_supply/test_ac
lrwxrwxrwx  1 root root 0 2013-01-18 17:17 test_battery -> ../../devices/virtual/power_supply/test_battery
lrwxrwxrwx  1 root root 0 2013-01-18 17:17 test_usb -> ../../devices/virtual/power_supply/test_usb

        可以发现当前注册了3个power_supply,那么它是怎么注册的呢?

调用函数:
struct power_supply *__must_check power_supply_register(struct device *parent,
		const struct power_supply_desc *desc,
		const struct power_supply_config *cfg)

或者:

devm_power_supply_register(struct device *parent,
		const struct power_supply_desc *desc,
		const struct power_supply_config *cfg)

两者都是注册power_supply子系统的,后者的注册表示不用的时候会自动释放。其中我们需要实现的参数有 struct power_supply_desc *desc 和 struct power_supply_config *cfg。第一个参数是设备的parent,直接传&pdev->dev即可。接下来分析一下后面两个参数。

第二个参数:

struct power_supply_desc {
	const char *name;    //注册的名字,会在 sys/class/power_supply/name 生成节点
	enum power_supply_type type;    设备的类型 一般为 dc 或 usb 或 battery 我们选择battety 对应的宏 为 POWER_SUPPLY_TYPE_BATTERY
	enum power_supply_property *properties;     // psy 属性
	size_t num_properties;    //psy属性个数

    // psy的回调函数用于获取psy属性的参数
    int (*get_property)(struct power_supply *psy,
			    enum power_supply_property psp,
			    union power_supply_propval *val);
	
   // psy的回调函数用于设置psy属性的参数
    int (*set_property)(struct power_supply *psy,
			    enum power_supply_property psp,
			    const union power_supply_propval *val);

    int (*property_is_writeable)(struct power_supply *psy,
				     enum power_supply_property psp);
	void (*external_power_changed)(struct power_supply *psy);
	void (*set_charged)(struct power_supply *psy);
}

简单明显的在代码中描述,现在讲重点, psy属性。它其实就是一个枚举的参数,如果需要设置什么属性就枚举什么,由于枚举的参数很多就提几个重点讲一下。看代码注释。

static enum power_supply_property rk30_adc_battery_props[] = {
	POWER_SUPPLY_PROP_STATUS,                // psy 的状态
	POWER_SUPPLY_PROP_HEALTH,                // psy 的健康值
	POWER_SUPPLY_PROP_PRESENT,            
	POWER_SUPPLY_PROP_VOLTAGE_NOW,           //当前电压值
	POWER_SUPPLY_PROP_TECHNOLOGY,  
	POWER_SUPPLY_PROP_CAPACITY,              //当前电量
	POWER_SUPPLY_PROP_MODEL_NAME,            //模块名字
	POWER_SUPPLY_PROP_MANUFACTURER,          //电池制造商
	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,    //设置的最大电压值
	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,    //设置的最小电压值
};

说明:当你注册成功后,你可以在 /sys/class/power_supply/test_battery 目录下看到这个属性对应文件

属性的节点存在了,那么他是怎么上报到应用层的呢?当然是通过回调函数去设置(set_property)或者读取(get_property)属性值啦.是通过一个switch去选择不同属性的参数,至于上报的参数需要自己设置或者算法去获取。提供了get_property的示例。

static int rk30_adc_battery_get_property(struct power_supply *psy,
				 enum power_supply_property psp,
				 union power_supply_propval *val)
{		
	switch (psp) {
	case POWER_SUPPLY_PROP_MODEL_NAME:
		val->strval = "KYLIN battery";
		break;
	case POWER_SUPPLY_PROP_MANUFACTURER:
		val->strval = "ZYSJ_ADC_BATTERY";
		break;
	case POWER_SUPPLY_PROP_STATUS:
		val->intval = rk30_adc_battery_get_status(gBatteryData);
		break;
	case POWER_SUPPLY_PROP_HEALTH:
		val->intval = battery_health;
		break;
	case POWER_SUPPLY_PROP_PRESENT:
		val->intval = battery_present;
		break;
	case POWER_SUPPLY_PROP_TECHNOLOGY:
		val->intval = battery_technology;
		break;
	case POWER_SUPPLY_PROP_CAPACITY:
		val->intval = rk30_adc_battery_get_capacity(gBatteryData);
		break;
	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
		break;
	case POWER_SUPPLY_PROP_CHARGE_FULL:
		//val->intval = 100;
		break;
	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
		val ->intval = rk30_adc_battery_get_voltage(gBatteryData);
		break;
	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
		val->intval = BATT_MAX_VOL_VALUE;
		break;
	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
		val->intval = BATT_ZERO_VOL_VALUE;
		break;
	default:
		pr_info("%s: some properties deliberately report errors.\n",
			__func__);
		return -EINVAL;
	}
	return 0;
}

回归到第一个注册函数的第三个参数 struct power_supply_config *cfg。

 struct power_supply_config{
 	struct device_node *of_node;
 	struct fwnode_handle *fwnode;
 	
 	/* Driver private data */
 	void *drv_data;            //用于传递数据
 	
 	chat ** supplied_to;    //一个字符串数组,保存了由该PSY供电的PSY列表,以此可将PSY组成互相级联的PSY链表。
 	size_t num_supplicants;  //supplicant的个数
 }

power_supply注册的流程讲完了,顺便提一下它的卸载流程,不然会造成内存浪费。

void power_supply_unregister(struct power_supply *psy) //传递注册的psy参数即可

二、power_supply向应用层上报

        当 power_supply更新状态时,调用power_supply_changed函数通知应用层。届时等待应用层调用回调函数进行 power_supply的设置或者获取。


void power_supply_changed(struct power_supply *psy)

说明:属性变化时,调用power_supply_changed更新psy状态,并向应用层上报状态

总结

         一个电池充放电管理关键还是在于如何检测是否正在充电,是否充满电,这个需要配合硬件,以上的API函数可以控制电池的充电和放电上报,你可以通过AD脚检测电池的电压,设置一个定时器去模拟电池充放电管理的过程,并且通过两个IO口,读取IO口的电平值判断电池是否充满电,是否正在充电,这样可以达到充放电的管理过程。

        这套函数同样使用与rk3288 和 rk3399 。

        回顾一下调试手段:

1、查看电池是否注册了
    cat /sys/class/power_supply/ xxx           //xxx 为注册的名字
2、电池的属性
    cat /sys/class/power_supply/test_battery    //里面有子系统的属性值

        文章到此结束啦,祝你生活愉快。

你可能感兴趣的:(android,驱动开发)