原文網址:http://www.xuebuyuan.com/1023185.html
1. repo init -u git://review.sonyericsson.net/platform/manifest -b volatile-jb-mr1-yangtze
2. https://wiki.sonyericsson.net/androiki/CN3-II/Bringup_Trail_FC34 如何編譯
3. https://wiki.sonyericsson.net/androiki/PLD_CM/Yangtze 如何編譯和flash
4. https://wiki.sonyericsson.net/androiki/MIB_Tokyo/Rhine/Hardware_Watchdog_debugging
小技巧:
MISCTA 2473控制kernel log輸出: 01 輸出,00 無輸出
repo sync [目錄路徑] 比如: kenel,system/vold
repo sync kernel 則只是同步kernel目錄下的程式碼
grep "ifelse" * -r 查詢當前目錄下(遞迴)所有檔案中包含ifelse的內容
owner:xiaoguang2.lu@sonymobile.com status:merged //查詢誰提交併且已經merged的gerrit
printk("func = %pf",func)可列印函式名稱出來
充電縮寫語:(acronym)
FSM: Finite State Machine
CC: Coulcomb Counter
FCC: Full Charge Capacity
OCV: Open Circuit Voltage
PMIC: Power Management IC
PC: Percentage Charge
RC: Remaining Charge
SOC: State of Charge
RUC: Remaining Usable Charge
UUC: Unusable Charge
一、DTS 學習
1. kernel/arch/arm/boot/dts 目錄下包含所有的dts.
a. board , msm8226.dtsi
b. pmic, msm-pm8226.dtsi
2. kernel/Androidkernel.mk; Android makefile to build kernel as a part of Android Build
3. kernel/arch/arm/configs 目錄下儲存對應的config定義, CONFIG_XXXXXX
4. 可參考 jb-mr1-rhine/kernel/arch/arm/boot/dts/msm8974-rhine_togari_row.dtsi
二、LCD Porting
1. http://review.sonyericsson.net/#/c/508903
三、Charger bringup
1. 和battery and hw guys 確定相關 硬體引數
2. http://review.sonyericsson.net/#/c/516297/
3. kernel 傳送給battery_logging的uevent格式?
power_supply_uevent@kernel/drivers/power/power_supply_sysfs.c 該函式新增傳送的資訊到uevent
ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->name); //psy->name="battery"
for (j = 0; j < psy->num_properties; j++) {
attr = &power_supply_attrs[psy->properties[j]]; //得到對應的power supply attr,
attrname = kstruprdup(attr->attr.name, GFP_KERNEL);//會把屬性名字轉成大寫,比如“status”->"STATUS"
ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf); //增加該屬性的資訊到uevent buffer中
}
qpnp_charger_probe@kernel/drivers/power/qpnp-charger.c中會定義"battery"的properties = msm_batt_power_props
static enum power_supply_property msm_batt_power_props[] = { //對應power_supply_attrs[]@kernel/drivers/power/power_supply_sysfs.c
POWER_SUPPLY_PROP_CHARGING_ENABLED, //表示這些屬性是被battery psy所需要的屬性,具體如何得到可檢視
POWER_SUPPLY_PROP_STATUS, //qpnp_batt_power_get_property 函式
POWER_SUPPLY_PROP_CHARGE_TYPE, //這些屬性會新增到/sys/class/power_supply/battery
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL,
};
static struct device_attribute power_supply_attrs[] = {
/* Properties of type `int' */
POWER_SUPPLY_ATTR(status), //表示attr.name = "status"
POWER_SUPPLY_ATTR(charge_type),
...
}
4. parse_uevent@vendor/semc/hardware/power/charge-log/battery_logging/battery_logging.c會分析從kernel傳上來的power uevent格式
傳送該uevent的path '\0'
POWER_SUPPLY_NAME=battery '\0'
POWER_SUPPLY_CHARGING_ENABLE=%d '\0'
POWER_SUPPLY_CHARGING_STATUS=%d '\0'
...
5. 順便分析下UEvent如何傳遞給user space?
a. @kernel/drivers/power/qpnp-charger.c中只要有任何關於charger的變化,比如charger的各種irq handler
b. @kernel/drivers/power/qpnp-bms.c中calculate_soc_from_voltage和calculate_state_of_charge
c. @kernel/arch/arm/boot/dts/msm-pm8226.dtsi中有pm8226_bms的device定義,msm8226-cn3ii.dtsi中有pm8226_bms的定義補充
其中沒有 qcom,use-voltage-soc 的定義所以chip->use_voltage_soc=false, 也就是隻用calculate_state_of_charge計算soc
順便chip->use_external_rsense=true,表示用外部的rsense.
d. @kernel/driver/power/power_supply_core.c中的power_supply_changed會被以上內容呼叫
schedule_work(&psy->changed_work);
e. power_supply_changed_work@kernel/driver/power/power_supply_core.c
kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE); //action=KOBJ_CHANGE
f. kobject_uevent_env@kernel/lib/kobject_uevent.c
static const char *kobject_actions[] = {
[KOBJ_ADD] = "add",
[KOBJ_REMOVE] = "remove",
[KOBJ_CHANGE] = "change",
[KOBJ_MOVE] = "move",
[KOBJ_ONLINE] = "online",
[KOBJ_OFFLINE] = "offline",
};
以下為新增到uevent buffer中傳送的內容
/* default keys */
retval = add_uevent_var(env, "ACTION=%s", action_string);//action_string="change"
retval = add_uevent_var(env, "DEVPATH=%s", devpath);//devpath = kobject_get_path(kobj, GFP_KERNEL);
retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);//也就是uevent 的name
retval = uevent_ops->uevent(kset, kobj, env); //會呼叫到power_supply_uevent@kernel/drivers/power/power_supply_sysfs.c
//也就是會新增具體的power battery資訊到uevent buffer中了
retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)++uevent_seqnum); //增加uevent傳送的計數,
//KERNEL_ATTR_RO(uevent_seqnum); 用cat sys/kernel/uevent_seqnum 可以檢視
CONFIG_NET=y被定義,以下程式碼是傳送uevent到userspace 的關鍵程式碼
#if defined(CONFIG_NET)
/* send netlink message */
list_for_each_entry(ue_sk, &uevent_sock_list, list) { //uevent_net_init會初始化一個uevent_sock,也只有一個
if (!netlink_has_listeners(uevent_sock, 1))
continue;
/* allocate message with the maximum possible size */
len = strlen(action_string) + strlen(devpath) + 2;
skb = alloc_skb(len + env->buflen, GFP_KERNEL);
if (skb) {
retval = netlink_broadcast_filtered(uevent_sock, skb,
0, 1, GFP_KERNEL,
kobj_bcast_filter,
kobj);
} else
retval = -ENOMEM;
}
#endif
6. Battery充滿的識別
1). @kernel/arch/arm/boot/dts/msm-pm8226.dtsi和msm8226-cn3ii.dtsi
qcom,chg-chgr@1000 {
status = "disabled";
reg = <0x1000 0x100>;
interrupts = <0x0 0x10 0x0>,
<0x0 0x10 0x1>,
<0x0 0x10 0x2>,
<0x0 0x10 0x3>,
<0x0 0x10 0x4>,
<0x0 0x10 0x5>,
<0x0 0x10 0x6>,
<0x0 0x10 0x7>; //具體的含義?
interrupt-names = "vbat-det-lo",
"vbat-det-hi",
"chgwdog",
"state-change",
"trkl-chg-on",
"fast-chg-on",
"chg-failed",
"chg-done";
};
2). qpnp_chg_hwinit@kernel/drivers/power
chip->chg_done_irq = spmi_get_irq_byname(chip->spmi,spmi_resource, "chg-done");
如何觸發"chg-done"這個interrupt?
3).獲取當前充電狀態
rc = qpnp_chg_read(chip, &chgr_sts,INT_RT_STS(chip->chgr_base), 1);
如果chgr_sts&CHG_DONE_IRQ == 1則表示充電完成
4).http://review.sonyericsson.net/#/c/480849, workaround for fake charge done
6. 如何檢視當前的charger資訊?
/sys/devices/qpnp-charger-eab16c00
7. 手機/sys/class/power_supply/battery和bms和usb的來源
1)qpnp_charger_proble@kernel/drivers/power/qpnp-charger.c
if (chip->bat_if_base){
chip->batt_psy.name = "battery";
chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
chip->batt_psy.properties = msm_batt_power_props;//所選擇的屬性
rc = power_supply_register(chip->dev, &chip->batt_psy);//註冊到/sys/class/power_supply/battery
}
2)qpnp_bms_probe@kernel/drivers/power/qpnp-bms.c
chip->bms_psy.name = "bms";
chip->bms_psy.type = POWER_SUPPLY_TYPE_BMS;
chip->bms_psy.properties = msm_bms_power_props;
rc = power_supply_register(chip->dev, &chip->bms_psy);//註冊到/sys/class/power_supply/bms
3)msm_otg_proble@kernel/drivers/usb/otg, 注意CONFIG_USB_MSM_OTG的定義在kernel/drivers/usb/gadget/Kconfig: config USB_CI13XXX_MSM-->select USB_MSM_OTG
motg->usb_psy.name = "usb";
motg->usb_psy.type = POWER_SUPPLY_TYPE_USB;
motg->usb_psy.supplied_to = otg_pm_power_supplied_to;
msm_otg_register_power_supply(pdev, motg))->power_supply_register(&pdev->dev, &motg->usb_psy);
4)充電器的識別過程
msm_chg_detect_work@kernel/drivers/usb/otg/msm_otg.c 主要完成充電器類別的識別過程
->msm_otg_notify_chg_type@msm_otg.c
->power_supply_set_supply_type(psy, charger_type)@msm_otg.c;//psy=motg->usb_psy
->psy->set_property(psy, POWER_SUPPLY_PROP_TYPE,&ret); //@kernel/drivers/power/power_supply_core.c, 最後會call
->otg_power_set_property_usb@msm_otg.c 但是該函式中沒有POWER_SUPPLY_PROP_TYPE屬性的設定??
->queue_work(system_nrt_wq, &motg->sm_work);->msm_otg_sm_work[otg->phy->state=OTG_STATE_B_IDLE]
-->msm_otg_notify_charger->msm_otg_notify_power_supply->power_supply_set_online//設定是否online
四、Audio Jack Porting
0. HW Guys: Wang, Junchao(9601), Liu,Xun
1. kernel/sound/soc/msm/msm8226.c;
kernel/sound/soc/codecs/wcd9306.c,Wcd9xxx-mbhc.c
tapan_slimbus_irq
2. adb shell 'echo -n "file wcd9xxx-mbhc.c +p" > /sys/kernel/debug/dynamic_debug/control'
3. wcd9xxx_insert_detect_setup@Wcd9xxx-mbhc.c
0x6c-->0x68 //參考80-NC836-2 WCD9306 AUDIO CODEC SOFTWARE INTERFACE.pdf 中0x14B MBHC_INSERT_DET_STATUS暫存器的說明,PLUG_TYPE 0:NC 1:NO (注意原來的文件有錯)
Audio Jack不插入耳機時MBHC_HSDET是低,插入耳機時MBHC_HSDET是高,所以是Normal Close(NC)型別的Audio Jack
4. @kernel/sound/soc/msm/msm8226.c;
S(v_no_mic, 30);
S(v_hs_max, 1650);
5. @kernel/sound/soc/codecs/Wcd9xxx-mbhc.c
wcd9xxx_codec_get_plug_type->
wcd9xxx_find_plug_type
6. Audio jack檢測耳機的流程
在函式wcd9xxx_mbhc_decide_swch_plug中如果檢測到是headset則不重複多次檢測,如果是headphone則需要
wcd9xxx_schedule_hs_detect_plug(mbhc,&mbhc->correct_plug_swch);啟動重複檢測以確認正確
插入headphone耳機
<7>[ 105.233608] wcd9xxx_mech_plug_detect_irq: enter
<7>[ 105.233625] wcd9xxx_swch_irq_handler: enter
<7>[ 105.238692] wcd9xxx_swch_irq_handler: Acquiring BCL
<7>[ 105.238706] wcd9xxx_swch_irq_handler: Acquiring BCL done
<7>[ 105.238864] wcd9xxx_swch_irq_handler: Current plug type 0, insert 1
<7>[ 105.238876] wcd9xxx_cancel_hs_detect_plug: Canceling correct_plug_swch
<7>[ 105.238885] wcd9xxx_cancel_hs_detect_plug: Release BCL
<7>[ 105.238897] wcd9xxx_cancel_hs_detect_plug: Acquiring BCL
<7>[ 105.238907] wcd9xxx_cancel_hs_detect_plug: Acquiring BCL done
<7>[ 105.239014] wcd9xxx_mbhc_detect_plug_type: enter
<7>[ 105.497933] wcd9xxx_mbhc_decide_swch_plug: enter
<7>[ 105.498378] wcd9xxx_codec_get_plug_type: enter
<7>[ 105.501350] wcd9xxx_mbhc_setup_hs_polling: enter
...
<7>[ 105.590299] wcd9xxx_find_plug_type: DCE #0, fc06, V 0008(0008), GND 0, VDDIO 0, HPHL 1 TYPE 2
<7>[ 105.590317] wcd9xxx_find_plug_type: DCE #1, fc06, V 0008(0008), GND 0, VDDIO 0, HPHL 1 TYPE 2
<7>[ 105.590332] wcd9xxx_find_plug_type: DCE #2, fc06, V 0008(0008), GND 1, VDDIO 0, HPHL 1 TYPE 2
<7>[ 105.590346] wcd9xxx_find_plug_type: DCE #3, fc06, V 0008(0008), GND 0, VDDIO 0, HPHL 1 TYPE 2
<7>[ 105.590359] wcd9xxx_find_plug_type: Plug type 2 detected
<7>[ 105.590368] wcd9xxx_codec_get_plug_type: leave
<7>[ 105.590655] wcd9xxx_report_plug: enter insertion 1 hph_status 0
<7>[ 105.590666] wcd9xxx_report_plug: Reporting insertion 1(1)
繼續進行檢測wcd9xxx_correct_swch_plug,用以確認檢測正確,如果檢測到是PLUG_TYPE_HEADPHONE則需要在 HS_DETECT_PLUG_TIME_MS=5000毫秒內多次檢測
<7>[ 105.717321] wcd9xxx_correct_swch_plug: Acquiring BCL
<7>[ 105.717335] wcd9xxx_correct_swch_plug: Acquiring BCL done
<7>[ 105.717344] wcd9xxx_codec_get_plug_type: enter
<7>[ 105.720967] wcd9xxx_mbhc_setup_hs_polling: enter
<7>[ 105.804823] wcd9xxx_find_plug_type: DCE #0, fc08, V 0010(0010), GND 0, VDDIO 0, HPHL 1 TYPE 2
<7>[ 105.804841] wcd9xxx_find_plug_type: DCE #1, fc08, V 0010(0010), GND 0, VDDIO 0, HPHL 1 TYPE 2
<7>[ 105.804856] wcd9xxx_find_plug_type: DCE #2, fc08, V 0010(0010), GND 1, VDDIO 0, HPHL 1 TYPE 2
<7>[ 105.804871] wcd9xxx_find_plug_type: DCE #3, fc08, V 0010(0010), GND 0, VDDIO 0, HPHL 1 TYPE 2
<7>[ 105.804884] wcd9xxx_find_plug_type: Plug type 2 detected
<7>[ 105.804892] wcd9xxx_codec_get_plug_type: leave
<7>[ 105.804901] wcd9xxx_correct_swch_plug: Release BCL
<7>[ 105.804912] wcd9xxx_correct_swch_plug: attempt(1) current_plug(2) new_plug(2)
<7>[ 105.804922] Good headphone detected, continue polling
。。。
拔出耳機
<7>[ 1010.417287] wcd9xxx_mech_plug_detect_irq: enter
<7>[ 1010.417304] wcd9xxx_swch_irq_handler: enter
<7>[ 1010.422617] wcd9xxx_swch_irq_handler: Acquiring BCL
<7>[ 1010.422635] wcd9xxx_swch_irq_handler: Acquiring BCL done
<7>[ 1010.422809] wcd9xxx_swch_irq_handler: Current plug type 2, insert 0
<7>[ 1010.422820] wcd9xxx_cancel_hs_detect_plug: Canceling correct_plug_swch
<7>[ 1010.422830] wcd9xxx_cancel_hs_detect_plug: Release BCL
<7>[ 1010.422842] wcd9xxx_cancel_hs_detect_plug: Acquiring BCL
<7>[ 1010.422851] wcd9xxx_cancel_hs_detect_plug: Acquiring BCL done
<7>[ 1010.422863] wcd9xxx_report_plug: enter insertion 0 hph_status 1
<7>[ 1010.422876] wcd9xxx_report_plug: Reporting removal 1(0)
<7>[ 1010.422911] wcd9xxx_set_and_turnoff_hph_padac PA is off
<7>[ 1010.445247] __hphocp_off_report: clear ocp status 80
<7>[ 1010.445261] __hphocp_off_report: clear ocp status 40
<7>[ 1010.445272] wcd9xxx_insert_detect_setup: Setting up insert detection
<7>[ 1010.445468] wcd9xxx_report_plug: leave hph_status 0
<7>[ 1010.446056] wcd9xxx_swch_irq_handler: Release BCL
<7>[ 1010.446067] wcd9xxx_swch_irq_handler: leave
<7>[ 1010.446079] wcd9xxx_mech_plug_detect_irq: leave 1
<7>[ 1010.446408] wcd9xxx_hs_insert_irq: enter
<7>[ 1010.446418] wcd9xxx_hs_insert_irq: Acquiring BCL
<7>[ 1010.446427] wcd9xxx_hs_insert_irq: Acquiring BCL done
<7>[ 1010.446880] wcd9xxx_hs_insert_irq_swch: Removal
<7>[ 1010.447010] wcd9xxx_hs_insert_irq: Release BCL
插入Headset
<7>[ 1084.338102] wcd9xxx_mech_plug_detect_irq: enter
<7>[ 1084.338119] wcd9xxx_swch_irq_handler: enter
<7>[ 1084.343428] wcd9xxx_swch_irq_handler: Acquiring BCL
<7>[ 1084.343447] wcd9xxx_swch_irq_handler: Acquiring BCL done
<7>[ 1084.343619] wcd9xxx_swch_irq_handler: Current plug type 0, insert 1
<7>[ 1084.343631] wcd9xxx_cancel_hs_detect_plug: Canceling correct_plug_swch
<7>[ 1084.343641] wcd9xxx_cancel_hs_detect_plug: Release BCL
<7>[ 1084.343653] wcd9xxx_cancel_hs_detect_plug: Acquiring BCL
<7>[ 1084.343662] wcd9xxx_cancel_hs_detect_plug: Acquiring BCL done
<7>[ 1084.343676] wcd9xxx_mbhc_detect_plug_type: enter
<7>[ 1084.598139] wcd9xxx_mbhc_decide_swch_plug: enter
<7>[ 1084.598340] wcd9xxx_codec_get_plug_type: enter
<7>[ 1084.601291] wcd9xxx_mbhc_setup_hs_polling: enter
<7>[ 1084.676366] wcd9xxx_find_plug_type: DCE #0, 026d, V 1306(1306), GND 0, VDDIO 0, HPHL 1 TYPE 1
<7>[ 1084.676384] wcd9xxx_find_plug_type: DCE #1, 02b7, V 1365(1365), GND 0, VDDIO 0, HPHL 1 TYPE 1
<7>[ 1084.676399] wcd9xxx_find_plug_type: DCE #2, 02bb, V 1368(1368), GND 1, VDDIO 0, HPHL 1 TYPE 1
<7>[ 1084.676414] wcd9xxx_find_plug_type: DCE #3, 02bb, V 1368(1368), GND 0, VDDIO 0, HPHL 1 TYPE 1
<7>[ 1084.676427] wcd9xxx_find_plug_type: Plug type 1 detected
<7>[ 1084.676436] wcd9xxx_codec_get_plug_type: leave
<7>[ 1084.676720] wcd9xxx_mbhc_decide_swch_plug: Valid plug found, determine plug type 1
<7>[ 1084.676733] wcd9xxx_find_plug_and_report: enter current_plug(0) new_plug(1)
<7>[ 1084.676745] wcd9xxx_report_plug: enter insertion 1 hph_status 0
<7>[ 1084.676755] wcd9xxx_report_plug: Reporting insertion 3(3)
<7>[ 1084.676802] wcd9xxx_insert_detect_setup: Setting up removal detection
<7>[ 1084.676955] wcd9xxx_report_plug: leave hph_status 3
<7>[ 1084.777467] wcd9xxx_start_hs_polling: enter
<7>[ 1084.779191] wcd9xxx_start_hs_polling: leave
<7>[ 1084.779202] wcd9xxx_find_plug_and_report: leave
<7>[ 1084.779212] wcd9xxx_mbhc_decide_swch_plug: leave
<7>[ 1084.779221] wcd9xxx_mbhc_detect_plug_type: leave
<7>[ 1084.779229] wcd9xxx_swch_irq_handler: Release BCL
<7>[ 1084.779238] wcd9xxx_swch_irq_handler: leave
<7>[ 1084.779250] wcd9xxx_mech_plug_detect_irq: leave 1
五、如何flash開發板
1. lunch
2. fastboot flash boot boot.img, flash kernel的image
fastboot flash system system.img, flash system的image
六、SIM card detection
1. kernel/arch/arm/boot/dts/msm8226-cn3ii.dts 中有gpio_keys節點
gpio_keys {
compatible = "gpio-keys"
input-name = "gpio-keys" //表示輸出event的名字
...
}
kernel/drivers/input/keyboard/gpio_keys.c會解析 gpio-keys 的dts
增加sim card detection 的gpio key
sim1 {
ompatible = "gpio-keys";
input-name = "sim1-detection";
sim1_det {
label = "sim1-detection";
gpios = <&msmgpio 60 0x0>; //msmgpio表示使用的是8226的gpio, 60表示GPIO60
linux,input-type = <5>; //define EV_SW 0x05
linux,code = <7>; //#define SW_JACK_PHYSICAL_INSERT 0x07 /* set = mechanical switch set */
gpio-key,wakeup;
debounce-interval = <10>;
};
};
2. http://review.sonyericsson.net/#/c/518583
3. https://wiki.sonyericsson.net/androiki/FP8615_Support_for_SIM_detection_for_Zeus_Docomo_Definition_Report
七、Vibrator
1. 檢查是否工作 #echo 1000 > /sys/class/timed_output/vibrator/enable
八、GPIO設定的確認
1. msmgpio@kernel/arch/arm/boot/dts/msm8226-cn3ii.dtsi
msmgpio: gpio@fd510000 {
compatible = "qcom,msm-gpio";
interrupt-controller;
#interrupt-cells = <2>;
reg = <0xfd510000 0x4000>;
gpio-controller;
#gpio-cells = <2>;
ngpio = <117>;
interrupts = <0 208 0>;
qcom,direct-connect-irqs = <8>;
};
2. pm8226_gpios@kernel/arch/arm/boot/dts/msm8226-cn3ii.dts
&pm8226_gpios {
gpio@c000 { /* GPIO 1 */
/* XO_PMIC_CDC_MCLK enable for tapan codec */
qcom,mode = <1>; /* Digital output */
qcom,output-type = <0>; /* CMOS logic */
qcom,pull = <5>; /* QPNP_PIN_PULL_NO*/
qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
qcom,master-en = <1>; /* Enable GPIO */
};
gpio@c100 { /* GPIO 2 */
qcom,mode = <1>;
qcom,output-type = <0>;
qcom,pull = <5>;
qcom,vin-sel = <2>;
qcom,out-strength = <3>;
qcom,src-sel = <2>;
qcom,master-en = <1>;
};
...
}
3. http://review.sonyericsson.net/#/c/518583/
4. GPIO 如何配置成I2C
1)@kernel/arch/arm/boot/dts/msm8226-cn3ii.dtsi, 以下設定i2c的引數
i2c@f9926000 { /* BLSP-1 QUP-4 */
cell-index = <0>;
compatible = "qcom,i2c-qup";
reg = <0xf9926000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
reg-names = "qup_phys_addr";
interrupts = <0 98 0>;
interrupt-names = "qup_err_intr";
qcom,i2c-bus-freq = <400000>;
qcom,i2c-src-freq = <400000>;
ti_lm3630_bl@36{
compatible = "ti,lm3630_bl";
reg = <0x36>;
gpio_hw_en = <&msmgpio 27 0>;
pwm_feedback = <0x08 0x10>;
ctl = <0x00 0x00>;
fsc = <20200 20200>;
iname = "lm3630-lcd-bl-1","lm3630-lcd-bl-2";
connected = <0x01 0x01>;
bank = <0x00 0x01>;
filter_str = <0x03>;
ovp_boost = <0x24>;
led_fault = <0x00>;
intf_name = "lm3630-lcd-bl-1","lm3630-lcd-bl-2";
brightness = <255 255>;
};
};
2)kernel/arch/arm/mach-msm/board-sony_cn3ii-gpiomux.c,以下配置GPIO14和15為I2C的功能,即GPIOMUX_FUNC_3
static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
{
.gpio = 14, /* BLSP1 QUP4 I2C_SDA */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
},
},
{
.gpio = 15, /* BLSP1 QUP4 I2C_SCL */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
},
},
}
static struct gpiomux_setting gpio_i2c_config = {
.func = GPIOMUX_FUNC_3,
.drv = GPIOMUX_DRV_2MA,
.pull = GPIOMUX_PULL_NONE,
};
八、GPIO Check
1. AP GPIO:
kernel/arch/arm/mach-msm/board-sony_cn3ii-gpiomux.c //這其中只是定義了某個GPIO的配置,如果程式需要使用,還要gpio_request
/
PMIC GPIO:
kernel/arch/arm/boot/dts/msm-pm8226.dtsi中有pm8226_gpios的定義
kernel/arch/arm/boot/dts/msm8226-cn3ii.dts中的&pm8226_gpios,
kernel/drivers/gpio/gpnp-pin.c 中會解析pm8226_gpios dts.
2. HW Guy: Liu, Helson for GPIO setting.
3. GPIO設定文件http://metadoc.sonyericsson.net/login_link.asp?doc=1/10262-17/FCP1191405/6&rev=latest
4. 還可以在 cat sys/kernel/debug/gpio 確認當前GPIO的狀態
九、battery logging port
1. device/somc/yangtze/BoardConfig.mk
# battery logging //開啟編譯libbatterylogging的開關
ifneq ($(TARGET_BUILD_VARIANT), user)
SONY_CFG_LIBBATTERYLOGGING := true
endif
device/somc/yangtze/platform.mk
->PRODUCT_PACKAGES += battery_logging //新增battery_logging編譯目錄
device/somc/yangtze/files/init.sony-platform.rc
ONLY_IN_DEBUG( //設定是否 實時開始和停止執行battery_logging, 其定義在/build/core/definitions.mk (-DONLY_IN_DEBUG)
//實際上表示只要編譯的版本是eng和userdebug版本都需要執行
on property:battery_log=1 //init.c分析時會把property:battery_log 當作一個action 的條件加入trigger連結串列,當通過setprop改變
//battery_log的屬性時會觸發該action: start/stop battery_logging
//具體的程式碼分析:property_set@system/core/init/property_service.c
start battery_logging
on property:battery_log=0 //setprop battery_log 0 可以停止battery_logging service,
stop battery_logging)
ONLY_IN_VARIANT(eng, //其定義在/build/core/definitions.mk (-DONLY_IN_VARIANT)
on property:dev.bootcomplete=1
start battery_logging)
ONLY_IN_VARIANT(userdebug,
on property:dev.bootcomplete=1
start battery_logging)
ONLY_IN_DEBUG(
service battery_logging /system/bin/battery_logging
disabled) //disable表示需要手動啟動
2. vendor/semc/hardware/device/yangtze/libbatterylogging
->out/target/product/cn3ii/obj/STATIC_LIBRARIES/libbatterylogging_intermediates/libbatterylogging.a
3. vendor/semc/hardware/power/charge-log/battery_logging
->out/target/product/cn3ii/system/bin/battery_logging
4. #battery_logging -p //輸出所有的需要輸出資訊的名稱和路徑
#battery_logging -d //輸出執行時的log
十、device tree source(DTS)
0. http://devicetree.org/Main_Page
1. *.dts/dtsi 檔案一般位於 kernel/arch/arm/boot/dts,比如msm8226-cn3ii.dts msm8226-cn3ii.dtsi
2. 如何決定用那個*.dts檔案?
@kernel/arch/arm/mach-msm/Makefile.boot
# MSM8226
zreladdr-$(CONFIG_ARCH_MSM8226) := 0x00008000 //是啥地址?
dtb-$(CONFIG_MACH_SONY_CN3II) += msm8226-cn3ii.dtb
@kernel/arch/arm/configs/cn3ii_defconfig
CONFIG_ARCH_MSM8226=y
CONFIG_MACH_SONY_CN3II=y
3. 編譯dts為dtb的工具為DTC,位於kernel/scripts/dtc
hostprogs-y := dtc //@Makefile中,該行表示用hostprogs編譯生成dtc
最後生成的dtc可執行檔案位於out/target/product/cn3ii/obj/KERNEL_OBJ/scripts/dtc/dtc
4.用dtc編譯*.dts生成的*.dtb檔案位於
out/target/product/cn3ii/obj/KERNEL_OBJ/arch/arm/boot/msm8226-cn3ii.dtb
存放在手機什麼地方?
bootloader如何讀取?如何傳遞給kernel?
head-common.S@kernel\arch\arm\kernel中有
.long __atags_pointer @ r6 //表示儲存dtb的地址通過r6傳遞給kernel
5. kernel中解析DTS
setup_machine_fdt@kernel/arch/arm/kernel/devtree.c
struct boot_param_header *devtree = phys_to_virt(dt_phys); //注意boot_param_header結構
setup_machine_fdt將分析dtb最後所有devices生成樹,如何和以前的版本結果就一樣了
6. kernel中各個device和driver誰先載入?
十一、charge only porting
1. device/somc/common/sony-generic.mk 新增
-include vendor/semc/hardware/device/device.mk
2. device/somc/yangtze/files/init.sony-platform.rc 中新增
on early-boot
exec /system/bin/chargemon
//write /sys/class/power_supply/battery/enable_stop_charging_at_low_battery 1
device/somc/yangtze/BoardConfig.mk 增加
# Device sysfs path definitions
TARGET_BACKLIGHT_DEVICE_PATH := /sys/class/leds/wled:backlight/brightness
TARGET_LED_R_DEVICE_PATH := /sys/class/leds/led:rgb_red/brightness
TARGET_LED_G_DEVICE_PATH := /sys/class/leds/led:rgb_green/brightness
TARGET_LED_B_DEVICE_PATH := /sys/class/leds/led:rgb_blue/brightness
TARGET_DISPLAY_DEVICE_PATH := /sys/devices/mdss_dsi_panel
3. vendor/semc/hardware/device/目錄下新增device.mk 和 cn3ii/cn3ii.mk, 新增以下關鍵內容
@device.mk
DEVICE_CONFIG=vendor/semc/hardware/device
# Call product specific makefiles.
-include $(DEVICE_CONFIG)/$(TARGET_PRODUCT)/$(TARGET_PRODUCT).mk
# Call platform specific makefiles.
-include $(DEVICE_CONFIG)/yangtze/platform.mk
@cn3ii.mk
SONY_CFG_CHARGEMON := true
PRODUCT_PACKAGES += chargemon
vendor/semc/hardware/device/yangtze$ 目錄下新增chargemon_common.mk和platform.mk
@platform.mk
PLATFORM_DEVICE_CONFIG=vendor/semc/hardware/device/yangtze
# chargemon
include $(PLATFORM_DEVICE_CONFIG)/chargemon_common.mk
6. 注意:
*.rc 檔案放在ramdisk中,而一般打包在boot.img或kernel.sin中
修改完*.mk檔案後,需要重新lunch才會生效
7. 如何debug
#define DEBUG_LOG //在log.h中定義,開啟log輸出到手機 data/cm.log
LOGM(2); //在main程式碼中開啟log輸出mode,
十二、電池充電的幾個關鍵過程
Trigle charge:
0. 當電池電壓很低時,如何charge?
1. Vbat>3.42V,直接進入sys boot; Vbat<3.42時進入SBL的充電邏輯,Vbat<2.9v進入SBL的trigle charge(200mA充電),當超過2.9v時,進入SBL的fast charge模式(500mA充電),一直充直到Vbat>3.7V後,boot sys.
進入trigle charge mode,然後當電池電壓充到3.7V(system weak threshod, Vweak)則退出trigle charge mode,啟動kernel
2. Auto trigle charge(ATC)的觸發條件: 電池電壓< Vweak系統需要啟動的最低電壓,然後 充電電流被限制在100mA;手機不能用100mA的電流啟動。
3. Two-step ATC 目前沒有用,當電池電壓特別低時分兩步充電
a. Vbat < Vtrkl, Buck off, Bat FET closed, 充電電流50mA-200mA,小電流充電, Vtrkl一般設定區間為2.05V-2.8V
b. Vweak > Vbat > Vtrkl, Buck on, Bat FET closed,充電電流300mA-500mA, Vweak一般設定區間為2.1V-3.6V
4. 用FLCB 充電,目前CN3-ii用該方案
Buck on, Bat FET open, 用VCHG直接給電池充電,不經過Bat FET.一直用ITRKL電流給電池充電,該Itrkl電流一般多大?
當Vbat > Vweak後,系統就啟動了
Fast charging
1. CC , Vweak < Vbat < Vbat_max, 用最大電流IBAT_MAX 給電池充電,IBAT_MAX的一般取值區間300mA-3000mA
2. CV, Vbat > Vbate_max, 逐漸降低充電電流Ibat,直到給電池的充電電壓VPH_PWR==VDD_MAX,VDD_MAX一般設定區間3.4V-4.5V
Charging termination[依據的是充電電流大小]
1. 結束條件:Ibat(充電電流) < Iterm (with deglitching),Iterm一般設定區間35mA-276mA
2. 結果:Bat FET Open, Buck on 這樣仍然可以給系統供電。如果系統需要的電流>Buck能提供的,那麼Battery如何供電給系統?Bat FET Open也能反向把電流從電池輸送給系統嗎?
Automatic Recharge[依據的是電池電壓大小]
1. 開始條件:Vbat < Vbat_det, 一般Vbat_det設定區間是3.3V-4.7V
2. 結果,又進入Fast charging階段
OVP(過壓保護)
1. 從外部USB 進入的電壓保護範圍[5v,28v],可以設定該指?如果大於這最大進入電壓,則第一級的保護電路生效。
2. 進入第二級保護電路,如果通過1進入的電壓,大於預先SSBI-programmable設定的門限(該門限設定區間[5.5v,7v]),如果電壓大於該門限,則OVP FET會OPEN,反之。
十三、如何讀寫充電暫存器
1. 讀暫存器
echo 0xccc > /sys/kernel/debug/spmi/spmi-0/address
echo 0xccc > /sys/kernel/debug/spmi/spmi-0/count
cat /sys/kernel/debug/spmi/spmi-0/data
寫暫存器
echo 0xccc > /sys/kernel/debug/spmi/spmi-0/address
echo 0xccc > /sys/kernel/debug/spmi/spmi-0/data
2. 如何控制使用內部或外部電阻rsense.
0x3848 IADC2_BMS_ADC_CH_SEL_CTL
0x0: INTRSNS
0x1: EXTRSNS
@kernel/arch/arm/boot/dts/msm8226-cn3ii.dtsi中
&pm8226_bms {
qcom,use-external-rsense = <1>;
}
qcom,pm8226@0 {
iadc@3600 {
qcom,rsense = <10000000>;
};
};
3. 另外Huashan PM8921的路徑為: sys/kernel/debug/pm8921-dbg
十四、增加識別wall charger
http://review.sonyericsson.net/#/c/534625/
十五、如何disable/enable充電
1. [User]SysFS: /sys/class/power_supply/battery/charging_enabled;
在charge only程式中,會通過miscTA 2312的值,來判斷是否diable/enable充電(1:disable;非1:enable)
disableCharging@vendor/semc/hardware/power/chargemon/src/main.c
hw_disableCharging@vendor/semc/hardware/power/chargemon/src/main.c
->hw_writeSysfs(DISABLE_CHARGING_PATH, DISABLE_CHARGING); //DISABLE_CHARGING_PATH=/sys/class/power_supply/battery/charging_enabled
[Kernel]的對應處理 qpnp_batt_power_set_property@kernel/drivers/power/qpnp-charger.c
chip->charging_disabled = !(val->intval);
qpnp_chg_charge_en(chip, !chip->charging_disabled); //操作0x1049的bit7,主要控制FSM是否工作
qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);//0x1049的bit7,主要控制所有與電池相關的功能(trikle charger, buck reg, batfet)是否工作。
2. Debugmenu中如何控制充電
@vendor/semc/packages/apps/debugmenu/src/com/sonyericsson/debugmenu/charging.java中會操作MiscTA 2312, 寫入1 disable或0 enable;
然後下次啟動執行charge only的時候會根據該Misc 他的值,enable/disbale充電。
十六、Charge only中的重要控制
1. charge only 是否進入的控制。
miscTA 2311, 0: 可以進入charge only; 2: 這次不讓進入,但下次讓進入; 其他(1):不讓進入charge only.
2. 在charge only程式中是否充電
miscTA 2312的值,來判斷是否diable/enable充電(1:disable;非1:enable)
/sys/class/power_supply/battery/charging_enabled;
3. Android USB device的控制
sys/class/android_usb/android0/enable 控制是否enable ADB功能
sys/class/android_usb/android0/functions, 設定USB支援的功能,在屬性sys.usb.config,兩者一致
sys/class/android_usb/android0/idProduct or idVendor, 重置USB的ID,但必須先disable USB
@vendor/semc/hardware/device/yangtze/chargemon_common.mk中有如下定義
USB_VENDOR_ID := 0fce
USB_PRODUCT_ID := e000
USB_ACCESSORY_VID := 18d1
USB_ACCESSORY_PID := 2d00
MASS_STORAGE := mass_storage
ACCESSORY := accessory
USB_ENABLE_PATH := /sys/class/android_usb/android0/enable
USB_SETFUNC_PATH := /sys/class/android_usb/android0/functions
USB_PRODUCT_ID_PATH := /sys/class/android_usb/android0/idProduct
USB_VENDOR_ID_PATH := /sys/class/android_usb/android0/idVendor
@device/somc/cn3ii/System.prop,中有 ro.usb.pid_suffix=1A9 重新設定USB PID
$在Ubantu上lsusb可以所有的usb device,其中就包括
Bus 001 Device 111: ID 0fce:51a9 Sony Ericsson Mobile Communications AB ,
idProduct,idVendor,function是在那裡設定的?
@device/somc/common/files/init.sony.usb.rc
on property:sys.usb.config=mtp,adb //任何sys.usb.config的改變,就會觸發後面的動作
exec /init.usbmode.sh
start adbd
setprop sys.usb.state ${sys.usb.config}
@device/somc/common/files/init.usbmode.sh
VENDOR_ID=0FCE
PID_SUFFIX_PROP=$(/system/bin/getprop ro.usb.pid_suffix)
USB_FUNCTION=$(/system/bin/getprop sys.usb.config)
get_pid_prefix ${USB_FUNCTION}中確定PID_PREFI的值,實際上是根據sys.usb.config
PID=${PID_PREFIX}${PID_SUFFIX_PROP},其中PID_PREFIX表示sony自己定義的功能 5:mtp,adb;0:mtp
echo ${VENDOR_ID} > /sys/class/android_usb/android0/idVendor
echo ${PID} > /sys/class/android_usb/android0/idProduct
@device/somc/common/sony-generic.mk
ADDITIONAL_DEFAULT_PROPERTIES += persist.sys.usb.config=mtp 但是隻設定了mtp功能,沒有adb功能?
@frameworks/base/services/java/com/android/server/usb/usbdevicemanager.java
函式setEnabledFunctions(..) 會根據setting UI的設定改變persist.sys.usb.config的值
if (mAdbEnabled) {
functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
} else {
functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
}
SystemProperties.set("persist.sys.usb.config", functions);
有個問題,設定persist.sys.usb.config是如何傳到sys.usb.config的???
@system/core/rootdir/init.usb.rc
on property:persist.sys.usb.config=*
setprop sys.usb.config none
setprop sys.usb.config ${persist.sys.usb.config} //兩者會同步
4. 可以優化的地方
a. 現在charge eoc後,如果拔掉充電器,則會上報report key KEY_F24, charge only process會在
hw_waitForUserAction@vendor/semc/hardware/power/chargemon/src/hw.c中
hw_wakeUnlock();
i = select(max_fd + 1, &listen, NULL, NULL, &delay);//等待5秒,也只有在這5秒中,系統才有機會suspend
hw_wakeLock();
而上報KEY_F24事件,主要是解決在charge only模式下,系統深度睡眠,拔掉充電器時,charge only不會退出關機
b. 而在 check_plugin_wakelock@kernel/drivers/power/qpnp-charger.c中,當拔掉充電器時會有wakelock,超時2秒
wake_lock_timeout(&chip->somc_params.plugin_wake_lock, PLUGIN_WAKELOCK_TIME_SEC);
c. 由此,是否可以不需要上報KEY_F24給charge only呢?直需要縮短 select 的延時<2秒,就可以避免charge only不會退出關機的問題
十七、電池引數的設定(百分比,溫度,電壓 之間的關係)
1. @kernel/arch/arm/boot/dts/msm8226-cn3ii.dtsi
&pm8226_bms {
qcom,batt-type = <3>; //電池型別為 BATT_OEM
}
@kernel/arch/arm/mach-msm/Makefile, 當前用的是pc_temp_ocv@bms-batterydata-sleipner.c
ifdef CONFIG_MACH_SONY_CN3II
obj-$(CONFIG_MACH_SONY_CN3II) += bms-batterydata-sleipner.o
設定電池的相關引數
set_battery_data@kernel/drivers/power/qpnp-bms.c
插值計算@kernel/arch/arm/mach-msm/baterydata-lib.c
十八、電池低電關機過程
1. 涉及關機的幾個引數配置
pm8226_bms: qcom,bms {
qcom,v-cutoff-uv = <3400000>; //關機電壓,但只用與計算SOC
qcom,low-soc-calculate-soc-threshold = <15>; //認為是低電的電池百分比
qcom,low-soc-calculate-soc-ms = <5000>; //低電情況下的心跳
qcom,calculate-soc-ms = <20000>;
qcom,low-voltage-threshold = <3420000>;
}
2. 系統休眠情況下的低電關機觸發
setup_vbat_monitoring@kernel/drivers/power/qpnp-bms.c 中會設定低電(高電,高溫,低溫)的threshold,
還有call back函式btm_notify_vbat, 如果電壓低於low-voltage-threshold-VBATT_ERROR_MARGIN也就是3.4V
->configure_vbat_monitor_low
喚醒系統 wake_lock(&chip->low_voltage_wake_lock);
開始計算soc, schedule_delayed_work(&chip->calculate_soc_delayed_work, 0);
針對電池低壓的情況下,重新配置引數
如果此時soc=0,則上報android 關機
3. 系統正常情況下的低電關機觸發
開機後馬上執行 calculate_soc_work,以後只要系統不休眠則 心跳間隔20s(soc > 15%),5s(soc < 15% & wake_lock_active(&chip->low_voltage_wake_lock))
->recalculate_soc
->calculate_state_of_charge
->adjust_soc
->very_low_voltage_check 如果電池電壓<3.42v,則wake_lock(&chip->low_voltage_wake_lock);不讓系統休眠, 隨後心跳間隔一直繼續,上報soc,如果soc=0則系統會關機。
十九、PMIC中充電部分中斷的申請和處理
1. @kernel/arch/arm/boot/dts/msm-pm8226.dtsi
qcom,chgr@1000 {
status = "disabled";
reg = <0x1000 0x100>;
interrupts = <0x0 0x10 0x0>,
<0x0 0x10 0x1>,
<0x0 0x10 0x2>,
<0x0 0x10 0x3>,
<0x0 0x10 0x4>,
<0x0 0x10 0x5>, //"fast-chg-on"對應的暫存器0x1000 + 0x10 = 0x1010, 0x05表示的是第5個bit
<0x0 0x10 0x6>,
<0x0 0x10 0x7>;
interrupt-names = "vbat-det-lo",
"vbat-det-hi",
"chgwdog",
"state-change",
"trkl-chg-on",
"fast-chg-on",
"chg-failed",
"chg-done";
};
對應的是SMBBP_CHAR_SMNNP_CHAR中 0x1010 SMBBP_CHGR_INT_RT_STS 中斷暫存器的bits
2. 如何引用,例子如下:
qpnp_chg_request_irqs@kernel/drivers/power/qpnp-charger.c
chip->chg_fastchg.irq = spmi_get_irq_byname(spmi,spmi_resource, "fast-chg-on");
二十、充電最大時間設定(trickle + fast charging)
1. @kernel/arch/arm/boot/dts/msm-pm8226.dtsi
pm8226_chg: qcom,charger {
qcom,tchg-mins = <150>; //表示150分鐘, 取值區間[4, 512]分鐘
}
2. qpnp_charger_read_dt_props@kernel/drivers/power/qpnp-charger.c
OF_PROP_READ(chip, tchg_mins, "tchg-mins", rc, 1);
qpnp_chg_hwinit
rc = qpnp_chg_tchg_max_set(chip, chip->tchg_mins); //此處往暫存器0x1061 SMBBP_CHGR_TCHG_MAX 寫入
3. 如果需要disable 充電最大時間的限制,則需要操作 暫存器0x1060 SMBBP_CHGR_TCHG_MAX_EN
4. 如果需要設定trickle charge的最大時間限制,則需要操作 暫存器0x105F SMBBP_CHGR_TTRKL_MAX,
enable/disable 則需要操作 暫存器0x105E SMBBP_CHGR_TTRKL_MAX_EN,
二十一、當kernel用power_supply_changed 傳送uevent 到 userspace的後續處理
1. register_android_server_BatteryService@frameworks/base/services/jni/com_android_server_BatteryService.cpp 註冊的sys path如下:
/sys/class/power_supply/???/online 其中???/type=Mains //注意大小寫是區分的
/sys/class/power_supply/usb/online 其中usb/type=USB
/sys/class/power_supply/battery/online 其中usb/type=Battery
/sys/class/power_supply/battery/status
/sys/class/power_supply/battery/health
/sys/class/power_supply/battery/present
/sys/class/power_supply/battery/capacity
/sys/class/power_supply/battery/voltage_now[batt_vol]
/sys/class/power_supply/battery/temp[batt_temp]
/sys/class/power_supply/battery/technology
2. 如果是power_supply_changed(&chip->batt_psy);則user space 會讀取所有註冊的關於battery 的sys path.
二十二、如何在kernel新增input key event給user space用
@kernel/drivers/power/qpnp-charger.c
註冊/* register input device */
chip->somc_params.chg_unplug_key = input_allocate_device();
input_set_capability(chip->somc_params.chg_unplug_key, EV_KEY, KEY_F24);
chip->somc_params.chg_unplug_key->name = "qpnp_chg_unplug_key";
chip->somc_params.chg_unplug_key->dev.parent = &(spmi->dev);
rc = input_register_device(chip->somc_params.chg_unplug_key);
//input_free_device(chip->somc_params.chg_unplug_key);
使用:
input_report_key(chip->somc_params.chg_unplug_key, KEY_F24, value ? 1 : 0);
input_sync(chip->somc_params.chg_unplug_key);
二十三、chager debug
1. echo -n "file qpnp-charger.c +p" > /sys/kernel/debug/dynamic_debug/control
2. disable charging:
echo 0 > /sys/class/power_supply/battery/charging_enabled
3. WARN_ON(1) & BUG_ON
二十四、高通Case和公司DMS的關係
1. 如果遇到問題是高通的bug,提交一個case給高通
2. 在公司的DMS中建立一個主DMS, 並且assign給 coordinator, 並且在Attachments/Reference頁籤中的External References上
External Reference 選擇Qcom
External Reference ID 輸入 Qcom的case ID;
3. 如果Qcom的solution沒有及時deliver, 我們可以建立一個child dms, 在Linked Records頁籤中單擊 Create Child,在該child DMS中diliver我們自己的solution;一旦Qcom diliver了Solution,則我們自己的solution需要revert.
二十五、 Touch screen, Display新的early suspend機制
1. User space 如果需要early suspend,則需要操作 "/dev/graphics/fb0"
ioctl(fb.fd, FBIOBLANK, FB_BLANK_UNBLANK); //resume
ioctl(fb.fd, FBIOBLANK, FB_BLANK_POWERDOWN); //suspend
2. 通過操作display的ioctl, 進而控制其他需要early supend的裝置,主要機制是notify的回撥
do_fb_ioctl@kernel/drivers/video/fbmem.c
fb_blank(info, arg)@kernel/drivers/video/fbmem.c
fb_notifier_call_chain(FB_EVENT_BLANK, &event)@kernel/drivers/video/fbmem.c
blocking_notifier_call_chain@kernel/kernel/notifier.c
notifier_call_chain(&nh->head, val, v, nr_to_call,nr_calls)@kernel/kernel/notifier.c
nb->notifier_call(nb, val, v)@kernel/kernel/notifier.c
3. 需要和display一塊suspend的裝置如何註冊notify, 比如touch screen
clearpad_probe@kernel/drivers/input/touchscreen/clearpad_core.c
this->fb_notif.notifier_call = synaptics_fb_notifier_callback;
rc = fb_register_client(&this->fb_notif); //註冊display notify的關鍵函式
另外還註冊正常的linux power管理的suspend/resume
static const struct dev_pm_ops synaptics_clearpad_pm = {
.suspend = synaptics_clearpad_pm_suspend,
.resume = synaptics_clearpad_pm_resume,
.suspend_noirq = synaptics_clearpad_pm_suspend_noirq,
};
以上兩條suspend的路徑最後都呼叫 synaptics_clearpad_suspend和synaptics_clearpad_resume
二十六、低電關機(soc=0%和電壓低於設定的低電壓 都會觸發低電關機)
1. 電壓低於設定電壓的處理
@msm-pm8226.dtsi中
pm8226_bms: qcom,bms{
qcom,low-soc-calculate-soc-threshold = <15>; //認為是低電壓的soc(15%)
qcom,low-soc-calculate-soc-ms = <5000>; //低電壓情況下,計算soc 的時間間隔5s
qcom,calculate-soc-ms = <20000>; //正常情況下,計算soc 的時間間隔20s
qcom,v-cutoff-uv = <3400000>;//用於計算soc
qcom,low-voltage-threshold = <3420000>;//用於設定關機低電壓
}
2. 系統一開機會馬上執行calculate_soc_work,然後間隔20s或5s 迴圈執行,只要系統不suspend,該schedule work會一直執行,如果s計算的soc有變化還會power_supply_changed上報給使用者空間,如果此時soc=0%則使用者空間會強制關機shut down.
3. 另外還有一種情況,就是系統已經suspend,但電池電壓小於預先設定的門限電壓,會觸發notify也就是btm_notify_vbat@qpnp-bms.c,如果是低電狀態則繼續呼叫configure_vbat_monitor_low,其中會wake_lock(&chip->low_voltage_wake_lock);讓系統不再suspend,馬上開始執行calculate_soc_work,也就是把soc=0%的資訊趕快通知給user space,好執行低電關機。具體分析如下:
3.1 設定低電notify的相關引數,setup_vbat_monitoring@qpnp-bms.c
->qpnp_adc_tm_channel_measure@qpnp-adc-tm.c; 設定adc channel的監控設定
chip->vbat_monitor_params.low_thr = chip->low_voltage_threshold; //低電壓門限設定
chip->vbat_monitor_params.high_thr = chip->max_voltage_uv - VBATT_ERROR_MARGIN; //高電壓門限設定
chip->vbat_monitor_params.state_request = ADC_TM_HIGH_LOW_THR_ENABLE; //觸發的型別 滿足高低電壓門限時觸發
chip->vbat_monitor_params.channel = VBAT_SNS;
chip->vbat_monitor_params.btm_ctx = (void *)chip;
chip->vbat_monitor_params.timer_interval = ADC_MEAS1_INTERVAL_1S; //Polling 時間
chip->vbat_monitor_params.threshold_notification = &btm_notify_vbat; //回撥函式
rc = qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
3.2 @qpnp-adc-tm.c
notify_adc_tm_fn是其中關鍵的處理函式
->notify_clients(adc_tm)-->adc_tm->btm_param->threshold_notification(ADC_TM_LOW_STATE, adc_tm->btm_param->btm_ctx);
qpnp_adc_tm_probe中初始化INIT_WORK(&adc_tm->sensor[sen_idx].work, notify_adc_tm_fn);
初始化qpnp_adc_tm_low_thr_isr中斷處理函式
rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_low_thr_irq,
qpnp_adc_tm_low_thr_isr,IRQF_TRIGGER_RISING, "qpnp_adc_tm_low_interrupt", adc_tm);
一旦電壓低於chip->vbat_monitor_params.low_thr則觸發qpnp_adc_tm_low_thr_isr,然後schedule_work(qpnp_adc_tm_low_thr_work);最後會呼叫qpnp_adc_tm_read_status,又會觸發schedule_work(&adc_tm->sensor[sensor_num].work);即notify_adc_tm_fn函式,從而會發notify訊息給BMS的btm_notify_vbat->configure_vbat_monitor_low和power_supply_changed
二十七、讀取的adc電壓和電池溫度的關係
1. @kernel/drivers/hwnon/qpnp-adc-common.c
計算電池溫度和電壓關係的函式qpnp_adc_scale_batt_therm
電池溫度和電壓關係的對應表adcmap_btm_threshold[], 該表需要電池team提供
static const struct qpnp_vadc_map_pt adcmap_btm_threshold[] = {
{-300, 1686}, ...
{0, 1342}, ...
{450, 619}, ... {溫度45度,電壓619mv}
}
通過線性逼近插值計算精度可以到達0.1Degc
2. 讀取電池溫度的流程
get_prop_batt_temp@kernel/drivers/power/qpnp-charger.c
qpnp_vadc_read(LR_MUX1_BATT_THERM, &results)@kernel/drivers/hwmon/qpnp-adc-voltage.c
qpnp_vadc_conv_seq_request(ADC_SEQ_NONE, channel, result)@kernel/drivers/hwmon/qpnp-adc-voltage.c
vadc_scale_fn[scale_type].chan(result->adc_code,vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result)@qpnp-adc-voltage.c
qpnp_adc_scale_batt_therm@kernel/drviers/hwmon/qpnp-adc-common.c
重點分析qpnp_vadc_conv_seq_request@qpnp-adc-voltage.c
a. vadc->adc->adc_channels 的賦值
qpnp_adc_get_devicetree_data@qpnp-adc-common.c
->adc_qpnp->adc_channels = adc_channel_list;其中adc_channel_list是分析讀取msm8226-cn3ii.dtsi中&pm8226_vadc的節點內容,其中有
chan@30 {
label = "batt_therm";
reg = <0x30>; //channel_num 通道號,也就是需要讀取的channel,針對battery thermal是LR_MUX1_BATT_THERM=48,正好匹配
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
qcom,scale-function = <1>; //adc_scale_fn的ID,也就是scale_type
qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
};
->vadc_scale_fn的定義
static struct qpnp_vadc_scale_fn vadc_scale_fn[] = {
[SCALE_DEFAULT] = {qpnp_adc_scale_default},
[SCALE_BATT_THERM] = {qpnp_adc_scale_batt_therm}, //battery thermal的scale函式qpnp_adc_scale_batt_therm@qpnp-adc-common.c
[SCALE_PMIC_THERM] = {qpnp_adc_scale_pmic_therm},
[SCALE_XOTHERM] = {qpnp_adc_tdkntcg_therm},
[SCALE_THERM_100K_PULLUP] = {qpnp_adc_scale_therm_pu2},
[SCALE_THERM_150K_PULLUP] = {qpnp_adc_scale_therm_pu1},
[SCALE_QRD_BATT_THERM] = {qpnp_adc_scale_qrd_batt_therm},
};
estimate_ocv
clamp_soc_based_on_voltage_with_max_count
問題:
DMS01852397
qpnp_chg_idcmax_set 中演算法和datasheet不一致?