本驱动是方便大家讨论及理解,电池的参数如电压,电量百分,温度以及相关状态都是人为给定。实际中都是通过读取相应硬件(如axpxxx)的寄存器并按照相应的算法获取。但框架都是一致。
本驱动的开发平台为瑞萨EMEV2,此驱动已经验证。效果贴图(通过es任务管理器查看):

Battery level 的值为25%
Battery status:Charging(AC)
Battery temp:30.0 C
Battery voltage:3730 mv
驱动说明:
1 一般移动设备的供电可来自外部即AC与usb,内部电池供电battery,所以需通过 power_supply_register   函数在/sys/class/power_supply下分别注册ac usb battery,注册完成可发现在设备目录/sys/class/power_supply下分别出现ac usb battery三个文件夹。
2  在注册power_supply前,需要对其分别填充。驱动中会注明。
3 为了达到充电的动态效果,注册了一个timer,每30s电压加5个mv,充到最大电压4150mv为full,此时电量为100%,电池温度设置为30。电量是通过电压按一点算法获取,人为设置为AC充电。
4 运行此驱动程序,在/sys/class/power_supply/battery下可观察到voltage_now,capacity,temp分别为电池的当前电压,电量及温度。
代码:
#include <linux/module.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/types.h>

#include <linux/slab.h>
#include <mach/charger.h>

/* Set ADC sample rate (30sec)*/
#define ADC_SAMPLE_RATE        30

#define OCVREG0                0        //3.1328
#define OCVREG1                0        //3.2736
#define OCVREG2                0        //3.5000
#define OCVREG3                3        //3.5552
#define OCVREG4                7        //3.6256
#define OCVREG5                13        //3.6608
#define OCVREG6                18        //3.6960
#define OCVREG7                27        //3.7312
#define OCVREG8                36        //3.7664
#define OCVREG9                46        //3.8016
#define OCVREGA                53        //3.8368
#define OCVREGB                62        //3.8720
#define OCVREGC                73        //3.9424
#define OCVREGD                85         //4.0128
#define OCVREGE                93         //4.0832
#define OCVREGF                100        //4.1536

/*AXP19 初始化开路电压*/
/*
    只针对AXP19,可以改变,注意和上表的剩余电量百分比一一对应
*/
#define OCVVOL0                3132
#define OCVVOL1                3273
#define OCVVOL2                3500
#define OCVVOL3                3555
#define OCVVOL4                3625
#define OCVVOL5                3660
#define OCVVOL6                3696
#define OCVVOL7                3731
#define OCVVOL8                3766
#define OCVVOL9                3801
#define OCVVOLA                3836
#define OCVVOLB                3872
#define OCVVOLC                3942
#define OCVVOLD                4012
#define OCVVOLE                4090//4083
#define OCVVOLF                4150//4150
 
#define  uint8   unsigned char
#define  uint16  unsigned short
#define  int16   short
#define  uint32  unsigned int
#define  int32   int
#define  uint64  unsigned long

typedef enum charger_type_t {
    CHARGER_BATTERY = 0,
    CHARGER_USB,
    CHARGER_AC
}charger_type_t;

struct emxx_battery_data {
    struct power_supply battery;
    struct power_supply usb;
    struct power_supply ac;

unsigned int battery_present;
    uint16 voltage_level;
    uint16 battery_temp;
    unsigned int battery_voltage;
    
    charger_type_t charger;
    int usb_state;

struct workqueue_struct *monitor_wqueue;
    struct delayed_work monitor_work;
};

static struct emxx_battery_data *battery_data;
unsigned int battery_vol;
static enum power_supply_property emxx_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_TEMP,            //温度
    POWER_SUPPLY_PROP_VOLTAGE_NOW,    //电压
};

static enum power_supply_property emxx_power_props[] = {
    POWER_SUPPLY_PROP_ONLINE, //外部供电查看是否存在AC或usb
};

static int emxx_battery_get_status(void)
{
    int ret;

switch (battery_data->charger) {
    case CHARGER_BATTERY:
        ret = POWER_SUPPLY_STATUS_NOT_CHARGING;
        break;
    case CHARGER_USB:
    case CHARGER_AC:
        if (battery_data->voltage_level == 100)
            ret = POWER_SUPPLY_STATUS_FULL;//如果电池充满了则显示full状态
        else
            ret = POWER_SUPPLY_STATUS_CHARGING; //未满并且外部电源存在则显示充电状态,人为设置为CHARGER_AC
        break;
    default:
        ret = POWER_SUPPLY_STATUS_UNKNOWN;
    }
    return ret;
}

static int emxx_battery_get_property(struct power_supply *psy,
                 enum power_supply_property psp,
                 union power_supply_propval *val)
{
    int ret = 0;

switch (psp) {
    case POWER_SUPPLY_PROP_STATUS:        /* 0 */
        val->intval = emxx_battery_get_status();
        break;
    case POWER_SUPPLY_PROP_HEALTH:        /* 1 */
        val->intval = POWER_SUPPLY_HEALTH_GOOD;
        break;
    case POWER_SUPPLY_PROP_PRESENT:        /* 2 */
        val->intval = battery_data->battery_present;
        break;
    case POWER_SUPPLY_PROP_TECHNOLOGY:    /* 4 */
        val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
        break;
    case POWER_SUPPLY_PROP_CAPACITY:    /* 26 */
        val->intval = battery_data->voltage_level;
        break;    
    case POWER_SUPPLY_PROP_TEMP:
        val->intval = battery_data->battery_temp;
        break;
    case POWER_SUPPLY_PROP_VOLTAGE_NOW:    
        val->intval = battery_data->battery_voltage;
        break;    
    default:
        ret = -EINVAL;
        break;
    }

return ret;
}
/*根据电压获取当前电量,此算法简单实用,根据不同电池需调节最大电压,最小电压以及每段的电压及对应的电量,可达到充电快慢的程度,实际中需要通过内阻,开路电压及充放电电流按一定算法获取后并经过库仑计校准得到电量,实际电量的计算是很复杂的,往往无法达到理想的检测效果*/
static uint8_t axp_restcap(int ocv)
{
    if(ocv >= OCVVOLF)
    {
        return OCVREGF;
    }
    else if(ocv < OCVVOL0)
    {
        return OCVREG0;
    }
    else if(ocv < OCVVOL1)
    {
        return OCVREG0 (OCVREG1 - OCVREG0) * (ocv - OCVVOL0) / (OCVVOL1 - OCVVOL0);
    }
    else if(ocv < OCVVOL2)
    {
        return OCVREG1 (OCVREG2 - OCVREG1) * (ocv - OCVVOL1) / (OCVVOL2 - OCVVOL1);
    }
    else if(ocv < OCVVOL3)
    {
        return OCVREG2 (OCVREG3 - OCVREG2) * (ocv - OCVVOL2) / (OCVVOL3 - OCVVOL2);
    }
    else if(ocv < OCVVOL4)
    {
        return OCVREG3 (OCVREG4 - OCVREG3) * (ocv - OCVVOL3) / (OCVVOL4 - OCVVOL3);
    }
    else if(ocv < OCVVOL5)
    {
        return OCVREG4 (OCVREG5 - OCVREG4) * (ocv - OCVVOL4) / (OCVVOL5 - OCVVOL4);
    }
    else if(ocv < OCVVOL6)                               
    {
        return OCVREG5 (OCVREG6 - OCVREG5) * (ocv - OCVVOL5) / (OCVVOL6 - OCVVOL5);
    }
    else if(ocv < OCVVOL7)
    {
        return OCVREG6 (OCVREG7 - OCVREG6) * (ocv - OCVVOL6) / (OCVVOL7 - OCVVOL6);
    }
    else if(ocv < OCVVOL8)
    {
        return OCVREG7 (OCVREG8 - OCVREG7) * (ocv - OCVVOL7) / (OCVVOL8 - OCVVOL7);
    }
    else if(ocv < OCVVOL9)
    {
        return OCVREG8 (OCVREG9 - OCVREG8) * (ocv - OCVVOL8) / (OCVVOL9 - OCVVOL8);
    }
    else if(ocv < OCVVOLA)
    {
        return OCVREG9 (OCVREGA - OCVREG9) * (ocv - OCVVOL9) / (OCVVOLA - OCVVOL9);
    }
    else if(ocv < OCVVOLB)
    {
        return OCVREGA (OCVREGB - OCVREGA) * (ocv - OCVVOLA) / (OCVVOLB - OCVVOLA);
    }
    else if(ocv < OCVVOLC)
    {
        return OCVREGB (OCVREGC - OCVREGB) * (ocv - OCVVOLB) / (OCVVOLC - OCVVOLB);
    }
    else if(ocv < OCVVOLD)
    {
        return OCVREGC (OCVREGD - OCVREGC) * (ocv - OCVVOLC) / (OCVVOLD - OCVVOLC);
    }
    else if(ocv < OCVVOLE)
    {
        return OCVREGD (OCVREGE - OCVREGD) * (ocv - OCVVOLD) / (OCVVOLE - OCVVOLD);
    }
    else if(ocv < OCVVOLF)
    {
        return OCVREGE (OCVREGF - OCVREGE) * (ocv - OCVVOLE) / (OCVVOLF - OCVVOLE);
    }
    else
    {
        return 0;
    }
}

static void Get_battery_preference(void)
{
    battery_data->voltage_level = axp_restcap(battery_vol);
    battery_vol = 5; //每30s轮询一次,电压加5mv
    battery_data->battery_temp = 30;
    
    if(battery_data->voltage_level > 100){
        battery_data->voltage_level = 100;
    }

if(battery_vol > 4150){
        battery_vol = 4150;
    }
/*针对android的特性,当温度超过一定值时,会自动关机,故要设定一阀值*/
    if(battery_data->battery_temp > 60){
        battery_data->battery_temp = 60;
    }
}

static void emxx_battery_work(struct work_struct *work)
{
    const int interval = HZ * ADC_SAMPLE_RATE;
    unsigned int old_voltage_level;
    unsigned int old_battery_voltage;
    unsigned int old_battery_temp;
    
    old_voltage_level = battery_data->voltage_level;
    old_battery_voltage = battery_data->battery_voltage;
    old_battery_temp = battery_data->battery_temp;
    
    Get_battery_preference();
  /*电压上报时需要扩大1000,温度需扩大10,才能用es任务管理器查看实际值*/
    battery_data->battery_voltage = battery_vol * 1000;
    battery_data->battery_temp = battery_data->battery_temp * 10;
    
    if(old_battery_temp > battery_data->battery_temp 100)
    {
        battery_data->battery_temp = old_battery_temp - 100;
    }
    else if(old_battery_temp < battery_data->battery_temp - 100)
    {
        battery_data->battery_temp = old_battery_temp 100;
    }
    
    /* If status have changed, update the status */
    if (old_voltage_level != battery_data->voltage_level || old_battery_voltage != battery_data->battery_voltage ||
        old_battery_temp != battery_data->battery_temp) {
        power_supply_changed(&battery_data->battery);  //当电压,温度,电量任意一个发生改变时,数据上报
    }
    queue_delayed_work(battery_data->monitor_wqueue,
            &(battery_data->monitor_work), interval);
}

static int emxx_power_get_property(struct power_supply *psy,
            enum power_supply_property psp,
            union power_supply_propval *val)
{
    charger_type_t charger;

charger = battery_data->charger;

switch (psp) {
    case POWER_SUPPLY_PROP_ONLINE:    /* 3 */
        if (psy->type == POWER_SUPPLY_TYPE_MAINS)
            val->intval = (charger ==  CHARGER_AC ? 1 : 0);
        else if (psy->type == POWER_SUPPLY_TYPE_USB) {
            if (battery_data->usb_state == EMXX_USB_OFF)
                val->intval = 0;
            else
                val->intval = 1;
        } else
            val->intval = 0;
        break;
    default:
        return -EINVAL;
    }

return 0;
}

static int emxx_battery_probe(struct platform_device *pdev)
{
    int ret;
    struct emxx_battery_data *data;

printk(KERN_INFO "Battery probe...\n");
    data = kzalloc(sizeof(*data), GFP_KERNEL);
    if (data == NULL) {
        ret = -ENOMEM;
        goto err_data_alloc_failed;
    }

/* Battey */
  /*填充struct power_supply battery*/
    data->battery.name = "battery";
    data->battery.type = POWER_SUPPLY_TYPE_BATTERY;
    data->battery.properties = emxx_battery_props; //添加相应字段到battery目录下,包括电压,电量及温度。
    data->battery.num_properties = ARRAY_SIZE(emxx_battery_props);
    data->battery.get_property = emxx_battery_get_property; //注册回调函数,以此动态获取属性

/* USB */
    data->usb.name = "usb";
    data->usb.type = POWER_SUPPLY_TYPE_USB;
    data->usb.properties = emxx_power_props;
    data->usb.num_properties = ARRAY_SIZE(emxx_power_props);
    data->usb.get_property = emxx_power_get_property;

/* AC */
    data->ac.name = "ac";
    data->ac.type = POWER_SUPPLY_TYPE_MAINS;
    data->ac.properties = emxx_power_props;
    data->ac.num_properties = ARRAY_SIZE(emxx_power_props);
    data->ac.get_property = emxx_power_get_property;

battery_data = data;    
   /*初始化电池电压为3700mv,温度为30*/
    battery_vol = 3700;
    battery_data->battery_temp = 30;

battery_data->charger = CHARGER_AC;
    
    ret = power_supply_register(&pdev->dev, &data->battery);
    if (ret)
        goto err_battery_failed;

ret = power_supply_register(&pdev->dev, &data->usb);
    if (ret)
        goto err_usb_failed;

ret = power_supply_register(&pdev->dev, &data->ac);
    if (ret)
        goto err_ac_failed;

INIT_DELAYED_WORK(&data->monitor_work, emxx_battery_work);
    data->monitor_wqueue =
        create_singlethread_workqueue("axp192");
    if (!data->monitor_wqueue) {
        ret = -ESRCH;
        goto err_workqueue_failed;
    }
    queue_delayed_work(data->monitor_wqueue, &data->monitor_work, HZ);

platform_set_drvdata(pdev, data);
    return 0;

err_workqueue_failed:
    power_supply_unregister(&data->ac);
err_ac_failed:
    power_supply_unregister(&data->usb);
err_usb_failed:
    power_supply_unregister(&data->battery);
err_battery_failed:
err_data_alloc_failed:
    return ret;
}

static int emxx_battery_remove(struct platform_device *pdev)
{
    struct emxx_battery_data *data = platform_get_drvdata(pdev);

printk(KERN_INFO "Battery driver remove...\n");

power_supply_unregister(&data->battery);
    power_supply_unregister(&data->usb);
    power_supply_unregister(&data->ac);

kfree(data);
    battery_data = NULL;
    return 0;
}

#ifdef CONFIG_PM
static int emxx_battery_suspend(struct platform_device *pdev,
                  pm_message_t state)
{
    return 0;
}

static int emxx_battery_resume(struct platform_device *pdev)
{
    struct emxx_battery_data *data = platform_get_drvdata(pdev);
    power_supply_changed(&data->battery);

cancel_delayed_work(&data->monitor_work);
    queue_delayed_work(data->monitor_wqueue, &data->monitor_work, HZ);

return 0;
}

#else
#define emxx_battery_suspend NULL
#define emxx_battery_resume NULL
#endif /* CONFIG_PM */

static struct platform_driver emxx_battery_driver = {
    .probe        = emxx_battery_probe,
    .remove        = emxx_battery_remove,
    .suspend    = emxx_battery_suspend,
    .resume     = emxx_battery_resume,
    .driver = {
        .name = "emxx-battery"
    }
};

static int __init emxx_battery_init(void)
{
    return platform_driver_register(&emxx_battery_driver);
}

static void __exit emxx_battery_exit(void)
{
    platform_driver_unregister(&emxx_battery_driver);
}

module_init(emxx_battery_init);
module_exit(emxx_battery_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Battery driver for the EMMA Mobile series");

linux 电池驱动相关推荐

  1. Linux 电池 驱动

    电池驱动 涉及文件 power_supply.h power_supply_core.c  电池核心 power_supply_leds.c  充电指示灯 power_supply_sysfs.c  ...

  2. Linux设备驱动的分层设计思想

    1.1 设备驱动核心层和例化 在面向对象的程序设计中,可以为某一类相似的事物定义一个基类,而具体的事物可以继承这个基类中的函数.如果对于继承的这个事物而言,其某函数的实 现与基类一致,那它就可以直接继 ...

  3. linux I2C 驱动

    原文地址: http://hello2mao.github.io/2015/12/02/Linux_I2C_driver.html 目录 一.LinuxI2C驱动--概述 1.1 写在前面 1.2 I ...

  4. Android电池驱动

    学习要点:1.电池驱动的架构: 2.电池电压的获取,百分比的转换(包括不同用电情况下的分析): 3.充电管理: 当我们要写一个驱动的时候,首先要知道内核提供给驱动的接口,就是当驱动挂载到内核上的时候, ...

  5. [RK3288][Android6.0] 调试笔记 --- 伪电池驱动添加

    Platform: ROCKCHIP OS: Android 6.0 Kernel: 3.10.92 由于电池部分是用户空间Service从另外一颗MCU获取,而Android需要显示电量, 所以按照 ...

  6. 高通SDM450 ADC读取电池驱动调试

    由于项目需要,使用的sdm450模块不带PMIC电源管理的,而项目又需要接电池使用,所以硬件把电池端接到一个ADC口,做了个简单的电池电路,通过ADC读取数值来确定电池电压,然后换算电池电量. 电池驱 ...

  7. kali Linux显卡驱动安装(双显卡笔记本注意事项和解决方案)

    kali Linux 显卡驱动安装及注意事项 一.禁用nouveau驱动这个我在上一篇博客里讲到,但是安装显卡还是必须做.(如果做过了就直从二往后看.) 打开终端在黑名单里添加mouveau驱动.:g ...

  8. Linux音频设备驱动

    在Linux中,先后出现了音频设备的两种框架OSS和ALSA,本节将在介绍数字音频设备及音频设备硬件接口的基础上,展现OSS和ALSA驱动的结构. 17.1-17.2节讲解了音频设备及PCM.IIS和 ...

  9. linux设备驱动第五篇:驱动中的并发与竟态

    目录[-] 综述 信号量与互斥锁 Completions 机制 自旋锁 其他的一些选择 不加锁算法 原子变量与位操作 seqlock(顺序锁) 读取-拷贝-更新(RCU) 小结 综述 在上一篇介绍了l ...

最新文章

  1. github的watch和star的位置
  2. 微信小程序中this指向作用域问题this.setData is not a function报错
  3. 从WebRtc学习RTP协议
  4. wpf计算字符大小占像素_LCD作为终端显示字符串的过程
  5. 用贝叶斯定理解决三门问题并用Python进行模拟(Bayes‘ Rule Monty Hall Problem Simulation Python)
  6. 构建LVS+Keepalived高可用群集
  7. 51单片机_15-1 LED亮度调节
  8. 安卓手机视频消重 去除qq短视频水印链接
  9. python全角半角的相互转换
  10. 饥荒联机版服务器搭建教程-WeGame
  11. Ubuntu安装最新的SlickEdit软件--破解教程
  12. PAT A1122 Hamiltonian Cycle ——春至花如锦,夏近叶成帷
  13. centos怎么卸载mysql
  14. 够快联想坚果云这三个产品哪个更好
  15. python计算正方形边长_计算圆周率,使用点模拟法,如何从以下python代码中看出正方形的边长?...
  16. 计算机应用课程设计样式大全,计算机应用课程设计样本.doc
  17. PTA 天梯赛习题集 L2-001 城市间紧急救援
  18. 二分法排序-JAVA
  19. STL之string类:知其然,需知其所以然
  20. 7-1 IP地址转换 (20分)PTA

热门文章

  1. 【codeup】1128 Problem B 出租车费
  2. 行政区划数据库表结构设计最佳实践
  3. 【计算机网络】BitTorrent技术对网络的潜在危害
  4. mipsel_24kc的linux内核,歌华链OpenWrt固件的软重启reboot补丁制作OpenWrt固件软重启补丁下载...
  5. iOS中蓝牙技术的实现
  6. 《修改BIOS为品牌机信息安装激活Windows XP SP2》
  7. Fiddler安装了证书,还是提示证书无效
  8. lopatkin俄大神精简Windows 10 Pro 19041.331 20H1 Release x86-x64 EN-RU BOMG v2
  9. iOS9-by-Tutorials-学习笔记五:Multitasking
  10. 怎么查看图片像素和大小?照片exif信息怎么看?