天天看點

[RK3288][Android6.0] 調試筆記 --- 僞電池驅動添加

Platform: ROCKCHIP

OS: Android 6.0

Kernel: 3.10.92

由于電池部分是使用者空間Service從另外一顆MCU擷取,而Android需要顯示電量,

是以按照電池驅動架構做了一個僞電池驅動, 主要是使用它的充電狀态和電池電量

這兩個property, 代碼如下:

#include <linux/module.h>

#include <linux/err.h>

#include <linux/platform_device.h>

#include <linux/power_supply.h>

#include <linux/types.h>

#include <linux/pci.h>

#include <linux/interrupt.h>

#include <asm/io.h>

#include <linux/timer.h>

#include <linux/slab.h>

#include <linux/of_irq.h>

#include <linux/of_gpio.h>

#include <linux/of.h>

#include <linux/of_device.h>

//#define DEBUG

struct rk3288_battery_data {

    int status;

    int health;

    int present;

    int capacity;

    struct power_supply battery;

};

static struct rk3288_battery_data *battery_data;

static enum power_supply_property rk3288_battery_props[] = {

    POWER_SUPPLY_PROP_STATUS,

    POWER_SUPPLY_PROP_HEALTH,

    POWER_SUPPLY_PROP_PRESENT,

    POWER_SUPPLY_PROP_TECHNOLOGY,

    POWER_SUPPLY_PROP_CAPACITY,

};

static int rk3288_battery_get_property(struct power_supply *psy,

                 enum power_supply_property psp,

                 union power_supply_propval *val)

{

    struct rk3288_battery_data *data = container_of(psy,

        struct rk3288_battery_data, battery);

    int ret = 0;

#ifdef DEBUG

    printk("%s : property: %d \n", __func__, psp);

#endif

    switch (psp) {

    case POWER_SUPPLY_PROP_STATUS:

        val->intval = data->status;

        break;

    case POWER_SUPPLY_PROP_HEALTH:

        val->intval = data->health ;

        break;

    case POWER_SUPPLY_PROP_PRESENT:

        val->intval = data->present ;

        break;

    case POWER_SUPPLY_PROP_TECHNOLOGY:

        val->intval = POWER_SUPPLY_TECHNOLOGY_LION;

        break;

    case POWER_SUPPLY_PROP_CAPACITY:

        val->intval = data->capacity ;

        break;

    default:

        ret = -EINVAL;

        break;

    }

    return ret;

}

static int rk3288_battery_set_property(struct power_supply *psy,

            enum power_supply_property psp,

            const union power_supply_propval *val)

{

    struct rk3288_battery_data *data = container_of(psy,

        struct rk3288_battery_data, battery);

    int ret = 0;

    int value = val->intval;

#ifdef DEBUG

    printk("%s :psp:%d val:%d\n", __func__, psp, value);

#endif

    switch (psp) {

    case POWER_SUPPLY_PROP_STATUS:

        if (value <= POWER_SUPPLY_STATUS_FULL) {

            data->status =value;

        } else {

            printk("Unreasonable value:%d\n", value);

            ret = 1;

        }

        break;

    case POWER_SUPPLY_PROP_HEALTH:

        if (value <= POWER_SUPPLY_HEALTH_COLD) {

            data->health = value;

        } else {

            printk("Unreasonable value:%d\n", value);

            ret = 1;

        }

        break;

    case POWER_SUPPLY_PROP_PRESENT:

        data->present = value;

        break;

    case POWER_SUPPLY_PROP_CAPACITY:

        //Capacity from 0 to 100.

        if (value > 0 && value <= 100) {

            data->capacity = value;

        } else {

            printk("Unreasonable value:%d\n", value);

            ret = 1;

        }

        break;

    default:

        ret = -EINVAL;

        break;

    }

    //Send uevent.

    power_supply_changed(&battery_data->battery);

    return ret;

}

static int rk3288_battery_is_writeable(struct power_supply *psy,

                 enum power_supply_property psp)

{

    switch (psp) {

    //Need to be written from medusa service.

    case POWER_SUPPLY_PROP_CAPACITY:

    case POWER_SUPPLY_PROP_STATUS:

    case POWER_SUPPLY_PROP_PRESENT:

    case POWER_SUPPLY_PROP_HEALTH:

        return 1;

    default:

        break;

    }

    return 0;

}

static int rk3288_battery_probe(struct platform_device *pdev)

{

    int ret;

    struct rk3288_battery_data *data;

    data = kzalloc(sizeof(*data), GFP_KERNEL);

    if (data == NULL) {

        ret = -ENOMEM;

        goto err_data_alloc_failed;

    }

    data->battery.properties = rk3288_battery_props;

    data->battery.num_properties = ARRAY_SIZE(rk3288_battery_props);

    data->battery.get_property = rk3288_battery_get_property;

    data->battery.name = "battery";

    data->battery.type = POWER_SUPPLY_TYPE_BATTERY;

    data->battery.set_property = rk3288_battery_set_property;

    data->battery.property_is_writeable = rk3288_battery_is_writeable;

    data->present = 1;    //Present

    data->status = POWER_SUPPLY_STATUS_UNKNOWN;

    data->health = POWER_SUPPLY_HEALTH_GOOD;

    data ->capacity = 1;

    ret = power_supply_register(&pdev->dev, &data->battery);

    if (ret)

        goto err_battery_failed;

    platform_set_drvdata(pdev, data);

    battery_data = data;

    return 0;

err_battery_failed:

    kfree(data);

err_data_alloc_failed:

    return ret;

}

static int rk3288_battery_remove(struct platform_device *pdev)

{

    struct rk3288_battery_data *data = platform_get_drvdata(pdev);

    power_supply_unregister(&data->battery);

    kfree(data);

    battery_data = NULL;

    return 0;

}

static const struct of_device_id rk3288_battery[] = {

    { .compatible = "rk3288,battery" },

    { }

};

static struct platform_driver rk3288_battery_driver = {

    .probe        = rk3288_battery_probe,

    .remove        = rk3288_battery_remove,

    .driver = {

        .owner = THIS_MODULE,

        .name = "rk3288-battery",

        .of_match_table = of_match_ptr(rk3288_battery),

    }

};

static int __init rk3288_battery_init(void)

{

    return platform_driver_register(&rk3288_battery_driver);

}

static void __exit rk3288_battery_exit(void)

{

    platform_driver_unregister(&rk3288_battery_driver);

}

module_init(rk3288_battery_init);

module_exit(rk3288_battery_exit);

MODULE_AUTHOR("kris.fei");

MODULE_LICENSE("GPL");

MODULE_DESCRIPTION("Battery driver");

繼續閱讀