电池容量足够低如何触发自动关机(Riogrande platform&Qualcom platform)

http://blog.csdn.net/pillarbuaa/article/details/7634744


1. 进入手机/sys/devices/platform/nmk-i2c.2/i2c-2/2-0040/leds/ 或 sys/class/leds/目录list如下
    pwr-red,pwr-green,pwr-blue //控制充电led    
    l-key-red,l-key-green,l-key-blue //控制left button led
    m-key-red,m-key-green,m-key-blue //控制middle button led
    r-key-red,r-key-green,r-key-blue //控制right button led     
    lcd-backlight //控制lcd backlight led
   设置其中brightness的值,可以调整各led的显示亮度
2. https://wiki.sonyericsson.net/androiki/Fuel_Gauge (SysFS interfaces)
    Riogrande

    Disable charging: adb shell "echo 0 > /sys/ab8500_chargalg/chargalg",用于得到没有充电的log
    Enable AC dedicated charger: adb shell "echo 1 > /sys/ab8500_chargalg/chargalg"
    Enable PC-USB and USB wall charger: adb shell "echo 2 > /sys/ab8500_chargalg/chargalg"    

    Qualcom

    Disable charging: echo 2 > /sys/module/pm8921_charger/parameters/disabled
    Enable charging: echo 0 > /sys/module/pm8921_charger/parameters/disabled 

3. Kernel 有log输出 
        "SysRq : Emergency Remount R/O"
        “Emergency Remount complete” 位于函数do_emergency_remount@kernel/fs/super.c
        “Shutting down AS3676” 位于函数 as3676_shutdown@kernel/drivers/leds/leds-as3676.c        
        "CPU1: shutdown"
        "Power down" 位于函数kernel_power_off@kernel/kernel/sys.c
   Java 有log输出 
        “Performing low-level shutdown...” 位于函数 rebootOrShutdown@frameworks/base/core/java/com/android/internal/app/shutdownthread.java
4. 手机手动关机的过程
    [JAVA framework]interceptPowerKeyDown和Runnable mPowerLongPress@frameworks/policies/base/phone/com/android/internal/policy/impl/PhoneWindowManager.java
    [JAVA framework]shutdown dialog 在frameworks/policies/base/phone/com/android/internal/policy/impl/GlobalActions.java
    [JAVA framework]Shutdown process 在frameworks/base/core/java/com/android/internal/app/ShutdownThread.java
        Through beginShutdownSequence(), actual shutdown process is done in run().
            Broadcasts ACTION_SHUTDOWN Intent
            Calls shutdown of ActivityManager service
            Calls disable of Bluetooth service
            Calls Radio(false) of Phone service
            Calls shutdown of Mount service
            Vibrate for a while
            Calls Power.shutdown(); //这个是关键
4.1 具体分析Power.shutdown如何从user spaced到kenrel space
    [JAVA]其中Power.shutdown@frameworks/base/core/java/android/os/power.java 
    [JNI] android_os_Power_shutdown@frameworks/base/core/jni/andorid_os_power.cpp
    [Library] android_reboot(ANDROID_RB_POWEROFF, 0, 0)@system/core/libcutils/android_reboot.c
    [Library] reboot(RB_POWER_OFF)@kernel/bionic/libc/unistd/reboot.c 
    [Library] _reboot@kernel/bionic/libc/arch-arm/syscalls/__reboot.S 其中bionic/libc/include/sys/linux-syscalls.h中定义了#define __NR_reboot    (__NR_SYSCALL_BASE + 88)这与kernel的定义就一致了,会产生系统中断88,调用kernel的sys_reboot
4.2 reboot系统调用: 
    [Kernel] kernel/arch/arm/include/asm/unistd.h 有#define __NR_reboot (__NR_SYSCALL_BASE+ 88);
    [Kernel] kernel/arch/arm/kernel/calls.s 有CALL(sys_reboot) /*88*/
    [Kernel] kernel/arch/arm/kernel/entry-common.s 会引用call.s 对sys_call_table(系统调用表)进行定义
    [Kernel] kernel/kernel/sys.c中有定义SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,    void __user *, arg),定义了reboot该系统调用    
    [Kernel] 如果是Power off 则会调用kernel_power_off和do_exit(0)@kernel/kernel/sys.c
    [Kernel] kernel_power_off-->kernel_shutdown_prepare-->device_shutdown[关闭非系统设备 比如:AS3676 会调用as3676_shutdown@kernel/drivers/leds/leds-as3676.c]和 sysdev_shutdown[关闭所有系统设备]
    [Kernel] 最后machine_power_off

5. LowBat interrupt trigger; 当电池电压低于某个值(在那设置?abx500_fg_parameters.lowbat_threshold的值@kernel/arch/arm/mach-ux500/board-mop500-bm.c)会触发如下中断函数
    1). [KERNEL]ab8500_fg_lowbatf_handler@kernel/drivers/power/ab8500_fg.c 有log: "Battery voltage is below LOW threshold", 其中为了避免是电池电压偶尔的下降,需要多次检测(ab8500_fg_low_bat_work 有log: ”Battery voltage still LOW“),从而最终确认是否真的是电池电压不够了,
    2). [KERNEL]最后会调用 ab8500_fg_check_capacity_limits->power_supply_changed@power_supply_core.c->power_supply_changed_work->kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);另外需要说明下,实际上任何电池温度和电量的变化都会触发 power_supply_changed.
    3). [KERNEL]在kernel/drivers/power/power_supply_core.c中power_supply_changed_work->power_supply_update_leds@kernel/drivers/power/power_supply_leds.c会设置power leds的颜色
    4). [KERNEL]谁发event通知java层电源低????? 
        在power_supply_class_init@kernel/drivers/power/power_supply_core.c中有
        power_supply_class = class_create(THIS_MODULE, "power_supply"); [正好与Java层的mPowerSupplyObserver.startObserving("SUBSYSTEM=power_supply")一致]
        还有power_supply_class->dev_uevent = power_supply_uevent;
        power_supply_changed_work->kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);会调用到power_supply_uevent@kernel/drivers/power/power_supply_sysfs.c 但是如何调用过来的,没分析清楚??
        //ab8500_fg_check_capacity_limits->sysfs_notify(&di->fg_kobject, NULL, "charge_now");
        
    
6. Java层的处理过程,[现在需要确认谁触发了ActivityMangagerService@frameworks/base/core/java/android/app/ActivityManager.java]
    1). [JAVA]BatteryService.java@framework/base/services/java/com/android/server, 会在SystemServer.java的run函数中初始化,然后添加到ServiceManager
    2). [JAVA][email protected], 会发送intent {Intent.ACTION_REQUEST_SHUTDOWN} 注意:除了电量百分比为0,同时还需要没有充电的情况下,才能触发shutdown, 因为有时候连着充电器,但有可能没有充电(比如高温的情况)。这样还能解决一个问题:就是如果充电器提供的电流不能满足手机的超负荷应用咋办?我们知道如果手机边充电边玩负载大的游戏,则系统会不断从电池拽电流,也就是根本没充电,最后电池电量耗光到0触发shutdown
    3). [JAVA]ActivityMangagerService 会下发 intent{ act=android.intent.action.ACTION_REQUEST_SHUTDOWN}给com.android.server.ShutdownActivity
    4). [JAVA]ShutdownActivity@frameworks/base/services/java/com/android/server/ShutdownActivity.java 接收到 intent 开始触发oncreate-> ShutdownThread.shutdown(ShutdownActivity.this, mConfirm);
    5). [JAVA]shutdown@frameworks/base/core/java/com/android/internal/app/ShutdownThread.java 会调用 beginShutdownSequence(context);其中有
        sInstance.mCpuWakeLock.setReferenceCounted(false); //sure never fall asleep
        sInstance.mScreenWakeLock.setReferenceCounted(false); //sure screen stays on
    6). [JAVA]sInstance.start();->run()
7. BatteryService.java具体分析,会接收kernel的uevent消息,并加以处理
    a. framework/base/services/java/com/android/server/BatteryService.java, 会在SystemServer.java的run函数中初始化,然后添加到ServiceManager
    b. [email protected]函数会被 mPowerSupplyObserver和mInvalidChargerObserver调用,两者都是UEventObserver.
         mPowerSupplyObserver.startObserving("SUBSYSTEM=power_supply"); //在uevent监听事件中增加该匹配 "SUBSYSTEM=power_supply" 的UEventObserver,一旦有匹配的uevent收到,会调用mPowerSupplyObserver->onUEvent->update
    c. [email protected]函数会得到最新的电池状态信息; update->native_update[JNI]->android_server_BatteryService_update@frameworks/base/services/jni/com_android_server_BatteryService.cpp
    d. com_android_server_BatteryService.cpp中 实际是读取的 #define POWER_SUPPLY_PATH "/sys/class/power_supply" 的内容,
    e. 顺便分析下C 向 JAVA如何传递数据,比如 private int [email protected], 在com_android_server_BatteryService.cpp中有
        jfieldID mBatteryStatus;
        gFieldIds.mBatteryStatus = env->GetFieldID(clazz, "mBatteryStatus", "I");
        env->SetIntField(obj, gFieldIds.mBatteryStatus, getBatteryStatus(buf));    
    f. JAVA的update->JNI的native_update,然后Batteryservice.java中的关于电池状态信息的变量会在 native_update中赋值,根据获取的电池状态,决定是否shutdownIfNoPower.

8. 可以直接修改ab8500的寄存器 https://wiki.sonyericsson.net/androiki/AB8500_Debug_registers_in_DebugFS
    ~ $ adb shell
    # cd /data
    # mkdir debug
    # mount -t debugfs nodev debug
    # cd debug/ab8500

    bank: AB8500_SYS_CTRL2_BLOCK 0x02
    address: AB8500_LOW_BAT_REG 0x03
    value:     3.65v 0b110110 0x36[6:1] 0x1[0]enable lowbat function -> 0x6D 对应 3.65v
            3.575v 0b110011 0x33[6:1] 0x1[0]enable lowbat function -> 0x67 对应 3.575v     
            3.55v 0b110010 0x32[6:1] 0x1[0]enable lowbat function -> 0x65 对应 3.55v //
            3.35v 0b100010 0x2A[6:1] 0x1[0]enable lowbat function -> 0x45 对应 3.35v //bad
        3.25v 0b100110 0x26[6:1] 0x1[0]enable lowbat function -> 0x4D 对应 3.25v //bad

    // READ/WRITE OUT VALUE OF REGISTER 0x0203(LowBat : Low battery feature management.)
    # echo 0x2 > register-bank
    # echo 0x3 > register-address
    # cat register-value
    # echo 0x67 > register-value

9. 修改 ab8500_fg_parameters@/kernel/arch/arm/mach-ux500/board-mop500-bm.c中的 fg.lowbat_threshold = 3350, 检查手机电池状态sys/class/power_supply/ab8500_fg中可以查看voltage_now,etc
    
10. 只修改fg.lowbat_threshold = 3350,同时修改 cap_tbl_A_100mA数据使之对应, 会导致电池capacity减小,不是最佳solution

****************************************************************************************************************************************************

以下是对应的qualcom platform 分析的kernel 部分

十九、Battery voltage alarm
1. 最小门限电压如何定义和设置
   @kernel/drivers/power/pm8921-charger.c
 struct pm8921_chg_chip.alarm_low_mv //the battery alarm voltage low
   @kernel/arch/arm/mach-msm/board-sony_viskan_huashan-pmic.c
 static struct pm8921_charger_platform_data pm8921_chg_pdata.alarm_low_mv = 3400,  //低电触发
        .alarm_high_mv = 4000,    //高电触发
2. 如何设置trigger the alarm of battery low voltage 
   @kernel/drivers/power/pm8921-charger.c
 pm8921_charger_probe-->pm8921_charger_configure_batt_alarm
 -->pm8xxx_batt_alarm_threshold_set(PM8XXX_BATT_ALARM_LOWER_COMPARATOR,chip->alarm_low_mv); //往寄存器里面写入最低电压门限
    pm8xxx_batt_alarm_register_notifier(&alarm_notifier);@kernel/drivers/mfd/pm8xxx-batt-alarm.c  //设置触发回调函数
           需要说明的是该函数只是往 battery alarm 中断触发函数链表中添加一个响应函数
3. Battery alarm中断如何设置和触发  
   a. 设备注册 @kernel/drivers/mfd/pm8921-core.c
 static struct mfd_cell batt_alarm_cell = {
  .resources = batt_alarm_cell_resources, //PM8921_BATT_ALARM_IRQ  是其中断资源号PM8921_IRQ_BLOCK_BIT(5, 6)
 } 
   b. 驱动注册 @kernel/drivers/mfd/pm8xxx-batt-alarm.c
 pm8xxx_batt_alarm_probe-->request_irq(chip->irq, pm8xxx_batt_alarm_isr,IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, cdata->irq_name,chip); //中断注册函数为 pm8xxx_batt_alarm_isr
   c. 如何触发 低电处理函数
 当电池电压低于alarm_low_mv 或 高于alarm_high_mv 时硬件中断产生 --> [email protected] --> [email protected]
 -->[email protected]
4. 如何把低电信息传递给user space
   set_heartbeat_update_interval@kernel/drivers/mfd/pm8921-core.c //设置多少时间间隔触发update_heartbeat 
   实际上电池的状态没间隔心跳时间获取一次,然后传递给userspace
   update_heartbeat 将得到电池容量百分比get_prop_batt_capacity, 然后power_supply_changed发送给user space. 

二十、电池容量的计算
1. @kernel/arch/arm/mach-msm/board-sony_viskan_huashan-pmic.c 
 static struct pm8921_charger_platform_data pm8921_chg_pdata.max_voltage = MAX_VOLTAGE_MV,(4200) //the max voltage (mV) the battery should be charged up to
            .min_voltage = 3200, //the voltage (mV) where charging method switches from trickle to fast. This is also the minimum voltage 
2. 调试路径 可以设置最小电池电压值
 /sys/devices/platform/msm_ssbi.0/pm8921-core/pm8921-charger/min_voltage_mv
  或者/sys/bus/platform/drivers/pm8921-charger/pm8921-charger/min_voltage_mv 
3. update_heartbeat函数会定时调用
 a. update_temp_state --> get_prop_batt_temp
 b .get_prop_batt_capacity --> voltage_based_capacity -->get_prop_battery_uvolts
 c. check_soc_and_resume --> update_charge_state

二十一、如何触发低电关机
1. get_prop_batt_capacity@kernel/drivers/power/pm8921-charger.c
   如果get_prop_battery_uvolts得到的电压值连续小于min_voltage_mv 次RETRY_NUM_FOR_FORCE_SHUTDOWN=5,就会触发
   update_charge_state(BIT(DIS_BIT_CHG_SHUTDOWN),DIS_BIT_CHG_SHUT_MASK);该函数会disable 充电
2. 然后把电池容量为0的信息传递给userspace
 [email protected] -->power_supply_changed@power_supply_core.c
 -->power_supply_changed_work 另外说明下power_supply_update_leds 会根据电量改变led灯的显示颜色
 -->psy->changed //如果property有任何改变则向user space 发送uevent.
 -->kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE); //发送电池电量已经改变的信息给userspace
3. /sys/class/power_supply/battery如何创建的
 a. [email protected]
  chip->batt_psy.name = "battery",
  chip->batt_psy.get_property = pm_batt_power_get_property,
  rc = power_supply_register(chip->dev, &chip->usb_psy);
 b. power_supply_register@power_supply_core.c
  dev->class = power_supply_class; //class.name="power_suppl"
  dev->type = &power_supply_dev_type; //最终会关联到static struct device_attributepower_supply_attrs@power_supply_sysfs.c
   //并且static struct device_attribute power_supply_attrs必须和enum power_supply_property 里面的变量定义一致
  rc = kobject_set_name(&dev->kobj, "%s", psy->name); //psy->name="battery"
  rc = device_add(dev); //生成/sys/class/power_supply/battery/*.*
 c. power_supply_class_init@power_supply_core.c
  power_supply_class = class_create(THIS_MODULE, "power_supply");
  power_supply_class->dev_uevent = power_supply_uevent;
  power_supply_init_attrs(&power_supply_dev_type); 
  {  
   dev_type->groups = power_supply_attr_groups;//会关联到__power_supply_attrs和power_supply_attr_is_visible
   //通过power_supply_attr_is_visible函数过滤只有[email protected]中的prop才会生成文件节点, 也就是/sys/class/power_supply/battery/下的文件
  }
 d. static enum power_supply_property [email protected]
4. User space 收到charging 的uevent事件后,会主动读取/sys/class/power_supply/battery/*.* 某些文件以获取充电相关的信息  
 -->power_supply_uevent@kernel/drivers/power/power_supply_sysfs.c

5. 如果电池的capacity=0,则触发user space低电关机,具体的流程与riogrande platform一样


以下是qualcom的8226平台的分析

二十六、低电关机(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也就是[email protected],如果是低电状态则继续调用configure_vbat_monitor_low,其中会wake_lock(&chip->low_voltage_wake_lock);让系统不再suspend,马上开始运行calculate_soc_work,也就是把soc=0%的信息赶快通知给user space,好执行低电关机。具体分析如下:
3.1 设置低电notify的相关参数,[email protected]
   ->[email protected]; 设置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


你可能感兴趣的:(电池容量足够低如何触发自动关机(Riogrande platform&Qualcom platform))