【转载】【非常好】MTK 电池流程.c

/* 概念: 
        ZCV:开路电压
        OCV: 开路电压
        VC:闭路电压
        CAR:库伦计
        DOD: 放电深度,100-DOD 即电容容量
        Cmax/Qmax: 电池容量

相关文件关系:
        Battery_common.c (s:\i841\mediatek\kernel\drivers\power)                    // 充电逻辑文件 
        Charging_hw_pmic.c (s:\i841\mediatek\platform\mt6582\kernel\drivers\power)  // 具体的充电芯片,相关电池参数检测
        Linear_charging.c (s:\i841\mediatek\kernel\drivers\power)                   // 充电状态控制,内部 PMIC
        Switch_charging.c (s:\i841\mediatek\kernel\drivers\power)                   // 充电状态控制,外部 Charge IC 

硬件原理图:
    
    NTC 检测温度电路原理如下:

                    Vu                                Ru:上拉电阻值           
                    ---                               Rd: 下拉电阻值 
                     |                                Rntc: NTC 温度电阻 阻值
                    |||   Ru                          Vu: 上拉电压值 
                     |                                Gnd: 地 
                ---------- -----Vntc                  Vntc: NTC 电压 
                |        |
        Rntc   |||      |||  Rd 
                |        |
                ----------                          Rntc = (Ru*Rd*Vntc) / (Vru * Rd - Vntc * Ru)
                     |
                   -----
                    ---
                     -
                    Gnd 


【充电初始化流程】:
    module_init(battery_init)
    battery_init(void)
        // 注册平台设备
        platform_device_register(&battery_device)
        // 注册平台驱动
        platform_driver_register(&battery_driver)
            // 二者匹配调用 probe 函数 
            battery_probe()
                /////////////////////////////////////////////////////////
                // 注册字符设备
                alloc_chrdev_region(&adc_cali_devno, 0, 1, ADC_CALI_DEVNAME)
                cdev_add(adc_cali_cdev, adc_cali_devno, 1)
                /////////////////////////////////////////////////////////////
                // 创建相关 sys 系统节点 
                class_create(THIS_MODULE, ADC_CALI_DEVNAME)
                device_create(adc_cali_class, NULL, adc_cali_devno, NULL, ADC_CALI_DEVNAME)

                ////////////////////////////////////////////////////////////
                // 与特定硬件的入口操作函数关联 
                get_charging_control()
                    // 用来绑定内部 PMIC 或者外部充电芯片的操作函数入口
                    battery_charging_control = chr_control_interface;
                                                        相关充电芯片驱动实现的函数有:
                                                            charging_hw_init
                                                            charging_dump_register     
                                                            charging_enable
                                                            charging_set_cv_voltage
                                                            charging_get_current
                                                            charging_set_current
                                                            charging_set_input_current     
                                                            charging_get_charging_status   
                                                            charging_reset_watch_dog_timer
                                                            charging_set_hv_threshold
                                                            charging_get_hv_status
                                                            charging_get_battery_status
                                                            charging_get_charger_det_status
                                                            charging_get_charger_type
                                                            charging_get_is_pcm_timer_trigger
                                                            charging_set_platform_reset
                                                            charging_get_platfrom_boot_mode
                                                            charging_set_power_off

                //////////////////////////////////////////////////////////////
                // 获得启动模式 
                battery_charging_control(CHARGING_CMD_GET_PLATFORM_BOOT_MODE, &g_platform_boot_mode)                                            
                        // 对应 pmic 的 charging_get_platfrom_boot_mode() 
                        charging_get_platfrom_boot_mode()
                            get_boot_mode()
                
                /////////////////////////////////////////////////////////////////////////////
                // Integrate with Android Battery Service 
                // 一般移动设备的供电可来自外部即 AC 与 usb,内部电池供电 battery,
                // 所以需通过 power_supply_register()   函数在 /sys/class/power_supply 下分别
                // 注册 ac usb battery,注册完成可发现在设备目录 /sys/class/power_supply 下分别
                // 出现 ac usb battery 三个文件夹 
                power_supply_register(&(dev->dev), &ac_main.psy)
                power_supply_register(&(dev->dev), &usb_main.psy)
                power_supply_register(&(dev->dev), &wireless_main.psy)
                power_supply_register(&(dev->dev), &battery_main.psy)

                /////////////////////////////////////////////////////////////////////////////
                // 初始化电池状态结构体 
                BMT_status.bat_exist = KAL_TRUE;            // phone must have battery 
                BMT_status.charger_exist = KAL_FALSE;       // for default, no charger 
                BMT_status.bat_vol = 0;
                BMT_status.ICharging = 0;
                BMT_status.temperature = 0;
                BMT_status.charger_vol = 0;
                BMT_status.total_charging_time = 0;
                BMT_status.PRE_charging_time = 0;
                BMT_status.CC_charging_time = 0;
                BMT_status.TOPOFF_charging_time = 0;
                BMT_status.POSTFULL_charging_time = 0;
                BMT_status.SOC = 0;
                BMT_status.UI_SOC = 0;
                BMT_status.bat_charging_state = CHR_PRE;
                BMT_status.bat_in_recharging_state = KAL_FALSE;
                BMT_status.bat_full= KAL_FALSE;
                BMT_status.nPercent_ZCV = 0;
                BMT_status.nPrecent_UI_SOC_check_point= battery_meter_get_battery_nPercent_UI_SOC();

                ///////////////////////////////////////////////////////////////////////////
                //创建一个定时器,用于定时唤醒下面的内核线程更新电量
                battery_kthread_hrtimer_init();
                    ktime = ktime_set(1, 0);    // 3s, 10* 1000 ms
                    // 高分辨率kernel定时器初始化
                    hrtimer_init(&battery_kthread_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
                    battery_kthread_timer.function = battery_kthread_hrtimer_func; 
                                                // 定时器处理函数 
                                                battery_kthread_hrtimer_func()
                                                    bat_thread_wakeup();  
                                                        // 唤醒下面的 bat_thread_kthread() 线程
                                                        wake_up(&bat_thread_wq); 
                                                    // 重置定时器 
                                                    hrtimer_start(&battery_kthread_timer, ktime, HRTIMER_MODE_REL)
                
                //////////////////////////////////////////////////////////////////////////////
                // 【核心充电线程】
                kthread_run(bat_thread_kthread, NULL, "bat_thread_kthread"); 
                                    // 设置定时器超时时间
                                    ktime_t ktime = ktime_set(3, 0);  // 10s, 10* 1000 ms
                                    while (1) {  
                                        // 这个是核心算法 
                                        BAT_thread();
                                                ///////////////////////////////////////////////////////////////////////////////////////////
                                                // 0. 第一次执行时运行,获得开机显示电量,初始化电池算法 oam 参数 
                                                // 开机时就会运行,只会运行一次,对电池算法 oam 方案进行初始化, 并获得开机显示电量百分比 
                                                if(battery_meter_initilized == KAL_FALSE)
                                                {
                                                    // 进行的一系列的电池参数与温度对应关系的表格的初始化,并根据电池当前电压,hw ocv 取一个较合适值,
                                                    // 取合适值对应容量,再与 RTC 保存容量比较,选择一个合适量,为开机电池容量,最后初始化 oam 算法参数 
                                                    battery_meter_initial()
                                                }
                                                ////////////////////////////////////////////////////////////////////////////////////////////////////
                                                // 1. 判断是插入的是否充电器还是电脑 USB,看能不能进行充电
                                                // 如果连接的 USB 线为 USB 充电线,或者电脑 USB 线,则打开 USB,
                                                // 这里会通过  BC1.1 来判断是电脑 USB 还是 USB 充电器,来决定充电电流 
                                                // 否则连接的不是充电线或者 USB 作为一个从设备使用,要断开 USB?
                                                mt_battery_charger_detect_check();

                                                ///////////////////////////////////////////////////////////////////////////////////////////////////////
                                                // 2. 通过具体的充电芯片来获得电池信息,充电信息, 获得电池电量百分比 
                                                // 通过 oam 算法,获得电量百分比 
                                                mt_battery_GetBatteryData();
                                
                                                ////////////////////////////////////////////////////////////////////////////////////////////////////////
                                                // 3. 电池温度保护
                                                // 电池温度检查,如果温度超过 60 度,关机重启 
                                                mt_battery_thermal_check();

                                                /////////////////////////////////////////////////////////////////////////////////////////////////////////
                                                // 4. 电池状态检查
                                                //  对电池状态进行检查,如果有问题,则会调用 printk() 进行打印 
                                                mt_battery_notify_check();

                                                //////////////////////////////////////////////////////////////////////////////////////////////////////////
                                                // 5. 调用具本的硬件相关函数进行充电,充电时会进行 CC/CV 之类的状态机切换就是在这里进行的
                                                // 如果存在充电线,则调用具体充电芯片相关的函数进行充电  
                                                if( BMT_status.charger_exist == KAL_TRUE )
                                                {
                                                        // 检查电池状态,设置到 BMT_status.bat_charging_state 中 
                                                        mt_battery_CheckBatteryStatus();  

                                                        // 充电策略,这里有两个文件: switch_charging.c 和 linear_charging.c 
                                                        // 他们的关系是,如果定义了任一外部充电 IC,则选择 switch_charging.c 的函数,否则就是 linear_charging.c 的函数
                                                        // 这里就是调用具体的芯片的充电相关函数进行充电 
                                                        mt_battery_charging_algorithm();   
                                                                    void mt_battery_charging_algorithm()
                                                                    {
                                                                         switch(BMT_status.bat_charging_state)
                                                                        {            
                                                                            case CHR_PRE :
                                                                                BAT_PreChargeModeAction();
                                                                                break;    
                                                                                
                                                                            case CHR_CC :
                                                                                BAT_ConstantCurrentModeAction();
                                                                                            /////////////////////////////////////////////////////////////
                                                                                            // MTK 充电是充 9s 停 1s 
                                                                                            // Charging 9s and discharging 1s : start
                                                                                            battery_charging_control(CHARGING_CMD_ENABLE,&charging_enable);
                                                                                break;    
                                                                                
                                                                            case CHR_TOP_OFF :
                                                                                BAT_TopOffModeAction();
                                                                                break;              

                                                                            case CHR_BATFULL:
                                                                                BAT_BatteryFullAction();
                                                                                break;
                                                                                
                                                                        case CHR_HOLD:
                                                                            BAT_BatteryHoldAction();
                                                                                break;
                                                                                
                                                                            case CHR_ERROR:
                                                                                BAT_BatteryStatusFailAction();
                                                                                break;                
                                                                        }    
                                                                       
                                                                    }
                                                }

                                                ///////////////////////////////////////////////////////////////////////////////////////////////////////////
                                                // 6. 更新电池显示状态 
                                                // 更新设置节点的内容: 
                                                //     /sys/class/power_supply/下的文件夹
                                                //                             wireless_main
                                                //                             battery_main
                                                //                             ac_main 
                                                //                             usb_main
                                                mt_battery_update_status();


                                        // 睡眠等待唤醒 
                                        wait_event(bat_thread_wq, (bat_thread_timeout == KAL_TRUE));

                                        // 每 10s 启动一次 
                                        hrtimer_start(&battery_kthread_timer, ktime, HRTIMER_MODE_REL);   
                                        ktime = ktime_set(BAT_TASK_PERIOD, 0);  // 10s, 10* 1000 ms


                                    }


                /////////////////////////////////////////////////////////////////////////
                // 电池过充保护相关检测与初始化,他 2s 检测一次
                charger_hv_detect_sw_workaround_init();
                        charger_hv_detect_thread = kthread_run(charger_hv_detect_sw_thread_handler, 0, "mtk charger_hv_detect_sw_workaround");
                                                                            // 这个函数是周期来检查电池电压是否超出限制,即过充保护,超出了就不能充电了 
                                                                            charger_hv_detect_sw_thread_handler()
                                                                                do{
                                                                                        ktime = ktime_set(0, BAT_MS_TO_NS(2000));
                                                                                        if(chargin_hw_init_done)
                                                                                            // 高压检测,应该是电池超过这个电压时,就不可以充电了 
                                                                                            battery_charging_control(CHARGING_CMD_SET_HV_THRESHOLD,&hv_voltage);
                                                                                                                        // 对应 PMIC charging_set_hv_threshold()

                                                                                        wait_event_interruptible(charger_hv_detect_waiter, (charger_hv_detect_flag == KAL_TRUE));

                                                                                        // 如果检测到充电器,则检测下电池是否存在 检测电池是否存在,通过读取 PMIC 的 CHR_CON7
                                                                                        if ((upmu_is_chr_det() == KAL_TRUE))
                                                                                        {
                                                                                            // 检测电池是否存在 
                                                                                            check_battery_exist(); 
                                                                                        }
                                                                                        hrtimer_start(&charger_hv_detect_timer, ktime, HRTIMER_MODE_REL); 
                                                                                }while (!kthread_should_stop());


        //////////////////////////////////////////////////////////////
        // battery notofy UI
        platform_device_register(&MT_batteryNotify_device)
        platform_driver_register(&mt_batteryNotify_driver)
            mt_batteryNotify_probe()
                ret_device_file = device_create_file(&(dev->dev), &dev_attr_BatteryNotify);
                ret_device_file = device_create_file(&(dev->dev), &dev_attr_BN_TestMode);
                battery_dir = proc_mkdir("mtk_battery_cmd", NULL);

电池测量模块初始化:
    module_init(battery_meter_init);
    battery_meter_init(void)
            platform_device_register(&battery_meter_device);
            platform_driver_register(&battery_meter_driver);
                // 调用对应的 probe 函数 
                battery_meter_probe()
                    // 测量模块接口设置【核心在于 bm_ctrl_cmd 函数】
                    battery_meter_ctrl = bm_ctrl_cmd;

*/
module_init(battery_init);
static int __init battery_init(void)
{
    int ret;

    ret = platform_device_register(&battery_device);
                                        struct platform_device battery_device = {
                                            .name   = "battery",
                                            .id        = -1,
                                        };
    if (ret) {
        battery_xlog_printk(BAT_LOG_CRTI, "****[battery_driver] Unable to device register(%d)\n", ret);
    return ret;
    }
    
    ret = platform_driver_register(&battery_driver);
                                           static struct platform_driver battery_driver = {
                                               .probe         = battery_probe,
                                               .remove        = battery_remove,
                                               .shutdown      = battery_shutdown,
                                               .driver        = {
                                                   .name = "battery",
                                                   .pm   = &battery_pm_ops
                                               },
                                           };
    if (ret) {
        battery_xlog_printk(BAT_LOG_CRTI, "****[battery_driver] Unable to register driver (%d)\n", ret);
    return ret;
    }

    // battery notofy UI
    ret = platform_device_register(&MT_batteryNotify_device);
                                                struct platform_device MT_batteryNotify_device = {
                                                    .name   = "mt-battery",
                                                    .id        = -1,
                                                };
    if (ret) {
        battery_xlog_printk(BAT_LOG_CRTI, "****[mt_batteryNotify] Unable to device register(%d)\n", ret);
        return ret;
    }    
    ret = platform_driver_register(&mt_batteryNotify_driver);
                                                static struct platform_driver mt_batteryNotify_driver = {
                                                    .probe        = mt_batteryNotify_probe,
                                                    .driver     = {
                                                        .name = "mt-battery",
                                                    },
                                                };
    if (ret) {
        battery_xlog_printk(BAT_LOG_CRTI, "****[mt_batteryNotify] Unable to register driver (%d)\n", ret);
        return ret;
    }

    battery_xlog_printk(BAT_LOG_CRTI, "****[battery_driver] Initialization : DONE !!\n");
    return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 第一个调用的 probe,充电相关函数初始化 
/* 相关文件关系:
        Battery_common.c (s:\i841\mediatek\kernel\drivers\power)                        // 充电逻辑文件 
        Charging_hw_pmic.c (s:\i841\mediatek\platform\mt6582\kernel\drivers\power)      // 具体的充电芯片,相关电池参数检测
   
        Linear_charging.c (s:\i841\mediatek\kernel\drivers\power)                       // 充电状态控制,内部 PMIC
        Switch_charging.c (s:\i841\mediatek\kernel\drivers\power)                       // 充电状态控制,外部 Charge IC 

*/
static int battery_probe//(struct platform_device *dev)    
{
    struct class_device *class_dev = NULL;
    int ret=0;

    battery_xlog_printk(BAT_LOG_CRTI, "******** battery driver probe!! ********\n" );

    /* Integrate with NVRAM */
    ret = alloc_chrdev_region(&adc_cali_devno, 0, 1, ADC_CALI_DEVNAME);  // #define ADC_CALI_DEVNAME "MT_pmic_adc_cali"
    if (ret) 
       battery_xlog_printk(BAT_LOG_CRTI, "Error: Can't Get Major number for adc_cali \n");
    adc_cali_cdev = cdev_alloc();
    adc_cali_cdev->owner = THIS_MODULE;
    adc_cali_cdev->ops = &adc_cali_fops;
                                static struct file_operations adc_cali_fops = {
                                    .owner        = THIS_MODULE,
                                    .unlocked_ioctl    = adc_cali_ioctl,
                                    .open        = adc_cali_open,
                                    .release    = adc_cali_release,    
                                };
    ret = cdev_add(adc_cali_cdev, adc_cali_devno, 1);
    if(ret)
       battery_xlog_printk(BAT_LOG_CRTI, "adc_cali Error: cdev_add\n");
    adc_cali_major = MAJOR(adc_cali_devno);
    adc_cali_class = class_create(THIS_MODULE, ADC_CALI_DEVNAME);
    class_dev = (struct class_device *)device_create(adc_cali_class, 
                                                   NULL, 
                                                   adc_cali_devno, 
                                                   NULL, 
                                                   ADC_CALI_DEVNAME);
    battery_xlog_printk(BAT_LOG_CRTI, "[BAT_probe] adc_cali prepare : done !!\n ");

    /* 与特定硬件的操作函数关联 */
	get_charging_control();
                static void get_charging_control(void)
                {
                    /* 这是一个函数指针,指向了硬件驱动对应的接口函数,这里指向的是 pmic 为例,后面调用 battery_charging_control(xxx)
                    即是调用 chr_control_interface(xxx) 
                        typedef kal_int32 (*CHARGING_CONTROL)(CHARGING_CTRL_CMD cmd, void *data);*/
                	battery_charging_control = chr_control_interface;
                                                     // This function is called to set the charger hw
                                                     kal_int32 chr_control_interface//(CHARGING_CTRL_CMD cmd, void *data)
                                                     {
                                                    	 kal_int32 status;
                                                    	 if(cmd < CHARGING_CMD_NUMBER)
                                                    		 status = charging_func[cmd](data);
                                                                            /* 这是在特定充电芯片中实现的,如 pmic 的 */
                                                                            // static kal_uint32 (*charging_func[CHARGING_CMD_NUMBER])(void *data)=
                                                                            // {
                                                                            //     charging_hw_init
                                                                            //    ,charging_dump_register     
                                                                            //    ,charging_enable
                                                                            //    ,charging_set_cv_voltage
                                                                            //    ,charging_get_current
                                                                            //    ,charging_set_current
                                                                            //    ,charging_set_input_current     // not support, empty function
                                                                            //    ,charging_get_charging_status   // not support, empty function
                                                                            //    ,charging_reset_watch_dog_timer
                                                                            //    ,charging_set_hv_threshold
                                                                            //    ,charging_get_hv_status
                                                                            //    ,charging_get_battery_status
                                                                            //    ,charging_get_charger_det_status
                                                                            //    ,charging_get_charger_type
                                                                            //    ,charging_get_is_pcm_timer_trigger
                                                                            //    ,charging_set_platform_reset
                                                                            //    ,charging_get_platfrom_boot_mode
                                                                            //    ,charging_set_power_off
                                                                            // };
                                                    	 else
                                                    		 return STATUS_UNSUPPORTED;
                                                     
                                                    	 return status;
                                                     }
                }

    /* 获得启动模式 */
    battery_charging_control(CHARGING_CMD_GET_PLATFORM_BOOT_MODE, &g_platform_boot_mode);
                                                     // 对应 pmic 的 charging_get_platfrom_boot_mode() 
                                                     static kal_uint32 charging_get_platfrom_boot_mode(void *data)
                                                     {
                                                         kal_uint32 status = STATUS_OK;
                                                       
                                                         *(kal_uint32*)(data) = get_boot_mode();
                                                                                        BOOTMODE get_boot_mode(void)
                                                                                        {
                                                                                            return g_boot_mode;
                                                                                        }
                                                     
                                                         battery_xlog_printk(BAT_LOG_CRTI, "get_boot_mode=%d\n", get_boot_mode());
                                                              
                                                         return status;
                                                     }

                                                     
    battery_xlog_printk(BAT_LOG_CRTI, "[BAT_probe] g_platform_boot_mode = %d\n ", g_platform_boot_mode);

	wake_lock_init(&battery_suspend_lock, WAKE_LOCK_SUSPEND, "battery suspend wakelock");    

    /* Integrate with Android Battery Service 
    一般移动设备的供电可来自外部即 AC 与 usb,内部电池供电 battery,所以需通过 power_supply_register   函数在 
    /sys/class/power_supply 下分别注册 ac usb battery,注册完成可发现在设备目录 /sys/class/power_supply 下分别
    出现 ac usb battery 三个文件夹 */
    ret = power_supply_register(&(dev->dev), &ac_main.psy);
                                /* 相关的核心结构体 
                                struct power_supply {
                                    struct listnode list;       
                                    char name[256];             
                                    char type[32];
                                    bool online;
                                    bool valid;
                                    char cap_path[PATH_MAX];
                                };*/
    if (ret)
    {            
        battery_xlog_printk(BAT_LOG_CRTI, "[BAT_probe] power_supply_register AC Fail !!\n");                    
        return ret;
    }             
    battery_xlog_printk(BAT_LOG_CRTI, "[BAT_probe] power_supply_register AC Success !!\n");

    ret = power_supply_register(&(dev->dev), &usb_main.psy);
    if (ret)
    {            
        battery_xlog_printk(BAT_LOG_CRTI, "[BAT_probe] power_supply_register USB Fail !!\n");                    
        return ret;
    }             
    battery_xlog_printk(BAT_LOG_CRTI, "[BAT_probe] power_supply_register USB Success !!\n");
    
    ret = power_supply_register(&(dev->dev), &wireless_main.psy);
    if (ret)
    {            
        battery_xlog_printk(BAT_LOG_CRTI, "[BAT_probe] power_supply_register WIRELESS Fail !!\n");                    
        return ret;
    }             
    battery_xlog_printk(BAT_LOG_CRTI, "[BAT_probe] power_supply_register WIRELESS Success !!\n");
    
    ret = power_supply_register(&(dev->dev), &battery_main.psy);
    if (ret)
    {
        battery_xlog_printk(BAT_LOG_CRTI, "[BAT_probe] power_supply_register Battery Fail !!\n");
        return ret;
    }
    battery_xlog_printk(BAT_LOG_CRTI, "[BAT_probe] power_supply_register Battery Success !!\n");

#if !defined(CONFIG_POWER_EXT)
    /* For EM */
	{
	    int ret_device_file=0;
		
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Charger_Voltage);
	    
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_0_Slope);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_1_Slope);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_2_Slope);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_3_Slope);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_4_Slope);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_5_Slope);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_6_Slope);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_7_Slope);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_8_Slope);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_9_Slope);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_10_Slope);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_11_Slope);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_12_Slope);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_13_Slope);

	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_0_Offset);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_1_Offset);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_2_Offset);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_3_Offset);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_4_Offset);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_5_Offset);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_6_Offset);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_7_Offset);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_8_Offset);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_9_Offset);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_10_Offset);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_11_Offset);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_12_Offset);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_13_Offset);

	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_ADC_Channel_Is_Calibration);

	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_Power_On_Voltage);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_Power_Off_Voltage);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_Charger_TopOff_Value);
	    
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_FG_Battery_CurrentConsumption);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_FG_SW_CoulombCounter);
	    ret_device_file = device_create_file(&(dev->dev), &dev_attr_Charging_CallState);
	}
	
	//battery_meter_initial();	//move to mt_battery_GetBatteryData() to decrease booting time
	
	/* Initialization BMT Struct 
    初始化电池状态结构体 */
    BMT_status.bat_exist = KAL_TRUE;       /* phone must have battery */
    BMT_status.charger_exist = KAL_FALSE;     /* for default, no charger */
    BMT_status.bat_vol = 0;
    BMT_status.ICharging = 0;
    BMT_status.temperature = 0;
    BMT_status.charger_vol = 0;
    BMT_status.total_charging_time = 0;
    BMT_status.PRE_charging_time = 0;
    BMT_status.CC_charging_time = 0;
    BMT_status.TOPOFF_charging_time = 0;
    BMT_status.POSTFULL_charging_time = 0;
	BMT_status.SOC = 0;
	BMT_status.UI_SOC = 0;

    BMT_status.bat_charging_state = CHR_PRE;
	BMT_status.bat_in_recharging_state = KAL_FALSE;
	BMT_status.bat_full= KAL_FALSE;
	BMT_status.nPercent_ZCV = 0;
	BMT_status.nPrecent_UI_SOC_check_point= battery_meter_get_battery_nPercent_UI_SOC();


    //battery kernel thread for 10s check and charger in/out event
    /* Replace GPT timer by hrtime 
    创建一个定时器,用于定时唤醒下面的内核线程更新电量 */
    battery_kthread_hrtimer_init();
            void battery_kthread_hrtimer_init(void)
            {
                ktime_t ktime;

                ktime = ktime_set(1, 0);	// 3s, 10* 1000 ms
                // 高分辨率kernel定时器初始化
                hrtimer_init(&battery_kthread_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
                battery_kthread_timer.function = battery_kthread_hrtimer_func;   
                                                            enum hrtimer_restart battery_kthread_hrtimer_func(struct hrtimer *timer)
                                                            {
                                                                bat_thread_wakeup(); 
                                                                        void bat_thread_wakeup(void)
                                                                        {
                                                                            battery_xlog_printk(BAT_LOG_CRTI, "******** battery : bat_thread_wakeup  ********\n" );
                                                                            
                                                                            bat_thread_timeout = KAL_TRUE;
                                                                            bat_meter_timeout = KAL_TRUE;

                                                                            // 唤醒下面的 bat_thread_kthread() 线程
                                                                            wake_up(&bat_thread_wq);    
                                                                        }
                                                                return HRTIMER_NORESTART;
                                                            }
                // 重置定时器 
                hrtimer_start(&battery_kthread_timer, ktime, HRTIMER_MODE_REL);

                battery_xlog_printk(BAT_LOG_CRTI, "battery_kthread_hrtimer_init : done\n" );
            }


    
    kthread_run(bat_thread_kthread, NULL, "bat_thread_kthread"); 
                            ///////////////////////////////////////////////////////////////////////////////////////////
                            //// Internal API 
                            int bat_thread_kthread(void *x)
                            {
                                // 设置定时器超时时间
                                ktime_t ktime = ktime_set(3, 0);  // 10s, 10* 1000 ms	
                                
                                /* Run on a process content */  
                                while (1) {               
                                    mutex_lock(&bat_mutex);
                                      
                            		if((chargin_hw_init_done == KAL_TRUE) && (battery_suspended == KAL_FALSE))
                                        /////////////////////////////////////////////////////////////////////////////////////////////////
                                        /////////////////////////////////////////////////////////////////////////////////////////////////
                                        /* 这个是核心算法 */
                            	        BAT_thread();
                                               void BAT_thread(void)
                                               {
                                                   static kal_bool  battery_meter_initilized = KAL_FALSE;
                                                   
                                                   _g_bat_sleep_total_time = 0;

                                                   ////////////////////////////////////////////////////////////////////////////////////////////////////
                                                   // 0. 第一次执行时运行,获得开机显示电量,初始化电池算法 oam 参数 
                                                   /* 开机时就会运行,只会运行一次,对电池算法 oam 方案进行初始化, 并获得开机显示电量百分比 */
                                                   if(battery_meter_initilized == KAL_FALSE)
                                                   {
                                                       /* 进行的一系列的电池参数与温度对应关系的表格的初始化,并根据电池当前电压,hw ocv 取一个较合适值,
                                                       取合适值对应容量,再与 rtc 容量比较,选择一个合适量,为开机电池容量,最后初始化 oam 算法参数 */
                                                       battery_meter_initial(); //move from battery_probe() to decrease booting time
                                                                    kal_int32 battery_meter_initial(void)
                                                                    {
                                                                    #if defined(CONFIG_POWER_EXT)
                                                                        return 0;
                                                                    #else

                                                                    /* 多电池支持 */
                                                                    #ifdef MTK_MULTI_BAT_PROFILE_SUPPORT
                                                                        fgauge_get_profile_id();
                                                                    #endif


                                                                        /* 针对 AUXADC SW_FG HW_FG 三种不同的电池算法方案,分别初始化,82平台使用的 SW_FG */
                                                                        #if defined(SOC_BY_AUXADC)
                                                                        g_auxadc_solution = 1;
                                                                        table_init();
                                                                        bm_print(BM_LOG_CRTI, "[battery_meter_initial] SOC_BY_AUXADC done\n");
                                                                        #endif

                                                                        #if defined(SOC_BY_HW_FG)
                                                                        fgauge_initialization();
                                                                        fgauge_algo_run_init();
                                                                        bm_print(BM_LOG_CRTI, "[battery_meter_initial] SOC_BY_HW_FG done\n");
                                                                        #endif

                                                                        #if defined(SOC_BY_SW_FG)
                                                                        g_auxadc_solution = 1;

                                                                        /* 温度-电池容量,温度-电池内阻,温度-NTC阻值表格等初始化,并获得了当前电池温度及所用掉的容量值  */
                                                                        table_init();
                                                                                void table_init(void)
                                                                                {
                                                                                    BATTERY_PROFILE_STRUC_P profile_p;
                                                                                    R_PROFILE_STRUC_P profile_p_r_table;

                                                                                    /* 获得当前电池温度*/
                                                                                    int temperature = force_get_tbat();
                                                                                                            /* 通过获得当前 NTC 电压,查表并进行线性插值法,得到当前的温度值  */
                                                                                                            int force_get_tbat(void)
                                                                                                            {
                                                                                                            #if defined(CONFIG_POWER_EXT) || defined(FIXED_TBAT_25)
                                                                                                                bm_print(BM_LOG_CRTI, "[force_get_tbat] fixed TBAT=25 t\n");
                                                                                                                return 25;
                                                                                                            #else
                                                                                                                int bat_temperature_volt=0;
                                                                                                                int bat_temperature_val=0;
                                                                                                                int fg_r_value=0;
                                                                                                                kal_int32 fg_current_temp=0;
                                                                                                                kal_bool fg_current_state=KAL_FALSE;
                                                                                                                int bat_temperature_volt_temp=0;
                                                                                                                int ret=0;
                                                                                                                
                                                                                                                /* Get V_BAT_Temperature */
                                                                                                                bat_temperature_volt = 2; 
                                                                                                                /* 对应 PMIC 的硬件接口函数,这个对应的函数是在下面  battery_meter_init 模块中设置的 
                                                                                                                获得电池 NTC 对应的电压 */
                                                                                                                ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_BAT_TEMP, &bat_temperature_volt); 
                                                                                                                                                      static kal_int32 read_adc_v_bat_temp(void *data)
                                                                                                                                                      {
                                                                                                                                                      #if defined(CONFIG_POWER_EXT)
                                                                                                                                                          *(kal_int32*)(data) = 0;
                                                                                                                                                      #else
                                                                                                                                                          #if defined(MTK_PCB_TBAT_FEATURE)

                                                                                                                                                              int ret = 0, data[4], i, ret_value = 0, ret_temp = 0;
                                                                                                                                                              int Channel=1;
                                                                                                                                                              
                                                                                                                                                              if( IMM_IsAdcInitReady() == 0 )
                                                                                                                                                              {
                                                                                                                                                                  bm_print(BM_LOG_CRTI, "[get_tbat_volt] AUXADC is not ready");
                                                                                                                                                                  return 0;
                                                                                                                                                              }
                                                                                                                                                          
                                                                                                                                                              i = times;
                                                                                                                                                              while (i--)
                                                                                                                                                              {
                                                                                                                                                                  ret_value = IMM_GetOneChannelValue(Channel, data, &ret_temp);
                                                                                                                                                                  ret += ret_temp;
                                                                                                                                                                  bm_print(BM_LOG_FULL, "[get_tbat_volt] ret_temp=%d\n",ret_temp);
                                                                                                                                                              }
                                                                                                                                                              
                                                                                                                                                              ret = ret*1500/4096 ;
                                                                                                                                                              ret = ret/times;
                                                                                                                                                              bm_print(BM_LOG_CRTI, "[get_tbat_volt] Battery output mV = %d\n",ret);

                                                                                                                                                              *(kal_int32*)(data) = ret;

                                                                                                                                                          #else
                                                                                                                                                              bm_print(BM_LOG_FULL, "[read_adc_v_charger] return PMIC_IMM_GetOneChannelValue(4,times,1);\n");
                                                                                                                                                              /* 读 PMIC 对应的 ADC 的值,并将其转化为对应的电压值,这里即读取 BATON 引脚电压 */
                                                                                                                                                              *(kal_int32*)(data) = PMIC_IMM_GetOneChannelValue(VBATTEMP_CHANNEL_NUMBER,*(kal_int32*)(data),1);
                                                                                                                                                                                                        //==============================================================================
                                                                                                                                                                                                        // PMIC-AUXADC 
                                                                                                                                                                                                        //==============================================================================
                                                                                                                                                                                                        int PMIC_IMM_GetOneChannelValue(int dwChannel, int deCount, int trimd)
                                                                                                                                                                                                        {

                                                                                                                                                                                                            kal_int32 ret_data; 
                                                                                                                                                                                                            kal_int32 count=0;
                                                                                                                                                                                                            kal_int32 u4Sample_times = 0;
                                                                                                                                                                                                            kal_int32 u4channel=0;  
                                                                                                                                                                                                            kal_int32 adc_result_temp=0;
                                                                                                                                                                                                               kal_int32 r_val_temp=0;   
                                                                                                                                                                                                            kal_int32 adc_result=0;   
                                                                                                                                                                                                            kal_int32 ret=0;
                                                                                                                                                                                                            kal_int32 adc_reg_val=0;
                                                                                                                                                                                                            
                                                                                                                                                                                                            /*
                                                                                                                                                                                                                0 : BATON2 **
                                                                                                                                                                                                                1 : CH6
                                                                                                                                                                                                                2 : THR SENSE2 **
                                                                                                                                                                                                                3 : THR SENSE1
                                                                                                                                                                                                                4 : VCDT
                                                                                                                                                                                                                5 : BATON1          // 其实对应的就是硬件 PMIC  ADC3
                                                                                                                                                                                                                6 : ISENSE
                                                                                                                                                                                                                7 : BATSNS
                                                                                                                                                                                                                8 : ACCDET    
                                                                                                                                                                                                                9-16 : audio
                                                                                                                                                                                                            */

                                                                                                                                                                                                            //do not suppport BATON2 and THR SENSE2 for sw workaround
                                                                                                                                                                                                            if (dwChannel==0 || dwChannel==2)
                                                                                                                                                                                                                return 0;

                                                                                                                                                                                                            wake_lock(&pmicAuxadc_irq_lock);
                                                                                                                                                                                                            
                                                                                                                                                                                                            /* 采样通道号数,读取对应的 PMIC 寄存器的 ADC 的值 */                                                                                                                                                        
                                                                                                                                                                                                            do  
                                                                                                                                                                                                            {

                                                                                                                                                                                                                mutex_lock(&pmic_adc_mutex);
                                                                                                                                                                                                                
                                                                                                                                                                                                                /* 硬件上,ADC 通过一个 mux 数据选择器对各路模拟信号进行切换,这里检查哪里通知有数据了 */
                                                                                                                                                                                                                PMIC_IMM_PollingAuxadcChannel();
                                                                                                                                                                                                                                    void PMIC_IMM_PollingAuxadcChannel(void)
                                                                                                                                                                                                                                    {
                                                                                                                                                                                                                                        kal_uint32 ret=0;
                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                         //xlog_printk(ANDROID_LOG_INFO, "Power/PMIC", "[PMIC_IMM_PollingAuxadcChannel] before:%d ",upmu_get_rg_adc_deci_gdly());

                                                                                                                                                                                                                                        if (upmu_get_rg_adc_deci_gdly()==1)
                                                                                                                                                                                                                                        {
                                                                                                                                                                                                                                            while(upmu_get_rg_adc_deci_gdly()==1)
                                                                                                                                                                                                                                            {
                                                                                                                                                                                                                                                unsigned long flags;
                                                                                                                                                                                                                                                spin_lock_irqsave(&pmic_adc_lock, flags);
                                                                                                                                                                                                                                                if (pmic_is_auxadc_busy()==0)
                                                                                                                                                                                                                                                {
                                                                                                                                                                                                                                                    //upmu_set_rg_adc_deci_gdly(0);
                                                                                                                                                                                                                                                    ret=pmic_config_interface_nolock(AUXADC_CON19,0,PMIC_RG_ADC_DECI_GDLY_MASK,PMIC_RG_ADC_DECI_GDLY_SHIFT);
                                                                                                                                                                                                                                                }
                                                                                                                                                                                                                                                spin_unlock_irqrestore(&pmic_adc_lock, flags);
                                                                                                                                                                                                                                            }
                                                                                                                                                                                                                                        }
                                                                                                                                                                                                                                        //xlog_printk(ANDROID_LOG_INFO, "Power/PMIC", "[PMIC_IMM_PollingAuxadcChannel] after:%d ",upmu_get_rg_adc_deci_gdly());
                                                                                                                                                                                                                                    }

                                                                                                                                                                                                                /* adc */
                                                                                                                                                                                                                if (dwChannel<9)
                                                                                                                                                                                                                {
                                                                                                                                                                                                                    upmu_set_rg_vbuf_en(1);

                                                                                                                                                                                                                    //set 0
                                                                                                                                                                                                                    ret=pmic_read_interface(AUXADC_CON22,&adc_reg_val,PMIC_RG_AP_RQST_LIST_MASK,PMIC_RG_AP_RQST_LIST_SHIFT);
                                                                                                                                                                                                                    adc_reg_val = adc_reg_val & (~(1<=9 && dwChannel<=16)
                                                                                                                                                                                                                {
                                                                                                                                                                                                                    ret=pmic_read_interface(AUXADC_CON23,&adc_reg_val,PMIC_RG_AP_RQST_LIST_RSV_MASK,PMIC_RG_AP_RQST_LIST_RSV_SHIFT);
                                                                                                                                                                                                                    adc_reg_val = adc_reg_val & (~(1<<(dwChannel-9)));
                                                                                                                                                                                                                    ret=pmic_config_interface(AUXADC_CON23,adc_reg_val,PMIC_RG_AP_RQST_LIST_RSV_MASK,PMIC_RG_AP_RQST_LIST_RSV_SHIFT);

                                                                                                                                                                                                                    //set 1
                                                                                                                                                                                                                    ret=pmic_read_interface(AUXADC_CON23,&adc_reg_val,PMIC_RG_AP_RQST_LIST_RSV_MASK,PMIC_RG_AP_RQST_LIST_RSV_SHIFT);
                                                                                                                                                                                                                    adc_reg_val = adc_reg_val | (1<<(dwChannel-9));
                                                                                                                                                                                                                    ret=pmic_config_interface(AUXADC_CON23,adc_reg_val,PMIC_RG_AP_RQST_LIST_RSV_MASK,PMIC_RG_AP_RQST_LIST_RSV_SHIFT);       
                                                                                                                                                                                                                }


                                                                                                                                                                                                                mutex_unlock(&pmic_adc_mutex);

                                                                                                                                                                                                                //Duo to HW limitation
                                                                                                                                                                                                                if(dwChannel!=8)
                                                                                                                                                                                                                msleep(1);

                                                                                                                                                                                                                count=0;
                                                                                                                                                                                                                ret_data=0;

                                                                                                                                                                                                                /* 根据不同通道选择,来读取对应的 PMIC 寄存器的值 */
                                                                                                                                                                                                                switch(dwChannel){         
                                                                                                                                                                                                                    case 0:    
                                                                                                                                                                                                                        while( upmu_get_rg_adc_rdy_baton2() != 1 )
                                                                                                                                                                                                                        {
                                                                                                                                                                                                                            msleep(1);
                                                                                                                                                                                                                            if( (count++) > count_time_out)
                                                                                                                                                                                                                            {
                                                                                                                                                                                                                                        xlog_printk(ANDROID_LOG_INFO, "Power/PMIC", "[IMM_GetOneChannelValue_PMIC] (%d) Time out!\n", dwChannel);
                                                                                                                                                                                                                                break;
                                                                                                                                                                                                                            }           
                                                                                                                                                                                                                        }
                                                                                                                                                                                                                        ret_data = upmu_get_rg_adc_out_baton2();                
                                                                                                                                                                                                                        break;
                                                                                                                                                                                                                
                                                                                                                                                                                                                    case 1:    
                                                                                                                                                                                                                        while( upmu_get_rg_adc_rdy_ch6() != 1 )
                                                                                                                                                                                                                        {
                                                                                                                                                                                                                            msleep(1);
                                                                                                                                                                                                                            if( (count++) > count_time_out)
                                                                                                                                                                                                                            {
                                                                                                                                                                                                                                        xlog_printk(ANDROID_LOG_INFO, "Power/PMIC", "[IMM_GetOneChannelValue_PMIC] (%d) Time out!\n", dwChannel);
                                                                                                                                                                                                                                break;
                                                                                                                                                                                                                            }           
                                                                                                                                                                                                                        }
                                                                                                                                                                                                                        ret_data = upmu_get_rg_adc_out_ch6();               
                                                                                                                                                                                                                        xlog_printk(ANDROID_LOG_INFO, "Power/PMIC", "[upmu_get_rg_adc_out_ch6] 0x%x\n", ret_data);
                                                                                                                                                                                                                        break;
                                                                                                                                                                                                                    case 2:    
                                                                                                                                                                                                                        while( upmu_get_rg_adc_rdy_thr_sense2() != 1 )
                                                                                                                                                                                                                        {
                                                                                                                                                                                                                            msleep(1);
                                                                                                                                                                                                                            if( (count++) > count_time_out)
                                                                                                                                                                                                                            {
                                                                                                                                                                                                                                        xlog_printk(ANDROID_LOG_INFO, "Power/PMIC", "[IMM_GetOneChannelValue_PMIC] (%d) Time out!\n", dwChannel);
                                                                                                                                                                                                                                break;
                                                                                                                                                                                                                            }           
                                                                                                                                                                                                                        }
                                                                                                                                                                                                                        ret_data = upmu_get_rg_adc_out_thr_sense2();                
                                                                                                                                                                                                                        break;              
                                                                                                                                                                                                                    case 3:    
                                                                                                                                                                                                                        while( upmu_get_rg_adc_rdy_thr_sense1() != 1 )
                                                                                                                                                                                                                        {
                                                                                                                                                                                                                            msleep(1);
                                                                                                                                                                                                                            if( (count++) > count_time_out)
                                                                                                                                                                                                                            {
                                                                                                                                                                                                                                        xlog_printk(ANDROID_LOG_INFO, "Power/PMIC", "[IMM_GetOneChannelValue_PMIC] (%d) Time out!\n", dwChannel);
                                                                                                                                                                                                                                break;
                                                                                                                                                                                                                            }           
                                                                                                                                                                                                                        }
                                                                                                                                                                                                                        ret_data = upmu_get_rg_adc_out_thr_sense1();                
                                                                                                                                                                                                                        break;
                                                                                                                                                                                                                    case 4:    
                                                                                                                                                                                                                        while( upmu_get_rg_adc_rdy_vcdt() != 1 )
                                                                                                                                                                                                                        {
                                                                                                                                                                                                                            msleep(1);
                                                                                                                                                                                                                            if( (count++) > count_time_out)
                                                                                                                                                                                                                            {
                                                                                                                                                                                                                                        xlog_printk(ANDROID_LOG_INFO, "Power/PMIC", "[IMM_GetOneChannelValue_PMIC] (%d) Time out!\n", dwChannel);
                                                                                                                                                                                                                                break;
                                                                                                                                                                                                                            }           
                                                                                                                                                                                                                        }
                                                                                                                                                                                                                        ret_data = upmu_get_rg_adc_out_vcdt();              
                                                                                                                                                                                                                        break;
                                                                                                                                                                                                                    /* 读取 PMIC 的 VBATON 引用的电压值*/
                                                                                                                                                                                                                    case 5:    
                                                                                                                                                                                                                        while( upmu_get_rg_adc_rdy_baton1() != 1 )
                                                                                                                                                                                                                        {
                                                                                                                                                                                                                            msleep(1);
                                                                                                                                                                                                                            if( (count++) > count_time_out)
                                                                                                                                                                                                                            {
                                                                                                                                                                                                                                        xlog_printk(ANDROID_LOG_INFO, "Power/PMIC", "[IMM_GetOneChannelValue_PMIC] (%d) Time out!\n", dwChannel);
                                                                                                                                                                                                                                break;
                                                                                                                                                                                                                            }           
                                                                                                                                                                                                                        }
                                                                                                                                                                                                                        ret_data = upmu_get_rg_adc_out_baton1();         
                                                                                                                                                                                                                                                    kal_uint32 upmu_get_rg_adc_rdy_baton1(void)
                                                                                                                                                                                                                                                    {
                                                                                                                                                                                                                                                      kal_uint32 ret=0;
                                                                                                                                                                                                                                                      kal_uint32 val=0;

                                                                                                                                                                                                                                                      pmic_lock();
                                                                                                                                                                                                                                                      ret=pmic_read_interface( (kal_uint32)(AUXADC_ADC3),
                                                                                                                                                                                                                                                                               (&val),
                                                                                                                                                                                                                                                                               (kal_uint32)(PMIC_RG_ADC_RDY_BATON1_MASK),
                                                                                                                                                                                                                                                                               (kal_uint32)(PMIC_RG_ADC_RDY_BATON1_SHIFT)
                                                                                                                                                                                                                                                                               );
                                                                                                                                                                                                                                                      pmic_unlock();

                                                                                                                                                                                                                                                      return val;
                                                                                                                                                                                                                                                    }
                                                                                                                                                                                                                        break;
                                                                                                                                                                                                                    case 6:    
                                                                                                                                                                                                                        while( upmu_get_rg_adc_rdy_isense() != 1 )
                                                                                                                                                                                                                        {
                                                                                                                                                                                                                            msleep(1);
                                                                                                                                                                                                                            if( (count++) > count_time_out)
                                                                                                                                                                                                                            {
                                                                                                                                                                                                                                        xlog_printk(ANDROID_LOG_INFO, "Power/PMIC", "[IMM_GetOneChannelValue_PMIC] (%d) Time out!\n", dwChannel);
                                                                                                                                                                                                                                break;
                                                                                                                                                                                                                            }           
                                                                                                                                                                                                                        }
                                                                                                                                                                                                                        ret_data = upmu_get_rg_adc_out_isense();                
                                                                                                                                                                                                                        break;
                                                                                                                                                                                                                    case 7:    
                                                                                                                                                                                                                        while( upmu_get_rg_adc_rdy_batsns() != 1 )
                                                                                                                                                                                                                        {
                                                                                                                                                                                                                            msleep(1);
                                                                                                                                                                                                                            if( (count++) > count_time_out)
                                                                                                                                                                                                                            {
                                                                                                                                                                                                                                        xlog_printk(ANDROID_LOG_INFO, "Power/PMIC", "[IMM_GetOneChannelValue_PMIC] (%d) Time out!\n", dwChannel);
                                                                                                                                                                                                                                break;
                                                                                                                                                                                                                            }           
                                                                                                                                                                                                                        }
                                                                                                                                                                                                                        ret_data = upmu_get_rg_adc_out_batsns();                
                                                                                                                                                                                                                        break; 
                                                                                                                                                                                                                        
                                                                                                                                                                                                                    case 8:    
                                                                                                                                                                                                                        while( upmu_get_rg_adc_rdy_ch5() != 1 );
                                                                                                                                                                                                                        ret_data = upmu_get_rg_adc_out_ch5();               
                                                                                                                                                                                                                        break;              
                                                                                                                                                                                                                    case 9:    
                                                                                                                                                                                                                case 10:  
                                                                                                                                                                                                                case 11:  
                                                                                                                                                                                                                case 12:
                                                                                                                                                                                                                    case 13:    
                                                                                                                                                                                                                case 14:  
                                                                                                                                                                                                                case 15:  
                                                                                                                                                                                                                case 16:        
                                                                                                                                                                                                                        while( upmu_get_rg_adc_rdy_int() != 1 )
                                                                                                                                                                                                                        {
                                                                                                                                                                                                                            msleep(1);
                                                                                                                                                                                                                            if( (count++) > count_time_out)
                                                                                                                                                                                                                            {
                                                                                                                                                                                                                                        xlog_printk(ANDROID_LOG_INFO, "Power/PMIC", "[IMM_GetOneChannelValue_PMIC] (%d) Time out!\n", dwChannel);
                                                                                                                                                                                                                                break;
                                                                                                                                                                                                                            }           
                                                                                                                                                                                                                        }
                                                                                                                                                                                                                        ret_data = upmu_get_rg_adc_out_int();               
                                                                                                                                                                                                                        break;              
                                                                                                                                                                                                                        
                                                                                                                                                                                                                    default:
                                                                                                                                                                                                                        xlog_printk(ANDROID_LOG_INFO, "Power/PMIC", "[AUXADC] Invalid channel value(%d,%d)\n", dwChannel, trimd);
                                                                                                                                                                                                                        wake_unlock(&pmicAuxadc_irq_lock);
                                                                                                                                                                                                                        return -1;
                                                                                                                                                                                                                        break;
                                                                                                                                                                                                                }

                                                                                                                                                                                                                u4channel += ret_data;

                                                                                                                                                                                                                u4Sample_times++;

                                                                                                                                                                                                                if (Enable_BATDRV_LOG == 2)
                                                                                                                                                                                                                {
                                                                                                                                                                                                                    //debug
                                                                                                                                                                                                                    xlog_printk(ANDROID_LOG_INFO, "Power/PMIC", "[AUXADC] u4channel[%d]=%d.\n", 
                                                                                                                                                                                                                        dwChannel, ret_data);
                                                                                                                                                                                                                }
                                                                                                                                                                                                                
                                                                                                                                                                                                            }while (u4Sample_times < deCount);

                                                                                                                                                                                                            /* Value averaging 
                                                                                                                                                                                                            adc 采样值取平均值 */ 
                                                                                                                                                                                                            adc_result_temp = u4channel / deCount;

                                                                                                                                                                                                            /* ADC 分辨率: 即 ADC 数据每加 1 所对应的电压变化,计算公式为 【测量电压范围/(2^AD位数-1)】*/
                                                                                                                                                                                                            switch(dwChannel){         
                                                                                                                                                                                                                case 0:                
                                                                                                                                                                                                                    r_val_temp = 1;           
                                                                                                                                                                                                                    adc_result = (adc_result_temp*r_val_temp*VOLTAGE_FULL_RANGE)/ADC_PRECISE;
                                                                                                                                                                                                                    break;
                                                                                                                                                                                                                case 1:    
                                                                                                                                                                                                                    r_val_temp = 1;
                                                                                                                                                                                                                    adc_result = (adc_result_temp*r_val_temp*VOLTAGE_FULL_RANGE)/ADC_PRECISE;
                                                                                                                                                                                                                    break;
                                                                                                                                                                                                                case 2:    
                                                                                                                                                                                                                    r_val_temp = 1;
                                                                                                                                                                                                                    adc_result = (adc_result_temp*r_val_temp*VOLTAGE_FULL_RANGE)/ADC_PRECISE;
                                                                                                                                                                                                                    break;
                                                                                                                                                                                                                case 3:    
                                                                                                                                                                                                                    r_val_temp = 1;
                                                                                                                                                                                                                    adc_result = (adc_result_temp*r_val_temp*VOLTAGE_FULL_RANGE)/ADC_PRECISE;
                                                                                                                                                                                                                    break;
                                                                                                                                                                                                                case 4:    
                                                                                                                                                                                                                    r_val_temp = 1;
                                                                                                                                                                                                                    adc_result = (adc_result_temp*r_val_temp*VOLTAGE_FULL_RANGE)/ADC_PRECISE;
                                                                                                                                                                                                                    break;

                                                                                                                                                                                                                /* ADC 分辨率: 即 ADC 数据每加 1 所对应的电压变化,计算公式为 
                                                                                                                                                                                                                      0-正数表示:     【测量电压范围/(2^AD位数)】 
                                                                                                                                                                                                                      负数-正数表示: 【测量电压范围/(2^AD位数-1)】 
                                                                                                                                                                                                                获得 BATON 电压值 

                                                                                                                                                                                                                        #define VOLTAGE_FULL_RANGE     1800  // 测量的电压范围
                                                                                                                                                                                                                        #define ADC_PRECISE           32768  // 15 bits   2^15 = 32768
                                                                                                                                                                                                                */
                                                                                                                                                                                                                case 5:    
                                                                                                                                                                                                                    r_val_temp = 1;

                                                                                                                                                                                                                    /* 这里得到将数字化数值转换为对应的模拟电压值 */
                                                                                                                                                                                                                    adc_result = (adc_result_temp*r_val_temp*VOLTAGE_FULL_RANGE)/ADC_PRECISE;
                                                                                                                                                                                                                    break;
                                                                                                                                                                                                                case 6:    
                                                                                                                                                                                                                    r_val_temp = 4;     // 电阻分压比,因为测量 adc 量程不够,要采用电阻分压
                                                                                                                                                                                                                    adc_result = (adc_result_temp*r_val_temp*VOLTAGE_FULL_RANGE)/ADC_PRECISE;
                                                                                                                                                                                                                    break;
                                                                                                                                                                                                                case 7:    
                                                                                                                                                                                                                    r_val_temp = 4;     // 电阻分压比,因为测量 adc 量程不够,要采用电阻分压
                                                                                                                                                                                                                    adc_result = (adc_result_temp*r_val_temp*VOLTAGE_FULL_RANGE)/ADC_PRECISE;
                                                                                                                                                                                                                    break;    
                                                                                                                                                                                                                case 8:    
                                                                                                                                                                                                                    r_val_temp = 1;
                                                                                                                                                                                                                    adc_result = (adc_result_temp*r_val_temp*VOLTAGE_FULL_RANGE)/ADC_PRECISE;
                                                                                                                                                                                                                    break;              
                                                                                                                                                                                                            case 9:    
                                                                                                                                                                                                            case 10:  
                                                                                                                                                                                                            case 11:  
                                                                                                                                                                                                            case 12:
                                                                                                                                                                                                            case 13:    
                                                                                                                                                                                                            case 14:  
                                                                                                                                                                                                            case 15:  
                                                                                                                                                                                                            case 16:        
                                                                                                                                                                                                                    adc_result = adc_result_temp;
                                                                                                                                                                                                                    break;  
                                                                                                                                                                                                                default:
                                                                                                                                                                                                                    xlog_printk(ANDROID_LOG_INFO, "Power/PMIC", "[AUXADC] Invalid channel value(%d,%d)\n", dwChannel, trimd);
                                                                                                                                                                                                                    wake_unlock(&pmicAuxadc_irq_lock);
                                                                                                                                                                                                                    return -1;
                                                                                                                                                                                                                    break;
                                                                                                                                                                                                            }

                                                                                                                                                                                                            if (Enable_BATDRV_LOG == 2)
                                                                                                                                                                                                            {
                                                                                                                                                                                                                //debug
                                                                                                                                                                                                                xlog_printk(ANDROID_LOG_INFO, "Power/PMIC", "[AUXADC] adc_result_temp=%d, adc_result=%d, r_val_temp=%d.\n", 
                                                                                                                                                                                                                        adc_result_temp, adc_result, r_val_temp);
                                                                                                                                                                                                            }

                                                                                                                                                                                                            wake_unlock(&pmicAuxadc_irq_lock);
                                                                                                                                                                                                            
                                                                                                                                                                                                            return adc_result;
                                                                                                                                                                                                           
                                                                                                                                                                                                        }

                                                                                                                                                          #endif
                                                                                                                                                      #endif

                                                                                                                                                          return STATUS_OK;
                                                                                                                                                      }


                                                                                                                /* 如果获得的 PMIC 的  BATON 引脚电压值不为 0 */
                                                                                                                if(bat_temperature_volt != 0)
                                                                                                                {   
                                                                                                                    #if defined(SOC_BY_HW_FG)
                                                                                                                    
                                                                                                                    /* 获得配置的放电电阻值的大小 */
                                                                                                                    fg_r_value = get_r_fg_value();
                                                                                                                                        int get_r_fg_value(void)
                                                                                                                                        {
                                                                                                                                            return (R_FG_VALUE+CUST_R_FG_OFFSET);
                                                                                                                                        }

                                                                                                                    ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT, &fg_current_temp);   
                                                                                                                                                    static kal_int32 fgauge_read_current(void *data)
                                                                                                                                                    {
                                                                                                                                                        return STATUS_OK;
                                                                                                                                                    }
                                                                                                                    ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT_SIGN, &fg_current_state);
                                                                                                                                                    static kal_int32 fgauge_read_current_sign(void *data)
                                                                                                                                                    {
                                                                                                                                                        return STATUS_OK;
                                                                                                                                                    }
                                                                                                                    fg_current_temp = fg_current_temp/10;
                                                                                                                    
                                                                                                                    if(fg_current_state==KAL_TRUE)
                                                                                                                    {
                                                                                                                        bat_temperature_volt_temp = bat_temperature_volt;
                                                                                                                        bat_temperature_volt = bat_temperature_volt - ((fg_current_temp*fg_r_value)/1000);
                                                                                                                    }
                                                                                                                    else
                                                                                                                    {
                                                                                                                        bat_temperature_volt_temp = bat_temperature_volt;
                                                                                                                        // 这里对 NTC 电压进行补偿: NTC 实际温度对应电压 = 测量电压 + 负载电压*负载电阻   // 【这里的 1000 是将小数整数化】
                                                                                                                        bat_temperature_volt = bat_temperature_volt + ((fg_current_temp*fg_r_value)/1000);
                                                                                                                    }
                                                                                                            #endif

                                                                                                                    ///////////////////////////////////////////////////////////////////////////////////////
                                                                                                                    /* 将 NTC 的电压通过查表获得对应温度值 */
                                                                                                                    bat_temperature_val = BattVoltToTemp(bat_temperature_volt);
                                                                                                                                                int BattVoltToTemp(int dwVolt)
                                                                                                                                                {
                                                                                                                                                    kal_int64 TRes_temp;
                                                                                                                                                    kal_int64 TRes;
                                                                                                                                                    int sBaTTMP = -100;

                                                                                                                                                    // TRes_temp = ((kal_int64)RBAT_PULL_UP_R*(kal_int64)dwVolt) / (RBAT_PULL_UP_VOLT-dwVolt); 
                                                                                                                                                    //TRes = (TRes_temp * (kal_int64)RBAT_PULL_DOWN_R)/((kal_int64)RBAT_PULL_DOWN_R - TRes_temp);


                                                                                                                                                    /* 电路原理如下:

                                                                                                                                                                    Vu                                Ru:上拉电阻值           
                                                                                                                                                                    ---                               Rd: 下拉电阻值 
                                                                                                                                                                     |                                Rntc: NTC 温度电阻 阻值
                                                                                                                                                                    |||   Ru                          Vu: 上拉电压值 
                                                                                                                                                                     |                                Gnd: 地 
                                                                                                                                                                ---------- -----Vntc                  Vntc: NTC 电压 
                                                                                                                                                                |        |
                                                                                                                                                        Rntc   |||      |||  Rd 
                                                                                                                                                                |        |
                                                                                                                                                                ----------                          Rntc = (Ru*Rd*Vntc) / (Vru * Rd - Vntc * Ru)
                                                                                                                                                                     |
                                                                                                                                                                   -----
                                                                                                                                                                    ---
                                                                                                                                                                     -
                                                                                                                                                                    Gnd 
                                                                                                                                                          */

                                                                                                                                                    
                                                                                                                                                    /* TRes_temp = 上拉电阻值 * NTC电压 */
                                                                                                                                                    TRes_temp = (RBAT_PULL_UP_R*(kal_int64)dwVolt); 

                                                                                                                                                    /* 上拉电阻分压 = 上拉电压 - NTC分压 = RBAT_PULL_UP_VOLT-dwVolt
                                                                                                                                                    do_div(): 做除法 

                                                                                                                                                    (上拉电阻值 * NTC电压)/上拉电阻分压 = (上拉电阻值/上拉电压分压)*NTC电压   */
                                                                                                                                                    do_div(TRes_temp, (RBAT_PULL_UP_VOLT-dwVolt));

                                                                                                                                                    /* (上拉电阻值/上拉电压分压)*NTC电压*下拉电阻值 */
                                                                                                                                                    TRes = (TRes_temp * RBAT_PULL_DOWN_R);

                                                                                                                                                    /* (上拉电阻值/上拉电压分压)*NTC电压*下拉电阻值 / (下拉电阻值 - (上拉电阻值/上拉电压分压)*NTC电压)*/
                                                                                                                                                    do_div(TRes, abs(RBAT_PULL_DOWN_R - TRes_temp));

                                                                                                                                                    /* convert register to temperature 
                                                                                                                                                    将得到的 NTC 阻值通过表格换算成温度 */
                                                                                                                                                    sBaTTMP = BattThermistorConverTemp((int)TRes); 
                                                                                                                                                                        int BattThermistorConverTemp//(int Res)
                                                                                                                                                                        {
                                                                                                                                                                            int i=0;
                                                                                                                                                                            int RES1=0,RES2=0;
                                                                                                                                                                            int TBatt_Value=-200,TMP1=0,TMP2=0;

                                                                                                                                                                            /* 如果大于最低温度阻值,返回 -20 */
                                                                                                                                                                            if(Res>=Batt_Temperature_Table[0].TemperatureR) /* Cust_battery_meter_table.h (s:\i841\mediatek\custom\mt6582\kernel\battery\battery) */
                                                                                                                                                                            {
                                                                                                                                                                                TBatt_Value = -20;
                                                                                                                                                                            }
                                                                                                                                                                            /* 如果大于最高温度阻值,返回 60 */
                                                                                                                                                                            else if(Res<=Batt_Temperature_Table[16].TemperatureR)
                                                                                                                                                                            {
                                                                                                                                                                                TBatt_Value = 60;
                                                                                                                                                                            }
                                                                                                                                                                            /* 其他温度 */
                                                                                                                                                                            else
                                                                                                                                                                            {
                                                                                                                                                                                RES1=Batt_Temperature_Table[0].TemperatureR;
                                                                                                                                                                                TMP1=Batt_Temperature_Table[0].BatteryTemp;

                                                                                                                                                                                /* 遍历 NTC 阻值与温度对应表,获得当前阻值所对应的表项 */
                                                                                                                                                                                for(i=0;i<=16;i++)
                                                                                                                                                                                {
                                                                                                                                                                                    if(Res>=Batt_Temperature_Table[i].TemperatureR)
                                                                                                                                                                                    {
                                                                                                                                                                                        RES2=Batt_Temperature_Table[i].TemperatureR;
                                                                                                                                                                                        TMP2=Batt_Temperature_Table[i].BatteryTemp;
                                                                                                                                                                                        break;
                                                                                                                                                                                    }
                                                                                                                                                                                    else
                                                                                                                                                                                    {
                                                                                                                                                                                        RES1=Batt_Temperature_Table[i].TemperatureR;
                                                                                                                                                                                        TMP1=Batt_Temperature_Table[i].BatteryTemp;
                                                                                                                                                                                    }
                                                                                                                                                                                }
                                                                                                                                                                                
                                                                                                                                                                                /* Liner Interpolation Method: 线性插值法,方法详见 Battery_Charging Introduction for Customer.pdf 
                                                                                                                                                                                核心就是一条直接函数,已知两个点的 (X0,Y0) (X1,Y1),并知道第三个点的 X,就对应的 Y 
                                                                                                                                                                                    计算公式为:
                                                                                                                                                                                        Y = [(X-X0)*Y1 + (X1-X)*Y0] / (X1-X0) 
                                                                                                                                                                                */
                                                                                                                                                                                TBatt_Value = (((Res-RES2)*TMP1)+((RES1-Res)*TMP2))/(RES1-RES2);
                                                                                                                                                                            }

                                                                                                                                                                            return TBatt_Value;    
                                                                                                                                                                        }

                                                                                                                                                      
                                                                                                                                                    return sBaTTMP;
                                                                                                                                                }

                                                                                                                }
                                                                                                                
                                                                                                                bm_print(BM_LOG_CRTI, "[force_get_tbat] %d,%d,%d,%d,%d,%d\n", 
                                                                                                                    bat_temperature_volt_temp, bat_temperature_volt, fg_current_state, fg_current_temp, fg_r_value, bat_temperature_val);
                                                                                                                                                    
                                                                                                                return bat_temperature_val;    
                                                                                                            #endif    
                                                                                                            }

                                                                                                            
                                                                                    // Re-constructure r-table profile according to current temperature
                                                                                    /* 获得温度-电池内阻表 */
                                                                                    profile_p_r_table = fgauge_get_profile_r_table(TEMPERATURE_T);
                                                                                                                        R_PROFILE_STRUC_P fgauge_get_profile_r_table(kal_uint32 temperature)
                                                                                                                        {
                                                                                                                            switch (temperature)
                                                                                                                            {
                                                                                                                                case TEMPERATURE_T0:
                                                                                                                                    return &r_profile_t0[0];
                                                                                                                                    break;
                                                                                                                                case TEMPERATURE_T1:
                                                                                                                                    return &r_profile_t1[0];
                                                                                                                                    break;
                                                                                                                                case TEMPERATURE_T2:
                                                                                                                                    return &r_profile_t2[0];
                                                                                                                                    break;
                                                                                                                                case TEMPERATURE_T3:
                                                                                                                                    return &r_profile_t3[0];
                                                                                                                                    break;
                                                                                                                                case TEMPERATURE_T:
                                                                                                                                    return &r_profile_temperature[0];
                                                                                                                                    break;
                                                                                                                                default:
                                                                                                                                    return NULL;
                                                                                                                                    break;
                                                                                                                            }
                                                                                                                        }

                                                                                    if (profile_p_r_table == NULL)
                                                                                    {
                                                                                        bm_print(BM_LOG_CRTI, "[FGADC] fgauge_get_profile_r_table : create table fail !\r\n");
                                                                                    }

                                                                                    /* 获得当前温度使用的 温度-电池内阻 表格*/
                                                                                    fgauge_construct_r_table_profile(temperature, profile_p_r_table);
                                                                                                        void fgauge_construct_r_table_profile(kal_int32 temperature, R_PROFILE_STRUC_P temp_profile_p)
                                                                                                        {
                                                                                                            R_PROFILE_STRUC_P low_profile_p, high_profile_p;
                                                                                                            kal_int32 low_temperature, high_temperature;
                                                                                                            int i, saddles;
                                                                                                            kal_int32 temp_v_1 = 0, temp_v_2 = 0;
                                                                                                            kal_int32 temp_r_1 = 0, temp_r_2 = 0;

                                                                                                            /* 这里跟 NTC 类似,获得在 温度上下限时的电池内阻表 */
                                                                                                            if (temperature <= TEMPERATURE_T1)
                                                                                                            {
                                                                                                                low_profile_p    = fgauge_get_profile_r_table(TEMPERATURE_T0);
                                                                                                                high_profile_p   = fgauge_get_profile_r_table(TEMPERATURE_T1);
                                                                                                                low_temperature  = (-10);
                                                                                                                high_temperature = TEMPERATURE_T1;
                                                                                                                
                                                                                                                if(temperature < low_temperature)
                                                                                                                {
                                                                                                                    temperature = low_temperature;
                                                                                                                }
                                                                                                            }
                                                                                                            else if (temperature <= TEMPERATURE_T2)
                                                                                                            {
                                                                                                                low_profile_p    = fgauge_get_profile_r_table(TEMPERATURE_T1);
                                                                                                                high_profile_p   = fgauge_get_profile_r_table(TEMPERATURE_T2);
                                                                                                                low_temperature  = TEMPERATURE_T1;
                                                                                                                high_temperature = TEMPERATURE_T2;
                                                                                                                
                                                                                                                if(temperature < low_temperature)
                                                                                                                {
                                                                                                                    temperature = low_temperature;
                                                                                                                }
                                                                                                            }
                                                                                                            else
                                                                                                            {
                                                                                                                low_profile_p    = fgauge_get_profile_r_table(TEMPERATURE_T2);  // 温度下限温度-电池内阻表
                                                                                                                high_profile_p   = fgauge_get_profile_r_table(TEMPERATURE_T3);  // 温度上限温度-电池内阻表
                                                                                                                low_temperature  = TEMPERATURE_T2;                              // 温度下限
                                                                                                                high_temperature = TEMPERATURE_T3;                              // 温度上限

                                                                                                                /* 防溢出温度区间 */
                                                                                                                if(temperature > high_temperature)
                                                                                                                {
                                                                                                                    temperature = high_temperature;
                                                                                                                }
                                                                                                            }

                                                                                                            /* 获得 温度-电池内阻表 的表格项数 */
                                                                                                            saddles = fgauge_get_saddles_r_table();
                                                                                                                                int fgauge_get_saddles_r_table(void)
                                                                                                                                {
                                                                                                                                    return sizeof(r_profile_t2) / sizeof(R_PROFILE_STRUC);
                                                                                                                                }

                                                                                                            /* Interpolation for V_BAT 
                                                                                                            插值得到当前温度对应的电池电压 V_BAT */
                                                                                                            for (i = 0; i < saddles; i++)
                                                                                                            {
                                                                                                                /* 如果表格中温度上限电压 > 温度下限时电压 */
                                                                                                                if( ((high_profile_p + i)->voltage) > ((low_profile_p + i)->voltage) )
                                                                                                                {
                                                                                                                    /* 温度上限时电压 */
                                                                                                                    temp_v_1 = (high_profile_p + i)->voltage;
                                                                                                                    /* 温度下限时电压  */
                                                                                                                    temp_v_2 = (low_profile_p + i)->voltage;    

                                                                                                                    /* 插值得到此时温度对应的电压值 */
                                                                                                                    (temp_profile_p + i)->voltage = temp_v_2 +
                                                                                                                    (
                                                                                                                        (
                                                                                                                            (temperature - low_temperature) * 
                                                                                                                            (temp_v_1 - temp_v_2)
                                                                                                                        ) / 
                                                                                                                        (high_temperature - low_temperature)                
                                                                                                                    );
                                                                                                                }
                                                                                                                /* 如果表格中温度上限电压 <= 温度下限时电压 */
                                                                                                                else
                                                                                                                {
                                                                                                                    temp_v_1 = (low_profile_p + i)->voltage;
                                                                                                                    temp_v_2 = (high_profile_p + i)->voltage;

                                                                                                                    (temp_profile_p + i)->voltage = temp_v_2 +
                                                                                                                    (
                                                                                                                        (
                                                                                                                            (high_temperature - temperature) * 
                                                                                                                            (temp_v_1 - temp_v_2)
                                                                                                                        ) / 
                                                                                                                        (high_temperature - low_temperature)                
                                                                                                                    );
                                                                                                                }

                                                                                                        #if 0    
                                                                                                                //(temp_profile_p + i)->resistance = (high_profile_p + i)->resistance;
                                                                                                                
                                                                                                                (temp_profile_p + i)->voltage = temp_v_2 +
                                                                                                                    (
                                                                                                                        (
                                                                                                                            (temperature - low_temperature) * 
                                                                                                                            (temp_v_1 - temp_v_2)
                                                                                                                        ) / 
                                                                                                                        (high_temperature - low_temperature)                
                                                                                                                    );
                                                                                                        #endif
                                                                                                            }

                                                                                                            /* Interpolation for R_BAT 
                                                                                                            插值得到当前温度对应的电池内阻 R_BAT */
                                                                                                            for (i = 0; i < saddles; i++)
                                                                                                            {
                                                                                                                if( ((high_profile_p + i)->resistance) > ((low_profile_p + i)->resistance) )
                                                                                                                {
                                                                                                                    /* 温度上限时电池内阻 */
                                                                                                                    temp_r_1 = (high_profile_p + i)->resistance;
                                                                                                                    /* 温度下限时电池内阻 */
                                                                                                                    temp_r_2 = (low_profile_p + i)->resistance;    

                                                                                                                    /* 插值得到此时温度对应的电池内阻值 */
                                                                                                                    (temp_profile_p + i)->resistance = temp_r_2 +
                                                                                                                    (
                                                                                                                        (
                                                                                                                            (temperature - low_temperature) * 
                                                                                                                            (temp_r_1 - temp_r_2)
                                                                                                                        ) / 
                                                                                                                        (high_temperature - low_temperature)                
                                                                                                                    );
                                                                                                                }
                                                                                                                else
                                                                                                                {
                                                                                                                    temp_r_1 = (low_profile_p + i)->resistance;
                                                                                                                    temp_r_2 = (high_profile_p + i)->resistance;

                                                                                                                    (temp_profile_p + i)->resistance = temp_r_2 +
                                                                                                                    (
                                                                                                                        (
                                                                                                                            (high_temperature - temperature) * 
                                                                                                                            (temp_r_1 - temp_r_2)
                                                                                                                        ) / 
                                                                                                                        (high_temperature - low_temperature)                
                                                                                                                    );
                                                                                                                }

                                                                                                        #if 0    
                                                                                                                //(temp_profile_p + i)->voltage = (high_profile_p + i)->voltage;
                                                                                                                
                                                                                                                (temp_profile_p + i)->resistance = temp_r_2 +
                                                                                                                    (
                                                                                                                        (
                                                                                                                            (temperature - low_temperature) * 
                                                                                                                            (temp_r_1 - temp_r_2)
                                                                                                                        ) / 
                                                                                                                        (high_temperature - low_temperature)                
                                                                                                                    );
                                                                                                        #endif
                                                                                                            }

                                                                                                            // Dumpt new r-table profile
                                                                                                            for (i = 0; i < saddles ; i++)
                                                                                                            {
                                                                                                                bm_print(BM_LOG_CRTI, " at %d = <%d,%d>\r\n",
                                                                                                                    temperature, (temp_profile_p+i)->resistance, (temp_profile_p+i)->voltage);
                                                                                                            }
                                                                                                            
                                                                                                        }


                                                                                    // Re-constructure battery profile according to current temperature
                                                                                    /* 获得当前温度对应的 温度-电池容量表格 */
                                                                                    profile_p = fgauge_get_profile(TEMPERATURE_T);
                                                                                                            BATTERY_PROFILE_STRUC_P fgauge_get_profile(kal_uint32 temperature)
                                                                                                            {
                                                                                                                switch (temperature)
                                                                                                                {
                                                                                                                    case TEMPERATURE_T0:
                                                                                                                        return &battery_profile_t0[0];
                                                                                                                        break;    
                                                                                                                    case TEMPERATURE_T1:
                                                                                                                        return &battery_profile_t1[0];
                                                                                                                        break;
                                                                                                                    case TEMPERATURE_T2:
                                                                                                                        return &battery_profile_t2[0];
                                                                                                                        break;
                                                                                                                    case TEMPERATURE_T3:
                                                                                                                        return &battery_profile_t3[0];
                                                                                                                        break;
                                                                                                                    case TEMPERATURE_T:
                                                                                                                        return &battery_profile_temperature[0];
                                                                                                                        break;
                                                                                                                    default:
                                                                                                                        return NULL;
                                                                                                                        break;
                                                                                                                }
                                                                                                            }

                                                                                    if (profile_p == NULL)
                                                                                    {
                                                                                        bm_print(BM_LOG_CRTI, "[FGADC] fgauge_get_profile : create table fail !\r\n");
                                                                                    }
                                                                                    
                                                                                    /* 由当前温度,通过 温度-电池容量表格,获得对应的 温度-电池容量 数据,
                                                                                    即能得到当前温度所对应的用掉的电池容量 */
                                                                                    fgauge_construct_battery_profile(temperature, profile_p);
                                                                                                            void fgauge_construct_battery_profile(kal_int32 temperature, BATTERY_PROFILE_STRUC_P temp_profile_p)
                                                                                                            {
                                                                                                                BATTERY_PROFILE_STRUC_P low_profile_p, high_profile_p;
                                                                                                                kal_int32 low_temperature, high_temperature;
                                                                                                                int i, saddles;
                                                                                                                kal_int32 temp_v_1 = 0, temp_v_2 = 0;

                                                                                                                /* 获得对就温度所在温度上限/下限所对应的 温度-电池容量表格 */
                                                                                                                if (temperature <= TEMPERATURE_T1)
                                                                                                                {
                                                                                                                    low_profile_p    = fgauge_get_profile(TEMPERATURE_T0);
                                                                                                                    high_profile_p   = fgauge_get_profile(TEMPERATURE_T1);
                                                                                                                    low_temperature  = (-10);
                                                                                                                    high_temperature = TEMPERATURE_T1;
                                                                                                                    
                                                                                                                    if(temperature < low_temperature)
                                                                                                                    {
                                                                                                                        temperature = low_temperature;
                                                                                                                    }
                                                                                                                }
                                                                                                                else if (temperature <= TEMPERATURE_T2)
                                                                                                                {
                                                                                                                    low_profile_p    = fgauge_get_profile(TEMPERATURE_T1);
                                                                                                                    high_profile_p   = fgauge_get_profile(TEMPERATURE_T2);
                                                                                                                    low_temperature  = TEMPERATURE_T1;
                                                                                                                    high_temperature = TEMPERATURE_T2;
                                                                                                                    
                                                                                                                    if(temperature < low_temperature)
                                                                                                                    {
                                                                                                                        temperature = low_temperature;
                                                                                                                    }
                                                                                                                }
                                                                                                                else
                                                                                                                {
                                                                                                                    low_profile_p    = fgauge_get_profile(TEMPERATURE_T2);  // 温度下限所对应的 温度-电池容量表格
                                                                                                                    high_profile_p   = fgauge_get_profile(TEMPERATURE_T3);  // 温度上限所对应的 温度-电池容量表格
                                                                                                                    low_temperature  = TEMPERATURE_T2;                      // 温度下限
                                                                                                                    high_temperature = TEMPERATURE_T3;                      // 温度上限
                                                                                                                    
                                                                                                                    if(temperature > high_temperature)
                                                                                                                    {
                                                                                                                        temperature = high_temperature;
                                                                                                                    }
                                                                                                                }

                                                                                                                /* 获得 温度-电池容量 表格项数 */
                                                                                                                saddles = fgauge_get_saddles();

                                                                                                                /* 遍历表格,插值获得当前温度对应的容量 */
                                                                                                                for (i = 0; i < saddles; i++)
                                                                                                                {
                                                                                                                    if( ((high_profile_p + i)->voltage) > ((low_profile_p + i)->voltage) )
                                                                                                                    {
                                                                                                                        temp_v_1 = (high_profile_p + i)->voltage;
                                                                                                                        temp_v_2 = (low_profile_p + i)->voltage;    

                                                                                                                        (temp_profile_p + i)->voltage = temp_v_2 +
                                                                                                                        (
                                                                                                                            (
                                                                                                                                (temperature - low_temperature) * 
                                                                                                                                (temp_v_1 - temp_v_2)
                                                                                                                            ) / 
                                                                                                                            (high_temperature - low_temperature)                
                                                                                                                        );
                                                                                                                    }
                                                                                                                    else
                                                                                                                    {
                                                                                                                        temp_v_1 = (low_profile_p + i)->voltage;
                                                                                                                        temp_v_2 = (high_profile_p + i)->voltage;

                                                                                                                        (temp_profile_p + i)->voltage = temp_v_2 +
                                                                                                                        (
                                                                                                                            (
                                                                                                                                (high_temperature - temperature) * 
                                                                                                                                (temp_v_1 - temp_v_2)
                                                                                                                            ) / 
                                                                                                                            (high_temperature - low_temperature)                
                                                                                                                        );
                                                                                                                    }
                                                                                                                
                                                                                                                    (temp_profile_p + i)->percentage = (high_profile_p + i)->percentage;
                                                                                                            #if 0        
                                                                                                                    (temp_profile_p + i)->voltage = temp_v_2 +
                                                                                                                        (
                                                                                                                            (
                                                                                                                                (temperature - low_temperature) * 
                                                                                                                                (temp_v_1 - temp_v_2)
                                                                                                                            ) / 
                                                                                                                            (high_temperature - low_temperature)                
                                                                                                                        );
                                                                                                            #endif
                                                                                                                }

                                                                                                                
                                                                                                                // Dumpt new battery profile
                                                                                                                for (i = 0; i < saddles ; i++)
                                                                                                                {
                                                                                                                    bm_print(BM_LOG_CRTI, " at %d = <%d,%d>\r\n",
                                                                                                                        temperature, (temp_profile_p+i)->percentage, (temp_profile_p+i)->voltage);
                                                                                                                }
                                                                                                                
                                                                                                            }

                                                                                }

                                                                        
                                                                        /* 首先获得电池电压,然后获得 hw ocv 电压,两者差值较小时,即 hw ocv 为准,
                                                                        然后以此计算出开机电池容量值,并且与 rtc 中记录的电量值进行比较,如果误差较小(小于 40%)
                                                                        则以 rtc 容量值为准,最后初始化 oam 算法的相关参数 */
                                                                        oam_init(); 
                                                                                void oam_init(void)
                                                                                {
                                                                                    int ret=0;
                                                                                    int vol_bat=0;
                                                                                    kal_int32 vbat_capacity = 0;

                                                                                    vol_bat = 5; //set avg times

                                                                                    /* 读 PMIC 引用 BATSNS 的电压,即电池电压 */
                                                                                    ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_BAT_SENSE, &vol_bat);      // battery_meter_ctrl() 被初化为 bm_ctrl_cmd()
                                                                                                                    static kal_int32 read_adc_v_bat_sense(void *data)
                                                                                                                    {
                                                                                                                    #if defined(CONFIG_POWER_EXT)
                                                                                                                        *(kal_int32*)(data) = 4201;
                                                                                                                    #else
                                                                                                                        /* 读 PMIC 对应的 ADC 的值,并将其转化为对应的电压值,这里即读取 BATSNS 引脚电压 */
                                                                                                                        *(kal_int32*)(data) = PMIC_IMM_GetOneChannelValue(VBAT_CHANNEL_NUMBER,*(kal_int32*)(data),1);
                                                                                                                    #endif

                                                                                                                        return STATUS_OK;
                                                                                                                    }
                                                                                    /* 这里应该是获得 hw ocv 电压 */
                                                                                    ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_OCV, &gFG_voltage);   
                                                                                                                    static kal_int32 read_hw_ocv(void *data)
                                                                                                                    {
                                                                                                                    /* 外部充电器的话直接固定值 */
                                                                                                                    #if defined(CONFIG_POWER_EXT)
                                                                                                                        *(kal_int32*)(data) = 3999;
                                                                                                                    #else
                                                                                                                        /* 这里应该是读取相应寄存器, 获得一个 hw ocv 电压  */
                                                                                                                        *(kal_int32*)(data) = get_hw_ocv();
                                                                                                                                                    int get_hw_ocv(void)
                                                                                                                                                    {
                                                                                                                                                    #if defined(CONFIG_POWER_EXT)
                                                                                                                                                        return 4001;    
                                                                                                                                                    #else
                                                                                                                                                        kal_int32 adc_result_reg=0;
                                                                                                                                                        kal_int32 adc_result=0;
                                                                                                                                                        kal_int32 r_val_temp=4;    

                                                                                                                                                        #if defined(SWCHR_POWER_PATH)
                                                                                                                                                        adc_result_reg = upmu_get_rg_adc_out_wakeup_swchr();
                                                                                                                                                        adc_result = (adc_result_reg*r_val_temp*VOLTAGE_FULL_RANGE)/ADC_PRECISE;
                                                                                                                                                        bm_print(BM_LOG_CRTI, "[oam] get_hw_ocv (swchr) : adc_result_reg=%d, adc_result=%d\n", 
                                                                                                                                                            adc_result_reg, adc_result);
                                                                                                                                                        #else
                                                                                                                                                        /* 这里应该是读取相应寄存器,获得充电电压值,因为从 PMIC 手册上说,只有在充电电压处于 4.3V <= x <= 7V 时才可以充电*/
                                                                                                                                                        adc_result_reg = upmu_get_rg_adc_out_wakeup_pchr();
                                                                                                                                                                                            kal_uint32 upmu_get_rg_adc_out_wakeup_pchr(void)
                                                                                                                                                                                            {
                                                                                                                                                                                              kal_uint32 ret=0;
                                                                                                                                                                                              kal_uint32 val=0;

                                                                                                                                                                                              pmic_lock();
                                                                                                                                                                                              ret=pmic_read_interface( (kal_uint32)(AUXADC_ADC8),
                                                                                                                                                                                                                       (&val),
                                                                                                                                                                                                                       (kal_uint32)(PMIC_RG_ADC_OUT_WAKEUP_PCHR_MASK),
                                                                                                                                                                                                                       (kal_uint32)(PMIC_RG_ADC_OUT_WAKEUP_PCHR_SHIFT)
                                                                                                                                                                                                                       );
                                                                                                                                                                                              pmic_unlock();

                                                                                                                                                                                              return val;
                                                                                                                                                                                            }
                                                                                                                                                        /* 将得到的 adc 数值转换为对应的 模拟电压值 */
                                                                                                                                                        adc_result = (adc_result_reg*r_val_temp*VOLTAGE_FULL_RANGE)/ADC_PRECISE;        
                                                                                                                                                        bm_print(BM_LOG_CRTI, "[oam] get_hw_ocv (pchr) : adc_result_reg=%d, adc_result=%d\n", 
                                                                                                                                                            adc_result_reg, adc_result);
                                                                                                                                                        #endif

                                                                                                                                                        adc_result += g_hw_ocv_tune_value;
                                                                                                                                                        return adc_result;
                                                                                                                                                    #endif    
                                                                                                                                                    }

                                                                                                                    #endif

                                                                                                                        return STATUS_OK;
                                                                                                                    }

                                                                                    /* 获取 hw ocv 电压对应的的电池剩余容量百分比 */
                                                                                    gFG_capacity_by_v = fgauge_read_capacity_by_v(gFG_voltage);
                                                                                                                        kal_int32 fgauge_read_capacity_by_v(kal_int32 voltage)
                                                                                                                        {    
                                                                                                                            int i = 0, saddles = 0;
                                                                                                                            BATTERY_PROFILE_STRUC_P profile_p;
                                                                                                                            kal_int32 ret_percent = 0;

                                                                                                                            /* 获得当前温度对应的 温度-电池容量表格 */
                                                                                                                            profile_p = fgauge_get_profile(TEMPERATURE_T);
                                                                                                                                                    
                                                                                                                            if (profile_p == NULL)
                                                                                                                            {
                                                                                                                                bm_print(BM_LOG_CRTI, "[FGADC] fgauge get ZCV profile : fail !\r\n");
                                                                                                                                return 100;
                                                                                                                            }

                                                                                                                            /* 获得 温度-电池容量 表格项数 */
                                                                                                                            saddles = fgauge_get_saddles();

                                                                                                                            if (voltage > (profile_p+0)->voltage)
                                                                                                                            {
                                                                                                                                return 100; // battery capacity, not dod
                                                                                                                            }    
                                                                                                                            if (voltage < (profile_p+saddles-1)->voltage)
                                                                                                                            {
                                                                                                                                return 0; // battery capacity, not dod
                                                                                                                            }

                                                                                                                            /* 遍历表格,插值获得当前电压对应的用掉容量百分比 */
                                                                                                                            for (i = 0; i < saddles - 1; i++)
                                                                                                                            {
                                                                                                                                if ((voltage <= (profile_p+i)->voltage) && (voltage >= (profile_p+i+1)->voltage))
                                                                                                                                {
                                                                                                                                    ret_percent = (profile_p+i)->percentage +
                                                                                                                                        (
                                                                                                                                            (
                                                                                                                                                ( ((profile_p+i)->voltage) - voltage ) * 
                                                                                                                                                ( ((profile_p+i+1)->percentage) - ((profile_p + i)->percentage) ) 
                                                                                                                                            ) /
                                                                                                                                            ( ((profile_p+i)->voltage) - ((profile_p+i+1)->voltage) )
                                                                                                                                        );         
                                                                                                                                    
                                                                                                                                    break;
                                                                                                                                }
                                                                                                                                
                                                                                                                            }
                                                                                                                            /* 获得当前剩余电量值 */
                                                                                                                            ret_percent = 100 - ret_percent;

                                                                                                                            return ret_percent;
                                                                                                                        }

                                                                                    
                                                                                    /* 获得当前电池电压对应的剩余容量百分比 */
                                                                                    vbat_capacity = fgauge_read_capacity_by_v(vol_bat);
                                                                                                                        kal_int32 fgauge_read_capacity_by_v(kal_int32 voltage)
                                                                                                                        {    
                                                                                                                            int i = 0, saddles = 0;
                                                                                                                            BATTERY_PROFILE_STRUC_P profile_p;
                                                                                                                            kal_int32 ret_percent = 0;

                                                                                                                            /* 获得当前温度对应的 温度-电池容量表格 */
                                                                                                                            profile_p = fgauge_get_profile(TEMPERATURE_T);
                                                                                                                            if (profile_p == NULL)
                                                                                                                            {
                                                                                                                                bm_print(BM_LOG_CRTI, "[FGADC] fgauge get ZCV profile : fail !\r\n");
                                                                                                                                return 100;
                                                                                                                            }

                                                                                                                            /* 获得 温度-电池容量 表格项数 */
                                                                                                                            saddles = fgauge_get_saddles();

                                                                                                                            if (voltage > (profile_p+0)->voltage)
                                                                                                                            {
                                                                                                                                return 100; // battery capacity, not dod
                                                                                                                            }    
                                                                                                                            if (voltage < (profile_p+saddles-1)->voltage)
                                                                                                                            {
                                                                                                                                return 0; // battery capacity, not dod
                                                                                                                            }

                                                                                                                            /* 遍历表格,插值获得当前电压对应的用掉容量百分比 */
                                                                                                                            for (i = 0; i < saddles - 1; i++)
                                                                                                                            {
                                                                                                                                if ((voltage <= (profile_p+i)->voltage) && (voltage >= (profile_p+i+1)->voltage))
                                                                                                                                {
                                                                                                                                    ret_percent = (profile_p+i)->percentage +
                                                                                                                                        (
                                                                                                                                            (
                                                                                                                                                ( ((profile_p+i)->voltage) - voltage ) * 
                                                                                                                                                ( ((profile_p+i+1)->percentage) - ((profile_p + i)->percentage) ) 
                                                                                                                                            ) /
                                                                                                                                            ( ((profile_p+i)->voltage) - ((profile_p+i+1)->voltage) )
                                                                                                                                        );         
                                                                                                                                    
                                                                                                                                    break;
                                                                                                                                }
                                                                                                                                
                                                                                                                            }
                                                                                                                            ret_percent = 100 - ret_percent;

                                                                                                                            return ret_percent;
                                                                                                                        }

                                                                                    /* 如果充电器插上了,则比较使用当前电压与 hw ocv 电压计算的两都容量差,如果差值较小,继续使用 hw ocv 电压及
                                                                                    对应容量为准 */
                                                                                    if(bat_is_charger_exist() == KAL_TRUE)
                                                                                                        ///////////////////////////////////////////////////////////////////////////////////////////
                                                                                                        //// Pulse Charging Algorithm 
                                                                                                        // 判断充电是否插上了 
                                                                                                        ///////////////////////////////////////////////////////////////////////////////////////////
                                                                                                        kal_bool bat_is_charger_exist(void)
                                                                                                        {
                                                                                                            return get_charger_detect_status();
                                                                                                                                int get_charger_detect_status(void)
                                                                                                                                {
                                                                                                                                    kal_bool chr_status;

                                                                                                                                    /* 对应的充电芯片的硬件函数 */
                                                                                                                                    battery_charging_control(CHARGING_CMD_GET_CHARGER_DET_STATUS,&chr_status);
                                                                                                                                                              static kal_uint32 charging_get_charger_det_status(void *data)
                                                                                                                                                               {
                                                                                                                                                                   kal_uint32 status = STATUS_OK;
                                                                                                                                                               
                                                                                                                                                              #if defined(CHRDET_SW_MODE_EN)
                                                                                                                                                                  kal_uint32 vchr_val=0;

                                                                                                                                                                  /* 读 PMIC 对应的 ADC 的值,并将其转化为对应的电压值,这里即读取 VCDT 引脚电压 */
                                                                                                                                                                  vchr_val = PMIC_IMM_GetOneChannelValue(4,5,1);
                                                                                                                                                                  vchr_val = (((330+39)*100*vchr_val)/39)/100;

                                                                                                                                                                  if( vchr_val > 4300 )
                                                                                                                                                                  {
                                                                                                                                                                      battery_xlog_printk(BAT_LOG_FULL, "[CHRDET_SW_WORKAROUND_EN] upmu_is_chr_det=Y (%d)\n", vchr_val);
                                                                                                                                                                      *(kal_uint32 *)data = KAL_TRUE;   
                                                                                                                                                                  }
                                                                                                                                                                  else
                                                                                                                                                                  {
                                                                                                                                                                      battery_xlog_printk(BAT_LOG_FULL, "[CHRDET_SW_WORKAROUND_EN] upmu_is_chr_det=N (%d)\n", vchr_val);
                                                                                                                                                                      *(kal_uint32 *)data = KAL_FALSE;
                                                                                                                                                                  }        
                                                                                                                                                              #else
                                                                                                                                                                   /* 读取 CHR_CON0 寄存器 */
                                                                                                                                                                   *(kal_bool*)(data) = upmu_get_rgs_chrdet();
                                                                                                                                                                                                    kal_uint32 upmu_get_rgs_chrdet(void)
                                                                                                                                                                                                    {
                                                                                                                                                                                                      kal_uint32 ret=0;
                                                                                                                                                                                                      kal_uint32 val=0;

                                                                                                                                                                                                      pmic_lock();
                                                                                                                                                                                                      ret=pmic_read_interface( (kal_uint32)(CHR_CON0),
                                                                                                                                                                                                                               (&val),
                                                                                                                                                                                                                               (kal_uint32)(PMIC_RGS_CHRDET_MASK),
                                                                                                                                                                                                                               (kal_uint32)(PMIC_RGS_CHRDET_SHIFT)
                                                                                                                                                                                                                               );
                                                                                                                                                                                                      pmic_unlock();

                                                                                                                                                                                                      return val;
                                                                                                                                                                                                    }
                                                                                                                                                              #endif
                                                                                                                                                                   
                                                                                                                                                                     /* 读取 CHR_CON0 寄存器 */
                                                                                                                                                                     if( upmu_get_rgs_chrdet() == 0 )
                                                                                                                                                                         g_charger_type = CHARGER_UNKNOWN;
                                                                                                                                                                     
                                                                                                                                                                   return status;
                                                                                                                                                               }
  
                                                                                                                                    return chr_status;
                                                                                                                                }
                                                                                                        }
                                                                                    // 如果插入了充电器,hw_ocv 大部分情况是准的,插着 charger 的情况,采集的时候可能会不准
                                                                                    {
                                                                                        bm_print(BM_LOG_CRTI, "[oam_init_inf] gFG_capacity_by_v=%d, vbat_capacity=%d, \n",gFG_capacity_by_v,vbat_capacity);

                                                                                        // to avoid plug in cable without battery, then plug in battery to make hw soc = 100% 
                                                                                        // if the difference bwtween ZCV and vbat is too large, using vbat instead ZCV 
                                                                                        /* 如果两者差值超过 30%,我们认为 hw ocv 存在偏差,会以 Vbat 作为 ocv
                                                                                            如果两者差值在 30%,继续以 hw ocv 作为 ocv 的数值 */
                                                                                        if(((gFG_capacity_by_v == 100) && (vbat_capacity < CUST_POWERON_MAX_VBAT_TOLRANCE)) ||(abs(gFG_capacity_by_v-vbat_capacity)>CUST_POWERON_DELTA_VBAT_TOLRANCE))  
                                                                                        {
                                                                                            bm_print(BM_LOG_CRTI, "[oam_init] fg_vbat=(%d), vbat=(%d), set fg_vat as vat\n", gFG_voltage,vol_bat);
                                                                                            
                                                                                            gFG_voltage = vol_bat;
                                                                                            gFG_capacity_by_v = vbat_capacity;
                                                                                        }       
                                                                                    }    

                                                                                    // 获得的比较真实的开机容量
                                                                                    gFG_capacity_by_v_init = gFG_capacity_by_v;

                                                                                    /* 这里与 rtc 中的电量进行比较,确定一个开机显示 UI 电量 */
                                                                                    dod_init();
                                                                                            void dod_init(void)
                                                                                            {
                                                                                                #if defined(SOC_BY_HW_FG)
                                                                                                int ret = 0;    
                                                                                                //use get_hw_ocv-----------------------------------------------------------------  
                                                                                                /* 获取 PMIC 硬件上的 hw ocv 电压 */
                                                                                                ret=battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_OCV, &gFG_voltage);
                                                                                                                    // 对应 PMIC 硬件相关操作函数
                                                                                                                    read_hw_ocv()
                                                                                                                            get_hw_ocv()
                                                                                                                            
                                                                                                /* 根据 hw ocv 电压,查表获取对应的电池剩余电量百分比*/
                                                                                                gFG_capacity_by_v = fgauge_read_capacity_by_v(gFG_voltage);
                                                                                                
                                                                                                bm_print(BM_LOG_CRTI, "[FGADC] get_hw_ocv=%d, HW_SOC=%d, SW_SOC = %d\n", 
                                                                                                    gFG_voltage, gFG_capacity_by_v, gFG_capacity_by_v_init);
                                                                                                
                                                                                                // compare with hw_ocv & sw_ocv, check if less than or equal to 5% tolerance 
                                                                                                // 将软件 ocv 与硬件 ocv 比较,误差要少于 5%, 才使用之前计算的 sw hov?
                                                                                                if ((abs(gFG_capacity_by_v_init - gFG_capacity_by_v) > 5) && (bat_is_charger_exist() == KAL_TRUE))
                                                                                                {
                                                                                                    gFG_capacity_by_v = gFG_capacity_by_v_init;
                                                                                                }
                                                                                                //-------------------------------------------------------------------------------
                                                                                                #endif
                                                                                                
                                                                                                #if defined(CONFIG_POWER_EXT)
                                                                                                g_rtc_fg_soc = gFG_capacity_by_v;    
                                                                                                #else

                                                                                                /* 获取  DOD0 的数值,电池电量每 10s 写入 RTC 一次,开机会从 RTC 里面读取 DOD0 的值 
                                                                                                保存在 rtc 数值,即上次关机的 UI 电量数值 */
                                                                                                g_rtc_fg_soc = get_rtc_spare_fg_value();
                                                                                                                            int get_rtc_spare_fg_value(void)
                                                                                                                            {
                                                                                                                                //RTC_AL_HOU bit8~14
                                                                                                                                u16 temp;
                                                                                                                                unsigned long flags;
                                                                                                                                
                                                                                                                                spin_lock_irqsave(&rtc_lock, flags);
                                                                                                                                temp = hal_rtc_get_register_status("FG");
                                                                                                                                spin_unlock_irqrestore(&rtc_lock, flags);
                                                                                                                                
                                                                                                                                return temp;
                                                                                                                            }
                                                                                                #endif

                                                                                                /* g_rtc_fg_soc: 为上次关机前的 UI 电量  
                                                                                                   gFG_capacity_by_v: 是经过 oam_init() 初始化后的电池真实电压
                                                                                                由于存在换电池的风险, 会去判断两者的差值:
                                                                                                    1. 40% 以内,采用 rtc 电量,即继续显示上次 UI 的电量  
                                                                                                    2. 如果在 40% 以外,采用真实电池电压的电量,因为有可能更换了电池 

                                                                                                设计的初衷: 因为电池特性,在确定 dod 会有误差,从而导致开关机电量跳变,
                                                                                                因此采用 rtc 是为了防止电量跳变
                                                                                                    */
                                                                                                if(g_rtc_fg_soc >= gFG_capacity_by_v)
                                                                                                {
                                                                                                    if(((g_rtc_fg_soc != 0) && ((g_rtc_fg_soc-gFG_capacity_by_v) < CUST_POWERON_DELTA_CAPACITY_TOLRANCE) &&(( gFG_capacity_by_v > CUST_POWERON_LOW_CAPACITY_TOLRANCE || bat_is_charger_exist() == KAL_TRUE)))
                                                                                                        || ((g_rtc_fg_soc != 0) &&(g_boot_reason == BR_WDT_BY_PASS_PWK || g_boot_reason == BR_WDT || g_boot_reason == BR_TOOL_BY_PASS_PWK || g_boot_reason == BR_2SEC_REBOOT || g_boot_mode == RECOVERY_BOOT)))
                                                                                                        
                                                                                                    {
                                                                                                        gFG_capacity_by_v = g_rtc_fg_soc;            
                                                                                                    }
                                                                                                }
                                                                                                else
                                                                                                {
                                                                                                    if(((g_rtc_fg_soc != 0) && ((gFG_capacity_by_v-g_rtc_fg_soc) < CUST_POWERON_DELTA_CAPACITY_TOLRANCE) &&(( gFG_capacity_by_v > CUST_POWERON_LOW_CAPACITY_TOLRANCE || bat_is_charger_exist() == KAL_TRUE)))
                                                                                                        || ((g_rtc_fg_soc != 0) &&(g_boot_reason == BR_WDT_BY_PASS_PWK || g_boot_reason == BR_WDT || g_boot_reason == BR_TOOL_BY_PASS_PWK || g_boot_reason == BR_2SEC_REBOOT || g_boot_mode == RECOVERY_BOOT)))
                                                                                                    {
                                                                                                        gFG_capacity_by_v = g_rtc_fg_soc;            
                                                                                                    }
                                                                                                }        

                                                                                                bm_print(BM_LOG_CRTI, "[FGADC] g_rtc_fg_soc=%d, gFG_capacity_by_v=%d\n", 
                                                                                                        g_rtc_fg_soc, gFG_capacity_by_v);
                                                                                                
                                                                                                if (gFG_capacity_by_v == 0 && bat_is_charger_exist() == KAL_TRUE) {
                                                                                                    gFG_capacity_by_v = 1;
                                                                                                    
                                                                                                    bm_print(BM_LOG_CRTI, "[FGADC] gFG_capacity_by_v=%d\n", 
                                                                                                        gFG_capacity_by_v);
                                                                                                }

                                                                                                //////////////////////////////////////////////////////////////////
                                                                                                // 在这里最终定义的开机 UI 电量显示
                                                                                                
                                                                                                gFG_capacity = gFG_capacity_by_v;      // 电池剩余容量百分比
                                                                                                gFG_capacity_by_c_init = gFG_capacity; 
                                                                                                gFG_capacity_by_c = gFG_capacity;
                                                                                                
                                                                                                gFG_DOD0 = 100 - gFG_capacity;         // 电池使用完电量百分比
                                                                                                gFG_DOD1=gFG_DOD0;                      // 电池使用完电量百分比

                                                                                                gfg_percent_check_point = gFG_capacity; // 容量检测百分比       

                                                                                            #if defined(CHANGE_TRACKING_POINT) 
                                                                                                gFG_15_vlot = fgauge_read_v_by_capacity( (100-g_tracking_point) );
                                                                                                bm_print(BM_LOG_CRTI, "[FGADC] gFG_15_vlot = %dmV\n", gFG_15_vlot);        
                                                                                            #else
                                                                                                //gFG_15_vlot = fgauge_read_v_by_capacity(86); //14%
                                                                                                /* 通过当前使用掉的容量,获取当前电压 */
                                                                                                gFG_15_vlot = fgauge_read_v_by_capacity( (100-g_tracking_point) );
                                                                                                bm_print(BM_LOG_CRTI, "[FGADC] gFG_15_vlot = %dmV\n", gFG_15_vlot);        
                                                                                                if( (gFG_15_vlot > 3800) || (gFG_15_vlot < 3600) ) 
                                                                                                {
                                                                                                    bm_print(BM_LOG_CRTI, "[FGADC] gFG_15_vlot(%d) over range, reset to 3700\n", gFG_15_vlot);
                                                                                                    gFG_15_vlot = 3700;
                                                                                                }
                                                                                            #endif
                                                                                            }


                                                                                    /* 先通过 battery_meter_get_battery_temperature() 获得电池温度,再通过 fgauge_get_Q_max() 计算电量 
                                                                                    这里获得当前温度的电池的最大容量 */
                                                                                    gFG_BATT_CAPACITY_aging = fgauge_get_Q_max(battery_meter_get_battery_temperature()); 
                                                                                                                                                    kal_int32 battery_meter_get_battery_temperature(void)
                                                                                                                                                    {
                                                                                                                                                        /* 通过获得当前 NTC 电压,查表并进行线性插值法,得到当前的温度值  */
                                                                                                                                                        return force_get_tbat(); 
                                                                                                                                                    }
                                                                                                                            // 通过当前温度获插值得到当前最大容量
                                                                                                                            kal_int32 fgauge_get_Q_max(kal_int16 temperature)
                                                                                                                            {
                                                                                                                                kal_int32 ret_Q_max=0;
                                                                                                                                kal_int32 low_temperature = 0, high_temperature = 0;
                                                                                                                                kal_int32 low_Q_max = 0, high_Q_max = 0;

                                                                                                                                /* 如果温度位于 -20< x <= 0  */
                                                                                                                                if (temperature <= TEMPERATURE_T1)
                                                                                                                                {
                                                                                                                                    low_temperature = (-10);
                                                                                                                                    low_Q_max = Q_MAX_NEG_10;
                                                                                                                                    high_temperature = TEMPERATURE_T1;
                                                                                                                                    high_Q_max = Q_MAX_POS_0;
                                                                                                                                    
                                                                                                                                    if(temperature < low_temperature)
                                                                                                                                    {
                                                                                                                                        temperature = low_temperature;
                                                                                                                                    }
                                                                                                                                }
                                                                                                                                /* 如果温度位于 0< x <= 25  */
                                                                                                                                else if (temperature <= TEMPERATURE_T2)
                                                                                                                                {
                                                                                                                                    low_temperature = TEMPERATURE_T1;
                                                                                                                                    low_Q_max = Q_MAX_POS_0;
                                                                                                                                    high_temperature = TEMPERATURE_T2;
                                                                                                                                    high_Q_max = Q_MAX_POS_25;
                                                                                                                                    
                                                                                                                                    if(temperature < low_temperature)
                                                                                                                                    {
                                                                                                                                        temperature = low_temperature;
                                                                                                                                    }
                                                                                                                                }
                                                                                                                                /* 如果温度位于 -25< x <=50  */
                                                                                                                                else
                                                                                                                                {
                                                                                                                                    low_temperature  = TEMPERATURE_T2;      // 低温下限
                                                                                                                                    low_Q_max = Q_MAX_POS_25;               // 低温最大容量
                                                                                                                                    high_temperature = TEMPERATURE_T3;      // 高温上限
                                                                                                                                    high_Q_max = Q_MAX_POS_50;              // 高温对应最大容量
                                                                                                                                    
                                                                                                                                    // 防止范围溢出
                                                                                                                                    if(temperature > high_temperature)
                                                                                                                                    {
                                                                                                                                        temperature = high_temperature;
                                                                                                                                    }
                                                                                                                                }

                                                                                                                                /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
                                                                                                                                核心算法:

                                                                                                                                   当前容量 = 低温下限最大容量 + (当前温度 - 低温下限) * [(高温容量 - 低温容量)/(高温上限-低温下限)] */
                                                                                                                                ret_Q_max = low_Q_max +
                                                                                                                                (
                                                                                                                                    (
                                                                                                                                        (temperature - low_temperature) * 
                                                                                                                                        (high_Q_max - low_Q_max)
                                                                                                                                    ) / 
                                                                                                                                    (high_temperature - low_temperature)                
                                                                                                                                );

                                                                                                                                bm_print(BM_LOG_FULL, "[fgauge_get_Q_max] Q_max = %d\r\n", ret_Q_max);

                                                                                                                                return ret_Q_max;
                                                                                                                            }
  

                                                                                    //oam_v_ocv_1 = gFG_voltage;
                                                                                    //oam_v_ocv_2 = gFG_voltage;

                                                                                    /* 通过当前使用电池容量的百分比,反换算出当前的电压 */
                                                                                    oam_v_ocv_init = fgauge_read_v_by_d(gFG_DOD0);
                                                                                                                kal_int32 fgauge_read_v_by_d(int d_val)
                                                                                                                {    
                                                                                                                    int i = 0, saddles = 0;
                                                                                                                    BATTERY_PROFILE_STRUC_P profile_p;
                                                                                                                    kal_int32 ret_volt = 0;

                                                                                                                    profile_p = fgauge_get_profile(TEMPERATURE_T);
                                                                                                                    if (profile_p == NULL)
                                                                                                                    {
                                                                                                                        bm_print(BM_LOG_CRTI, "[fgauge_read_v_by_capacity] fgauge get ZCV profile : fail !\r\n");
                                                                                                                        return 3700;
                                                                                                                    }

                                                                                                                    saddles = fgauge_get_saddles();

                                                                                                                    if (d_val < (profile_p+0)->percentage)
                                                                                                                    {        
                                                                                                                        return 3700;         
                                                                                                                    }    
                                                                                                                    if (d_val > (profile_p+saddles-1)->percentage)
                                                                                                                    {        
                                                                                                                        return 3700;
                                                                                                                    }

                                                                                                                    for (i = 0; i < saddles - 1; i++)
                                                                                                                    {
                                                                                                                        if ((d_val >= (profile_p+i)->percentage) && (d_val <= (profile_p+i+1)->percentage))
                                                                                                                        {
                                                                                                                            ret_volt = (profile_p+i)->voltage -
                                                                                                                                (
                                                                                                                                    (
                                                                                                                                        ( d_val - ((profile_p+i)->percentage) ) * 
                                                                                                                                        ( ((profile_p+i)->voltage) - ((profile_p+i+1)->voltage) ) 
                                                                                                                                    ) /
                                                                                                                                    ( ((profile_p+i+1)->percentage) - ((profile_p+i)->percentage) )
                                                                                                                                );         
                                                                                                                            
                                                                                                                            break;
                                                                                                                        }        
                                                                                                                    }    

                                                                                                                    return ret_volt;
                                                                                                                }

                                                                                    oam_v_ocv_2 = oam_v_ocv_1 = oam_v_ocv_init;         // 通过当前使用电池容量的百分比,反换算出当前的电压
                                                                                    g_vol_bat_hw_ocv = gFG_voltage;                     // hw ocv 电压

                                                                                    //vbat = 5; //set avg times
                                                                                    //ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_BAT_SENSE, &vbat);    
                                                                                    //oam_r_1 = fgauge_read_r_bat_by_v(vbat);
                                                                                    /* 通过当前 hw ocv 电压,获得的当前电池内阻 */
                                                                                    oam_r_1 = fgauge_read_r_bat_by_v(gFG_voltage);
                                                                                    oam_r_2 = oam_r_1;
                                                                                        
                                                                                    oam_d0 = gFG_DOD0;
                                                                                    oam_d_5 = oam_d0;
                                                                                    oam_i_ori = gFG_current;
                                                                                    g_d_hw_ocv = oam_d0;

                                                                                    if(oam_init_i == 0)
                                                                                    {
                                                                                        bm_print(BM_LOG_CRTI, "[oam_init] oam_v_ocv_1,oam_v_ocv_2,oam_r_1,oam_r_2,oam_d0,oam_i_ori\n");
                                                                                        oam_init_i=1;
                                                                                    }

                                                                                    bm_print(BM_LOG_CRTI, "[oam_init] %d,%d,%d,%d,%d,%d\n", 
                                                                                        oam_v_ocv_1, oam_v_ocv_2, oam_r_1, oam_r_2, oam_d0, oam_i_ori);

                                                                                    bm_print(BM_LOG_CRTI, "[oam_init_inf] hw_OCV, hw_D0, RTC, D0, oam_OCV_init, tbat\n");
                                                                                    bm_print(BM_LOG_CRTI, "[oam_run_inf] oam_OCV1, oam_OCV2, vbat, I1, I2, R1, R2, Car1, Car2,qmax, tbat\n");
                                                                                    bm_print(BM_LOG_CRTI, "[oam_result_inf] D1, D2, D3, D4, D5, UI_SOC\n");
                                                                                    
                                                                                    
                                                                                    bm_print(BM_LOG_CRTI, "[oam_init_inf] %d, %d, %d, %d, %d, %d\n",
                                                                                        gFG_voltage, (100 - fgauge_read_capacity_by_v(gFG_voltage)), g_rtc_fg_soc, gFG_DOD0 ,oam_v_ocv_init, force_get_tbat());
                                                                                 
                                                                                }


                                                                        
                                                                        bm_print(BM_LOG_CRTI, "[battery_meter_initial] SOC_BY_SW_FG done\n");
                                                                        #endif

                                                                        return 0;
                                                                    #endif
                                                                    }

                                                        
                                                        /* 获得要监控的电量,(用这个电量反换出电压来校验?)*/
                                                        BMT_status.nPercent_ZCV = battery_meter_get_battery_nPercent_zcv();
                                                                                                kal_int32 battery_meter_get_battery_nPercent_zcv(void)    
                                                                                                {
                                                                                                #if defined(CONFIG_POWER_EXT)
                                                                                                    return 3700;
                                                                                                #else
                                                                                                    return gFG_15_vlot; // 15% zcv,  15% can be customized by 100-g_tracking_point
                                                                                                #endif  
                                                                                                }
                                                       battery_meter_initilized = KAL_TRUE;
                                                   }

                                                   ////////////////////////////////////////////////////////////////////////////////////////////////////
                                                   // 1. 判断是插入的是否充电器还是电脑 USB,看能不能进行充电
                                                   /* 如果连接的 USB 线为 USB 充电线,或者电脑 USB 线,则打开 USB,
                                                   这里会通过  BC1.1 来判断是电脑 USB 还是 USB 充电器,来决定充电电流 
                                                   否则连接的不是充电线或者 USB 作为一个从设备使用,要断开 USB? 
                                                   */
                                                   mt_battery_charger_detect_check();
                                                                        static void mt_battery_charger_detect_check(void)
                                                                        {
                                                                            /* 根据 USB 是主从状态,以及外部充电电压是否正常来判断是否允许充电,
                                                                            这里如果是 USB 作为从设备,允许充电    */
                                                                            if( upmu_is_chr_det() == KAL_TRUE )
                                                                                                ///////////////////////////////////////////////////////////////////////////////////////////
                                                                                                //// PMIC PCHR Related APIs
                                                                                                ///////////////////////////////////////////////////////////////////////////////////////////
                                                                                                kal_bool upmu_is_chr_det(void)
                                                                                                {
                                                                                                #if defined(CONFIG_POWER_EXT)
                                                                                                    //return KAL_TRUE;
                                                                                                    return get_charger_detect_status();
                                                                                                                    // 如果是外部充电芯片,则直接会调用外部芯片的充电相关函数,如 charging_hw_bq24196.c 中的
                                                                                                                    battery_charging_control(CHARGING_CMD_GET_CHARGER_DET_STATUS,&chr_status);
                                                                                                #else   
                                                                                                    kal_uint32 tmp32;
                                                                                                    /* 这里是 PMIC,调用 PMIC 的充电相关函数 charging_hw_pmic.c, 
                                                                                                    这里查询 PMIC 的 CHR_CON0 寄存器,检查充电状态 */
                                                                                                    tmp32=get_charger_detect_status();
                                                                                                                        int get_charger_detect_status(void)
                                                                                                                        {
                                                                                                                            kal_bool chr_status;

                                                                                                                            battery_charging_control(CHARGING_CMD_GET_CHARGER_DET_STATUS,&chr_status);
                                                                                                                                                        static kal_uint32 charging_get_charger_det_status(void *data)
                                                                                                                                                         {
                                                                                                                                                               kal_uint32 status = STATUS_OK;
                                                                                                                                                         
                                                                                                                                                        #if defined(CHRDET_SW_MODE_EN)
                                                                                                                                                            kal_uint32 vchr_val=0;

                                                                                                                                                            // 获得 PMIC 的 VCDT 充电电压值
                                                                                                                                                            vchr_val = PMIC_IMM_GetOneChannelValue(4,5,1);
                                                                                                                                                            vchr_val = (((330+39)*100*vchr_val)/39)/100;

                                                                                                                                                            if( vchr_val > 4300 )
                                                                                                                                                            {
                                                                                                                                                                battery_xlog_printk(BAT_LOG_FULL, "[CHRDET_SW_WORKAROUND_EN] upmu_is_chr_det=Y (%d)\n", vchr_val);
                                                                                                                                                                *(kal_uint32 *)data = KAL_TRUE; 
                                                                                                                                                            }
                                                                                                                                                            else
                                                                                                                                                            {
                                                                                                                                                                battery_xlog_printk(BAT_LOG_FULL, "[CHRDET_SW_WORKAROUND_EN] upmu_is_chr_det=N (%d)\n", vchr_val);
                                                                                                                                                                *(kal_uint32 *)data = KAL_FALSE;
                                                                                                                                                            }        
                                                                                                                                                        #else
                                                                                                                                                               *(kal_bool*)(data) = upmu_get_rgs_chrdet();
                                                                                                                                                        #endif
                                                                                                                                                               /* 读取 PMIC  CHR_CON0 寄存器 */
                                                                                                                                                               if( upmu_get_rgs_chrdet() == 0 )
                                                                                                                                                                   g_charger_type = CHARGER_UNKNOWN;
                                                                                                                                                               
                                                                                                                                                               return status;
                                                                                                                                                         }

                                                                                                                            return chr_status;
                                                                                                                        }
                                                                                                    if(tmp32 == 0)
                                                                                                    {
                                                                                                        return KAL_FALSE;
                                                                                                    }
                                                                                                    else
                                                                                                    {
                                                                                                        /* 如果 USB 作为一个不是以从设备运行,是不允许充电的 */
                                                                                                        if( mt_usb_is_device() )
                                                                                                                        // Usb20.c (s:\i841\mediatek\platform\mt6582\kernel\drivers\usb20) 
                                                                                                                        /* ================================ */
                                                                                                                        /* connect and disconnect functions */
                                                                                                                        /* ================================ */
                                                                                                                        bool mt_usb_is_device(void)
                                                                                                                        {
                                                                                                                            DBG(4,"called\n");

                                                                                                                            /* 如果 mtk_musb 为 0 的话,表明 MTK 的 USB 在作为一个主机使用,不允许充电的 */
                                                                                                                            if(!mtk_musb){
                                                                                                                                DBG(0,"mtk_musb is NULL\n");
                                                                                                                                return false; // don't do charger detection when usb is not ready
                                                                                                                            } else {
                                                                                                                                DBG(4,"is_host=%d\n",mtk_musb->is_host);
                                                                                                                            }
                                                                                                                          return !mtk_musb->is_host;
                                                                                                                        }
                                                                                                        {
                                                                                                            battery_xlog_printk(BAT_LOG_FULL, "[upmu_is_chr_det] Charger exist and USB is not host\n");

                                                                                                            return KAL_TRUE;
                                                                                                        }
                                                                                                        else
                                                                                                        {
                                                                                                            battery_xlog_printk(BAT_LOG_FULL, "[upmu_is_chr_det] Charger exist but USB is host\n");

                                                                                                            return KAL_FALSE;
                                                                                                        }
                                                                                                    }
                                                                                                    #endif  
                                                                                                }

                                                                            ////////////////////////////////////////////////////////////////////////////////////////////////////////
                                                                            // 如果插入的是 USB 充电线或者 电脑的 USB 线,则打开 USB ,因为充电时 MTK 作为从设备,是允许充电的
                                                                            {
                                                                                wake_lock(&battery_suspend_lock);
                                                                                
                                                                                BMT_status.charger_exist = KAL_TRUE;
                                                                            
                                                                            // 无线充电支持宏
                                                                        #if defined(MTK_WIRELESS_CHARGER_SUPPORT)
                                                                                mt_charger_type_detection();

                                                                                if((BMT_status.charger_type==STANDARD_HOST) || (BMT_status.charger_type==CHARGING_HOST) )
                                                                                {
                                                                                    // 这应该是做为从设备连接到电脑上用的
                                                                                    mt_usb_connect();
                                                                                }
                                                                        #else        
                                                                                /* 这个结构体是在前面初始化的,所以第一次执行,该值未设置 = 0,
                                                                                在这里通过 BC1.1 协议检测外部连接的 USB 线类型,是主是从,还是充电/被充
                                                                                最后根据类型判断要不要启动 USB */
                                                                                if(BMT_status.charger_type == CHARGER_UNKNOWN)
                                                                                {
                                                                                    /* 调用 PMIC 硬件相关函数,检测充电类型, 这里应用了 BC1.1 协议来检测  */
                                                                                    mt_charger_type_detection();
                                                                                                        CHARGER_TYPE mt_charger_type_detection(void)
                                                                                                        {
                                                                                                            CHARGER_TYPE CHR_Type_num = CHARGER_UNKNOWN;

                                                                                                            mutex_lock(&charger_type_mutex);
                                                                                                            
                                                                                                        #if defined(MTK_WIRELESS_CHARGER_SUPPORT)
                                                                                                            battery_charging_control(CHARGING_CMD_GET_CHARGER_TYPE,&CHR_Type_num);
                                                                                                            BMT_status.charger_type = CHR_Type_num; 
                                                                                                        #else
                                                                                                            /* 调用 PMIC 硬件相关函数,检测充电类型, 这里应用了 BC1.1 协议来检测  */
                                                                                                            if(BMT_status.charger_type == CHARGER_UNKNOWN)
                                                                                                            {
                                                                                                                /* 调用 PMIC 硬件相关函数,检测充电类型, 这里应用了 BC1.1 协议来检测  */
                                                                                                                battery_charging_control(CHARGING_CMD_GET_CHARGER_TYPE,&CHR_Type_num);
                                                                                                                                                 static kal_uint32 charging_get_charger_type(void *data)
                                                                                                                                                 {
                                                                                                                                                     kal_uint32 status = STATUS_OK;
                                                                                                                                                #if defined(CONFIG_POWER_EXT)
                                                                                                                                                     *(CHARGER_TYPE*)(data) = STANDARD_HOST;
                                                                                                                                                #else
                                                                                                                                                #if defined(MTK_WIRELESS_CHARGER_SUPPORT)
                                                                                                                                                    int wireless_state = 0;
                                                                                                                                                    /* 无线充电判断引脚,直接拉低就好 */
                                                                                                                                                    wireless_state = mt_get_gpio_in(wireless_charger_gpio_number);
                                                                                                                                                    if(wireless_state == WIRELESS_CHARGER_EXIST_STATE)
                                                                                                                                                    {
                                                                                                                                                        *(CHARGER_TYPE*)(data) = WIRELESS_CHARGER;
                                                                                                                                                        battery_xlog_printk(BAT_LOG_CRTI, "WIRELESS_CHARGER!\r\n");
                                                                                                                                                        return status;
                                                                                                                                                    }
                                                                                                                                                #endif

                                                                                                                                                    if(g_charger_type!=CHARGER_UNKNOWN && g_charger_type!=WIRELESS_CHARGER)
                                                                                                                                                    {
                                                                                                                                                        *(CHARGER_TYPE*)(data) = g_charger_type;
                                                                                                                                                        battery_xlog_printk(BAT_LOG_CRTI, "return %d!\r\n", g_charger_type);
                                                                                                                                                        return status;
                                                                                                                                                    }

                                                                                                                                                    charging_type_det_done = KAL_FALSE;

                                                                                                                                                    /*//////////////////////////////////////////////////////////////////////////////////////////////
                                                                                                                                                    BC1.1 充电协议,主要用来区分是插入的是 USB 还是充电器,如果是 USB 只能提供 500ma 充电,
                                                                                                                                                    如果是充电器,则可以大电流充电  */
                                                                                                                                                    /********* Step initial  ***************/        
                                                                                                                                                    hw_bc11_init();
                                                                                                                                                                 static void hw_bc11_init(void)
                                                                                                                                                                 {
                                                                                                                                                                     msleep(300);
                                                                                                                                                                     Charger_Detect_Init();
                                                                                                                                                                         
                                                                                                                                                                     //RG_BC11_BIAS_EN=1    
                                                                                                                                                                     upmu_set_rg_bc11_bias_en(0x1);
                                                                                                                                                                     //RG_BC11_VSRC_EN[1:0]=00
                                                                                                                                                                     upmu_set_rg_bc11_vsrc_en(0x0);
                                                                                                                                                                     //RG_BC11_VREF_VTH = [1:0]=00
                                                                                                                                                                     upmu_set_rg_bc11_vref_vth(0x0);
                                                                                                                                                                     //RG_BC11_CMP_EN[1.0] = 00
                                                                                                                                                                     upmu_set_rg_bc11_cmp_en(0x0);
                                                                                                                                                                     //RG_BC11_IPU_EN[1.0] = 00
                                                                                                                                                                     upmu_set_rg_bc11_ipu_en(0x0);
                                                                                                                                                                     //RG_BC11_IPD_EN[1.0] = 00
                                                                                                                                                                     upmu_set_rg_bc11_ipd_en(0x0);
                                                                                                                                                                     //BC11_RST=1
                                                                                                                                                                     upmu_set_rg_bc11_rst(0x1);
                                                                                                                                                                     //BC11_BB_CTRL=1
                                                                                                                                                                     upmu_set_rg_bc11_bb_ctrl(0x1);
                                                                                                                                                                 
                                                                                                                                                                     //msleep(10);
                                                                                                                                                                     mdelay(50);
                                                                                                                                                                     
                                                                                                                                                                     if(Enable_BATDRV_LOG == BAT_LOG_FULL)
                                                                                                                                                                     {
                                                                                                                                                                            battery_xlog_printk(BAT_LOG_FULL, "hw_bc11_init() \r\n");
                                                                                                                                                                        hw_bc11_dump_register();
                                                                                                                                                                     }  

                                                                                                                                                                 }

                                                                                                                                                 
                                                                                                                                                    /********* Step DCD ***************/  
                                                                                                                                                    if(1 == hw_bc11_DCD())
                                                                                                                                                    {
                                                                                                                                                        /********* Step A1 ***************/
                                                                                                                                                        if(1 == hw_bc11_stepA1())
                                                                                                                                                        {
                                                                                                                                                            *(CHARGER_TYPE*)(data) = APPLE_2_1A_CHARGER;
                                                                                                                                                            battery_xlog_printk(BAT_LOG_CRTI, "step A1 : Apple 2.1A CHARGER!\r\n");
                                                                                                                                                        }    
                                                                                                                                                        else
                                                                                                                                                        {
                                                                                                                                                            *(CHARGER_TYPE*)(data) = NONSTANDARD_CHARGER;
                                                                                                                                                            battery_xlog_printk(BAT_LOG_CRTI, "step A1 : Non STANDARD CHARGER!\r\n");
                                                                                                                                                        }
                                                                                                                                                    }
                                                                                                                                                    else
                                                                                                                                                    {
                                                                                                                                                         /********* Step A2 ***************/
                                                                                                                                                         if(1 == hw_bc11_stepA2())
                                                                                                                                                         {
                                                                                                                                                             /********* Step B2 ***************/
                                                                                                                                                             if(1 == hw_bc11_stepB2())
                                                                                                                                                             {
                                                                                                                                                                 *(CHARGER_TYPE*)(data) = STANDARD_CHARGER;
                                                                                                                                                                 battery_xlog_printk(BAT_LOG_CRTI, "step B2 : STANDARD CHARGER!\r\n");
                                                                                                                                                             }
                                                                                                                                                             else
                                                                                                                                                             {
                                                                                                                                                                 *(CHARGER_TYPE*)(data) = CHARGING_HOST;
                                                                                                                                                                 battery_xlog_printk(BAT_LOG_CRTI, "step B2 :  Charging Host!\r\n");
                                                                                                                                                             }
                                                                                                                                                         }
                                                                                                                                                         else
                                                                                                                                                         {
                                                                                                                                                            *(CHARGER_TYPE*)(data) = STANDARD_HOST;
                                                                                                                                                             battery_xlog_printk(BAT_LOG_CRTI, "step A2 : Standard USB Host!\r\n");
                                                                                                                                                         }
                                                                                                                                                 
                                                                                                                                                    }
                                                                                                                                                 
                                                                                                                                                     /********* Finally setting *******************************/
                                                                                                                                                     hw_bc11_done();
                                                                                                                                                                 static void hw_bc11_done(void)
                                                                                                                                                                 {
                                                                                                                                                                    //RG_BC11_VSRC_EN[1:0]=00
                                                                                                                                                                    upmu_set_rg_bc11_vsrc_en(0x0);
                                                                                                                                                                    //RG_BC11_VREF_VTH = [1:0]=0
                                                                                                                                                                    upmu_set_rg_bc11_vref_vth(0x0);
                                                                                                                                                                    //RG_BC11_CMP_EN[1.0] = 00
                                                                                                                                                                    upmu_set_rg_bc11_cmp_en(0x0);
                                                                                                                                                                    //RG_BC11_IPU_EN[1.0] = 00
                                                                                                                                                                    upmu_set_rg_bc11_ipu_en(0x0);
                                                                                                                                                                    //RG_BC11_IPD_EN[1.0] = 00
                                                                                                                                                                    upmu_set_rg_bc11_ipd_en(0x0);
                                                                                                                                                                    //RG_BC11_BIAS_EN=0
                                                                                                                                                                    upmu_set_rg_bc11_bias_en(0x0); 
                                                                                                                                                                 
                                                                                                                                                                    Charger_Detect_Release();
                                                                                                                                                                                    void Charger_Detect_Release(void)
                                                                                                                                                                                    {
                                                                                                                                                                                        /* RG_USB20_BC11_SW_EN = 1'b0 */
                                                                                                                                                                                        USBPHY_CLR8(0x1a, 0x80);
                                                                                                                                                                                        udelay(1);
                                                                                                                                                                                        //4 14. turn off internal 48Mhz PLL.
                                                                                                                                                                                        usb_enable_clock(false);
                                                                                                                                                                                        printk("Charger_Detect_Release\n");
                                                                                                                                                                                    }

                                                                                                                                                                    if(Enable_BATDRV_LOG == BAT_LOG_FULL)
                                                                                                                                                                    {
                                                                                                                                                                        battery_xlog_printk(BAT_LOG_FULL, "hw_bc11_done() \r\n");
                                                                                                                                                                        hw_bc11_dump_register();
                                                                                                                                                                    }
                                                                                                                                                                    
                                                                                                                                                                 }


                                                                                                                                                    charging_type_det_done = KAL_TRUE;

                                                                                                                                                    g_charger_type = *(CHARGER_TYPE*)(data);
                                                                                                                                                #endif
                                                                                                                                                     return status;
                                                                                                                                                }

                                                                                                                BMT_status.charger_type = CHR_Type_num; 
                                                                                                            }   
                                                                                                        #endif

                                                                                                            mutex_unlock(&charger_type_mutex);
                                                                                                            
                                                                                                            return BMT_status.charger_type;
                                                                                                        }


                                                                                    /* 如果充电线是 标准主模式 或者 主充电模式, 连接上 USB  */
                                                                                    if((BMT_status.charger_type==STANDARD_HOST) || (BMT_status.charger_type==CHARGING_HOST) )
                                                                                    {
                                                                                            /*  连接 USB,充电时可以连接 USB 的 */
                                                                                            mt_usb_connect();
                                                                                                        void mt_usb_connect(void)
                                                                                                        {
                                                                                                            printk("[MUSB] USB is ready for connect\n");
                                                                                                            DBG(3, "is ready %d is_host %d power %d\n",mtk_musb->is_ready,mtk_musb->is_host , mtk_musb->power);
                                                                                                            if (!mtk_musb || !mtk_musb->is_ready || mtk_musb->is_host || mtk_musb->power)
                                                                                                                return;

                                                                                                            DBG(0,"cable_mode=%d\n",cable_mode);

                                                                                                            /*     CABLE_MODE_CHRG_ONLY = 0, CABLE_MODE_NORMAL, CABLE_MODE_HOST_ONLY, CABLE_MODE_MAX 
                                                                                                            上面这些模式,应该是通过 BC1.1 来判断出来的 */
                                                                                                            if(cable_mode != CABLE_MODE_NORMAL)
                                                                                                            {
                                                                                                                DBG(0,"musb_sync_with_bat, USB_CONFIGURED\n");

                                                                                                                
                                                                                                                musb_sync_with_bat(mtk_musb,USB_CONFIGURED);
                                                                                                                                void musb_sync_with_bat(struct musb *musb,int usb_state)
                                                                                                                                {
                                                                                                                                #ifndef FPGA_PLATFORM
                                                                                                                                    DBG(0,"BATTERY_SetUSBState, state=%d\n",usb_state);
                                                                                                                                
                                                                                                                                    // linear_charging.c,线性充电
                                                                                                                                    BATTERY_SetUSBState(usb_state);
                                                                                                                                                void BATTERY_SetUSBState(int usb_state_value)
                                                                                                                                                {
                                                                                                                                                #if defined(CONFIG_POWER_EXT)
                                                                                                                                                    battery_xlog_printk(BAT_LOG_CRTI, "[BATTERY_SetUSBState] in FPGA/EVB, no service\r\n");
                                                                                                                                                #else
                                                                                                                                                    if ( (usb_state_value < USB_SUSPEND) || ((usb_state_value > USB_CONFIGURED))){
                                                                                                                                                        battery_xlog_printk(BAT_LOG_CRTI, "[BATTERY] BAT_SetUSBState Fail! Restore to default value\r\n");    
                                                                                                                                                        usb_state_value = USB_UNCONFIGURED;
                                                                                                                                                    } else {
                                                                                                                                                        battery_xlog_printk(BAT_LOG_CRTI, "[BATTERY] BAT_SetUSBState Success! Set %d\r\n", usb_state_value);    
                                                                                                                                                        g_usb_state = usb_state_value;    
                                                                                                                                                    }
                                                                                                                                                #endif  
                                                                                                                                                }
                                                                                                                                                    
                                                                                                                                    wake_up_bat();
                                                                                                                                                void wake_up_bat (void)
                                                                                                                                                {
                                                                                                                                                    battery_xlog_printk(BAT_LOG_CRTI, "[BATTERY] wake_up_bat. \r\n");
                                                                                                                                                    
                                                                                                                                                    chr_wake_up_bat = KAL_TRUE;    
                                                                                                                                                    bat_thread_timeout = KAL_TRUE;
                                                                                                                                                    
                                                                                                                                                    wake_up(&bat_thread_wq);
                                                                                                                                                }
                                                                                                                                #endif
                                                                                                                                }
                                                                                                                mtk_musb->power = true;
                                                                                                                return;
                                                                                                            }

                                                                                                            if (!wake_lock_active(&mtk_musb->usb_lock))
                                                                                                                wake_lock(&mtk_musb->usb_lock);

                                                                                                            // Program the HDRC to start (enable interrupts, dma, etc.).
                                                                                                            // 启动 USB 
                                                                                                            musb_start(mtk_musb);
                                                                                                                            /*-------------------------------------------------------------------------*/ 
                                                                                                                            /*
                                                                                                                            * Program the HDRC to start (enable interrupts, dma, etc.).
                                                                                                                            */
                                                                                                                            void musb_start(struct musb *musb)
                                                                                                                            {
                                                                                                                                void __iomem    *regs = musb->mregs;
                                                                                                                                int vbusdet_retry = 5;

                                                                                                                                u8  intrusbe;
                                                                                                                                DBG(0, "start, is_host=%d is_active=%d\n", musb->is_host, musb->is_active);
                                                                                                                                if(musb->is_active) {
                                                                                                                                    if(musb->is_host) {
                                                                                                                                        DBG(0, "we are host now, add more interrupt devctl=%x\n", musb_readb(mtk_musb->mregs,MUSB_DEVCTL));
                                                                                                                                        musb->intrtxe = 0xffff;
                                                                                                                                        musb_writew(regs, MUSB_INTRTXE, musb->intrtxe);
                                                                                                                                        musb->intrrxe = 0xfffe;
                                                                                                                                        musb_writew(regs, MUSB_INTRRXE, musb->intrrxe);
                                                                                                                                        musb_writeb(regs,MUSB_INTRUSBE,0xf7);
                                                                                                                                        return;
                                                                                                                                    }
                                                                                                                                }
                                                                                                                                musb_platform_enable(musb);
                                                                                                                                musb_generic_disable(musb);

                                                                                                                                intrusbe= musb_readb(regs, MUSB_INTRUSBE);
                                                                                                                                if (musb->is_host){
                                                                                                                                    musb->intrtxe = 0xffff;
                                                                                                                                    musb_writew(regs, MUSB_INTRTXE, musb->intrtxe);
                                                                                                                                    musb->intrrxe = 0xfffe;
                                                                                                                                    musb_writew(regs, MUSB_INTRRXE, musb->intrrxe);
                                                                                                                                    intrusbe = 0xf7;

                                                                                                                                    while(!musb_platform_get_vbus_status(musb)) {
                                                                                                                                        mdelay(100);
                                                                                                                                        if(vbusdet_retry--<=1) {
                                                                                                                                            DBG(0, "VBUS detection fail!\n");
                                                                                                                                            break;
                                                                                                                                        }
                                                                                                                                    }

                                                                                                                                } else if(!musb->is_host){
                                                                                                                                    intrusbe |= MUSB_INTR_RESET; //device mode enable reset interrupt
                                                                                                                                }

                                                                                                                                musb_writeb(regs,MUSB_INTRUSBE,intrusbe);

                                                                                                                                if (musb_speed) {
                                                                                                                                    /* put into basic highspeed mode and start session */
                                                                                                                                    musb_writeb(regs, MUSB_POWER, MUSB_POWER_SOFTCONN
                                                                                                                                            | MUSB_POWER_HSENAB
                                                                                                                                            /* ENSUSPEND wedges tusb */
                                                                                                                                            | MUSB_POWER_ENSUSPEND);
                                                                                                                                } else {
                                                                                                                                    /* put into basic fullspeed mode and start session */
                                                                                                                                    musb_writeb(regs, MUSB_POWER, MUSB_POWER_SOFTCONN
                                                                                                                                            /* ENSUSPEND wedges tusb */
                                                                                                                                            | MUSB_POWER_ENSUSPEND);
                                                                                                                                }
                                                                                                                                musb->is_active = 1;
                                                                                                                            }

                                                                                                            printk("[MUSB] USB connect\n");
                                                                                                        }

                                                                                    }
                                                                                }
                                                                        #endif        

                                                                                battery_xlog_printk(BAT_LOG_CRTI, "[BAT_thread]Cable in, CHR_Type_num=%d\r\n", BMT_status.charger_type);
                                                                                
                                                                            }
                                                                            ////////////////////////////////////////////////////////////////////////////////////
                                                                            // 如果连接入的不是正常的充电线,或者此时 USB 接口以主机状态运行 ,则设置电池状态参数,断开 USB 连接?
                                                                            else 
                                                                            {
                                                                                wake_unlock(&battery_suspend_lock);

                                                                                BMT_status.charger_exist = KAL_FALSE;
                                                                                BMT_status.charger_type = CHARGER_UNKNOWN;
                                                                                BMT_status.bat_full = KAL_FALSE;
                                                                                BMT_status.bat_in_recharging_state = KAL_FALSE;
                                                                                BMT_status.bat_charging_state = CHR_PRE;
                                                                                BMT_status.total_charging_time = 0;
                                                                                BMT_status.PRE_charging_time = 0;
                                                                                BMT_status.CC_charging_time = 0;
                                                                                BMT_status.TOPOFF_charging_time = 0;
                                                                                BMT_status.POSTFULL_charging_time = 0;

                                                                                battery_xlog_printk(BAT_LOG_CRTI, "[BAT_thread]Cable out \r\n");

                                                                                // 断开 USB 与电脑的连接  
                                                                                mt_usb_disconnect();
                                                                                            void mt_usb_disconnect(void)
                                                                                            {
                                                                                                printk("[MUSB] USB is ready for disconnect\n");

                                                                                                if (!mtk_musb || !mtk_musb->is_ready || mtk_musb->is_host || !mtk_musb->power)
                                                                                                    return;

                                                                                                musb_stop(mtk_musb);

                                                                                                if (wake_lock_active(&mtk_musb->usb_lock))
                                                                                                    wake_unlock(&mtk_musb->usb_lock);

                                                                                                DBG(0,"cable_mode=%d\n",cable_mode);

                                                                                                if (cable_mode != CABLE_MODE_NORMAL) {
                                                                                                    DBG(0,"musb_sync_with_bat, USB_SUSPEND\n");
                                                                                                    musb_sync_with_bat(mtk_musb,USB_SUSPEND);
                                                                                                    mtk_musb->power = false;
                                                                                                }

                                                                                                printk("[MUSB] USB disconnect\n");
                                                                                            }

                                                                            }
                                                                        }

                                                   ///////////////////////////////////////////////////////////////////////////////////////////////////////
                                                   // 2. 通过具体的充电芯片来获得电池信息,充电信息, 获得电池电量百分比 
                                                   /* 通过 oam 算法,获得电量百分比 */
                                                   mt_battery_GetBatteryData();
                                                                        void mt_battery_GetBatteryData(void)
                                                                        { 
                                                                            kal_uint32 bat_vol, charger_vol, Vsense, ZCV; 
                                                                            kal_int32 ICharging, temperature, temperatureR, temperatureV, SOC;
                                                                            static kal_int32 bat_sum, icharging_sum, temperature_sum;
                                                                            static kal_int32 batteryVoltageBuffer[BATTERY_AVERAGE_SIZE];
                                                                            static kal_int32 batteryCurrentBuffer[BATTERY_AVERAGE_SIZE];
                                                                            static kal_int32 batteryTempBuffer[BATTERY_AVERAGE_SIZE];
                                                                            static kal_uint8 batteryIndex = 0;
                                                                            static kal_int32 previous_SOC = -1;

                                                                            // 获得 BATSNS 引脚电压 
                                                                            bat_vol = battery_meter_get_battery_voltage();
                                                                                                        kal_int32 battery_meter_get_battery_voltage(void)
                                                                                                        {
                                                                                                            int ret=0;
                                                                                                            int val=5;
                                                                                                            
                                                                                                            val = 5; //set avg times
                                                                                                            // 获得 PMIC 的 BATSNS 引脚电压 
                                                                                                            ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_BAT_SENSE, &val);
                                                                                                                                static kal_int32 read_adc_v_bat_sense(void *data)
                                                                                                                                {
                                                                                                                                #if defined(CONFIG_POWER_EXT)
                                                                                                                                    *(kal_int32*)(data) = 4201;
                                                                                                                                #else
                                                                                                                                    *(kal_int32*)(data) = PMIC_IMM_GetOneChannelValue(VBAT_CHANNEL_NUMBER,*(kal_int32*)(data),1);
                                                                                                                                #endif

                                                                                                                                    return STATUS_OK;
                                                                                                                                }

                                                                                                            g_sw_vbat_temp = val;

                                                                                                            return val;
                                                                                                        }
                                                                                                        
                                                                            /* 获得 PMIC 的  ISENSE 引脚电压*/
                                                                            Vsense = battery_meter_get_VSense();
                                                                                                    kal_int32 battery_meter_get_VSense(void)
                                                                                                    {
                                                                                                    #if defined(CONFIG_POWER_EXT)
                                                                                                        return 0;
                                                                                                    #else
                                                                                                            int ret=0;
                                                                                                            int val=0;
                                                                                                            
                                                                                                            val = 1; //set avg times
                                                                                                        /* 获得 PMIC 的  ISENSE 引脚电压*/
                                                                                                        ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_I_SENSE, &val);
                                                                                                                            read_adc_v_i_sense(void *data)
                                                                                                                                    *(kal_int32*)(data) = PMIC_IMM_GetOneChannelValue(ISENSE_CHANNEL_NUMBER,*(kal_int32*)(data),1);
                                                                                                        return val;
                                                                                                    #endif
                                                                                                    }

                                                                            /* 获得充电电流 */
                                                                            ICharging = battery_meter_get_charging_current();
                                                                                                               kal_int32 battery_meter_get_charging_current(void)
                                                                                                               {
                                                                                                                   kal_int32 ADC_BAT_SENSE_tmp[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
                                                                                                                   kal_int32 ADC_BAT_SENSE_sum=0;
                                                                                                                   kal_int32 ADC_BAT_SENSE=0;
                                                                                                                   kal_int32 ADC_I_SENSE_tmp[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
                                                                                                                   kal_int32 ADC_I_SENSE_sum=0;
                                                                                                                   kal_int32 ADC_I_SENSE=0;    
                                                                                                                   int repeat=20;
                                                                                                                   int i=0;
                                                                                                                   int j=0;
                                                                                                                   kal_int32 temp=0;
                                                                                                                   int ICharging=0;
                                                                                                                   int ret=0;
                                                                                                                   int val=1;

                                                                                                                   for(i=0 ; i ADC_BAT_SENSE)
                                                                                                                   {
                                                                                                                       ICharging = (ADC_I_SENSE - ADC_BAT_SENSE + g_I_SENSE_offset)*1000/CUST_R_SENSE;
                                                                                                                   }
                                                                                                                   else
                                                                                                                   {
                                                                                                                       ICharging = 0;
                                                                                                                   }

                                                                                                                   return ICharging;
                                                                                                               }

                                                                            /* 获得充电器电压 */
                                                                            charger_vol = battery_meter_get_charger_voltage();
                                                                                                            kal_int32 battery_meter_get_charger_voltage(void)
                                                                                                            {
                                                                                                                int ret=0;
                                                                                                                int val=0;
                                                                                                                
                                                                                                                val = 5; // set avg times
                                                                                                                ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_CHARGER, &val);
                                                                                                                                            static kal_int32 read_adc_v_charger(void *data)
                                                                                                                                            {    
                                                                                                                                            #if defined(CONFIG_POWER_EXT)
                                                                                                                                                *(kal_int32*)(data) = 5001;
                                                                                                                                            #else
                                                                                                                                                kal_int32 val;
                                                                                                                                                /* 获取 PMIC 的 VCDT 引脚电压 */
                                                                                                                                                val = PMIC_IMM_GetOneChannelValue(VCHARGER_CHANNEL_NUMBER,*(kal_int32*)(data),1);
                                                                                                                                                val = (((R_CHARGER_1+R_CHARGER_2)*100*val)/R_CHARGER_2)/100;
                                                                                                                                                
                                                                                                                                                *(kal_int32*)(data) = val;
                                                                                                                                            #endif

                                                                                                                                                return STATUS_OK;
                                                                                                                                            }


                                                                                                                //val = (((R_CHARGER_1+R_CHARGER_2)*100*val)/R_CHARGER_2)/100;
                                                                                                                return val;
                                                                                                            }
                                                                            /* 通过获得当前 NTC 电压,查表并进行线性插值法,得到当前的温度值  */
                                                                            temperature = battery_meter_get_battery_temperature();
                                                                                                        return force_get_tbat();
                                                                                                        
                                                                            /* 这里用来获取电池 NTC 的电压 */
                                                                            temperatureV = battery_meter_get_tempV();
                                                                                                    ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_BAT_TEMP, &val);                                                                                                                           
                                                                                                                            static kal_int32 read_adc_v_bat_temp(void *data)
                                                                                                                            {
                                                                                                                            #if defined(CONFIG_POWER_EXT)
                                                                                                                                *(kal_int32*)(data) = 0;
                                                                                                                            #else
                                                                                                                                #if defined(MTK_PCB_TBAT_FEATURE)

                                                                                                                                    int ret = 0, data[4], i, ret_value = 0, ret_temp = 0;
                                                                                                                                    int Channel=1;
                                                                                                                                    
                                                                                                                                    if( IMM_IsAdcInitReady() == 0 )
                                                                                                                                                     return g_adc_init_flag;
                                                                                                                                    {
                                                                                                                                        bm_print(BM_LOG_CRTI, "[get_tbat_volt] AUXADC is not ready");
                                                                                                                                        return 0;
                                                                                                                                    }
                                                                                                                                
                                                                                                                                    i = times;
                                                                                                                                    while (i--)
                                                                                                                                    {
                                                                                                                                        ret_value = IMM_GetOneChannelValue(Channel, data, &ret_temp);
                                                                                                                                        ret += ret_temp;
                                                                                                                                        bm_print(BM_LOG_FULL, "[get_tbat_volt] ret_temp=%d\n",ret_temp);
                                                                                                                                    }
                                                                                                                                    
                                                                                                                                    ret = ret*1500/4096 ;
                                                                                                                                    ret = ret/times;
                                                                                                                                    bm_print(BM_LOG_CRTI, "[get_tbat_volt] Battery output mV = %d\n",ret);

                                                                                                                                    *(kal_int32*)(data) = ret;

                                                                                                                                #else
                                                                                                                                    bm_print(BM_LOG_FULL, "[read_adc_v_charger] return PMIC_IMM_GetOneChannelValue(4,times,1);\n");
                                                                                                                                    /* 读取 PMIC 的 BATON1 引脚电压 */
                                                                                                                                    *(kal_int32*)(data) = PMIC_IMM_GetOneChannelValue(VBATTEMP_CHANNEL_NUMBER,*(kal_int32*)(data),1);
                                                                                                                                #endif
                                                                                                                            #endif

                                                                                                                                return STATUS_OK;
                                                                                                                            }

                                                                            /* 获得 下拉电阻与 NTC 并并联的电压 */
                                                                            temperatureR = battery_meter_get_tempR(temperatureV);
                                                                                                            /* 上拉电压/下拉电压  = 上拉电阻/ 下拉电阻 */
                                                                                                            TRes = (RBAT_PULL_UP_R*dwVolt) / (RBAT_PULL_UP_VOLT-dwVolt);      

                                                                            /* bat_thread_wakeup() 每 10s 唤醒一次,唤醒时设置  bat_meter_timeout = KAL_TRUE
                                                                            这时候更新电池电量百分比 */
                                                                            if(bat_meter_timeout == KAL_TRUE || bat_spm_timeout == TRUE)
                                                                            {
                                                                                /* oam 算法通过两种方式更新电压,去逼近真实的开路电压,最终查表获取近似真实的电量值百分比,方法 1,查表获得电池百分比,方法 2,库伦积分
                                                                                以方法2获得的参数补偿方法 1 的值,具体方法见 oam_run()*/
                                                                                SOC = battery_meter_get_battery_percentage();
                                                                                                                kal_int32 battery_meter_get_battery_percentage(void)
                                                                                                                {
                                                                                                                #if defined(CONFIG_POWER_EXT)
                                                                                                                    return 50;
                                                                                                                #else

                                                                                                                    if(bat_is_charger_exist() == KAL_FALSE)
                                                                                                                                        // 这里查询 PMIC 的 CHR_CON0 寄存器,检查充电状态
                                                                                                                                        return get_charger_detect_status();
                                                                                                                                                        battery_charging_control(CHARGING_CMD_GET_CHARGER_DET_STATUS,&chr_status);
                                                                                                                                                                            static kal_uint32 charging_get_charger_det_status(void *data)
                                                                                                                                                                             {
                                                                                                                                                                                   kal_uint32 status = STATUS_OK;
                                                                                                                                                                             
                                                                                                                                                                            #if defined(CHRDET_SW_MODE_EN)
                                                                                                                                                                                kal_uint32 vchr_val=0;

                                                                                                                                                                                vchr_val = PMIC_IMM_GetOneChannelValue(4,5,1);
                                                                                                                                                                                vchr_val = (((330+39)*100*vchr_val)/39)/100;

                                                                                                                                                                                if( vchr_val > 4300 )
                                                                                                                                                                                {
                                                                                                                                                                                    battery_xlog_printk(BAT_LOG_FULL, "[CHRDET_SW_WORKAROUND_EN] upmu_is_chr_det=Y (%d)\n", vchr_val);
                                                                                                                                                                                    *(kal_uint32 *)data = KAL_TRUE; 
                                                                                                                                                                                }
                                                                                                                                                                                else
                                                                                                                                                                                {
                                                                                                                                                                                    battery_xlog_printk(BAT_LOG_FULL, "[CHRDET_SW_WORKAROUND_EN] upmu_is_chr_det=N (%d)\n", vchr_val);
                                                                                                                                                                                    *(kal_uint32 *)data = KAL_FALSE;
                                                                                                                                                                                }        
                                                                                                                                                                            #else
                                                                                                                                                                                   *(kal_bool*)(data) = upmu_get_rgs_chrdet();
                                                                                                                                                                            #endif
                                                                                                                                                                                   
                                                                                                                                                                                   if( upmu_get_rgs_chrdet() == 0 )
                                                                                                                                                                                       g_charger_type = CHARGER_UNKNOWN;
                                                                                                                                                                                   
                                                                                                                                                                                   return status;
                                                                                                                                                                             }

                                                                                                                        fg_qmax_update_for_aging_flag = 1;

                                                                                                                    // AUX ADC算法指只依赖ADC读值,然后查表读取电量的算法
                                                                                                                    #if defined(SOC_BY_AUXADC)
                                                                                                                    return auxadc_algo_run();
                                                                                                                    #endif
                                                                                                                    
                                                                                                                    //通过开路电压查表得到初始电量D0,后续电量通过电流积分累积,通用性强,依赖初始电量的精确度。
                                                                                                                    #if defined(SOC_BY_HW_FG)
                                                                                                                    if(g_auxadc_solution == 1)
                                                                                                                    {
                                                                                                                        return auxadc_algo_run();
                                                                                                                    }
                                                                                                                    else    
                                                                                                                    {
                                                                                                                        fgauge_algo_run();    
                                                                                                                        return gFG_capacity_by_c; // hw fg, //return gfg_percent_check_point; // voltage mode    
                                                                                                                    }
                                                                                                                    #endif
                                                                                                                    
                                                                                                                    /*//////////////////////////////////////////////////////////////////////////  
                                                                                                                    6582 平台用的计量方法【在 Battery_Charging_Introduction_for_customer_V1.0.pdf】 
                                                                                                                    SW FG算法和HW FG算法。事实上MTK平台项目通常采用的是混合型算法。 */
                                                                                                                    #if defined(SOC_BY_SW_FG)
                                                                                                                        oam_run();
                                                                                                                                void oam_run(void)
                                                                                                                                {
                                                                                                                                    /* SW FG的核心 在于 通过两种方式更新电压,去逼近真实开路电压  最终查表获取近似真实的电量值。 
                                                                                                                                        ocv1 被假定为开路电压  
                                                                                                                                        ocv2则是闭路电压,
                                                                                                                                        
                                                                                                                                     D0 D1 D2 D3 D4 D5 代表不同的放电深度*/
                                                                                                                                    int vol_bat=0;
                                                                                                                                    //int vol_bat_hw_ocv=0;
                                                                                                                                    //int d_hw_ocv=0;
                                                                                                                                    int charging_current=0;
                                                                                                                                    int ret=0;
                                                                                                                                    //kal_uint32 now_time;
                                                                                                                                    struct timespec now_time;
                                                                                                                                    kal_int32 delta_time = 0;

                                                                                                                                    //now_time = rtc_read_hw_time();
                                                                                                                                    getrawmonotonic(&now_time);

                                                                                                                                    //delta_time = now_time - last_oam_run_time;
                                                                                                                                    delta_time = now_time.tv_sec - last_oam_run_time.tv_sec;

                                                                                                                                    bm_print(BM_LOG_FULL, "[oam_run_time] last time=%d, now time=%d, delta time=%d\n", 
                                                                                                                                    last_oam_run_time.tv_sec, now_time.tv_sec, delta_time);
                                                                                                                                    
                                                                                                                                    last_oam_run_time = now_time;

                                                                                                                                    // Reconstruct table if temp changed;
                                                                                                                                    fgauge_construct_table_by_temp();
                                                                                                                                                                void fgauge_construct_table_by_temp(void)
                                                                                                                                                                {
                                                                                                                                                                #if defined(CONFIG_POWER_EXT)
                                                                                                                                                                #else
                                                                                                                                                                    kal_uint32 i;
                                                                                                                                                                    static kal_int32 init_temp = KAL_TRUE;
                                                                                                                                                                    static kal_int32 curr_temp, last_temp, avg_temp;
                                                                                                                                                                    static kal_int32 battTempBuffer[TEMP_AVERAGE_SIZE];
                                                                                                                                                                    static kal_int32 temperature_sum;
                                                                                                                                                                    static kal_uint8 tempIndex = 0;

                                                                                                                                                                    /* 通过获得当前 NTC 电压,查表并进行线性插值法,得到当前的温度值  */
                                                                                                                                                                    curr_temp = battery_meter_get_battery_temperature();

                                                                                                                                                                    // Temperature window init
                                                                                                                                                                    if (init_temp == KAL_TRUE)
                                                                                                                                                                    {
                                                                                                                                                                        for (i=0; i 100) oam_d_1 = 100;
                                                                                                                                    
                                                                                                                                    oam_d_2 = oam_d0 + (oam_car_2*100/10)/gFG_BATT_CAPACITY_aging;
                                                                                                                                    if(oam_d_2 < 0)   oam_d_2 = 0;
                                                                                                                                    if(oam_d_2 > 100) oam_d_2 = 100;

                                                                                                                                    /*//////////////////////////////////////////////////////////////////////////////////
                                                                                                                                    // 整个程序的核心在这里, 他使用了两种方法更新电量:
                                                                                                                                            1. 使用补偿过的闭路电压,查表获得电量       【返回给用户的】
                                                                                                                                            2. 使用软件库伦积分,得到电量值             【用来校正的】

                                                                                                                                        两个方法相对独立,但是在此处,方法 1 使用了 方法 2 的电流来进行较正!!!!!!!!!!
                                                                                                                                    //////////////////////////////////////////////////////////////////////////////////////
                                                                                                                                    mtk_imp_tracking() 对闭合电压补偿后,当作开路电压使用
                                                                                                                                    通过对当前有负载的电池电压进行补偿,获得当前开路电压 */
                                                                                                                                    oam_v_ocv_1 = vol_bat + mtk_imp_tracking(vol_bat, oam_i_2, 5);
                                                                                                                                                                            // ============================================================ // SW FG
                                                                                                                                                                            // 这个里面返回的是 I*R 的值,即 当前电流 * 当前负载
                                                                                                                                                                            kal_int32 mtk_imp_tracking(kal_int32 ori_voltage, kal_int32 ori_current, kal_int32 recursion_time)
                                                                                                                                                                            {
                                                                                                                                                                                kal_int32 ret_compensate_value = 0;
                                                                                                                                                                                kal_int32 temp_voltage_1 = ori_voltage;     // 闭路电压
                                                                                                                                                                                kal_int32 temp_voltage_2 = temp_voltage_1;  // 开路电压,第一次 = 闭路电压,后来都是补偿过 IR 的 
                                                                                                                                                                                int i = 0;

                                                                                                                                                                                /* 迭代 5 次,反复执行 闭合补偿得开路电压,开路电压查表得内阻,内阻补偿闭路电压 */
                                                                                                                                                                                for(i=0 ; i < recursion_time ; i++) 
                                                                                                                                                                                {
                                                                                                                                                                                    /* 将闭路电压当做开路电压查内阻 */
                                                                                                                                                                                    gFG_resistance_bat = fgauge_read_r_bat_by_v(temp_voltage_2); 
                                                                                                                                                                                    /* 算出 IR drop */
                                                                                                                                                                                    ret_compensate_value = ( (ori_current) * (gFG_resistance_bat + R_FG_VALUE)) / 1000;
                                                                                                                                                                                    // ret_compensate是int型变量 做除法时取整处理 会引入较大误差, 加上这个值使结果四舍五入
                                                                                                                                                                                    ret_compensate_value = (ret_compensate_value+(10/2)) / 10; 
                                                                                                                                                                                    /* 开路电压 = 当前电压 + IR drop   */
                                                                                                                                                                                    temp_voltage_2 = temp_voltage_1 + ret_compensate_value;

                                                                                                                                                                                    bm_print(BM_LOG_FULL, "[mtk_imp_tracking] temp_voltage_2=%d,temp_voltage_1=%d,ret_compensate_value=%d,gFG_resistance_bat=%d\n", 
                                                                                                                                                                                        temp_voltage_2,temp_voltage_1,ret_compensate_value,gFG_resistance_bat);
                                                                                                                                                                                }
                                                                                                                                                                                
                                                                                                                                                                                /* 通过上面获得的开路电压查找最终内阻 */
                                                                                                                                                                                gFG_resistance_bat = fgauge_read_r_bat_by_v(temp_voltage_2); 
                                                                                                                                                                                /* 算出 IR drop */
                                                                                                                                                                                ret_compensate_value = ( (ori_current) * (gFG_resistance_bat + R_FG_VALUE + FG_METER_RESISTANCE)) / 1000;  
                                                                                                                                                                                /* 四舍五入 */
                                                                                                                                                                                ret_compensate_value = (ret_compensate_value+(10/2)) / 10; 

                                                                                                                                                                                gFG_compensate_value = ret_compensate_value; // I*R 补偿负载 

                                                                                                                                                                                bm_print(BM_LOG_FULL, "[mtk_imp_tracking] temp_voltage_2=%d,temp_voltage_1=%d,ret_compensate_value=%d,gFG_resistance_bat=%d\n", 
                                                                                                                                                                                    temp_voltage_2,temp_voltage_1,ret_compensate_value,gFG_resistance_bat);    

                                                                                                                                                                                /* 该内阻 R* 电流 I 算出最终的电压补偿值 V 
                                                                                                                                                                                        Vbat 是闭路电压 
                                                                                                                                                                                        SW ocv 是开路电压 
                                                                                                                                                                                        Sw ocv = V + Vbat 
                                                                                                                                                                                 */
                                                                                                                                                                                return ret_compensate_value;
                                                                                                                                                                            }

                                                                                                                                    ////////////////////////////////////////////////////////////////////////
                                                                                                                                    /* 通过补偿的开路电压,获得电池电量百分比 */
                                                                                                                                    oam_d_3 = fgauge_read_d_by_v(oam_v_ocv_1);        
                                                                                                                                    if(oam_d_3 < 0)   oam_d_3 = 0;
                                                                                                                                    if(oam_d_3 > 100) oam_d_3 = 100;

                                                                                                                                    /* 通过开路电压,获得电池内阻 */
                                                                                                                                    oam_r_1 = fgauge_read_r_bat_by_v(oam_v_ocv_1);

                                                                                                                                    ////////////////////////////////////////////////////////////////////////
                                                                                                                                    /* 通过库伦积分获得的电池容量百分比,来获得电池开路电压*/
                                                                                                                                    oam_v_ocv_2 = fgauge_read_v_by_d(oam_d_2);
                                                                                                                                    /* 通过开路电压,获得电池内阻 */
                                                                                                                                    oam_r_2 = fgauge_read_r_bat_by_v(oam_v_ocv_2);    

                                                                                                                                #if 0
                                                                                                                                    oam_d_4 = (oam_d_2+oam_d_3)/2;
                                                                                                                                #else
                                                                                                                                    oam_d_4 = oam_d_3;
                                                                                                                                #endif

                                                                                                                                    // 从上一次运行本函数到现在当前电量变化的值
                                                                                                                                    gFG_columb = oam_car_2/10;  //mAh

                                                                                                                                    /* 判断充电状态 */
                                                                                                                                    if( (oam_i_1 < 0) || (oam_i_2 < 0) )
                                                                                                                                        gFG_Is_Charging = KAL_TRUE;
                                                                                                                                    else
                                                                                                                                        gFG_Is_Charging = KAL_FALSE;

                                                                                                                                #if 0
                                                                                                                                    if(gFG_Is_Charging == KAL_FALSE)
                                                                                                                                    {
                                                                                                                                        d5_count_time = 60;         
                                                                                                                                    }
                                                                                                                                    else
                                                                                                                                    {
                                                                                                                                        charging_current = get_charging_setting_current();    
                                                                                                                                        charging_current = charging_current / 100;
                                                                                                                                        d5_count_time_rate = (((gFG_BATT_CAPACITY_aging*60*60/100/(charging_current-50))*10)+5)/10;
                                                                                                                                        
                                                                                                                                        if(d5_count_time_rate < 1)
                                                                                                                                            d5_count_time_rate = 1;

                                                                                                                                        d5_count_time = d5_count_time_rate;
                                                                                                                                    }
                                                                                                                                #else
                                                                                                                                    d5_count_time = 60;
                                                                                                                                #endif    

                                                                                                                                    /////////////////////////////////////////////////////////////////////////////////////////////
                                                                                                                                    // D5 与 D3 对比                                                                                                           
                                                                                                                                    /* 对获得的 D3 进行优化,有 1min 的限制,不会跳变,电量变化更平滑 
                                                                                                                                    1分钟内电量值不会改变,且每分钟电量的变化不会大于1%,这样用户体验会比较好。
                                                                                                                                    防止因为低电压时陡峭的电量曲线,以及比较耗电的应用,或突然的大电流引起的电量跳变。
                                                                                                                                    当然特殊应用下应该取消这个功能,否则会带来电量变化延时等问题*/
                                                                                                                                    if(d5_count >= d5_count_time)
                                                                                                                                    // 60s 执行一次
                                                                                                                                    {
                                                                                                                                        /* 限制电量变化,每 1 分钟,只能变化 1% */
                                                                                                                                        
                                                                                                                                        /* 放电状态 */
                                                                                                                                        if(gFG_Is_Charging == KAL_FALSE)
                                                                                                                                        {
                                                                                                                                            if( oam_d_3 > oam_d_5 )
                                                                                                                                            {
                                                                                                                                                oam_d_5 = oam_d_5 + 1;
                                                                                                                                            }
                                                                                                                                            else
                                                                                                                                            {                
                                                                                                                                                if(oam_d_4 > oam_d_5)
                                                                                                                                                {
                                                                                                                                                    oam_d_5 = oam_d_5 + 1;
                                                                                                                                                }
                                                                                                                                            }
                                                                                                                                        }
                                                                                                                                        /* 充电状态 */
                                                                                                                                        else
                                                                                                                                        {            
                                                                                                                                            if( oam_d_5 > oam_d_3 )
                                                                                                                                            {
                                                                                                                                                oam_d_5 = oam_d_5 - 1;
                                                                                                                                            }
                                                                                                                                            else
                                                                                                                                            {                
                                                                                                                                                if(oam_d_4 < oam_d_5)
                                                                                                                                                {
                                                                                                                                                    oam_d_5 = oam_d_5 - 1;
                                                                                                                                                }
                                                                                                                                            }
                                                                                                                                        }
                                                                                                                                        d5_count = 0;
                                                                                                                                        oam_d_3_pre = oam_d_3;
                                                                                                                                        oam_d_4_pre = oam_d_4;
                                                                                                                                    }
                                                                                                                                    else
                                                                                                                                    // 10s 执行一次本函数
                                                                                                                                    {
                                                                                                                                        d5_count = d5_count + 10;
                                                                                                                                    }
                                                                                                                                    
                                                                                                                                    bm_print(BM_LOG_CRTI, "[oam_run] %d,%d,%d,%d,%d,%d,%d,%d\n", 
                                                                                                                                        d5_count, d5_count_time, oam_d_3_pre, oam_d_3, oam_d_4_pre, oam_d_4, oam_d_5, charging_current);    

                                                                                                                                    if(oam_run_i == 0)
                                                                                                                                    {
                                                                                                                                        bm_print(BM_LOG_FULL, "[oam_run] oam_i_1,oam_i_2,oam_car_1,oam_car_2,oam_d_1,oam_d_2,oam_v_ocv_1,oam_d_3,oam_r_1,oam_v_ocv_2,oam_r_2,vol_bat,g_vol_bat_hw_ocv,g_d_hw_ocv\n");
                                                                                                                                        oam_run_i=1;
                                                                                                                                    }    

                                                                                                                                    bm_print(BM_LOG_FULL, "[oam_run] %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", 
                                                                                                                                            oam_i_1,oam_i_2,oam_car_1,oam_car_2,oam_d_1,oam_d_2,oam_v_ocv_1,oam_d_3,oam_r_1,oam_v_ocv_2,oam_r_2,vol_bat,g_vol_bat_hw_ocv,g_d_hw_ocv);    

                                                                                                                                    bm_print(BM_LOG_FULL, "[oam_total] %d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
                                                                                                                                            gFG_capacity_by_c, gFG_capacity_by_v, gfg_percent_check_point,
                                                                                                                                            oam_d_1, oam_d_2, oam_d_3, oam_d_4, oam_d_5, gFG_capacity_by_c_init, g_d_hw_ocv);

                                                                                                                                    bm_print(BM_LOG_CRTI, "[oam_total_s] %d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
                                                                                                                                        gFG_capacity_by_c,        // 1
                                                                                                                                        gFG_capacity_by_v,        // 2
                                                                                                                                        gfg_percent_check_point,  // 3
                                                                                                                                        (100-oam_d_1),            // 4
                                                                                                                                        (100-oam_d_2),            // 5
                                                                                                                                        (100-oam_d_3),            // 6
                                                                                                                                        (100-oam_d_4),            // 9
                                                                                                                                        (100-oam_d_5),            // 10
                                                                                                                                        gFG_capacity_by_c_init,   // 7
                                                                                                                                        (100-g_d_hw_ocv)          // 8
                                                                                                                                        );          

                                                                                                                                    bm_print(BM_LOG_FULL, "[oam_total_s_err] %d,%d,%d,%d,%d,%d,%d\n",
                                                                                                                                        (gFG_capacity_by_c - gFG_capacity_by_v), 
                                                                                                                                        (gFG_capacity_by_c - gfg_percent_check_point),
                                                                                                                                        (gFG_capacity_by_c - (100-oam_d_1)), 
                                                                                                                                        (gFG_capacity_by_c - (100-oam_d_2)), 
                                                                                                                                        (gFG_capacity_by_c - (100-oam_d_3)), 
                                                                                                                                        (gFG_capacity_by_c - (100-oam_d_4)), 
                                                                                                                                        (gFG_capacity_by_c - (100-oam_d_5))
                                                                                                                                        );

                                                                                                                                    bm_print(BM_LOG_CRTI, "[oam_init_inf] %d, %d, %d, %d, %d, %d\n",
                                                                                                                                        gFG_voltage, (100 - fgauge_read_capacity_by_v(gFG_voltage)), g_rtc_fg_soc, gFG_DOD0 ,oam_v_ocv_init, force_get_tbat());

                                                                                                                                     bm_print(BM_LOG_CRTI, "[oam_run_inf] %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", 
                                                                                                                                           oam_v_ocv_1,oam_v_ocv_2,vol_bat,oam_i_1,oam_i_2,oam_r_1,oam_r_2,oam_car_1,oam_car_2,gFG_BATT_CAPACITY_aging,force_get_tbat(), oam_d0);  

                                                                                                                                      bm_print(BM_LOG_CRTI, "[oam_result_inf] %d, %d, %d, %d, %d, %d\n", 
                                                                                                                                           oam_d_1, oam_d_2, oam_d_3, oam_d_4, oam_d_5, BMT_status.UI_SOC);  
                                                                                                                                }
 
                                                                                                                        


                                                                                                                        // 这边的返回值将填充BMT_status.SOC ,这个参数再经过优化得到BMT_status.UI_SOC就是菜单栏看到的电池电量了。

                                                                                                                        //////////////////////////////////////////////////////////////////////////////////////////////
                                                                                                                        /* D5 是做过平滑,每 1min 电量变化只能是 1% 的,可能会有延时  */
                                                                                                                        #if (OAM_D5 == 1)
                                                                                                                            return (100-oam_d_5);
                                                                                                                        #else
                                                                                                                        /* D2 则是原版的,没有做平滑处理,电量变化可能会跳变,但是变化及时 */
                                                                                                                            return (100-oam_d_2);
                                                                                                                        #endif
                                                                                                                    #endif

                                                                                                                #endif
                                                                                                                }

                                                                                bat_meter_timeout = KAL_FALSE;
                                                                                bat_spm_timeout = FALSE;
                                                                            }
                                                                            else
                                                                            {
                                                                                if (previous_SOC == -1)
                                                                                    /* 通过两种方式更新电压,去逼近真实的开路电压,最终查表获取近似真实的电量值百分比 */
                                                                                    SOC = battery_meter_get_battery_percentage();
                                                                                else
                                                                                    SOC = previous_SOC;     
                                                                            }
                                                                            
                                                                            ZCV = battery_meter_get_battery_zcv();
                                                                                                     return gFG_voltage; // 返回 hw ocv 电压 

                                                                            /* 更新电池状态 */
                                                                            BMT_status.ICharging = mt_battery_average_method(&batteryCurrentBuffer[0],ICharging, &icharging_sum, batteryIndex); 
                                                                            BMT_status.bat_vol = mt_battery_average_method(&batteryVoltageBuffer[0],bat_vol, &bat_sum, batteryIndex);
                                                                            BMT_status.temperature = mt_battery_average_method(&batteryTempBuffer[0],temperature, &temperature_sum, batteryIndex);
                                                                            BMT_status.Vsense = Vsense;
                                                                            BMT_status.charger_vol = charger_vol;   
                                                                            BMT_status.temperatureV = temperatureV;
                                                                            BMT_status.temperatureR = temperatureR;
                                                                            BMT_status.SOC = SOC;   
                                                                            BMT_status.ZCV = ZCV;
                                                                            
                                                                            if(BMT_status.charger_exist == KAL_FALSE)
                                                                            {
                                                                                if(BMT_status.SOC > previous_SOC && previous_SOC >= 0)
                                                                                    BMT_status.SOC = previous_SOC;
                                                                            }

                                                                            previous_SOC = BMT_status.SOC;
                                                                            
                                                                            batteryIndex++;
                                                                            if (batteryIndex >= BATTERY_AVERAGE_SIZE)
                                                                                batteryIndex = 0;
                                                                            

                                                                            
                                                                            battery_xlog_printk(BAT_LOG_CRTI, "AvgVbat=(%d),bat_vol=(%d),AvgI=(%d),I=(%d),VChr=(%d),AvgT=(%d),T=(%d),pre_SOC=(%d),SOC=(%d),ZCV=(%d)\n",
                                                                                BMT_status.bat_vol,bat_vol,BMT_status.ICharging,ICharging,BMT_status.charger_vol,BMT_status.temperature,temperature,previous_SOC,BMT_status.SOC,BMT_status.ZCV);    


                                                                        }

                                                   ////////////////////////////////////////////////////////////////////////////////////////////////////////
                                                   // 3. 电池温度保护
                                                   /* 电池温度检查,如果温度超过 60 度,关机重启 */
                                                   mt_battery_thermal_check();
                                                                        static void mt_battery_thermal_check(void)
                                                                        {
                                                                            if( (g_battery_thermal_throttling_flag==1) || (g_battery_thermal_throttling_flag==3) )
                                                                            {
                                                                                if(battery_cmd_thermal_test_mode == 1){
                                                                                    BMT_status.temperature = battery_cmd_thermal_test_mode_value;
                                                                                    battery_xlog_printk(BAT_LOG_FULL, "[Battery] In thermal_test_mode , Tbat=%d\n", BMT_status.temperature);
                                                                                }
                                                                            
                                                                        #if defined(MTK_JEITA_STANDARD_SUPPORT)
                                                                                //ignore default rule
                                                                        #else    
                                                                                if(BMT_status.temperature >= 60)
                                                                                {
                                                                                    #if defined(CONFIG_POWER_EXT)
                                                                                        battery_xlog_printk(BAT_LOG_CRTI, "[BATTERY] CONFIG_POWER_EXT, no update battery update power down.\n");
                                                                                    #else
                                                                                    {
                                                                                        if( (g_platform_boot_mode==META_BOOT) || (g_platform_boot_mode==ADVMETA_BOOT) || (g_platform_boot_mode==ATE_FACTORY_BOOT) )
                                                                                        {
                                                                                            battery_xlog_printk(BAT_LOG_FULL, "[BATTERY] boot mode = %d, bypass temperature check\n", g_platform_boot_mode);
                                                                                        }
                                                                                        else
                                                                                        // 正常启动的话,超过温度,系统重启
                                                                                        {
                                                                                            struct battery_data *bat_data = &battery_main;
                                                                                            struct power_supply *bat_psy = &bat_data->psy;

                                                                                            battery_xlog_printk(BAT_LOG_CRTI, "[Battery] Tbat(%d)>=60, system need power down.\n", BMT_status.temperature);

                                                                                            bat_data->BAT_CAPACITY = 0;

                                                                                            power_supply_changed(bat_psy); 

                                                                                            if( BMT_status.charger_exist == KAL_TRUE )
                                                                                            {
                                                                                                // can not power down due to charger exist, so need reset system
                                                                                                //battery_charging_control(CHARGING_CMD_SET_PLATFORM_RESET,NULL);
                                                                                            }
                                                                                            //avoid SW no feedback
                                                                                            battery_charging_control(CHARGING_CMD_SET_POWER_OFF,NULL);
                                                                                                                    static kal_uint32 charging_set_power_off(void *data)
                                                                                                                    {
                                                                                                                        kal_uint32 status = STATUS_OK;
                                                                                                                     
                                                                                                                        battery_xlog_printk(BAT_LOG_CRTI, "charging_set_power_off=%d\n");

                                                                                                                        /* */
                                                                                                                        mt_power_off();
                                                                                                                                void mt_power_off(void)
                                                                                                                                {
                                                                                                                                    printk("mt_power_off\n");

                                                                                                                                    /* pull PWRBB low */
                                                                                                                                    rtc_bbpu_power_down();
                                                                                                                                                void rtc_bbpu_power_down(void)
                                                                                                                                                {
                                                                                                                                                    unsigned long flags;

                                                                                                                                                    spin_lock_irqsave(&rtc_lock, flags);
                                                                                                                                                    hal_rtc_bbpu_pwdn();
                                                                                                                                                    spin_unlock_irqrestore(&rtc_lock, flags);
                                                                                                                                                }

                                                                                                                                    while (1) {
                                                                                                                                #if defined(CONFIG_POWER_EXT)
                                                                                                                                        //EVB
                                                                                                                                        printk("EVB without charger\n");
                                                                                                                                #else   
                                                                                                                                        //Phone 
                                                                                                                                        printk("Phone with charger\n");
                                                                                                                                        if (pmic_chrdet_status() == KAL_TRUE)
                                                                                                                                            arch_reset(0, "power_off_with_charger");
                                                                                                                                #endif
                                                                                                                                    }
                                                                                                                                }
                                                                                                                            
                                                                                                                        return status;
                                                                                                                    }
                                                                                            //mt_power_off();
                                                                                        }
                                                                                    }
                                                                                    #endif
                                                                                }
                                                                        #endif
                                                                                
                                                                            }

                                                                        }

                                                   /////////////////////////////////////////////////////////////////////////////////////////////////////////
                                                   // 4. 电池状态检查
                                                   /*  对电池状态进行检查,如果有问题,则会调用 printk() 进行打印 */
                                                   mt_battery_notify_check();
                                                                        void mt_battery_notify_check(void)
                                                                        {
                                                                            g_BatteryNotifyCode = 0x0000;

                                                                            if(g_BN_TestMode == 0x0000) /* for normal case */
                                                                            {
                                                                                battery_xlog_printk(BAT_LOG_FULL, "[BATTERY] mt_battery_notify_check\n");

                                                                                mt_battery_notify_VCharger_check();

                                                                                mt_battery_notify_VBatTemp_check();

                                                                                mt_battery_notify_ICharging_check();

                                                                                mt_battery_notify_VBat_check();

                                                                                mt_battery_notify_TatalChargingTime_check();
                                                                            }   
                                                                            else  /* for UI test */
                                                                            {
                                                                                mt_battery_notify_UI_test();
                                                                            }
                                                                        }


                                                   //////////////////////////////////////////////////////////////////////////////////////////////////////////
                                                   // 5. 调用具本的硬件相关函数进行充电,充电时会进行 CC/CV 之类的状态机切换就是在这里进行的
                                                   /* 如果存在充电线,则调用具体充电芯片相关的函数进行充电  */
                                                   if( BMT_status.charger_exist == KAL_TRUE )
                                                   {
                                                       /* 检查电池状态,设置到 BMT_status.bat_charging_state 中 */
                                                       mt_battery_CheckBatteryStatus();     

                                                       /* 充电策略,这里有两个文件: switch_charging.c 和 linear_charging.c 
                                                       他们的关系是,如果定义了任一外部充电 IC,则选择 switch_charging.c 的函数,否则就是 linear_charging.c 的函数
                                                       这里就是调用具体的芯片的充电相关函数进行充电 */
                                                       mt_battery_charging_algorithm();
                                                                            void mt_battery_charging_algorithm()
                                                                            {
                                                                                 switch(BMT_status.bat_charging_state)
                                                                                {            
                                                                                    case CHR_PRE :
                                                                                        BAT_PreChargeModeAction();
                                                                                        break;    
                                                                                        
                                                                                    case CHR_CC :
                                                                                        BAT_ConstantCurrentModeAction();
                                                                                        break;    
                                                                                        
                                                                                    case CHR_TOP_OFF :
                                                                                        BAT_TopOffModeAction();
                                                                                        break;              

                                                                                    case CHR_BATFULL:
                                                                                        BAT_BatteryFullAction();
                                                                                        break;
                                                                                        
                                                                                case CHR_HOLD:
                                                                                    BAT_BatteryHoldAction();
                                                                                        break;
                                                                                        
                                                                                    case CHR_ERROR:
                                                                                        BAT_BatteryStatusFailAction();
                                                                                        break;                
                                                                                }    
                                                                               
                                                                            }
                                                   }
                                                
                                                   ///////////////////////////////////////////////////////////////////////////////////////////////////////////
                                                   // 6. 更新电池显示状态 
                                                   /* 更新设置节点的内容: 
                                                        /sys/class/power_supply/下的文件夹
                                                                                wireless_main
                                                                                battery_main
                                                                                ac_main 
                                                                                usb_main
                                                   */
                                                   mt_battery_update_status();
                                                                        static void mt_battery_update_status(void)
                                                                        {
                                                                        #if defined(CONFIG_POWER_EXT)
                                                                            battery_xlog_printk(BAT_LOG_CRTI, "[BATTERY] CONFIG_POWER_EXT, no update Android.\n");
                                                                        #else
                                                                            {
                                                                                wireless_update(&wireless_main);
                                                                                battery_update(&battery_main);          
                                                                                ac_update(&ac_main);
                                                                                usb_update(&usb_main);
                                                                            }

                                                                        #endif  
                                                                        }
                                               }


                                    mutex_unlock(&bat_mutex);
                                
                                    battery_xlog_printk(BAT_LOG_FULL, "wait event \n" );

                                    /* 睡眠等待唤醒 */
                            		wait_event(bat_thread_wq, (bat_thread_timeout == KAL_TRUE));
                            	
                                    bat_thread_timeout = KAL_FALSE;
                                    /* 每 10s 启动一次 */
                                    hrtimer_start(&battery_kthread_timer, ktime, HRTIMER_MODE_REL);   
                                    ktime = ktime_set(BAT_TASK_PERIOD, 0);  // 10s, 10* 1000 ms

                                    /* 如果有充电线插入且 xxx */
                                    if( chr_wake_up_bat == KAL_TRUE && g_smartbook_update != 1)	// for charger plug in/ out
                                    {
                                        g_smartbook_update = 0;
                                        /* 重新计算当前电池电量,复位 oam 算法相关参数  */
                                       	battery_meter_reset();
                                                    kal_int32 battery_meter_reset(void)
                                                    {
                                                    #if defined(CONFIG_POWER_EXT)
                                                        return 0;
                                                    #else
                                                        /* 获得 ui 显示的百分比 */
                                                        kal_uint32 ui_percentage = bat_get_ui_percentage();
                                                                                        kal_uint32 bat_get_ui_percentage(void)
                                                                                        {
                                                                                        	//  for plugging out charger in recharge phase, using SOC as UI_SOC
                                                                                        	if(chr_wake_up_bat == KAL_TRUE)
                                                                                        		return BMT_status.SOC; 
                                                                                        	else
                                                                                        		return BMT_status.UI_SOC;
                                                                                                            //    typedef struct 
                                                                                                            //    {
                                                                                                            //        kal_bool            bat_exist;
                                                                                                            //        kal_bool            bat_full;                 // 电池是否充满标志
                                                                                                            //        INT32           bat_charging_state;
                                                                                                            //        UINT32          bat_vol;         
                                                                                                            //        kal_bool            bat_in_recharging_state;    
                                                                                                            //        kal_uint32      Vsense;
                                                                                                            //        kal_bool            charger_exist;   
                                                                                                            //        UINT32          charger_vol;        
                                                                                                            //        INT32           charger_protect_status; 
                                                                                                            //        INT32           ICharging;
                                                                                                            //        INT32           IBattery;
                                                                                                            //        INT32           temperature;
                                                                                                            //        INT32           temperatureR;
                                                                                                            //        INT32           temperatureV;
                                                                                                            //        UINT32          total_charging_time;
                                                                                                            //        UINT32          PRE_charging_time;
                                                                                                            //        UINT32          CC_charging_time;
                                                                                                            //        UINT32          TOPOFF_charging_time;
                                                                                                            //        UINT32          POSTFULL_charging_time;
                                                                                                            //        UINT32          charger_type;
                                                                                                            //        INT32           SOC;
                                                                                                            //        INT32           UI_SOC;                       // ui 显示电量百分比
                                                                                                            //        UINT32          nPercent_ZCV;
                                                                                                            //        UINT32          nPrecent_UI_SOC_check_point;
                                                                                                            //        UINT32          ZCV;
                                                                                                            //    } PMU_ChargerStruct;
                                                                                        }

                                                        /* //////////////////////////////////////////////// 
                                                        // 如果电池充满了,则更新电池最大容量  */
                                                        if(bat_is_charging_full() == KAL_TRUE) // charge full
                                                                            // 判断电池是否充满
                                                                            kal_bool bat_is_charging_full(void)
                                                                            {
                                                                            	if((BMT_status.bat_full == KAL_TRUE) && (BMT_status.bat_in_recharging_state == KAL_FALSE))
                                                                            		return KAL_TRUE;
                                                                            	else
                                                                            		return KAL_FALSE;
                                                                            }
                                                        {
                                                            /* 如果 fg_qmax_update_for_aging_flag == 1 
                                                            则更新电池电容量,并将 fg_qmax_update_for_aging_flag 置为 0 */
                                                            if(fg_qmax_update_for_aging_flag == 1)
                                                            {
                                                                fg_qmax_update_for_aging();
                                                                                void fg_qmax_update_for_aging(void)
                                                                                {
                                                                                #if defined(CONFIG_POWER_EXT)
                                                                                #else
                                                                                    kal_bool hw_charging_done = bat_is_charging_full();

                                                                                    /* 如果电池充满了,更新电池最大容量 */
                                                                                    if(hw_charging_done == KAL_TRUE) // charging full, g_HW_Charging_Done == 1
                                                                                    {
                                                                                        /* gFG_DOD0 应该是 100%-ui 显示百分比 
                                                                                        即当前使用完的容量百分比 */
                                                                                        if(gFG_DOD0 > 85)
                                                                                        {
                                                                                            // 表示在放电
                                                                                            if(gFG_columb < 0) // gFG_columb: 从上一次运行本函数到现在当前电量变化的值
                                                                                                gFG_columb = gFG_columb - gFG_columb*2;     //  absolute value
                                                                                            
                                                                                            gFG_BATT_CAPACITY_aging = ( ( (gFG_columb*1000)+(5*gFG_DOD0) ) / gFG_DOD0 ) / 10; // gFG_BATT_CAPACITY_aging: 当前温度电池最大容量

                                                                                            // tuning
                                                                                            gFG_BATT_CAPACITY_aging = (gFG_BATT_CAPACITY_aging * 100) / AGING_TUNING_VALUE;

                                                                                            /* 如果当前电池容量值为 0 */
                                                                                            if(gFG_BATT_CAPACITY_aging == 0)
                                                                                            {
                                                                                                /* 先通过 battery_meter_get_battery_temperature() 获得电池温度,再通过 fgauge_get_Q_max() 计算电量 
                                                                                                这里获得当前电池的容量 */
                                                                                                gFG_BATT_CAPACITY_aging = fgauge_get_Q_max(battery_meter_get_battery_temperature()); 

                                                                                                bm_print(BM_LOG_CRTI, "[fg_qmax_update_for_aging] error, restore gFG_BATT_CAPACITY_aging (%d)\n", gFG_BATT_CAPACITY_aging);
                                                                                            }
                                                                                            
                                                                                            bm_print(BM_LOG_CRTI, "[fg_qmax_update_for_aging] need update : gFG_columb=%d, gFG_DOD0=%d, new_qmax=%d\r\n", 
                                                                                                gFG_columb, gFG_DOD0, gFG_BATT_CAPACITY_aging);
                                                                                        }
                                                                                        else
                                                                                        {
                                                                                            bm_print(BM_LOG_CRTI, "[fg_qmax_update_for_aging] no update : gFG_columb=%d, gFG_DOD0=%d, new_qmax=%d\r\n", 
                                                                                                gFG_columb, gFG_DOD0, gFG_BATT_CAPACITY_aging);
                                                                                        }
                                                                                    }
                                                                                    /* 如果电池未充满 */
                                                                                    else
                                                                                    {
                                                                                        bm_print(BM_LOG_CRTI, "[fg_qmax_update_for_aging] hw_charging_done=%d\r\n", hw_charging_done);
                                                                                    }
                                                                                #endif    
                                                                                }

                                                                fg_qmax_update_for_aging_flag=0;
                                                            }
                                                        }   


                                                        /* car: 库伦计的缩写
                                                        这里是复位库伦计 */
                                                        reset_parameter_car();
                                                                    void reset_parameter_car(void)
                                                                    {
                                                                        #if defined(SOC_BY_HW_FG)
                                                                        int ret = 0;
                                                                        /* 调用对应充电芯片的操作函数,复位硬件,这里对应 PMIC 的函数为  */
                                                                        ret = battery_meter_ctrl(BATTERY_METER_CMD_HW_RESET, NULL);    
                                                                                                static kal_int32 fgauge_hw_reset//(void *data)
                                                                                                {
                                                                                                    return STATUS_OK;
                                                                                                }
                                                                        gFG_columb = 0;
                                                                        #endif

                                                                        #if defined(SOC_BY_SW_FG)
                                                                        oam_car_1 = 0;
                                                                        oam_car_2 = 0;
                                                                        gFG_columb = 0;
                                                                        #endif
                                                                    }
                                                        /* DOD: DOD: 放电深度,100-DOD 即电容容量 */
                                                        reset_parameter_dod_full(ui_percentage); 
                                                                    void reset_parameter_dod_full(kal_uint32 ui_percentage)
                                                                    {
                                                                        #if defined(SOC_BY_HW_FG)
                                                                        bm_print(BM_LOG_CRTI, "[battery_meter_reset]1 DOD0=%d,DOD1=%d,ui=%d\n", gFG_DOD0, gFG_DOD1, ui_percentage);
                                                                        gFG_DOD0 = 100 - ui_percentage;
                                                                        gFG_DOD1 = gFG_DOD0;
                                                                    	bm_print(BM_LOG_CRTI, "[battery_meter_reset]2 DOD0=%d,DOD1=%d,ui=%d\n", gFG_DOD0, gFG_DOD1, ui_percentage);
                                                                        #endif

                                                                        // 我们用的是这种,软件库伦积分
                                                                        #if defined(SOC_BY_SW_FG)
                                                                        bm_print(BM_LOG_CRTI, "[battery_meter_reset]1 oam_d0=%d,oam_d_5=%d,ui=%d\n", oam_d0, oam_d_5, ui_percentage);
                                                                    	oam_d0 = 100 - ui_percentage;
                                                                        gFG_DOD0 = oam_d0;
                                                                        gFG_DOD1 = oam_d0;
                                                                        oam_d_1 = oam_d0;
                                                                        oam_d_2 = oam_d0;
                                                                        oam_d_3 = oam_d0;
                                                                        oam_d_4 = oam_d0;
                                                                        oam_d_5 = oam_d0;   // 相当于平滑处理过的 D3 
                                                                    	bm_print(BM_LOG_CRTI, "[battery_meter_reset]2 oam_d0=%d,oam_d_5=%d,ui=%d\n", oam_d0, oam_d_5, ui_percentage);
                                                                        #endif
                                                                    }

                                                        
                                                        return 0;
                                                    #endif
                                                    }
                                                    
                            			chr_wake_up_bat = KAL_FALSE;
                            			            
                                        battery_xlog_printk(BAT_LOG_CRTI, "[BATTERY] Charger plug in/out, Call battery_meter_reset. (%d)\n", BMT_status.UI_SOC);
                                    }
                                    
                                }

                                return 0;
                            }
    battery_xlog_printk(BAT_LOG_CRTI, "[battery_probe] bat_thread_kthread Done\n");    
    
    // 电池过充保护相关检测与初始化,他 2s 检测一次
    charger_hv_detect_sw_workaround_init();
                    void charger_hv_detect_sw_workaround_init(void)
                    {
                        ktime_t ktime;

                        ktime = ktime_set(0, BAT_MS_TO_NS(2000));
                        hrtimer_init(&charger_hv_detect_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
                        charger_hv_detect_timer.function = charger_hv_detect_sw_workaround;    
                        hrtimer_start(&charger_hv_detect_timer, ktime, HRTIMER_MODE_REL);

                        // 这个函数是周期来检查电池电压是否超出限制,即过充保护,超出了就不能充电了 
                        charger_hv_detect_thread = kthread_run(charger_hv_detect_sw_thread_handler, 0, "mtk charger_hv_detect_sw_workaround");
                                                                        // 这个函数是周期来检查电池电压是否超出限制,即过充保护,超出了就不能充电了 
                                                                        int charger_hv_detect_sw_thread_handler(void *unused)
                                                                        {
                                                                            ktime_t ktime;
                                                                            kal_uint32 charging_enable;
                                                                            kal_uint32 hv_voltage = BATTERY_VOLT_07_000000_V;
                                                                            kal_bool hv_status; 


                                                                            do
                                                                            {
                                                                                ktime = ktime_set(0, BAT_MS_TO_NS(2000));       

                                                                                if(chargin_hw_init_done)
                                                                                    /* 高压检测,应该是电池超过这个电压时,就不可以充电了 */
                                                                                    battery_charging_control(CHARGING_CMD_SET_HV_THRESHOLD,&hv_voltage);
                                                                                                             static kal_uint32 charging_set_hv_threshold(void *data)
                                                                                                             {
                                                                                                                kal_uint32 status = STATUS_OK;

                                                                                                                kal_uint32 set_hv_voltage;
                                                                                                                kal_uint32 array_size;
                                                                                                                kal_uint16 register_value;
                                                                                                                kal_uint32 voltage = *(kal_uint32*)(data);
                                                                                                                
                                                                                                                array_size = GETARRAYNUM(VCDT_HV_VTH);
                                                                                                                set_hv_voltage = bmt_find_closest_level(VCDT_HV_VTH, array_size, voltage); 
                                                                                                                register_value = charging_parameter_to_value(VCDT_HV_VTH, array_size ,set_hv_voltage);
                                                                                                                /* 设置 PMIC 的 CHR_CON1 */
                                                                                                                upmu_set_rg_vcdt_hv_vth(register_value);

                                                                                                                return status;
                                                                                                             }
                                                                                    
                                                                                wait_event_interruptible(charger_hv_detect_waiter, (charger_hv_detect_flag == KAL_TRUE));
                                                                            
                                                                                /* 如果检测到充电器,则检测下电池是否存在 */
                                                                                if ((upmu_is_chr_det() == KAL_TRUE))
                                                                                {
                                                                                    /* 检测电池是否存在 */
                                                                                    check_battery_exist(); 
                                                                                                void check_battery_exist(void)
                                                                                                {
                                                                                                #if defined(CONFIG_DIS_CHECK_BATTERY)
                                                                                                    battery_xlog_printk(BAT_LOG_CRTI, "[BATTERY] Disable check battery exist.\n");
                                                                                                #else
                                                                                                    kal_uint32 baton_count = 0;
                                                                                                    kal_uint32 charging_enable = KAL_FALSE;
                                                                                                    kal_uint32 battery_status;
                                                                                                    kal_uint32 i;

                                                                                                    for(i=0;i<3;i++)
                                                                                                    {
                                                                                                        /* 检测电池是否存在,通过读取 PMIC 的 CHR_CON7  */
                                                                                                        battery_charging_control(CHARGING_CMD_GET_BATTERY_STATUS,&battery_status);
                                                                                                                                static kal_uint32 charging_get_battery_status(void *data)
                                                                                                                                 {
                                                                                                                                      kal_uint32 status = STATUS_OK;

                                                                                                                                      upmu_set_baton_tdet_en(1);
                                                                                                                                      upmu_set_rg_baton_en(1);
                                                                                                                                      *(kal_bool*)(data) = upmu_get_rgs_baton_undet();
                                                                                                                                      
                                                                                                                                      return status;
                                                                                                                                 }
                                                                                                        baton_count += battery_status;

                                                                                                    }
                                                                                                       
                                                                                                    if( baton_count >= 3)
                                                                                                    {
                                                                                                        if( (g_platform_boot_mode==META_BOOT) || (g_platform_boot_mode==ADVMETA_BOOT) || (g_platform_boot_mode==ATE_FACTORY_BOOT) )
                                                                                                        {
                                                                                                            battery_xlog_printk(BAT_LOG_FULL, "[BATTERY] boot mode = %d, bypass battery check\n", g_platform_boot_mode);
                                                                                                        }
                                                                                                        else
                                                                                                        {
                                                                                                            battery_xlog_printk(BAT_LOG_FULL, "[BATTERY] Battery is not exist, power off FAN5405 and system (%d)\n", baton_count);
                                                                                                            
                                                                                                            //battery_charging_control(CHARGING_CMD_ENABLE,&charging_enable);
                                                                                                            //battery_charging_control(CHARGING_CMD_SET_PLATFORM_RESET,NULL);    
                                                                                                        }
                                                                                                    }    
                                                                                                #endif
                                                                                                }

                                                                                }
                                                                                
                                                                                charger_hv_detect_flag = KAL_FALSE;

                                                                                if(chargin_hw_init_done)
                                                                                    /* 查看 PMIC 是否开启了高压保护? */
                                                                                    battery_charging_control(CHARGING_CMD_GET_HV_STATUS,&hv_status);
                                                                                                             static kal_uint32 charging_get_hv_status(void *data)
                                                                                                             {
                                                                                                                  kal_uint32 status = STATUS_OK;

                                                                                                                  *(kal_bool*)(data) = upmu_get_rgs_vcdt_hv_det();
                                                                                                                  
                                                                                                                  return status;
                                                                                                             }


                                                                                if(hv_status == KAL_TRUE)
                                                                                {
                                                                                    battery_xlog_printk(BAT_LOG_CRTI, "[charger_hv_detect_sw_thread_handler] charger hv\n");    
                                                                                    
                                                                                    charging_enable = KAL_FALSE;
                                                                                    if(chargin_hw_init_done)
                                                                                        battery_charging_control(CHARGING_CMD_ENABLE,&charging_enable);
                                                                                }
                                                                                else
                                                                                {
                                                                                    battery_xlog_printk(BAT_LOG_FULL, "[charger_hv_detect_sw_thread_handler] upmu_chr_get_vcdt_hv_det() != 1\n");    
                                                                                }

                                                                                if(chargin_hw_init_done)
                                                                                    battery_charging_control(CHARGING_CMD_RESET_WATCH_DOG_TIMER,NULL);
                                                                               
                                                                                hrtimer_start(&charger_hv_detect_timer, ktime, HRTIMER_MODE_REL);    
                                                                                
                                                                            } while (!kthread_should_stop());
                                                                            
                                                                            return 0;
                                                                        }

                        if (IS_ERR(charger_hv_detect_thread))
                        {
                            battery_xlog_printk(BAT_LOG_FULL, "[%s]: failed to create charger_hv_detect_sw_workaround thread\n", __FUNCTION__);
                        }

                        battery_xlog_printk(BAT_LOG_CRTI, "charger_hv_detect_sw_workaround_init : done\n" );
                    }

    /*LOG System Set*/
    init_proc_log();

#endif   
	g_bat_init_flag = KAL_TRUE;
	
    return 0;
	
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 第二个调用的 probe 
static int mt_batteryNotify_probe(struct platform_device *dev)    
{
    int ret_device_file = 0;
    //struct proc_dir_entry *entry = NULL;
    struct proc_dir_entry *battery_dir = NULL;

    battery_xlog_printk(BAT_LOG_CRTI, "******** mt_batteryNotify_probe!! ********\n" );


    ret_device_file = device_create_file(&(dev->dev), &dev_attr_BatteryNotify);
    ret_device_file = device_create_file(&(dev->dev), &dev_attr_BN_TestMode);
    
    battery_dir = proc_mkdir("mtk_battery_cmd", NULL);
    if (!battery_dir)
    {
        pr_err("[%s]: mkdir /proc/mtk_battery_cmd failed\n", __FUNCTION__);
    }
    else
    {
        #if 1
        proc_create("battery_cmd", S_IRUGO | S_IWUSR, battery_dir, &battery_cmd_proc_fops);
        battery_xlog_printk(BAT_LOG_CRTI, "proc_create battery_cmd_proc_fops\n");
        #else
        entry = create_proc_entry("battery_cmd", S_IRUGO | S_IWUSR, battery_dir);
        if (entry)
        {
            entry->read_proc = battery_cmd_read;
            entry->write_proc = battery_cmd_write;
        }
        #endif
    }

    battery_xlog_printk(BAT_LOG_CRTI, "******** mtk_battery_cmd!! ********\n" );    
		
    return 0;

}







////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 电池测量模块初始化
module_init(battery_meter_init);
static int __init battery_meter_init(void)
{
    int ret;
    
    ret = platform_device_register(&battery_meter_device);
                                            struct platform_device battery_meter_device = {
                                                    .name                = "battery_meter",
                                                    .id                  = -1,
                                            };
    if (ret) {
        bm_print(BM_LOG_CRTI, "[battery_meter_driver] Unable to device register(%d)\n", ret);
        return ret;
    }
    
    ret = platform_driver_register(&battery_meter_driver);
                                            static struct platform_driver battery_meter_driver = {
                                                .probe        = battery_meter_probe,
                                                .remove       = battery_meter_remove,
                                                .shutdown     = battery_meter_shutdown,
                                                .suspend      = battery_meter_suspend,
                                                .resume       = battery_meter_resume,
                                                .driver       = {
                                                    .name = "battery_meter",
                                                },
                                            };
    if (ret) {
        bm_print(BM_LOG_CRTI, "[battery_meter_driver] Unable to register driver (%d)\n", ret);
        return ret;
    }

    bm_print(BM_LOG_CRTI, "[battery_meter_driver] Initialization : DONE \n");

    return 0;

}


/////////////////////////////////////////////////////////////////////
// 调用的 probe 
// ============================================================ //
static int battery_meter_probe(struct platform_device *dev)    
{
    int ret_device_file = 0;

	battery_meter_ctrl = bm_ctrl_cmd;

    bm_print(BM_LOG_CRTI, "[battery_meter_probe] probe\n");
    //select battery meter control method
     battery_meter_ctrl = bm_ctrl_cmd;
    //LOG System Set
    init_proc_log_fg();

	//last_oam_run_time = rtc_read_hw_time(); 
	getrawmonotonic(&last_oam_run_time);
    //Create File For FG UI DEBUG
    ret_device_file = device_create_file(&(dev->dev), &dev_attr_FG_Current);    
    ret_device_file = device_create_file(&(dev->dev), &dev_attr_FG_g_fg_dbg_bat_volt);
    ret_device_file = device_create_file(&(dev->dev), &dev_attr_FG_g_fg_dbg_bat_current);
    ret_device_file = device_create_file(&(dev->dev), &dev_attr_FG_g_fg_dbg_bat_zcv);
    ret_device_file = device_create_file(&(dev->dev), &dev_attr_FG_g_fg_dbg_bat_temp);
    ret_device_file = device_create_file(&(dev->dev), &dev_attr_FG_g_fg_dbg_bat_r);
    ret_device_file = device_create_file(&(dev->dev), &dev_attr_FG_g_fg_dbg_bat_car);
    ret_device_file = device_create_file(&(dev->dev), &dev_attr_FG_g_fg_dbg_bat_qmax);
    ret_device_file = device_create_file(&(dev->dev), &dev_attr_FG_g_fg_dbg_d0);
    ret_device_file = device_create_file(&(dev->dev), &dev_attr_FG_g_fg_dbg_d1);
    ret_device_file = device_create_file(&(dev->dev), &dev_attr_FG_g_fg_dbg_percentage);
    ret_device_file = device_create_file(&(dev->dev), &dev_attr_FG_g_fg_dbg_percentage_fg);
    ret_device_file = device_create_file(&(dev->dev), &dev_attr_FG_g_fg_dbg_percentage_voltmode);

    return 0;
}





















你可能感兴趣的:(【转载】【非常好】MTK 电池流程.c)