can't able to update the design capacity in bq27441-G1

简介: /*************************************************************************** * can't able to update the design capacity in bq27441-G1 * 声明...
/***************************************************************************
 *       can't able to update the design capacity in bq27441-G1
 * 声明:
 *     本文主要是记录分析bq27441-G1芯片无法修改一些参数的原因,主要是因为
 * bq27x00_powersupply_init中绑定了bq27x00_battery_poll作为定时任务,之后
 * 直接调用bq27x00_update获取电池信息,这个时候bq27x00_battery_poll还没有
 * 执行,所以第一次bq27x00_update获取的是默认的bq27441-G1信息,而在此之后
 * bq27x00_update中会对有些信息进行选择更新,所以造成了design capacity不
 * 准确。
 *
 *                                         2016-2-22 深圳 南山平山村 曾剑锋
 **************************************************************************/

/**
 * 参考文章:
 *     Application of bq27441-g1 with 3.X Linux kernel
 *         http://e2e.ti.com/support/power_management/battery_management/f/180/p/471744/1701660
 */


static int __init bq27x00_powersupply_init(struct bq27x00_device_info *di)
{
    int ret;

    di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
    if (di->chip == BQ274XX) {
        set_properties_array(di, bq274xx_battery_props,
            ARRAY_SIZE(bq274xx_battery_props));
    } else if (di->chip == BQ276XX) {
        set_properties_array(di, bq276xx_battery_props,
            ARRAY_SIZE(bq276xx_battery_props));
    } else if (di->chip == BQ27520) {
        set_properties_array(di, bq27520_battery_props,
            ARRAY_SIZE(bq27520_battery_props));
    } else if (di->chip == BQ2753X) {
        set_properties_array(di, bq2753x_battery_props,
            ARRAY_SIZE(bq2753x_battery_props));
    } else {
        set_properties_array(di, bq27x00_battery_props,
            ARRAY_SIZE(bq27x00_battery_props));
    }
    di->bat.get_property = bq27x00_battery_get_property;
    di->bat.external_power_changed = bq27x00_external_power_changed;

    INIT_DELAYED_WORK(&di->work, bq27x00_battery_poll); ------------------+
    mutex_init(&di->lock);                                                |
                                                                          |
    ret = power_supply_register(di->dev, &di->bat);                       |
    if (ret) {                                                            |
        dev_err(di->dev, "failed to register battery: %d\n", ret);        |
        return ret;                                                       |
    }                                                                     |
                                                                          |
    dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION);       |
                                                                          |
    bq27x00_update(di);                                 ------------------*------+
                                                                          |      |
    return 0;                                                             |      |
}                                                                         |      |
                                                                          |      |
static void bq27x00_battery_poll(struct work_struct *work)   <------------+      |
{                                                                                |
    struct bq27x00_device_info *di =                                             |
        container_of(work, struct bq27x00_device_info, work.work);               |
                                                                                 |
    if (((di->chip == BQ274XX) || (di->chip == BQ276XX)) &&                      |
        !rom_mode_gauge_dm_initialized(di)) {                                    |
        rom_mode_gauge_dm_init(di);                   -------------------+       |
    }                                                                    |       |
                                                                         |       |
    bq27x00_update(di);                               -------------------*-------+
                                                                         |       |
    if (poll_interval > 0) {                                             |       |
        /* The timer does not have to be accurate. */                    |       |
        set_timer_slack(&di->work.timer, poll_interval * HZ / 4);        |       |
        schedule_delayed_work(&di->work, poll_interval * HZ);            |       |
    }                                                                    |       |
}                                                                        |       |
                                                                         |       |
#define INITCOMP_TIMEOUT_MS     10000                                    |       |
static void rom_mode_gauge_dm_init(struct bq27x00_device_info *di)  <----+       |
{                                                                                |
    int i;                                                                       |
    int timeout = INITCOMP_TIMEOUT_MS;                                           |
    u8 subclass, offset;                                                         |
    u32 blk_number;                                                              |
    u32 blk_number_prev = 0;                                                     |
    u8 buf[32];                                                                  |
    bool buf_valid = false;                                                      |
    struct dm_reg *dm_reg;                                                       |
                                                                                 |
    dev_dbg(di->dev, "%s:\n", __func__);                                         |
                                                                                 |
    while (!rom_mode_gauge_init_completed(di) && timeout > 0) {                  |
        msleep(100);                                                             |
        timeout -= 100;                                                          |
    }                                                                            |
                                                                                 |
    if (timeout <= 0) {                                                          |
        dev_err(di->dev, "%s: INITCOMP not set after %d seconds\n",              |
            __func__, INITCOMP_TIMEOUT_MS/100);                                  |
        return;                                                                  |
    }                                                                            |
                                                                                 |
    if (!di->dm_regs || !di->dm_regs_count) {                                    |
        dev_err(di->dev, "%s: Data not available for DM initialization\n",       |
            __func__);                                                           |
        return;                                                                  |
    }                                                                            |
                                                                                 |
    enter_cfg_update_mode(di);                                                   |
    for (i = 0; i < di->dm_regs_count; i++) {                                    |
        dm_reg = &di->dm_regs[i];                                                |
        subclass = dm_reg->subclass;                                             |
        offset = dm_reg->offset;                                                 |
                                                                                 |
        /*                                                                       |
         * Create a composite block number to see if the subsequent              |
         * register also belongs to the same 32 btye block in the DM             |
         */                                                                      |
        blk_number = subclass << 8;                                              |
        blk_number |= offset >> 5;                                               |
                                                                                 |
        if (blk_number == blk_number_prev) {                                     |
            copy_to_dm_buf_big_endian(di, buf, offset,                           |
                dm_reg->len, dm_reg->data);                                      |
        } else {                                                                 |
                                                                                 |
            if (buf_valid)                                                       |
                update_dm_block(di, blk_number_prev >> 8,                        |
                    (blk_number_prev << 5) & 0xFF , buf);                        |
            else                                                                 |
                buf_valid = true;                                                |
                                                                                 |
            read_dm_block(di, dm_reg->subclass, dm_reg->offset,                  |
                buf);                                                            |
            copy_to_dm_buf_big_endian(di, buf, offset,                           |
                dm_reg->len, dm_reg->data);                                      |
        }                                                                        |
        blk_number_prev = blk_number;                                            |
    }                                                                            |
                                                                                 |
    /* Last buffer to be written */                                              |
    if (buf_valid)                                                               |
        update_dm_block(di, subclass, offset, buf);                              |
                                                                                 |
    exit_cfg_update_mode(di);                                                    |
}                                                                                |
                                                                                 |
static void bq27x00_update(struct bq27x00_device_info *di)      <----------------+
{
    struct bq27x00_reg_cache cache = {0, };
    bool is_bq27200 = (di->chip == BQ27200);
    bool is_bq27500 = (di->chip == BQ27500);
    bool is_bq274xx = (di->chip == BQ274XX);
    bool is_bq276xx = (di->chip == BQ276XX);

    cache.flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, !is_bq27500);
    if (cache.flags >= 0) {
        if (is_bq27200 && (cache.flags & BQ27200_FLAG_CI)) {
            dev_info(di->dev, "battery is not calibrated! ignoring capacity values\n");
            cache.capacity = -ENODATA;
            cache.energy = -ENODATA;
            cache.time_to_empty = -ENODATA;
            cache.time_to_empty_avg = -ENODATA;
            cache.time_to_full = -ENODATA;
            cache.charge_full = -ENODATA;
            cache.health = -ENODATA;
        } else {
            cache.capacity = bq27x00_battery_read_soc(di);
            if (!(is_bq274xx || is_bq276xx)) {
                cache.energy = bq27x00_battery_read_energy(di);
                cache.time_to_empty =
                    bq27x00_battery_read_time(di,
                            BQ27XXX_REG_TTE);
                cache.time_to_empty_avg =
                    bq27x00_battery_read_time(di,
                            BQ27XXX_REG_TTECP);
                cache.time_to_full =
                    bq27x00_battery_read_time(di,
                            BQ27XXX_REG_TTF);
            }
            cache.charge_full = bq27x00_battery_read_fcc(di);
            cache.health = bq27x00_battery_read_health(di);
        }
        cache.temperature = bq27x00_battery_read_temperature(di);
        if (!is_bq274xx)
            cache.cycle_count = bq27x00_battery_read_cyct(di);
        cache.power_avg =
            bq27x00_battery_read_pwr_avg(di, BQ27XXX_POWER_AVG);

        /* We only have to read charge design full once */
        if (di->charge_design_full <= 0)       // pay attention at here
            di->charge_design_full = bq27x00_battery_read_dcap(di);

        printk("---------------------------------------\n");
        printk("cache.capacity : %d\n", cache.capacity);
        printk("cache.energy : %d\n", cache.energy);
        printk("cache.time_to_empty : %d\n", cache.time_to_empty);
        printk("cache.charge_full : %d\n", cache.charge_full);
        printk("cache.health : %d\n", cache.health);
        printk("cache.tmperature : %d\n", cache.temperature);
        printk("cache.power_avg : %d\n", cache.power_avg);
        printk("di->charge_design_full : %d\n", di->charge_design_full);
        printk("---------------------------------------\n");
    }

    if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) {
        di->cache = cache;
        power_supply_changed(&di->bat);
    }

    di->last_update = jiffies;
}

 

目录
相关文章
|
18天前
|
监控 算法
Error: 500-InternalError, Out of host capacity.
【10月更文挑战第28天】Error: 500-InternalError, Out of host capacity.
27 5
|
5月前
|
存储 运维 网络协议
CloudStack 中 op_host_capacity 表中的 capacity_type 取值详解
CloudStack 中 op_host_capacity 表中的 capacity_type 取值详解
|
存储 算法 BI
SAP WM初阶之LX04 Capacity Load Utilization
SAP WM初阶之LX04 Capacity Load Utilization
SAP WM初阶之LX04 Capacity Load Utilization
|
存储 知识图谱
SAP WM中阶Storage Type的Capacity Check – Check According to Maximum Weight
SAP WM中阶Storage Type的Capacity Check – Check According to Maximum Weight
SAP WM中阶Storage Type的Capacity Check – Check According to Maximum Weight
SAP WM中阶Storage Type的Capacity Check – Check based on palletization according to SUT 1
SAP WM中阶Storage Type的Capacity Check – Check based on palletization according to SUT 1
SAP WM中阶Storage Type的Capacity Check – Check based on palletization according to SUT 1
SAP WM中阶Storage Type的Capacity Check – Usage check based on material
SAP WM中阶Storage Type的Capacity Check – Usage check based on material
SAP WM中阶Storage Type的Capacity Check – Usage check based on material
SAP WM Storage Type Capacity Check Method 5 (Usage check based on SUT)
SAP WM Storage Type Capacity Check Method 5 (Usage check based on SUT)
SAP WM Storage Type Capacity Check Method 5 (Usage check based on SUT)
SAP WM中阶Storage Type的Capacity Check – Usage check based on SUT
SAP WM中阶Storage Type的Capacity Check – Usage check based on SUT
SAP WM中阶Storage Type的Capacity Check – Usage check based on SUT
SAP WM中阶Storage Type的Capacity Check – Check based on maximum quantity per bin in storage type.
SAP WM中阶Storage Type的Capacity Check – Check based on maximum quantity per bin in storage type.
SAP WM中阶Storage Type的Capacity Check – Check based on maximum quantity per bin in storage type.