linux电源管理子系统

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 守护进程
可以监听到这种变化.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值