查看: 3304|回复: 4

[原创] imx6ull编写cw2015锂电池库仑计驱动

[复制链接]
  • TA的每日心情

    2021-2-4 09:24
  • 签到天数: 190 天

    [LV.7]常住居民III

    38

    主题

    591

    帖子

    28

    金牌会员

    Rank: 6Rank: 6

    积分
    2193
    最后登录
    2023-12-1
    发表于 2020-7-30 14:48:13 | 显示全部楼层 |阅读模式
    本帖最后由 mzy2364 于 2020-7-30 14:47 编辑

    在多数情况下,作为用户是不需要写Linux驱动代码的,因为芯片厂或者方案厂会为我们提供,但是作为嵌入式Linux开发者,学会看驱动甚至学会写驱动会大大提高开发效率。这里就cw2015的驱动代码,带领读者简单了解下i2c驱动框架下的电源管理驱动。
    需要完成的功能:
    在设备树下面添加CW2015;
    cw2015注册为power_supply设备,在/sys/class/power_supply下面可以看到cw2015;
    通过power_supply提供的接口函数利用i2c读取电池的电量信息和电压信息;
    通过power_supply提供的接口函数利用GPIO函数读取电池充电状态。
    开始写驱动
    1、准备工作
    linux内核的电源驱动文件在内核目录的/drivers/power文件夹下面,这里面有很多电源芯片的驱动文件,这些文件对我们编写驱动有非常大的参考意义,读者在编写的驱动的时候可以多看一看。
    2、驱动的基本框架
    接下来我们来看一下power_supply的基本驱动框架,power_supply的3个核心文件在内核目录的/drivers/power/下面
    power_supply_core.c 用于抽象核心数据结构、实现公共逻辑
    power_supply_leds.c 实现sysfs以及uevent功能
    power_supply_sysfs.c 基于linux led class,提供PSY设备状态指示的通用实现
    来看一下power_supply的结构体:(在kernel/include/power_supply.h)
    1. struct power_supply {
    2.         const struct power_supply_desc *desc;        /* 属性的描述信息结构体 */

    3.         char **supplied_to;
    4.         size_t num_supplicants;

    5.         char **supplied_from;
    6.         size_t num_supplies;
    7.         struct device_node *of_node;

    8.         /* Driver private data */
    9.         void *drv_data;

    10.         /* private */
    11.         struct device dev;
    12.         struct work_struct changed_work;
    13.         struct delayed_work deferred_register_work;
    14.         spinlock_t changed_lock;
    15.         bool changed;
    16.         atomic_t use_cnt;
    17. #ifdef CONFIG_THERMAL
    18.         struct thermal_zone_device *tzd;
    19.         struct thermal_cooling_device *tcd;
    20. #endif

    21. #ifdef CONFIG_LEDS_TRIGGERS
    22.         struct led_trigger *charging_full_trig;
    23.         char *charging_full_trig_name;
    24.         struct led_trigger *charging_trig;
    25.         char *charging_trig_name;
    26.         struct led_trigger *full_trig;
    27.         char *full_trig_name;
    28.         struct led_trigger *online_trig;
    29.         char *online_trig_name;
    30.         struct led_trigger *charging_blink_full_solid_trig;
    31.         char *charging_blink_full_solid_trig_name;
    32. #endif
    33. };
    复制代码
    这里只介绍了第一个结构体,用于描述power_supply设备的属性,包括电源设备的名称、类型以及接口函数。
    power_supply_desc的结构体:
    1. /* Description of power supply */
    2. struct power_supply_desc {
    3.         const char *name;                /* 名称 */
    4.         enum power_supply_type type;        /* 电源的类型 */
    5.         enum power_supply_property *properties;                /* 属性列表 */
    6.         size_t num_properties;                /* properties属性的个数 */

    7.         /*
    8.          * Functions for drivers implementing power supply class.
    9.          * These shouldn't be called directly by other drivers for accessing
    10.          * this power supply. Instead use power_supply_*() functions (for
    11.          * example power_supply_get_property()).
    12.          */
    13.     /* 获取参数和属性的接口函数 */
    14.         int (*get_property)(struct power_supply *psy,
    15.                             enum power_supply_property psp,
    16.                             union power_supply_propval *val);
    17.         int (*set_property)(struct power_supply *psy,
    18.                             enum power_supply_property psp,
    19.                             const union power_supply_propval *val);
    20.         int (*property_is_writeable)(struct power_supply *psy,
    21.                                      enum power_supply_property psp);
    22.         void (*external_power_changed)(struct power_supply *psy);
    23.         void (*set_charged)(struct power_supply *psy);

    24.         /*
    25.          * Set if thermal zone should not be created for this power supply.
    26.          * For example for virtual supplies forwarding calls to actual
    27.          * sensors or other supplies.
    28.          */
    29.         bool no_thermal;
    30.         /* For APM emulation, think legacy userspace. */
    31.         int use_for_apm;
    32. };
    复制代码
    对于电源类型、电源属性这些枚举类型建议读者去阅读源码去获取。
    power_supply_config结构体:

    1. /* Run-time specific power supply configuration */
    2. struct power_supply_config {
    3.         struct device_node *of_node;
    4.         /* Driver private data */
    5.         void *drv_data;

    6.         char **supplied_to;
    7.         size_t num_supplicants;
    8. };
    复制代码
    3个重要的结构体之间的关系由一个函数进行建立:
    1. struct power_supply *__must_check power_supply_register(struct device *parent,const struct power_supply_desc *desc,const struct power_supply_config *cfg)
    复制代码
    power_supply的简要驱动步骤一般为:
    l 填充 power_supply_desc 结构体,指定驱动的名称、类型、参数获取函数等;
    l 调用函数 power_supply_register /sys/class/power_supply 下面注册对应的设备;
    l 内核通过 get_property 函数获取指定的参数(电池健康状态、充电状态等等)。[url=]恢复数据[/url]

    修改设备树
    驱动文件写完以后需要修改设备树,才能匹配硬件
    1. &i2c2 {
    2.         clock_frequency = <100000>;
    3.         pinctrl-names = "default";
    4.         pinctrl-0 = <&pinctrl_i2c2>;
    5.         status = "okay";

    6.    ...

    7.         cw2015: cw2015@62{
    8.                 compatible = "cw2015";
    9.                 cw2015_charge_gpio = <&gpio1 1 GPIO_ACTIVE_LOW>;
    10.                 reg = <0x62>;
    11.         };

    12. };
    复制代码
    编译新的内核和设备树
    我们将cw2015的驱动添加进内核,然后编译新的内核和设备树替换到目标板,使用以下命令可以查看电量
    1. cat /sys/class/power_supply/cw2015-battery/status
    复制代码




    由于字数限制,完整内容请查看pdf
    imx6ull移植cw2015驱动.pdf (578.84 KB, 下载次数: 53)
    哎...今天够累的,签到来了~
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2024-3-26 15:16
  • 签到天数: 266 天

    [LV.8]以坛为家I

    3300

    主题

    6547

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    32032
    最后登录
    2024-4-26
    发表于 2020-7-30 17:12:50 | 显示全部楼层
    感谢分享
    签到签到
    回复

    使用道具 举报

    该用户从未签到

    2

    主题

    108

    帖子

    0

    中级会员

    Rank: 3Rank: 3

    积分
    281
    最后登录
    2020-9-10
    发表于 2020-7-31 08:50:15 | 显示全部楼层
    学习了
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2021-6-30 17:11
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    5

    主题

    427

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    1100
    最后登录
    2024-4-25
    发表于 2021-1-22 23:19:36 | 显示全部楼层

    学习了
    加油
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2024-1-21 12:18
  • 签到天数: 1081 天

    [LV.10]以坛为家III

    16

    主题

    1903

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    5044
    最后登录
    2024-4-26
    发表于 2021-1-25 17:10:50 | 显示全部楼层
    学习了
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-4-27 05:56 , Processed in 0.119117 second(s), 23 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表