原文网址: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 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,则我们自己的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不一致?

Stay hungry, stay foolish!

android开发 dts、各种接口porting----不错相关推荐

  1. Android开发之通过接口回调机制加载数据(源代码分享)

    Android开发之通过接口回调机制加载数据的简单实现,在实际开发中通过callback方法得到网络加载的数据的使用频率远比通过直接开启线程或异步任务加载数据的频率高的多,这篇文章的代码将简单实现该机 ...

  2. android开发 dts、各种接口porting

    原文网址:http://www.xuebuyuan.com/1023185.html 1. repo init -u git://review.sonyericsson.net/platform/ma ...

  3. android开发接口调用,Android开发中webService接口调用示例

    代码示例: package com.study.ws; import java.io.IOException; import org.ksoap2.SoapEnvelope; import org.k ...

  4. android开发股票数据接口,股票数据接口-股票数据接口api

    原标题:股票数据接口-股票数据接口api 量亿数据专注金融领域API数据接口,其中包括期货.股票.期权.外汇等,只需要注册即可申请使用. 免费申请网址:http://www.liangyee.com/ ...

  5. Android开发之移动互联网周刊第二期,不错,推荐给大家

    Android开发之移动互联网周刊第二期,不错,推荐给大家 http://www.apkbus.com/zhoukan/2/index.html 转载于:https://blog.51cto.com/ ...

  6. Android接口一般定义格式,Android开发规范

    原标题:Android开发规范 一.书写规范 1. 编码方式统一用UTF-8. 2. 花括号不要单独一行,和它前面的代码同一行.而且,花括号与前面的代码之间用一个空格隔开. 3. 空格的使用 if.e ...

  7. Android开发笔记(五十四)数据共享接口ContentProvider

    ContentProvider 前面几节介绍了进程间通信的几种方式,包括消息包级别的Messenger.接口调用级别的AIDL.启动页面/服务级别的Notification,还有就是本节这个数据库级别 ...

  8. Android开发笔记(五十三)远程接口调用AIDL

    AIDL概述 AIDL全称是"Android Interface Definition Language",即Android的接口定义语言.AIDL用来协助开发者来处理进程间通信, ...

  9. Android开发笔记(四十七)Runnable接口实现多线程

    Runnable概述 Runnable接口可声明一连串的事务,常用于多线程处理.但是实现Runnable接口并不意味着开启了一个新线程,只是定义了接下来要做的事情,至于说这些事情要在主线程处理,还是在 ...

最新文章

  1. 冲刺第九天 12.5 WED
  2. 64位内核开发第五讲,调试与反调试
  3. python中beautifulsoup是什么库_BeautifulSoup库详解(个人整理)
  4. mysql排序两位数_MySQL_Mysql row number()排序函数的用法和注意,虽然使用不多,但是也有情况 - phpStudy...
  5. 快速开发工作流_01_简单流程案例
  6. linux下使用命令行分区、格式化文件系统、更新卷标名称
  7. python-Key Error问题
  8. Google map API:查询地理位置和经纬度信息示例
  9. C++后台开发学习路线
  10. android 照片同步 icloud,如何将iCloud照片传输到Android手机
  11. VC静态库开发与使用
  12. 网易企业邮箱如何设置反垃圾规则?【网易企业邮箱】
  13. 数据库底层原理-------数据结构
  14. SDRAM学习(一)——初始化
  15. 怎么下载linux sio镜像,在linux下如何安裝ftdi_sio USB轉串口驅動
  16. Django1.11.4 在前端显示图片
  17. 给服务器添加硬盘,Ubuntu挂载硬盘
  18. TiDB 作为 MySQL Slave 实现实时数据同步
  19. 【百度​Sugar BI​ - 自动分析】你负责准备数据,我负责生成报表题
  20. 项目需求讨论-APP手势解锁及指纹解锁

热门文章

  1. Android保活从入门到放弃:乖乖引导用户加白名单吧(附7大机型加白示例)
  2. 微信小程序之性别单选效果
  3. Activiti7 + Spring Boot + mybatis Plus + Oracle 数据库整合-学习篇(二)
  4. 手把手教截图识别文字
  5. 计算机公式s是什么意思,概率统计中S是什么意思?如何算得?
  6. 破解锐捷3.35-0618的密码
  7. 【孙伟】Flash(Adobe Animate)动画制作入门视频教程-孙伟-专题视频课程
  8. 利用函数(求数组最大值、判断平年闰年、翻转数组、判断是否为素数)
  9. Termius 的替代方法
  10. 批量修改文件名(find rename sed)