原文网址: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, POER_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 TA的值,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,则我