CPU:RK3288
Android:7.1
Linux:4.4.143
充放电芯片:bq25703
PD芯片:fusb302
电量计:cw2015
dts配置:kernel/arch/arm/boot/dts/rk3288-xxx.dts
&i2c5 {
status = “okay”;
i2c-scl-rising-time-ns = <475>;
i2c-scl-falling-time-ns = <26>;
clock-frequency = <100000>;
bq25700: bq25700@6b {
compatible = “ti,bq25703”;
reg = <0x6b>; —》I2C slave address
extcon = <&fusb0>; —》外部连接器,PD
interrupt-parent = <&gpio3>;
interrupts =
pinctrl-names = “default”;
pinctrl-0 = <&charger_ok>;
ti,charge-current = <4000000>;
ti,max-charge-voltage = <8400000>;
ti,max-input-voltage = <20000000>;
ti,max-input-current = <6000000>;
ti,input-current-sdp = <2000000>; //关机时,使用该电流
ti,input-current-dcp = <2000000>;
ti,input-current-cdp = <5000000>;
ti,input-current-dc = <7000000>;
ti,minimum-sys-voltage = <6000000>;
ti,otg-voltage = <5000000>;
ti,otg-current = <500000>;
ti,input-current = <500000>;
pd-charge-only = <0>; //将值设置为0即支持普通充电
status = “okay”;
};
fusb0: fusb30x@22 {
compatible = “fairchild,fusb302”;
reg = <0x22>;
pinctrl-names = “default”;
pinctrl-0 = <&fusb0_int>;
//vbus-5v-gpios = <&gpio0 RK_PC2 GPIO_ACTIVE_HIGH>;
int-n-gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>;
// discharge-gpios = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>;
charge-dev = <&bq25700>;
// support-uboot-charge = <1>;
port-num = <0>; //使用的usb控制器,关机充电时需要
status = “okay”;
};
}
&i2c0 {
clock-frequency = <400000>;
CW2015@62 {
compatible = “cw201x”;
reg = <0x62>;
bat_low_gpio = <&gpio0 7 GPIO_ACTIVE_LOW>;
bat_config_info = <0x15 0x7E 0x79 0x6E 0x6C 0x69 0x66 0x65
0x63 0x62 0x5C 0x58 0x52 0x52 0x49 0x31
0x29 0x23 0x24 0x26 0x29 0x37 0x4B 0x5C
0x62 0x45 0x0B 0x85 0x23 0x43 0x6C 0x81
0x83 0x82 0x83 0x85 0x3A 0x16 0x93 0x1B
0x07 0x45 0x35 0x66 0x8E 0x91 0x92 0x45
0x5B 0x78 0x9A 0xAD 0x80 0x81 0x8B 0xCB
0x2F 0x00 0x64 0xA5 0xB5 0xC1 0x46 0xAE>;
// is_usb_charge = <1>;
monitor_sec = <2>; //电量查询时间间隔,2S
virtual_power = <0>;
divider_res1 = <200>; //分压电阻大小
divider_res2 = <200>;
status = “okay”;
};
配置文档:documentation/devicetree/bindings/power/bq25703.txt:
documentation/devicetree/bindings/mfd/fusb302.txt
documentation/devicetree/bindings/power/cw2015_battery.txt
驱动目录:kernel/drivers/mfd/fusb302.c
kernel/drivers/power/bq25700_charger.c
kernel/drivers/power/cw2015_battery.c
1、PD芯片模块&驱动加载
static int fusb30x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
...
chip->fusb30x_wq = create_workqueue("fusb302_wq");
INIT_WORK(&chip->work, fusb302_work_func);
...
ret = devm_request_threaded_irq(&client->dev,
chip->gpio_int_irq,
NULL,
cc_interrupt_handler,
IRQF_onESHOT | IRQF_TRIGGER_LOW,
client->name,
chip);
2、充电IC bq25700 模块&驱动加载
bq25700_probe
i2c_check_functionality //是否支持 SMBUS 通信
devm_regmap_init_i2c //采用 regmap api 操作 i2c,初始化 bq25700 的 regmap_config
devm_regmap_field_alloc //为 regmap 分配内存空间
i2c_set_clientdata
bq25700_field_read //读 chip id
bq25700_fw_probe
bq25700_fw_read_u32_props //获取 dts 中的属性,包括 charge-current、max-charge-voltage、input-current-sdp/dcp/cdp、minimum-sys-voltage 、otg-voltage、otg-current
bq25700_hw_init
//1. bq25700_chip_reset //芯片重启
//2. WDTWR_ADJ = 0 //disable watchdog
//3. 初始化电流电压和其他参数
//4. 配置 ADC 用以持续转化,禁能
bq25700_parse_dt //获取 dts 中的属性 pd-charge-only
bq25700_init_usb
usb_charger_wq = alloc_ordered_workqueue //分配工作队列,用于事件通知链
extcon_get_edev_by_phandle(dev, 0) //获取外部连接器 fusb302
bq25700_register_cg_nb(charger); //注册 charger 通知链。如果 pd_charge_only 为 0 ,表示不仅仅采用 TypeC 充电,则执行。添加等待队列。
bq25700_charger_evt_worker //初始化 charger 等待队列
bq25700_charger_evt_handel //判断 charger 类型,并使能 INPUT_CURRENT/CHARGE_CURRENT
bq25700_charger_evt_notifier //添加 charger 事件通知链
bq25700_register_cg_extcon //注册 charger 外部控制器,以及其事件通知链
bq25700_register_host_nb(charger); //注册 host 通知链
bq25700_register_discnt_nb(charger); //注册 disconnect 通知链
bq25700_register_pd_nb(charger); //注册 pd 通知链
schedule_delayed_work //提交任务到工作队列
bq25700_init_sysfs //创建 sysfs 中的属性节点
//根据 AC_STAT 确定触发条件,设定中断触发条件
device_init_wakeup
devm_request_threaded_irq
enable_irq_wake //使能中断唤醒
bq25700_power_supply_init //注册 power supply 的 desc
bq25700_power_supply_get_property //获取系统属性的接口
int extcon_register_notifier(struct extcon_dev *edev, unsigned int id,
struct notifier_block *nb)
{
...
raw_notifier_chain_register(&edev->nh[idx], nb);
...
}
static int bq25700_register_cg_nb(struct bq25700_device *charger)
{
...
INIT_DELAYED_WORK(&charger->usb_work, bq25700_charger_evt_worker);
charger->cable_cg_nb.notifier_call = bq25700_charger_evt_notifier;
bq25700_register_cg_extcon(charger, charger->cable_edev, &charger->cable_cg_nb);
...
}
static int bq25700_register_host_nb(struct bq25700_device *charger)
{
...
INIT_DELAYED_WORK(&charger->host_work, bq25700_host_evt_worker);
charger->cable_host_nb.notifier_call = bq25700_host_evt_notifier;
// extcon_register_notifier见./kernel/drivers/extcon/extcon.c
ret = extcon_register_notifier(charger->cable_edev, EXTCON_USB_HOST, &charger->cable_host_nb);
...
}
static int bq25700_register_discnt_nb(struct bq25700_device *charger)
{
...
INIT_DELAYED_WORK(&charger->discnt_work, bq25700_discnt_evt_worker);
charger->cable_discnt_nb.notifier_call = bq25700_discnt_evt_notfier;
ret = extcon_register_notifier(charger->cable_edev, EXTCON_USB, &charger->cable_discnt_nb);
...
}
static int bq25700_register_pd_nb(struct bq25700_device *charger)
{
...
INIT_DELAYED_WORK(&charger->pd_work, bq25700_pd_evt_worker);
charger->cable_pd_nb.notifier_call = bq25700_pd_evt_notifier;
extcon_register_notifier(charger->cable_edev, EXTCON_CHG_USB_FAST, &charger->cable_pd_nb);
...
}
static int bq25700_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
...
ret = devm_request_threaded_irq(dev, client->irq, NULL,
bq25700_irq_handler_thread,
irq_flag | IRQF_ONESHOT,
"bq25700_irq", charger);
enable_irq_wake(client->irq);
...
}
通知实例
otg_mode_store->rockchip_usb2phy_set_mode-> (kernel/drivers/phy/rockchip/phy-rockchip-inno-usb2.c)
extcon_set_state_sync->extcon_sync->raw_notifier_call_chain
开机初始化打印
[ 1.013590] chip id is 78 --》bq25700芯片ID
[ 1.042547] bq25700-charger 5-006b: GPIO lookup for consumer typec0-enable
[ 1.042561] bq25700-charger 5-006b: using device tree for GPIO lookup
[ 1.042575] of_get_named_gpiod_flags: can’t parse ‘typec0-enable-gpios’ property of node ‘/i2c@ff170000/bq25700@6b[0]’
[ 1.042587] of_get_named_gpiod_flags: can’t parse ‘typec0-enable-gpio’ property of node ‘/i2c@ff170000/bq25700@6b[0]’
[ 1.042597] bq25700-charger 5-006b: using lookup tables for GPIO lookup
[ 1.042608] bq25700-charger 5-006b: lookup for GPIO typec0-enable failed
[ 1.042619] bq25700-charger 5-006b: GPIO lookup for consumer typec1-enable
[ 1.042628] bq25700-charger 5-006b: using device tree for GPIO lookup
[ 1.042639] of_get_named_gpiod_flags: can’t parse ‘typec1-enable-gpios’ property of node ‘/i2c@ff170000/bq25700@6b[0]’
[ 1.042649] of_get_named_gpiod_flags: can’t parse ‘typec1-enable-gpio’ property of node ‘/i2c@ff170000/bq25700@6b[0]’
[ 1.042658] bq25700-charger 5-006b: using lookup tables for GPIO lookup
[ 1.042668] bq25700-charger 5-006b: lookup for GPIO typec1-enable failed
[ 1.042678] bq25700-charger 5-006b: GPIO lookup for consumer typec0-discharge
[ 1.042688] bq25700-charger 5-006b: using device tree for GPIO lookup
[ 1.042698] of_get_named_gpiod_flags: can’t parse ‘typec0-discharge-gpios’ property of node ‘/i2c@ff170000/bq25700@6b[0]’
[ 1.042709] of_get_named_gpiod_flags: can’t parse ‘typec0-discharge-gpio’ property of node ‘/i2c@ff170000/bq25700@6b[0]’
[ 1.042719] bq25700-charger 5-006b: using lookup tables for GPIO lookup
[ 1.042728] bq25700-charger 5-006b: lookup for GPIO typec0-discharge failed
[ 1.042738] bq25700-charger 5-006b: GPIO lookup for consumer typec1-discharge
[ 1.042747] bq25700-charger 5-006b: using device tree for GPIO lookup
[ 1.042758] of_get_named_gpiod_flags: can’t parse ‘typec1-discharge-gpios’ property of node ‘/i2c@ff170000/bq25700@6b[0]’
[ 1.042768] of_get_named_gpiod_flags: can’t parse ‘typec1-discharge-gpio’ property of node ‘/i2c@ff170000/bq25700@6b[0]’
[ 1.042778] bq25700-charger 5-006b: using lookup tables for GPIO lookup
[ 1.042787] bq25700-charger 5-006b: lookup for GPIO typec1-discharge failed
[ 1.042797] bq25700-charger 5-006b: GPIO lookup for consumer otg-mode-en
[ 1.042806] bq25700-charger 5-006b: using device tree for GPIO lookup
[ 1.042816] of_get_named_gpiod_flags: can’t parse ‘otg-mode-en-gpios’ property of node ‘/i2c@ff170000/bq25700@6b[0]’
[ 1.042826] of_get_named_gpiod_flags: can’t parse ‘otg-mode-en-gpio’ property of node ‘/i2c@ff170000/bq25700@6b[0]’
[ 1.042836] bq25700-charger 5-006b: using lookup tables for GPIO lookup
[ 1.042846] bq25700-charger 5-006b: lookup for GPIO otg-mode-en failed
[ 1.043209] bq25700-charger 5-006b: Invalid or missing extcon dev1
2、插拔typec适配器充电日志打印
日志打印信息:
[ 681.428862] fusb302 5-0022: CC connected in CC2 as UFP —》fusb_state_attached_sink-》force_usb_mode_store
[ 681.428949] jon debug:::usb_mode:30
[ 681.429051] force_usb_mode_store 0->2
[ 681.429144] jon debug:::usb_mode set 2
[ 681.472246] healthd: battery l=25 v=7142 t=18.8 h=2 st=3 chg=u
[ 681.478031] type=1400 audit(1634649279.583:44): avc: denied { search } for pid=227 comm=“Binder:227_1” name=“416” dev=“proc” ino=13324 scontext=u:r:mediaserver:s0 tcontext=u:r:system_server:s0 tclass=dir permissive=1
[ 681.512553] rk_battery_charger_detect_cb , battery_charger_detect 2
[ 681.534022] healthd: battery l=25 v=7142 t=18.8 h=2 st=3 chg=u
[ 681.746237] fusb302 5-0022: PD connected as UFP, fetching 5V
[ 681.779401] jon SET vol_idx: 164mv
[ 681.779417] jon SET cur_idx: 60mA
[ 681.779423] jon SET harger->init_data.ichg: 62mA
[ 681.811527] healthd: battery l=25 v=7142 t=18.8 h=2 st=3 chg=u
1、插入AC流程
硬件连接:fusb302芯片INT#管脚连到SOC(RK3288 GPIO0 A6,见dts配置: int-n-gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>)
插入AC-》产生硬件中断-》
cc_interrupt_handler-》queue_work (kernel/drivers/mfd/fusb302.c, fusb30x_probe->devm_request_threaded_irq注册)
fusb302_work_func-》
state_machine_typec-》
fusb_state_attached_sink-》
force_usb_mode_store-》
2、拔出AC流程
3、正常充电流程
【环境操作】1、查看电池文件系统
rk3288:/ # ls -l ./sys/devices/platform/ff170000.i2c/i2c-5/5-006b/power_supply/bq25700-charger
-r–r--r-- 1 root root 4096 2021-10-22 20:42 charge_control_limit_max
-r–r--r-- 1 root root 4096 2021-10-22 20:42 constant_charge_current
-r–r--r-- 1 root root 4096 2021-10-22 20:42 constant_charge_current_max
-r–r--r-- 1 root root 4096 2021-10-22 20:42 constant_charge_voltage
-r–r--r-- 1 root root 4096 2021-10-22 20:42 constant_charge_voltage_max
-r–r--r-- 1 root root 4096 2021-10-22 20:35 current_max
lrwxrwxrwx 1 root root 0 2021-10-22 20:42 device -> …/…/…/5-006b
-r–r--r-- 1 root root 4096 2021-10-22 20:42 health
-r–r--r-- 1 root root 4096 2021-10-22 20:42 input_current_limit
-r–r--r-- 1 root root 4096 2021-10-22 20:42 manufacturer
-rwxrwxrwx 1 root root 4096 2021-10-22 20:47 online
drwxr-xr-x 2 root root 0 2021-10-22 20:35 power
-r–r--r-- 1 root root 4096 2021-10-22 20:42 status
lrwxrwxrwx 1 root root 0 2021-10-22 20:42 subsystem -> …/…/…/…/…/…/…/class/power_supply
-r–r--r-- 1 root root 4096 2021-10-22 20:35 type
-rw-r–r-- 1 root root 4096 2021-10-22 20:35 uevent
-r–r--r-- 1 root root 4096 2021-10-22 20:35 voltage_max
rk3288:/ # ls -l ./sys/bus/i2c/drivers/bq25700-charger
total 0
lrwxrwxrwx 1 root root 0 2021-10-22 20:42 5-006b -> …/…/…/…/devices/platform/ff170000.i2c/i2c-5/5-006b
–w------- 1 root root 4096 2021-10-22 20:42 bind
–w------- 1 root root 4096 2021-10-22 20:42 uevent
–w------- 1 root root 4096 2021-10-22 20:42 unbind
1、delay_work延时工作
INIT_DELAYED_WORK(dwork, work); //参数1是个delayed_work结构体,参数2是个函数名 schedule_delayed_work (struct delayed_work *dwork, unsigned long delay); //将当前dwork变量进入到等待队列中,在后续的delay时间后,将会调用dwork变量对应的work函数 bool cancel_delayed_work(struct delayed_work *dwork); //如果当前dwork在等待队列中,则将取消掉
2、notifier通知机制
static RAW_NOTIFIER_HEAD(test_chain); raw_notifier_chain_register(&test_chain, nb); // nb为struct notifier_block raw_notifier_call_chain(&test_chain, val, NULL);【参考资料】
RK3399充电管理
https://blog.csdn.net/m0_37631324/article/details/105956187?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163462546616780255278368%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=163462546616780255278368&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allbaidu_landing_v2~default-1-105956187.pc_search_result_hbase_insert&utm_term=rk3399+%E5%85%85%E7%94%B5%E7%AE%A1%E7%90%86&spm=1018.2226.3001.4187
BQ25700 IC 驱动分析
https://blog.csdn.net/dearsq/article/details/72335905
内核通知链 notifier_block
http://bbs.chinaunix.net/thread-2011776-1-1.html
Android电池管理体系(一)
https://blog.csdn.net/zhou12314/article/details/79379276?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163490557516780271563114%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=163490557516780271563114&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~rank_v31_ecpm-14-79379276.pc_search_result_hbase_insert&utm_term=bq27500&spm=1018.2226.3001.4187



