展讯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

");

return -EINVAL;

}

if (sprd_ext_ic_op == NULL) {

dev_err(&pdev->dev, "sprd_ext_ic_op not found

");

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

", 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

");

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

",

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

",

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

");

//充电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

");

//注册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

", 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

", 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

");

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

");

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

",

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

",

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

");

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

",

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

",

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

");

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

",

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

");

//从满电状态转换为充电状态

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

");

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

");

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!!!!

");

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

", 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!!!!

");

}

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!!!!

");

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

");

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

",

sprdbat_data->bat_info.adp_type);

SPRDBAT_DEBUG("plugin_callback: end...

");

return 0;

}

static int plugout_callback(void)

{

uint32_t adp_type = sprdbat_data->bat_info.adp_type;

SPRDBAT_DEBUG("charger plug out interrupt happen

");

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

");

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

");

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

");

}

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

",

__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

");

/* 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

");

}

} 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

");

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

");

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

");

}

}

2.5.2 充电超时监控函数sprdbat_chg_timeout_monitor

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

static void sprdbat_chg_timeout_monitor(void)

{

SPRDBAT_DEBUG("sprdbat_chg_timeout_monitor enter

");

if (sprdbat_data->bat_info.chg_stop_flags &

SPRDBAT_CHG_END_TIMEOUT_BIT) {

SPRDBAT_DEBUG("sprdbat_chg_timeout_monitor recharge

");

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

");

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

",

__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

");

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

");

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

", 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

");

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

");

if (chg_fault & SPRDBAT_CHG_END_OTP_OVERHEAT_BIT)

SPRDBAT_DEBUG("power hot

");

if (chg_fault & SPRDBAT_CHG_END_TIMEOUT_BIT) {

SPRDBAT_DEBUG(" safe time expire

");

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

");

sprdbat_change_module_state(SPRDBAT_VBAT_OVP_E);

} else {

SPRDBAT_DEBUG("warning: vbat ovp

");

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

");

}

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, //强制关闭充电

};

以上是 展讯sprd_battery.c充电驱动 的全部内容, 来源链接: utcz.com/z/513434.html

回到顶部