大家好,欢迎来到IT知识分享网。
1. linux电源管理子系统用于管理系统的充放电以及供电.不同设备供电方式多样,即使是一个
设备也可以支持多个供电方式,例如一个平板可以使用usb,dc,电池供电.
电源管理子系统用于抽象这些供电,对上层它提供统一的操作接口,方便上层的编码.对下层
它实现了充电管理的共有逻辑以及sysfs接口的创建,驱动程序只需要按照规则实现底层接口
就可以了,简化了驱动程序的设计.
2. 电源管理的结构
一个struct power_supply 实例代表一个供电设备,比如一个usb供电设备,电池供电
设备. 通常用户不需要自己定义一个struct power_supply实例,当我们调用power_supply_register()
函数时函数内部会动态创建一个struct power_supply 实例.看下power_supply_register()
函数
/ power_supply_register() - 注册新的电源供应设备 @parent: 电源供应设备的父设备,通常是调用此函数的探测函数所属的设备 @desc: 电源供应的描述信息,必须在此电源供应的整个生命周期内保持有效 @cfg: 注册过程中访问的运行时特定配置,可能为NULL 返回值:成功时返回新分配的power_supply的指针,否则返回ERR_PTR。 使用返回的power_supply指针调用power_supply_unregister()来释放资源。 */ struct power_supply *__must_check power_supply_register(struct device *parent, const struct power_supply_desc *desc, const struct power_supply_config *cfg)
该函数有两个重要的参数struct power_supply_desc和struct power_supply_config.
struct power_supply_desc是我们初始化的重点.从名字可知,它是描述一个供电设备.不同供电设备
提供不同的功能,这种差异就是在这里体现的.
power_supply_desc: /* Description of power supply */ struct power_supply_desc { const char *name; //名字,这个名字会体现在/sys/class/xxx 下 enum power_supply_type type; //供电类型,例如常用的POWER_SUPPLY_TYPE_BATTERY, enum power_supply_usb_type *usb_types; //usb类型 size_t num_usb_types; enum power_supply_property *properties; //指向power supply 所有的属性 size_t num_properties; /* * Functions for drivers implementing power supply class. * These shouldn't be called directly by other drivers for accessing * this power supply. Instead use power_supply_*() functions (for * example power_supply_get_property()). */ /* 为实现电源供应类的驱动程序提供的函数。 这些函数不应被其他驱动程序直接调用以访问此电源供应。相反,应使用power_supply_*()函数(例如power_supply_get_property())来访问。 */ int (*get_property)(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val); int (*set_property)(struct power_supply *psy, enum power_supply_property psp, const union power_supply_propval *val); /* * property_is_writeable() will be called during registration * of power supply. If this happens during device probe then it must * not access internal data of device (because probe did not end). */ 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); /* * Set if thermal zone should not be created for this power supply. * For example for virtual supplies forwarding calls to actual * sensors or other supplies. */ bool no_thermal; /* For APM emulation, think legacy userspace. */ int use_for_apm; };
linux电源管理子系统是如何抽象一个供电设备的? 它把一个供电设备抽象成众多的属性,定义
在enum power_supply_property 枚举类型中, 例如一个电池供电设备它有最大电压,最大电流
当前电压,健康状况等等.power_supply_desc->properties参数表明设备支持的属性,设备注册成功
后这些属性就会一一对应到/sys/power/supply/name/xxx下的一个文件.应用层可以读写这些文件
来获取或设置供电设备的属性值.power_supply_desc->get_property,和power_supply_desc->set_property
就是驱动里获取和设置这些属性的实现接口.
struct power_supply_config
power_supply_config的内容很少,一般保留设备的私有数据.
如何基于电源管理子系统注册一个供电设备?
1. 定义个power_supply_desc实例,
2. 初始化power_supply_desc->properties 定义供电设备支持的属性
3. 实现这些属性的get_property, set_property底层实现接口.
4. 定义一个power_supply_config实例,指定一些设备的私有数据.
5. 调用power_supply_register()函数注册供电设备.
static enum power_supply_property mybat_battery_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_TECHNOLOGY, POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_VOLTAGE_OCV, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_CHARGE_COUNTER, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_CURRENT_AVG, POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_CURRENT_MAX, POWER_SUPPLY_PROP_VOLTAGE_MAX, }; static int mybat_battery_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { struct mybat_data *data = power_supply_get_drvdata(psy); int ret = 0; switch (psp) { case POWER_SUPPLY_PROP_STATUS: val->intval = data->xxx break; case POWER_SUPPLY_PROP_HEALTH: val->intval = data->xxx break; case POWER_SUPPLY_PROP_PRESENT: val->intval = data->xxx break; .... default: ret = -EINVAL; break; } return ret; } static int probe(struct platform_device *pdev) { /*定义一个实例*/ struct power_supply_desc *battery_desc = devm_kzalloc(&pdev->dev, sizeof(struct power_supply_desc), GFP_KERNEL); if (battery_desc == NULL) { //error } struct power_supply_config battery_cfg = {}; battery_desc->properties = mybat_battery_props; //设备支持的属性 battery_desc->num_properties = ARRAY_SIZE(mybat_battery_props); //属性数量 battery_desc->get_property = mybat_battery_get_property; //获取属性 battery_desc->set_property = mybat_battery_set_property; //设置属性 battery_desc->property_is_writeable = mybat_battery_property_is_writeable; battery_desc->name = "battery"; //名字,会出现在/sys/class/powersupply/xxx battery_desc->type = POWER_SUPPLY_TYPE_BATTERY; battery_desc->no_thermal = true; battery_cfg.drv_data = struct mybat_data; //定义私有数据 power_supply_register(&pdev->dev, battery_desc, &battery_cfg); /*注册完成后会创建爱你/sys/class/power_supply/battery目录,并在目录下有 mybat_battery_props定义的这些属性文件.应用层访问这些属性文件获取电池属性.*/ }
驱动通知应用:
当电池状态发生变化时可以通过power_supply_changed()函数通知上层. 上层的uevent 守护进程
可以监听到这种变化.
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/144444.html