展讯sprd_battery.c 充电驱动

sprd_battery.c 是充电驱动,这个是充电功能的核心内容,电量显示策略、温度检测策略、充电保护机制等功能在这里实现,功能实现与硬件细节剥离,调用通用接口实现逻辑控制;

1 sprdbat_probe函数:


static int sprdbat_probe(struct platform_device *pdev)
{
    int ret = -ENODEV;
    enum usb_charger_state usb_online_state = USB_CHARGER_DEFAULT;
    struct power_supply *ret_ptr = NULL;
    struct sprdbat_drivier_data *data = NULL;
    struct device_node *np = pdev->dev.of_node;
    struct power_supply_desc *battery_desc = NULL,
        *ac_desc = NULL, *usb_desc = NULL;
    struct power_supply_config battery_cfg = {}, ac_cfg = {}, usb_cfg = {};

    if (!np) {
        dev_err(&pdev->dev, "device node not found\n");
        return -EINVAL;
    }
    if (sprd_ext_ic_op == NULL) {
        dev_err(&pdev->dev, "sprd_ext_ic_op not found\n");
        return -EINVAL;
    }

    data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
    if (data == NULL) {
        ret = -ENOMEM;
        goto err_data_alloc_failed;
    }

    data->pdata = sprdbat_parse_dt(pdev);
    if (IS_ERR_OR_NULL(data->pdata))
        return -ENOMEM;

    data->dev = &pdev->dev;
    platform_set_drvdata(pdev, data);
    sprdbat_data = data;

    //通过ADC获取温度
    data->pdata->channel_temp = iio_channel_get(data->dev, "adc_temp");
    if (IS_ERR(data->pdata->channel_temp)) {
        ret = PTR_ERR(data->pdata->channel_temp);
        goto err_iio_get_temp;
    }

    //通过ADC获取vbat电压
    data->pdata->channel_vbat = iio_channel_get(data->dev, "adc_vbat");
    if (IS_ERR(data->pdata->channel_vbat)) {
        ret = PTR_ERR(data->pdata->channel_vbat);
        goto err_iio_get_vbat;
    }

    //通过ADC获取充电电压
    data->pdata->channel_vchg = iio_channel_get(data->dev, "adc_vchg");
    if (IS_ERR(data->pdata->channel_vchg)) {
        ret = PTR_ERR(data->pdata->channel_vchg);
        goto err_iio_get_vchg;
    }
    print_pdata(sprdbat_data->pdata);
    battery_desc = devm_kzalloc(&pdev->dev,
        sizeof(struct power_supply_desc), GFP_KERNEL);
    if (battery_desc == NULL) {
        ret = -ENOMEM;
        goto err_desc_alloc_failed;
    }

    //注册battery 的power_supply接口,这个为上层提供电量、充电状态等的接口
    battery_desc->properties = sprdbat_battery_props;
    battery_desc->num_properties = ARRAY_SIZE(sprdbat_battery_props);
    battery_desc->get_property = sprdbat_battery_get_property;
    battery_desc->set_property = sprdbat_battery_set_property;
    battery_desc->property_is_writeable =
            sprdbat_battery_property_is_writeable;
    battery_desc->name = "battery";
    battery_desc->type = POWER_SUPPLY_TYPE_BATTERY;
    battery_desc->no_thermal = true;
    battery_cfg.drv_data = sprdbat_data;

    ac_desc = devm_kzalloc(&pdev->dev,
        sizeof(struct power_supply_desc), GFP_KERNEL);
    if (ac_desc == NULL) {
        ret = -ENOMEM;
        goto err_desc_alloc_failed;
    }
    ac_desc->properties = sprdbat_ac_props;
    ac_desc->num_properties = ARRAY_SIZE(sprdbat_ac_props);
    ac_desc->get_property = sprdbat_ac_get_property;
    ac_desc->set_property = sprdbat_ac_set_property;
    ac_desc->property_is_writeable =
            sprdbat_ac_property_is_writeable;

    //注册AC的充电power_supply接口
    ac_desc->name = "ac";
    ac_desc->type = POWER_SUPPLY_TYPE_MAINS;
    ac_desc->no_thermal = true;
    ac_cfg.drv_data = sprdbat_data;

    //usb接口的接口
    usb_desc = devm_kzalloc(&pdev->dev,
        sizeof(struct power_supply_desc), GFP_KERNEL);
    if (usb_desc == NULL) {
        ret = -ENOMEM;
        goto err_desc_alloc_failed;
    }
    usb_desc->properties = sprdbat_usb_props;
    usb_desc->num_properties = ARRAY_SIZE(sprdbat_usb_props);
    usb_desc->get_property = sprdbat_usb_get_property;
    usb_desc->name = "usb";
    usb_desc->type = POWER_SUPPLY_TYPE_USB;
    usb_desc->no_thermal = true;
    usb_cfg.drv_data = sprdbat_data;

    data->start_charge = sprdbat_start_charge;
    data->stop_charge = sprdbat_stop_charge;

    ret_ptr = power_supply_register(&pdev->dev, battery_desc, &battery_cfg);
    if (IS_ERR(ret_ptr)) {
        goto err_battery_failed;
    } else {
        data->battery = ret_ptr;
        data->battery->supplied_to = battery_supply_list;
        data->battery->num_supplicants =
            ARRAY_SIZE(battery_supply_list);
    }

    ret_ptr = power_supply_register(&pdev->dev, ac_desc, &ac_cfg);
    if (IS_ERR(ret_ptr)) {
        goto err_ac_failed;
    } else {
        data->ac = ret_ptr;
        data->ac->supplied_to = supply_list;
        data->ac->num_supplicants = ARRAY_SIZE(supply_list);
    }

    ret_ptr = power_supply_register(&pdev->dev, usb_desc, &usb_cfg);
    if (IS_ERR(ret_ptr)) {
        goto err_usb_failed;
    } else {
        data->usb = ret_ptr;
        data->usb->supplied_to = supply_list;
        data->usb->num_supplicants = ARRAY_SIZE(supply_list);
    }

    /*
     * TODO: switch polling to interrupt again need open this code.
     * data->chg_nb.notifier_call = sprdbat_chg_event_call;
     * ret = power_supply_reg_notifier(&data->chg_nb);
     *
     * if (ret)
     *  dev_err(data->dev, "failed to reg notifier: %d\n", ret);
     */
     //注册文件节点
    ret = sysfs_create_group(&data->battery->dev.kobj,
            &sprd_bat_group);
    if (ret) {
        dev_err(&pdev->dev,
            "failed to create sprd_bat sysfs device attributes\n");
        goto err_sysfs_create_gr;
    }

    //vbat检测脚
    data->gpio_vbat_detect = data->pdata->gpio_vbat_detect;
    if (data->gpio_vbat_detect > 0) {
        devm_gpio_request(&pdev->dev,
            data->gpio_vbat_detect, "vbat_detect");
        gpio_direction_input(data->gpio_vbat_detect);
        data->irq_vbat_detect = gpio_to_irq(data->gpio_vbat_detect);

        irq_set_status_flags(data->irq_vbat_detect, IRQ_NOAUTOEN);
        ret =
            devm_request_threaded_irq(&pdev->dev,
            data->irq_vbat_detect, NULL,
            sprdbat_vbat_detect_irq,
            IRQ_TYPE_LEVEL_LOW | IRQF_NO_SUSPEND,
            "sprdbat_vbat_detect", data);
        if (ret)
            dev_err(&pdev->dev, "failed to use vbat gpio: %d\n",
                ret);
    }

    //otg 使能管脚
    data->gpio_otg_en = data->pdata->gpio_otg_en;
    if (data->gpio_otg_en > 0) {
        devm_gpio_request(&pdev->dev,
            data->gpio_otg_en, "otg_en");
        ret = gpio_direction_output(data->gpio_otg_en, 0);
        if (ret)
            dev_err(&pdev->dev, "failed to use otg_en gpio: %d\n",
                ret);
    }

    data->bat_info.bat_present = 1;

    mutex_init(&data->lock);

    //充电睡眠唤醒锁
    wake_lock_init(&(data->charger_wake_lock), WAKE_LOCK_SUSPEND,
               "charger_wake_lock");

    //初始化电池工作队列
    INIT_DELAYED_WORK(&data->battery_work, sprdbat_battery_works);

    //初始化电池睡眠队列
    INIT_DELAYED_WORK(&data->battery_sleep_work,
              sprdbat_battery_sleep_works);

    //初始化电池检测中断的队列
    INIT_WORK(&data->vbat_detect_irq_work, sprdbat_vbat_detect_irq_works);
    //电池拔插队列
    INIT_WORK(&data->plug_work, sprdbat_plug_works);
    //电池充电队列
    INIT_DELAYED_WORK(&sprdbat_data->sprdbat_charge_work,
              sprdbat_charge_works);
    data->monitor_wqueue = create_freezable_workqueue("sprdbat_monitor");
    if (data->monitor_wqueue == NULL)
        goto err_create_wq;

    //充电初始化
    sprdchg_init(data->pdata);
    //库仑计的初始化
    sprdfgu_init(data->pdata);

    if (sprdchg_timer_op->timer_request)
        sprdchg_timer_op->timer_request(sprdbat_timer_handler,
        data->pdata);
    else
        SPRDBAT_DEBUG("warning !!charge timer ops = null\n");

    //充电led的控制
#ifdef CONFIG_LEDS_TRIGGERS
    data->charging_led.name = "sprdbat_charging_led";
    data->charging_led.default_trigger = "battery-charging";
    data->charging_led.brightness_set = sprdchg_led_brightness_set;
    ret = led_classdev_register(&pdev->dev, &data->charging_led);
    if (ret)
        goto err_led_reg;
#endif

    sprd_ext_ic_op->ic_init(sprdbat_data);
    sprdbat_info_init(data);

    SPRDBAT_DEBUG("register_usb_notifier\n");
    //注册usb插拔的回调函数
    sprdbat_data->usb_charger =
        usb_charger_find_by_name("usb-charger.0");
    if (IS_ERR(sprdbat_data->usb_charger)) {
        ret = -EPROBE_DEFER;
        dev_err(&pdev->dev,
            "Failed to find USB gadget: %d\n", ret);
        goto err_usb_find_name;
    }

    //这个函数实质上回调了工作队列plug_work,也就是调用了sprdbat_plug_works
    sprdbat_data->chg_usb_nb.notifier_call = sprdbat_usb_plug_event;

    ret = usb_charger_register_notify(sprdbat_data->usb_charger,
                      &sprdbat_data->chg_usb_nb);
    if (ret != 0) {
        dev_err(&pdev->dev,
            "Failed to register notifier: %d\n", ret);
        goto err_usb_reg_notify;
    }
    sprdbat_data->usb_charger->get_charger_type =
        sprdchg_charger_is_adapter_for_usb;

    //获取usb的状态
    usb_online_state = usb_charger_get_state(sprdbat_data->usb_charger);
    if (usb_online_state == USB_CHARGER_PRESENT)
        queue_work(sprdbat_data->monitor_wqueue,
           &sprdbat_data->plug_work);

    if (data->gpio_vbat_detect > 0)
        enable_irq(sprdbat_data->irq_vbat_detect);

    queue_delayed_work(system_power_efficient_wq,
            &data->battery_work, 15 * HZ);
    SPRDBAT_DEBUG("sprdbat_probe----------end\n");
    return 0;

err_usb_reg_notify:
err_usb_find_name:
#ifdef CONFIG_LEDS_TRIGGERS
    led_classdev_unregister(&data->charging_led);
err_led_reg:
#endif
    destroy_workqueue(data->monitor_wqueue);
err_create_wq:
    sysfs_remove_group(&data->battery->dev.kobj,
               &sprd_bat_group);
err_sysfs_create_gr:
    power_supply_unregister(data->usb);
err_usb_failed:
    power_supply_unregister(data->ac);
err_ac_failed:
    power_supply_unregister(data->battery);
err_battery_failed:
    iio_channel_release(data->pdata->channel_vchg);
err_desc_alloc_failed:
    sprdbat_data = NULL;
err_iio_get_vchg:
    iio_channel_release(data->pdata->channel_vbat);
err_iio_get_vbat:
    iio_channel_release(data->pdata->channel_temp);
err_iio_get_temp:
err_data_alloc_failed:
    sprdbat_data = NULL;
    return ret;

}

1.1 解析设备树:

sprdbat_parse_dt函数如下:

battery-adapt-fun:电池兼容函数索引0 即为电池 ID识别
battery-adapt-support:电池兼容开关
charger-det-gpios:充电检测管脚
otg-en-gpios:otg使能管脚
chg-end-vol-check:检查充电是否满的电压(单位为mv)
chg-bat-safety-vol:充电时蓄电池的安全电压
rechg-vol:注意这里可以去掉复充电压
adp-cdp-cur:cdp充电电流(单位为ma)
adp-dcp-cur:dcp充电电流(单位为ma)
adp-sdp-cur :sdp充电电流(单位为ma)
adp-unknown-cur:未知充电电流
adp-fchg-cur:快充充电电流
adp-cdp-cur-limit:用于POWER_SUPPLY_PROP_CURRENT_MAX节点,为CDP类型的最大限制
adp-dcp-cur-limit:为DCP类型的最大限制
adp-unknown-cur-limit:为unknown类型的最大限制
adp-fchg-cur-limit:为快充类型的最大限制
ovp-stop:过电压保护:停止充电电压(mv)
ovp-restart:过电压保护:过压恢复电压
fchg-ovp-stop:快充过电压保护:停止充电电压(mv)
fchg-ovp-restart:快充过电压保护:重启充电电压(mv)
chg-timeout :充电超时,最终在函数sprdbat_is_chg_timeout调用到
chg-rechg-timeout:复充超时
trickle-timeout:涓流超时
chg-end-cur:充电端电流
chg-polling-time:充电状态检查周期(单位:s)
chg-polling-time-fast:
cap-one-per-time:每个百分比变化最短时间
cap-valid-range-poweron:应该是保存的电池容量,不确定,设备树里暂时没有用到过
temp-support:温度检测开关
temp-comp-res:读取温度补偿电阻器
only-vol-mode:获取电池容量模式,仅电压模式
fgu-mode:库仑计模式
chg-full-condition:满电判断条件电流电压或者外置 IC
alm_soc:暂且没看到用的地方
soft-vbat-uvlo :低电压关机
rint:电池内阻
cnom:电池容量
rsense-real:fgu 对地电阻真实阻抗
rsense-spec:fgu 对地电阻真实理论值
relax-current:进入 relax 模式下的电流值
fgu-cal-ajust:fgu校准偏移
temp-tab-val:ntc电阻表电压
charge-vol-tab:对应charge-vol-tab-cap,电压对应电量,只有电压测量方式
charge-vol-tab-cap:电量表
ocv-tab-vol:开路电压测量对应ocv-tab-cap
ocv-tab-cap:电量表
discharge-vol-tab:未充电的开路电压表,只有电压测量方式
discharge-vol-tab-cap:电量表

JEITA 功能:可以根据温度,提供动态修正充电电流及恒压电压的功能
jeita-temp-tab 设置的对应温度点
为调整点对充电电流及恒压电压做调整;jeita-temp-recovery-tab 设置的温度点为温区恢复点;
温度变化到更高或者更低区间后如果恢复回来有 3℃的缓冲区
每个区间对应的电流值和电压值在 jeita-cur-tab 和 jeita-cccv-tab
cnom-temp-tab:电池容量和温度的表格,
rint-temp-tab:电池内阻和温度的表格

2. 各个工作队列的作用:

2.1 sprdbat_battery_works函数

这个函数是在probe函数中最后调用到的,也就是一开始probe的时候就会调用到的

static void sprdbat_battery_works(struct work_struct *work)
{
    SPRDBAT_DEBUG("sprdbat_battery_works\n");

    mutex_lock(&sprdbat_data->lock);

    //由设备树可知,only_vol_mode是不存在的,所以读取vbat的电压和开路电压
    if (!sprdbat_data->pdata->only_vol_mode) {
        sprdbat_data->bat_info.vbat_vol = sprdbat_read_vbat_vol();
        sprdbat_data->bat_info.vbat_ocv = sprdfgu_read_vbat_ocv();
    }

    //更新电池信息里的温度
    sprdbat_data->bat_info.last_temp =
            sprdbat_data->bat_info.cur_temp;
    if (jeita_debug_enable)
        sprdbat_data->bat_info.cur_temp = jeita_debug;
    else
        sprdbat_data->bat_info.cur_temp = sprdbat_read_temp();

    //读取现在库仑计读数
    sprdbat_data->bat_info.bat_current = sprdfgu_read_batcurrent();

    //读取充电电压
    sprdbat_data->bat_info.vchg_vol = sprdchg_read_vchg_vol();

    //读取现在充电平均电压
    sprdbat_data->bat_info.avg_chg_vol =
        sprdbat_get_avgval_from_buff(sprdbat_data->bat_info.vchg_vol,
                     chg_vol_buff, VOL_BUFF_CNT, 0);

    //读取现在库仑计平均读数
    sprdbat_data->bat_info.bat_current_avg =
        sprdbat_get_avgval_from_buff(sprdbat_data->bat_info.bat_current,
                     current_buff, CUR_BUFF_CNT, 1);
    if (sprdbat_data->pdata->only_vol_mode) {
        if (sprdbat_data->bat_info.module_state ==
            POWER_SUPPLY_STATUS_DISCHARGING ||
            sprdbat_data->bat_info.module_state ==
            POWER_SUPPLY_STATUS_UNKNOWN) {
            sprdbat_data->bat_info.vbat_vol =
                sprdbat_read_vbat_vol();
            sprdbat_data->bat_info.vbat_ocv =
                sprdfgu_read_vbat_ocv();
            sprdbat_update_capacty();
        }
    } else {
        //更新电池电量
        sprdbat_update_capacty();
    }

    mutex_unlock(&sprdbat_data->lock);
    sprdbat_print_battery_log();
    //不断轮询
    queue_delayed_work(system_power_efficient_wq,
               &sprdbat_data->battery_work,
               15 * HZ);
}

其中函数sprdbat_update_capacty更新电池电量:

static void sprdbat_update_capacty(void)
{
    uint32_t fgu_capacity;
    int flush_time = 0;
    int period_time = 0;
    struct timespec64 cur_time;
    int chging_flag;

    if (sprdbat_data->bat_info.capacity == ~0U)
        return;

    if (sprdbat_data->pdata->only_vol_mode) {
        if (sprdbat_data->bat_info.module_state ==
            POWER_SUPPLY_STATUS_CHARGING)
            chging_flag = 1;
        else
            chging_flag = 0;

        fgu_capacity = sprdfgu_only_vol_read_capacity(chging_flag);
    } else {
        fgu_capacity = sprdfgu_read_capacity();
    }

    cur_time = ktime_to_timespec64(ktime_get_boottime());

    if (POWER_SUPPLY_STATUS_CHARGING ==
        sprdbat_data->bat_info.module_state) {
        if (sprdbat_data->bat_info.capacity >= 99) {
            trickle_time = cur_time.tv_sec -
                trickle_s_time;
        } else {
            trickle_s_time = cur_time.tv_sec;
            trickle_time = 0;
        }
    } else {
        //直接进入到这里
        //涓流时间trickle_s_time=现在时间
        trickle_s_time = cur_time.tv_sec;
        //trickle_time = 涓流超时时间+周期变化时间+1
        trickle_time = sprdbat_data->pdata->trickle_timeout +
            sprdbat_data->pdata->cap_one_per_time + 1;
    }

    SPRDBAT_DEBUG("trickle_s_time: = %lld,trickle_time: = %d\n",
            trickle_s_time, trickle_time);
    //刷新时间 =  现在时间 - 电量变化时间
    //sprdbat_update_capacity_time这个时间会在fgu_capacity != sprdbat_data->bat_info.capacity产生变化
    flush_time =
        (int)(cur_time.tv_sec -
        sprdbat_data->sprdbat_update_capacity_time);

    //周期时间为每次调用sprdbat_update_capacty的cur_time-上一次调用该函数的时间
    period_time =
        (int)(cur_time.tv_sec -
        sprdbat_data->sprdbat_last_query_time);
    sprdbat_data->sprdbat_last_query_time = cur_time.tv_sec;

    SPRDBAT_DEBUG("fgu_cap: = %d,flush: = %d,period:=%d\n",
              fgu_capacity, flush_time, period_time);

    //根据不同状态来确定充电时间:
    switch (sprdbat_data->bat_info.module_state) {
    case POWER_SUPPLY_STATUS_CHARGING:
        //如果是充电状态,但是计算出来的电量跟上一次的小,那就属于不正常的情况
        if (fgu_capacity < sprdbat_data->bat_info.capacity) {
            //电流大于0,避免下降
            if (sprdfgu_read_batcurrent() >= 0) {
                pr_info("avoid vol jumping\n");
                fgu_capacity = sprdbat_data->bat_info.capacity;
            } else {
                //假设周期时间小于最大更新时间,则正常减1
                if (period_time <
                    sprdbat_data->pdata->cap_one_per_time) {
                    fgu_capacity =
                        sprdbat_data->bat_info.capacity - 1;
                    SPRDBAT_DEBUG
                        ("cap decrease fgu_cap:=%d\n",
                        fgu_capacity);
                }
                //精度化一下电量
                if ((sprdbat_data->bat_info.capacity -
                     fgu_capacity) >=
                    (flush_time /
                     sprdbat_data->pdata->cap_one_per_time)) {
                    fgu_capacity =
                        sprdbat_data->bat_info.capacity -
                        flush_time /
                        sprdbat_data->pdata->
                        cap_one_per_time;
                }

            }
        } else if (fgu_capacity > sprdbat_data->bat_info.capacity) {
            //假设周期时间小于最大更新时间,则正常加1
            if (period_time < sprdbat_data->
                pdata->cap_one_per_time) {
                fgu_capacity =
                    sprdbat_data->bat_info.capacity + 1;
                SPRDBAT_DEBUG
                    ("avoid  jumping! fgu_cap: = %d\n",
                     fgu_capacity);
            }
            //精度化一下电量
            if ((fgu_capacity - sprdbat_data->bat_info.capacity) >=
                (flush_time /
                 sprdbat_data->pdata->cap_one_per_time)) {
                fgu_capacity =
                    sprdbat_data->bat_info.capacity +
                    flush_time /
                    sprdbat_data->pdata->cap_one_per_time;
            }
        }

        //我认为是还未更新到正常电量,但是adc算出的已经是100,但这时候显示的是99;
        if ((sprdbat_data->bat_info.capacity != 100)
            && (fgu_capacity >= 100)) {
            fgu_capacity = 99;
        }

        //涓流充电流程
        if ((sprdbat_data->bat_info.capacity >= 99) &&
            (trickle_time >= sprdbat_data->pdata->trickle_timeout) &&
            (sprdbat_data->pdata->trickle_timeout > 0)) {
            SPRDBAT_DEBUG("cap is full, but charge continue\n");
            sprdbat_change_module_state
                (SPRDBAT_CHARGING_TO_FULL_E);
        }

        //低电量关机
        if (sprdbat_data->bat_info.vbat_vol <=
            (sprdbat_data->pdata->soft_vbat_uvlo -
             SPRDBAT_SHUTDOWN_OFSSET)) {
            fgu_capacity = 0;
            SPRDBAT_DEBUG("soft uvlo, shutdown by kernel.. vol:%d",
                      sprdbat_data->bat_info.vbat_vol);
            orderly_poweroff(true);
        }

        break;
    case POWER_SUPPLY_STATUS_NOT_CHARGING:
    case POWER_SUPPLY_STATUS_DISCHARGING:
        //未充电状态不应该是计算出来的电量大于原来的电量,所以继续保持原来的电量
        if (fgu_capacity >= sprdbat_data->bat_info.capacity) {
            fgu_capacity = sprdbat_data->bat_info.capacity;
        } else {
            //否则则慢慢下降
            if (period_time < sprdbat_data->
                pdata->cap_one_per_time) {
                fgu_capacity =
                    sprdbat_data->bat_info.capacity - 1;
                SPRDBAT_DEBUG
                    ("avoid jumping! fgu_capacity: = %d\n",
                     fgu_capacity);
            }
            //同样也是精度化
            if ((sprdbat_data->bat_info.capacity - fgu_capacity) >=
                (flush_time /
                 sprdbat_data->pdata->cap_one_per_time)) {
                fgu_capacity =
                    sprdbat_data->bat_info.capacity -
                    flush_time /
                    sprdbat_data->pdata->cap_one_per_time;
            }
        }
        break;
    case POWER_SUPPLY_STATUS_FULL:
        //展讯平台是根据电量来复充的
        sprdbat_data->sprdbat_update_capacity_time = cur_time.tv_sec;
        //假设计算出来的电压小于复充电压-150且不在充电的情况
        if ((sprdbat_data->bat_info.vbat_ocv <
             (sprdbat_data->pdata->rechg_vol - 150))
            && sprdfgu_read_batcurrent() < 0) {
            SPRDBAT_DEBUG("vbat_ocv < rechg_vol -150\n");
            //从满电状态转换为充电状态
            sprdbat_change_module_state(SPRDBAT_FULL_TO_CHARGING_E);
        }
        //电量保持100%
        if (fgu_capacity != 100)
            fgu_capacity = 100;

        if (sprdbat_data->bat_info.vbat_vol <=
            (sprdbat_data->pdata->soft_vbat_uvlo -
             SPRDBAT_SHUTDOWN_OFSSET)) {
            fgu_capacity = 0;
            SPRDBAT_DEBUG
                ("soft uvlo, shutdown by kernel status full\n");
            SPRDBAT_DEBUG("vol:%d",
                sprdbat_data->bat_info.vbat_vol);
            orderly_poweroff(true);
        }

        break;
    default:
        break;
    }

    //低电压关机
    if (sprdbat_data->bat_info.vbat_vol <=
        sprdbat_data->pdata->soft_vbat_uvlo) {
        fgu_capacity = 0;
        SPRDBAT_DEBUG("soft uvlo, vbat very low,level..0.. vol:%d",
                  sprdbat_data->bat_info.vbat_vol);
    }

    //更新时间状态,并且用power_supply_changed给上层切换状态
    if (fgu_capacity != sprdbat_data->bat_info.capacity) {
        sprdbat_data->bat_info.capacity = fgu_capacity;
        sprdbat_data->sprdbat_update_capacity_time = cur_time.tv_sec;
        sprdfgu_record_cap(sprdbat_data->bat_info.capacity);
        power_supply_changed(sprdbat_data->battery);
    } else {
        if (sprdbat_data->bat_info.cur_temp !=
            sprdbat_data->bat_info.last_temp)
            power_supply_changed(sprdbat_data->battery);
    }

}

2.2 sprdbat_battery_sleep_works函数

此函数是为了唤醒电量计算的功能,在sprdbat_resume函数调用:


static void sprdbat_battery_sleep_works(struct work_struct *work)
{
    SPRDBAT_DEBUG("sprdbat_battery_sleep_works\n");
    if (!queue_delayed_work(system_power_efficient_wq,
        &sprdbat_data->battery_work, 0)) {
        cancel_delayed_work_sync(&sprdbat_data->battery_work);
        queue_delayed_work(system_power_efficient_wq,
            &sprdbat_data->battery_work, 0);
    }
}

其本质意义就是重新调用电池计算的功能定时器;

2.3 sprdbat_vbat_detect_irq_works函数:

此函数是在sprdbat_vbat_detect_irq中断检测到调用的:

当vbat检测管脚为低电量时,则进入该中断

devm_request_threaded_irq(&pdev->dev,
            data->irq_vbat_detect, NULL,
            sprdbat_vbat_detect_irq,
            IRQ_TYPE_LEVEL_LOW | IRQF_NO_SUSPEND,
            "sprdbat_vbat_detect", data);

static __used irqreturn_t sprdbat_vbat_detect_irq(int irq, void *dev_id)
{
    disable_irq_nosync(sprdbat_data->irq_vbat_detect);
    SPRDBAT_DEBUG("battery detect handle!!!!\n");
    queue_work(sprdbat_data->monitor_wqueue,
           &sprdbat_data->vbat_detect_irq_work);
    return IRQ_HANDLED;
}

sprdbat_vbat_detect_irq_works函数:


static void sprdbat_vbat_detect_irq_works(struct work_struct *work)
{
    int value;

    value = gpio_get_value(sprdbat_data->gpio_vbat_detect);
    SPRDBAT_DEBUG("bat_detect value:0x%x\n", value);
    mutex_lock(&sprdbat_data->lock);

    //假设高电平进入此中断,那属于不正常的情况
    if (value) {
        if (!sprdbat_data->bat_info.bat_present) {
            sprdbat_data->bat_info.bat_present = 1;
            //电池拔出后重新插入
            sprdbat_change_module_state
                (SPRDBAT_CHG_UNSPEC_RESTART_E);
            //假设是不是在非充电状态
            if (POWER_SUPPLY_STATUS_DISCHARGING !=
                sprdbat_data->bat_info.module_state)
                sprdbat_data->start_charge();
            SPRDBAT_DEBUG("vbat_detect-start_charge!!!!\n");
        }
        irq_set_irq_type(sprdbat_data->irq_vbat_detect,
            IRQ_TYPE_LEVEL_LOW);
    } else {
        //电池拔出
        sprdbat_data->bat_info.bat_present = 0;
        sprdbat_change_module_state(SPRDBAT_CHG_UNSPEC_E);
        //停止充电
        sprdbat_data->stop_charge();
        SPRDBAT_DEBUG("vbat_detect-stop_charge!!!!\n");
        irq_set_irq_type(sprdbat_data->irq_vbat_detect,
            IRQ_TYPE_LEVEL_HIGH);
    }
    enable_irq(sprdbat_data->irq_vbat_detect);
    mutex_unlock(&sprdbat_data->lock);
}

2.4 sprdbat_plug_works函数

在usb插入的回调函数sprdbat_usb_plug_event中会使用,在probe如果初始状态也是会使用:


static void sprdbat_plug_works(struct work_struct *work)
{
    if (usb_charger_get_state(sprdbat_data->usb_charger)
        == USB_CHARGER_PRESENT)
        plugin_callback();
    else
        plugout_callback();
}

static int plugin_callback(void)
{
    SPRDBAT_DEBUG("charger plug in interrupt happen\n");

    mutex_lock(&sprdbat_data->lock);
    sprdbat_data->sprdbat_vbat_ovp_cnt = 0;

    //排除异常情况
    if (sprdbat_data->bat_info.module_state
        != POWER_SUPPLY_STATUS_DISCHARGING) {
        mutex_unlock(&sprdbat_data->lock);
        return 0;
    }

    sprdbat_data->bat_info.adp_type = sprdchg_charger_is_adapter();
    if ((sprdbat_data->bat_info.adp_type == SDP_TYPE) ||
        (sprdbat_data->bat_info.adp_type == CDP_TYPE)) {
        sprdbat_data->bat_info.usb_online = 1;
        power_supply_changed(sprdbat_data->usb);
    } else {
        sprdbat_data->bat_info.ac_online = 1;
        power_supply_changed(sprdbat_data->ac);
    }

    sprdbat_data->bat_info.chgr_temp
        = sprdbat_get_avg_chgr_temp(NORMAL_TEMP, true);

    //充电器插入
    sprdbat_change_module_state(SPRDBAT_ADP_PLUGIN_E);
    sprdbat_adp_plug_nodify(1);
    //快充检测
    sprdbat_fchg_detect();
    sprdbat_charge_prepare();
    //开始充电,回调内部充电里面的函数
    sprdbat_data->start_charge();
    if (sprdchg_timer_op->timer_enable) {
        u32 polling_time = sprdbat_data->pdata->chg_polling_time;

        if (sprdbat_data->pdata->only_vol_mode)
            sprdchg_timer_op->timer_enable(polling_time, ONE_TIME);
        else
            sprdchg_timer_op->timer_enable(polling_time,
                               PERIOD_TIME);
    }

    mutex_unlock(&sprdbat_data->lock);

    SPRDBAT_DEBUG("plugin_callback:adp_type:%d\n",
              sprdbat_data->bat_info.adp_type);
    SPRDBAT_DEBUG("plugin_callback: end...\n");
    return 0;
}

static int plugout_callback(void)
{
    uint32_t adp_type = sprdbat_data->bat_info.adp_type;

    SPRDBAT_DEBUG("charger plug out interrupt happen\n");

    mutex_lock(&sprdbat_data->lock);

    if (sprdbat_data->bat_info.module_state
        == POWER_SUPPLY_STATUS_DISCHARGING) {
        mutex_unlock(&sprdbat_data->lock);
        return 0;
    }

    disable_irq_nosync(sprdbat_data->irq_vchg_ovi);

    if (sprdchg_timer_op->timer_disable)
        sprdchg_timer_op->timer_disable();

    sprdbat_change_module_state(SPRDBAT_ADP_PLUGOUT_E);
    sprdbat_data->stop_charge();

    if ((sprd_fchg_op != NULL) && sprd_fchg_op->fchg_deinit)
        sprd_fchg_op->fchg_deinit();

    sprdbat_adp_plug_nodify(0);
    sprdbat_data->bat_info.module_state = POWER_SUPPLY_STATUS_DISCHARGING;

    sprdbat_data->bat_info.adp_type = SDP_TYPE;
    sprdbat_data->bat_info.ac_online = 0;
    sprdbat_data->bat_info.usb_online = 0;
    sprdbat_data->fchg_det = 0;
    mutex_unlock(&sprdbat_data->lock);

    if (sprd_ext_ic_op->set_input_cur_limit) {
        unsigned int limit = sprdbat_data->pdata->adp_sdp_cur_limit;

        sprd_ext_ic_op->set_input_cur_limit(limit);
        sprdbat_data->bat_info.input_cur_limit = limit;
    }

    if ((adp_type == SDP_TYPE) || (adp_type == CDP_TYPE))
        power_supply_changed(sprdbat_data->usb);
    else
        power_supply_changed(sprdbat_data->ac);

    return 0;
}

2.5 sprdbat_charge_works函数

这个函数会在sprdbat_change_module_state中使用,还有sprdbat_timer_handler函数中使用定时器中断;


static void sprdbat_charge_works(struct work_struct *work)
{
    SPRDBAT_DEBUG("sprdbat_charge_works----------start\n");
    mutex_lock(&sprdbat_data->lock);

    //只有电压模式暂时不考虑
    if (!sprdbat_data->pdata->only_vol_mode) {
        sprdbat_data->bat_info.vbat_vol = sprdbat_read_vbat_vol();
        sprdbat_data->bat_info.vbat_ocv = sprdfgu_read_vbat_ocv();
    }

    //读取电流
    sprdbat_data->bat_info.bat_current = sprdfgu_read_batcurrent();

    //假设外部充电IC存在,则喂狗
    if (sprd_ext_ic_op->timer_callback_ext)
        sprd_ext_ic_op->timer_callback_ext();

    //没有充电则是返回
    if (sprdbat_data->bat_info.module_state ==
        POWER_SUPPLY_STATUS_DISCHARGING) {
        SPRDBAT_DEBUG("not charing return\n");
        mutex_unlock(&sprdbat_data->lock);
        return;
    }

    if (sprdbat_data->pdata->only_vol_mode &&
        !sprdchg_timer_op->timer_enable) {
        mutex_unlock(&sprdbat_data->lock);
        return;
    }

    //只有电压模式暂时不考虑
    if (sprdbat_data->pdata->only_vol_mode) {
        unsigned int poll_time_fast =
                sprdbat_data->pdata->chg_polling_time_fast;
        unsigned int poll_time =
                sprdbat_data->pdata->chg_polling_time;

        if (sprdbat_data->bat_info.chg_stop_flags ==
            SPRDBAT_CHG_END_NONE_BIT) {
            if (sprdbat_data->bat_info.chging_on) {
                sprd_ext_ic_op->charge_stop_ext
                    (SPRDBAT_CHG_END_NONE_BIT);
                sprdbat_data->bat_info.chging_on = 0;
                sprdchg_timer_op->timer_disable();
                sprdchg_timer_op->timer_enable(poll_time_fast,
                                   ONE_TIME);
                mutex_unlock(&sprdbat_data->lock);
                return;
            }
            sprdbat_data->bat_info.vbat_vol =
                sprdbat_read_vbat_vol();
            sprdbat_data->bat_info.vbat_ocv =
                sprdfgu_read_vbat_ocv();
            sprdbat_update_capacty();
            sprdbat_data->bat_info.chging_on = 1;
            sprd_ext_ic_op->charge_start_ext();
            msleep(20);
            sprdchg_timer_op->timer_disable();
            sprdchg_timer_op->timer_enable(poll_time, ONE_TIME);
        } else {
            //读取vbat_vol
            sprdbat_data->bat_info.vbat_vol =
                sprdbat_read_vbat_vol();
            //读取vbat开路电压
            sprdbat_data->bat_info.vbat_ocv =
                sprdfgu_read_vbat_ocv();
            //更新电量
            sprdbat_update_capacty();
            sprdchg_timer_op->timer_disable();
            sprdchg_timer_op->timer_enable(poll_time, ONE_TIME);
        }
    }

    if (sprdbat_data->bat_info.chg_stop_flags & SPRDBAT_CHG_END_FULL_BIT)
        //充满标志位,如果判断开路电压降低到rechg-vol
        sprdbat_chg_rechg_monitor();

    sprdbat_chg_status_monitor();
    sprdbat_chg_timeout_monitor();
    sprdbat_chg_ovp_monitor();
    sprdbat_temp_monitor();
    sprdbat_chgr_temp_monitor();
    sprdbat_fault_monitor();
    mutex_unlock(&sprdbat_data->lock);

    sprdbat_chg_print_log();
    SPRDBAT_DEBUG("sprdbat_charge_works----------end\n");

}

2.5.1 充满电监控函数sprdbat_chg_status_monitor


static void sprdbat_chg_status_monitor(void)
{
    int chg_status = POWER_SUPPLY_STATUS_CHARGING;

    SPRDBAT_DEBUG
        (" %s,ocv=%d, cur=%d,chg_end_vol_l=%d,chg_end_cur=%d\n",
    __func__, sprdbat_data->bat_info.vbat_ocv,
    sprdbat_data->bat_info.bat_current,
    sprdbat_data->pdata->chg_end_vol_l,
    sprdbat_data->pdata->chg_end_cur);

    //这个暂且不理
    if (sprdbat_data->pdata->only_vol_mode) {
        if (sprdbat_data->bat_info.vbat_vol >
            sprdbat_data->pdata->chg_end_vol_l) {
            sprdbat_data->chg_full_trigger_cnt++;
            if (sprdbat_data->chg_full_trigger_cnt >= 2) {
                sprdbat_data->chg_full_trigger_cnt = 0;
                if (sprdbat_data->bat_info.capacity >= 99 &&
                    trickle_time >=
                    sprdbat_data->pdata->cap_one_per_time) {
                    sprdbat_change_module_state
                        (SPRDBAT_CHG_FULL_E);
                    sprdbat_data->stop_charge();
                } else {
                    sprdfgu_force_set_soc(1000);
                }
            }
        } else {
            sprdbat_data->chg_full_trigger_cnt = 0;
        }
        return;
    }

    //chg_full_condition 的设备树由chg-full-condition决定,并且是0,决定充电结束条件
    if (sprdbat_data->pdata->chg_full_condition == FROM_EXT_IC) {
        chg_status = sprd_ext_ic_op->get_charging_status();
        if (chg_status == POWER_SUPPLY_STATUS_FULL) {
            SPRDBAT_DEBUG("chg full\n");
            /* capacity is high enough, set the status to full */
            if (sprdbat_data->bat_info.capacity >= 99 &&
                trickle_time >=
                sprdbat_data->pdata->cap_one_per_time)
                sprdbat_change_module_state(SPRDBAT_CHG_FULL_E);
            else
                sprdfgu_force_set_soc(1000);
        } else {
            SPRDBAT_DEBUG("chging or fault\n");
        }
    } else if (sprdbat_data->pdata->chg_full_condition == VOL_AND_CUR) {
        //两个条件同时成立两次,一是vbat的电压大于截止充电电压条件,二是vbat的充电电流小于充电电流
        if ((sprdbat_data->bat_info.vbat_vol >
             sprdbat_data->pdata->chg_end_vol_l)
            && (sprdbat_data->bat_info.bat_current <
            sprdbat_data->pdata->chg_end_cur)) {
            sprdbat_data->chg_full_trigger_cnt++;
            if (sprdbat_data->chg_full_trigger_cnt >= 2) {
                SPRDBAT_DEBUG("charge full stop charge\n");
                sprdbat_data->chg_full_trigger_cnt = 0;
                /* cap is high enough, set the status to full */
                if (sprdbat_data->bat_info.capacity >= 99 &&
                    trickle_time >=
                    sprdbat_data->pdata->cap_one_per_time) {
                    sprdbat_change_module_state
                        (SPRDBAT_CHG_FULL_E);
                    sprdbat_data->stop_charge();
                } else {
                    sprdfgu_force_set_soc(1000);
                }
            }
        } else {
            sprdbat_data->chg_full_trigger_cnt = 0;
        }
    } else if (sprdbat_data->pdata->chg_full_condition == VOL_AND_STATUS) {
        if ((sprdbat_data->bat_info.vbat_vol >
             sprdbat_data->pdata->chg_end_vol_l
             || sprd_ext_ic_op->get_charging_status())
            && (sprdbat_data->bat_info.bat_current <
            sprdbat_data->pdata->chg_end_cur)) {
            sprdbat_data->chg_full_trigger_cnt++;
            if (sprdbat_data->chg_full_trigger_cnt >= 2) {
                SPRDBAT_DEBUG("charge full stop charge\n");
                sprdbat_data->chg_full_trigger_cnt = 0;
                /* cap is high enough, set the status to full */
                if (sprdbat_data->bat_info.capacity >= 99 &&
                    trickle_time >=
                    sprdbat_data->pdata->cap_one_per_time) {
                    sprdbat_change_module_state
                        (SPRDBAT_CHG_FULL_E);
                    sprdbat_data->stop_charge();
                } else {
                    sprdfgu_force_set_soc(1000);
                }
            }
        } else {
            sprdbat_data->chg_full_trigger_cnt = 0;
        }
    } else {
        SPRDBAT_DEBUG("bad chg_full_condition\n");
    }
}

2.5.2 充电超时监控函数sprdbat_chg_timeout_monitor

充电超时后如果满足电量充足则状态设置为满电状态,如果电池电压过低则需要重新启动充电


static void sprdbat_chg_timeout_monitor(void)
{
    SPRDBAT_DEBUG("sprdbat_chg_timeout_monitor enter\n");
    if (sprdbat_data->bat_info.chg_stop_flags &
        SPRDBAT_CHG_END_TIMEOUT_BIT) {
        SPRDBAT_DEBUG("sprdbat_chg_timeout_monitor recharge\n");
        sprdbat_change_module_state(SPRDBAT_CHG_TIMEOUT_RESTART_E);
        sprdbat_data->start_charge();
    }
    if (sprdbat_data->bat_info.chg_stop_flags == SPRDBAT_CHG_END_NONE_BIT) {
        if (sprdbat_is_chg_timeout()) {
            SPRDBAT_DEBUG
                ("sprdbat_chg_timeout_monitor chg timeout\n");
            if (sprdbat_data->bat_info.vbat_ocv >
                sprdbat_data->pdata->rechg_vol) {
                sprdbat_change_module_state(SPRDBAT_CHG_FULL_E);
                sprdbat_data->stop_charge();
            } else {
                sprdbat_data->bat_info.chg_this_timeout =
                    sprdbat_data->pdata->chg_rechg_timeout;
                sprdbat_change_module_state
                    (SPRDBAT_CHG_TIMEOUT_E);
                sprdbat_data->stop_charge();
            }
        }
    }
}

2.5.3 充电器过压保护监控函数

充电器过压采用轮询方式轮询用户配置电压参数修改充电状态,快充电压如果下降2000mv 则退出快充,重新设定充电电流。

ovp-stop = <6500>; //充电过压保护
ovp-restart = <5800>; //过压恢复电压
fchg-ovp-stop = <11000>; //快充过压电压
fchg-ovp-restart = <10000>; //快充过压恢复电压

static void sprdbat_chg_ovp_monitor(void)
{
    int ovp_restart, ovp_stop;

    if (sprdbat_data->fchg_det) {
        ovp_restart = sprdbat_data->pdata->fchg_ovp_restart;
        ovp_stop = sprdbat_data->pdata->fchg_ovp_stop;
    } else {
        ovp_restart = sprdbat_data->pdata->ovp_restart;
        ovp_stop = sprdbat_data->pdata->ovp_stop;
    }
    SPRDBAT_DEBUG("%s chg_vol = %d,ovp_stop =%d,ovp_restart=%d\n",
        __func__, sprdbat_data->bat_info.avg_chg_vol,
        ovp_stop, ovp_restart);

    if (sprdbat_data->bat_info.chg_stop_flags & SPRDBAT_CHG_END_OVP_BIT) {
        if (sprdbat_data->bat_info.avg_chg_vol <= ovp_restart) {
            SPRDBAT_DEBUG("charge vol low restart chg\n");
            sprdbat_change_module_state(SPRDBAT_OVI_RESTART_E);
            sprdbat_data->start_charge();
        } else {
            SPRDBAT_DEBUG("sprdbat_chg_ovp_monitor ovp return ");
        }
    } else if (sprdbat_data->bat_info.avg_chg_vol >= ovp_stop) {
        SPRDBAT_DEBUG("charge vol is too high\n");
        sprdbat_change_module_state(SPRDBAT_OVI_STOP_E);
        sprdbat_data->stop_charge();
    }

    if (sprdbat_data->fchg_det) {
        /*if vbus vol <(vbus - 2000mv),exit*/
        uint32_t fchg_l = sprdbat_data->pdata->fchg_vol - 2000;

        if (sprdbat_data->bat_info.avg_chg_vol <= fchg_l) {
            SPRDBAT_DEBUG("fchg_l_low:%d\n", fchg_l);
            sprdbat_data->fchg_det = 0;
            if ((sprd_fchg_op != NULL)
                && (sprd_fchg_op->fchg_deinit))
                sprd_fchg_op->fchg_deinit();
            sprdbat_charge_prepare();
            sprdbat_data->start_charge();
            power_supply_changed(sprdbat_data->battery);
        }
    }
}

2.5.4 充电器温度监控函数

具体参考《SL8541E充电介绍.pdf》

2.5.5 sprdbat_chgr_temp_monitor函数

暂且不知道作用

2.5.6 sprdbat_fault_monitor监控错误函数


static void sprdbat_fault_monitor(void)
{
    int chg_fault, status, vbat_ovp, terminal_voltage;

    SPRDBAT_DEBUG("sprdbat_fault_monitor enter\n");
    status = sprdbat_data->cur_temp_status;
    terminal_voltage = sprdbat_data->pdata->jeita_tab[status].z;
    vbat_ovp = terminal_voltage + VBAT_OVP_THRESHOLD;
    chg_fault = sprd_ext_ic_op->get_charging_fault();

    if (chg_fault == SPRDBAT_CHG_END_NONE_BIT)
        sprdbat_fault_recovery_monitor();

    if (chg_fault & SPRDBAT_CHG_END_OTP_COLD_BIT)
        SPRDBAT_DEBUG(" power cold\n");

    if (chg_fault & SPRDBAT_CHG_END_OTP_OVERHEAT_BIT)
        SPRDBAT_DEBUG("power hot\n");

    if (chg_fault & SPRDBAT_CHG_END_TIMEOUT_BIT) {
        SPRDBAT_DEBUG("  safe time expire\n");
        sprdbat_change_module_state(SPRDBAT_CHG_TIMEOUT_E);
    }
    if (chg_fault & SPRDBAT_CHG_END_BAT_OVP_BIT) {
        if (sprdbat_data->sprdbat_vbat_ovp_cnt > VBAT_OVP_CNT_THRESHOLD &&
            sprdbat_data->bat_info.vbat_vol > vbat_ovp) {
            SPRDBAT_DEBUG("fault: vbat ovp\n");
            sprdbat_change_module_state(SPRDBAT_VBAT_OVP_E);
        } else {
            SPRDBAT_DEBUG("warning: vbat ovp\n");
            sprdbat_fchg_detect();
            sprdbat_charge_prepare();
            sprdbat_data->start_charge();
            sprdbat_data->sprdbat_vbat_ovp_cnt++;
        }
    } else {
        sprdbat_data->sprdbat_vbat_ovp_cnt = 0;
    }

    if (chg_fault == SPRDBAT_CHG_END_UNSPEC)
        SPRDBAT_DEBUG(" unspec fault\n");

}

3. 其他状态位

3.1 充电状态:

enum sprdbat_event {
SPRDBAT_ADP_PLUGIN_E, //充电器插入
SPRDBAT_ADP_PLUGOUT_E, //充电器拔出
SPRDBAT_OVI_STOP_E, //充电器电压过高
SPRDBAT_OVI_RESTART_E, //充电器过压后恢复
SPRDBAT_OTP_COLD_STOP_E, //电池温度过低
SPRDBAT_OTP_OVERHEAT_STOP_E, //电池温度过高
SPRDBAT_OTP_COLD_RESTART_E, //电池温度从低温恢复
SPRDBAT_OTP_OVERHEAT_RESTART_E, //电池温度从高温恢复
SPRDBAT_CHG_FULL_E, //充满电
SPRDBAT_RECHARGE_E, //满电后复充
SPRDBAT_CHG_TIMEOUT_E, //充电超时
SPRDBAT_CHG_TIMEOUT_RESTART_E, //超时后重新启动充电
SPRDBAT_VBAT_OVP_E, //电池过压
SPRDBAT_VBAT_OVP_RESTART_E, //电池过压恢复
SPRDBAT_CHG_UNSPEC_E, //电池拔出
SPRDBAT_CHG_UNSPEC_RESTART_E, //电池拔出后重新插入
SPRDBAT_FULL_TO_CHARGING_E, //满电强制启动充电
SPRDBAT_CHARGING_TO_FULL_E, //充电强制显示 100
SPRDBAT_CHG_FORCE_STOP_E, //强制启动充电
SPRDBAT_CHG_FORCE_START_E, //强制关闭充电
};

原文地址:https://www.cnblogs.com/linhaostudy/p/12303724.html

时间: 2024-11-05 11:18:01

展讯sprd_battery.c 充电驱动的相关文章

展讯sc7731 LCD驱动简明笔记之三

此篇笔记基于sc7731 - android 5.1,对lcd的gralloc库做一个简明笔记. 第一部分 调用gralloc.sc8830.so所谓的Gralloc模块,它就是一个模块,一个操作kernel层framebuffer驱动的动态库模块,它属于大名鼎鼎的HAL层.用的时候就加载到内存空间,不用的时候就从内存空间中卸载掉.下面看下系统如何将该模块加载到内存空间的.在Android系统中,所有访问HAL层模块的应用,都需要通过一个叫 hw_get_module() 的方法去获得需要的HA

展讯sc7731 LCD驱动简明笔记之二

此篇笔记基于sc7731 - android 5.1,对lcd的framebuffer做一个简明笔记. 一共分为两大部分:第一部分,关于LCD的硬件方面的:第二部分,关于lcd核心处理(framebuffer)部分的. 第一部分,LCD硬件相关的 一.液晶 液晶是一种高分子有机材料.当给它加上直流电场后,原本有序的分子排列被打乱,一部分液晶变得不透明,颜色加深,便因此显示出字符和图形. 液晶的光电效应:干涉.散射.衍射.旋光.吸收等. 二.LCD种类 1. 构造: 使用两块玻璃板夹着一块液晶:一

展讯7731平台驱动调试总结-驱动配置部分

转载至:http://blog.csdn.net/bmw7bmw7/article/details/46126223 展讯7731平台驱动调试总结-驱动配置部分 1. 关键配置文件路径 1). 项目板级配置:idh.code/device/sprd/scx35_sp7731geaplus_pad_qhd/文件夹内各文件 ⑴.BoardConfig.mk---板级宏配置文件.包括设置该板(项目)所使用的uboot/kerenl全局配置宏文件,摄像头接口类型.分辨率等参数,所使用的重力加速度.光线传

展讯7731平台驱动调试总结(2)---- 驱动配置部分

1. 关键配置文件路径 1). 项目板级配置:idh.code/device/sprd/scx35_sp7731geaplus_pad_qhd/文件夹内各文件 ⑴.BoardConfig.mk---板级宏配置文件.包括设置该板(项目)所使用的uboot/kerenl全局配置宏文件,摄像头接口类型.分辨率等参数,所使用的重力加速度.光线传感器,内部存储空间大小分配等. ⑵. init.board.rc---板级自定义启动服务文件(TP,传感器等设备的启动指令放置在此文件中) ⑶.system.pr

展讯LCD浏览之前记

基于展讯sc7731 - Android 5.1 代码分析浏览.将屏蔽细节,把握整体,并且不涉及其他设备和LCD的交互. 以下对sc7731 lcd大体流程进行简要说明. 第一,lcd 的两个阶段 1. 在uboot引起系统阶段,大约1~5秒左右,需要打印一个厂商log.这里对驱动要求非常简单,只要能打印log即可. (下面皆以lcd_ili9486s1_mipi.c为例)  驱动文件放置路径: u-boot64/drivers/video/sprdfb/lcd/ 添加新屏时需要修改的文件分别为

展讯平台 LCD(Mipi) 加载流程分析

stage1 阶段的详细分析参见 uboot 详细注释讲解 我们从 uboot 的 stage2 开始分析. 加载流程分析 首先是完成硬件的初始化. 函数调用流程为: u-boot64/arch/arm/board.c: board_init_r() u-boot64/common/stdio.c: stdio_init() u-boot64/common/lcd.c: drv_lcd_init() lcd_init() u-boot/drivers/video/sprdfb/sprdfb_ma

展讯平台 LCD(Mipi)移植步骤及问题归纳

原创文章,原文地址:http://blog.csdn.net/dearsq/article/details/51210703 欢迎转载,转载请保留地址! PortingGuide Backlight 背光的硬件设计有两种情况: 1. 内置并联背光 2. 外置串联背光 对于 1 的情况,步骤如下: 1.移植对应的 lcd 驱动. 2.设置u-boot\drivers\video\sprdfb\sprdfb_main.c中的背光为内置: void set_backlight(uint32_t val

展讯CEO:低毛利生存 由中低端转向高端

最近一两年来,芯片市场的热闹有从细分.垂直的圈子向整个大社会场景发酵的迹象. 备受各界关注的高通发垄断案,国家大基金的成立,以及展讯.锐迪科等私有化等等,都意味着这个行业的热度在快速上升.这里面既有芯片产业从欧美.日韩向中国大陆进行梯度产业转移的市场大势,也有中国信息产业界对“缺芯少屏”这一产业桎梏的突围情愫. 无论从哪个角度来看,在中国芯片业本轮纵横捭阖中,展讯都是一家值得更多笔墨的公司.它曾“以彼之道还施彼身”,让联发科的2G产品遭遇严重压力.在国家扶持集成电路发展的风口上,展讯又被紫光以私

三星为何宁选展讯而不与联发科合作

三星为何宁选展讯而不与联发科合作?这个问题一直是业界的悬案,相信很多朋友都有过这种疑问. 老杳还特意就这个问题问过李力游,不过LEO只是神秘的一笑,并没有给出具体解释. 这几年业界多次传出三星要与联发科合作,至今为止依然没有变成现实. 老杳这里只是试着给出自己的解释,当然如果有不同理解可以讨论. 展讯与三星的合作最早起源于5500万美元收购的美国射频公司Quorum,有关这笔收购到底是亏还是赚每个人有不同的看法,客观的说是Quorum的射频芯片帮展讯打开了三星合作的大门,这应当也是当年初入展讯的