PMIC驅動分析


 

一.初始化分析

Pmic.c (kernel-3.10\drivers\misc\mediatek\power\mt6735)
 
struct platform_device pmic_mt_device = {
    .name   = "mt-pmic",
    .id        = -1,
};
 
static struct platform_driver pmic_mt_driver = {
    .probe        = pmic_mt_probe,
    .remove       = pmic_mt_remove,
    .shutdown     = pmic_mt_shutdown,
    //#ifdef CONFIG_PM
    .suspend      = pmic_mt_suspend,
    .resume       = pmic_mt_resume,
    //#endif
    .driver       = {
        .name = "mt-pmic",
    },
};
 
pmic_mt_init
    ret = platform_device_register(&pmic_mt_device);
    ret = platform_driver_register(&pmic_mt_driver); //進入probe
    pmic_auxadc_init();//
Pmic_auxadc.c (kernel-3.10\drivers\misc\mediatek\power\mt6735)
 
 
 
 
二.probe函數
    pmic_mt_probe
        PMIC_INIT_SETTING_V1
 
            pmic_set_register_value(PMIC_WDTRSTB_STATUS_CLR,1); //
            .......一系列寄存器的初始化。。。。。
            PMIC_CUSTOM_SETTING_V1
                pmu_drv_tool_customization_init(); //DCT,也就是dct/DrvGen
            //PMIC Interrupt Service
    pmic_thread_handle = kthread_create(pmic_thread_kthread, (void *) NULL, "pmic_thread");
            wake_up_process(pmic_thread_handle); //運行這個thread,單獨分析1
            PMIC_EINT_SETTING();  //中斷設置,單獨分析2
            mtk_regulator_init
                mtk_ldos[MT6328_POWER_LDO_VMC].pvoltages=(void *)mt6328_VMC_E1_2_voltages; //設置SD2.0/3.0  memory card用到的電壓
                for (i = 0; i < ARRAY_SIZE(mtk_ldos); i++) //設置pmic輸出的ldos
                    ......對每個ldo進行賦值,mtk_ldos是個數組,原型是mtk_regulator,在pmic.h中聲明
                    mtk_ldos[i].rdev= regulator_register(&mtk_ldos[i].desc,&mtk_ldos[i].config); //注冊regulator
                    //lookup and obtain a reference to a regulator.
                    mtk_ldos[i].reg=regulator_get(&(dev->dev), mtk_ldos[i].desc.name); 
            low_battery_protect_init(); //初始化電池電量過低保護
            battery_oc_protect_init(); //應該是電池大電流保護
            bat_percent_notify_init //電池電量通知,單獨分析3
            dlpt_notify_init //動態頻率調節,單獨分析4
            pmic_debug_init //調試節點初始化
                proc_mkdir("mt_pmic", NULL); ///proc/mt_pmic
                proc_create("dump_ldo_status", S_IRUGO | S_IWUSR, mt_pmic_dir, &pmic_debug_proc_fops); //打印ldo
                proc_create("dump_pmic_reg", S_IRUGO | S_IWUSR, mt_pmic_dir, &pmic_dump_register_proc_fops); //打印寄存器
           pmic_ftm_init  //初始化,提供一些接口給應用,這里不太重要
                alloc_chrdev_region(&pmic_devno, 0, 1, PMIC_DEVNAME);
                pmic_cdev = cdev_alloc();
                pmic_cdev->owner = THIS_MODULE;
                pmic_cdev->ops = &pmic_ftm_fops;
                ret = cdev_add(pmic_cdev, pmic_devno, 1);
                pmic_class = class_create(THIS_MODULE, PMIC_DEVNAME);
            for (i = 0; i < ARRAY_SIZE(mtk_bucks); i++) //降壓濾波,DCDC口的調試sysfs,/sys/devices/platform/mt-pmic
                ret_device_file = device_create_file(&(dev->dev),&mtk_bucks[i].en_att);
ret_device_file = device_create_file(&(dev->dev),&mtk_bucks[i].voltage_att);
            for (i = 0; i < ARRAY_SIZE(mtk_ldos); i++) //LDO的sysfs
                ret_device_file = device_create_file(&(dev->dev),&mtk_ldos[i].en_att);
ret_device_file = device_create_file(&(dev->dev),&mtk_ldos[i].voltage_att);
            device_create_file(&(dev->dev), &dev_attr_pmic_access); //讀取寄存器的接口
            .........其他的一些調試接口..............
                
            
 
 
三.單獨分析
1.單獨分析1
static struct pmic_interrupts interrupts[] = {
PMIC_M_INTS_GEN(MT6328_INT_STATUS0,MT6328_INT_CON0,MT6328_INT_CON0_SET,MT6328_INT_CON0_CLR,interrupt_status0),
PMIC_M_INTS_GEN(MT6328_INT_STATUS1,MT6328_INT_CON1,MT6328_INT_CON1_SET,MT6328_INT_CON1_CLR,interrupt_status1),
PMIC_M_INTS_GEN(MT6328_INT_STATUS2,MT6328_INT_CON2,MT6328_INT_CON2_SET,MT6328_INT_CON2_CLR,interrupt_status2),
};
 
pmic_thread_kthread
    //sched_setscheduler()函數將pid所指定進程的調度策略和調度參數分別設置為param指向的sched_param結構中指定的policy和參數。sched_param結構中的sched_priority成員的值可以    為任何整數,該整數位於policy所指定調度策略的優先級范圍內(含邊界值)。policy參數的可能值在頭文件中定義。
    sched_setscheduler(current, SCHED_FIFO, &param); //這里是FIFO優先級策略調度,優先級是98
    set_current_state(TASK_INTERRUPTIBLE); //可以中斷的等待
    pmic_enable_charger_detection_int
        pmic_rdy=1; //賦值為1
    while (1) {
 
        pmic_wrap_eint_status //得到PMIC到AP中斷腳的狀態
            mt_pmic_wrap_eint_status
                WRAP_RD32(PMIC_WRAP_EINT_STA); //INT related control, this INT is for PMIC chip to AP
        pmic_int_handler //配置初始化PMIC中斷
            for (i = 0; i < ARRAY_SIZE(interrupts); i++) //有3個寄存器
                interrupts[i].interrupts[j].callback(); //找到具體的中斷,調用中斷處理函數,這里分析插拔充電器,單獨分析5
interrupts[i].interrupts[j].times++;
                ret=pmic_config_interface(interrupts[i].address,0x1,0x1,j);
        pmic_wrap_eint_clr(0x0); //清除
            mt_pmic_wrap_eint_clr
                WRAP_WR32(PMIC_WRAP_EINT_CLR,(1<<offset));
        int_status_val=upmu_get_reg_value(interrupts[i].address); //得到中斷狀態
 
 
 
 
2.單獨分析2
PMIC_EINT_SETTING
    //enable pwrkey/homekey interrupt
    upmu_set_reg_value(MT6328_INT_CON0_SET, 0xf);
    //for all interrupt events, turn on interrupt module clock
    pmic_set_register_value(PMIC_RG_INTRP_CK_PDN,0);
    //For BUCK OC related interrupt, please turn on pwmoc_6m_ck (6MHz) ,DCDC相關降壓口
    pmic_set_register_value(PMIC_RG_PWMOC_6M_CK_PDN,0);
    pmic_register_interrupt_callback(0,pwrkey_int_handler);  //電源鍵按下中斷回調

    pmic_register_interrupt_callback(1,homekey_int_handler); //home鍵按下相關回調
    pmic_register_interrupt_callback(2,pwrkey_int_handler_r);  //電源鍵釋放中斷回調
    pmic_register_interrupt_callback(3,homekey_int_handler_r); //home鍵釋放中斷回調
    pmic_register_interrupt_callback(6,bat_h_int_handler);  

        g_low_battery_level=0;
exec_low_battery_callback(LOW_BATTERY_LEVEL_0); //調用回調函數,由register_low_battery_notify注冊的回調函數
            low_battery_callback = lbcb_tb[i].lbcb;
            low_battery_callback(low_battery_level); //執行回調函數
        pmic_set_register_value(PMIC_AUXADC_LBAT_VOLT_MIN,BAT_LV_1_THD); //最小值設置為3.25V
        lbat_min_en_setting(0);
lbat_max_en_setting(0); //關閉setting
        lbat_min_en_setting(1); //啟動setting,打開中斷
    pmic_register_interrupt_callback(7,bat_l_int_handler); //與bat_h_int_handler差不多,這里設置為3V
    pmic_register_interrupt_callback(38,chrdet_int_handler); //單獨分析5,充電器的插入
       
    pmic_register_interrupt_callback(42,fg_cur_h_int_handler);
        g_battery_oc_level=0;
        exec_battery_oc_callback(BATTERY_OC_LEVEL_0); //調用register_battery_oc_notify注冊的函數
        bat_oc_h_en_setting(0);
        bat_oc_l_en_setting(0);
        bat_oc_l_en_setting(1); //使能低電流中斷
    pmic_register_interrupt_callback(43,fg_cur_l_int_handler); //與fg_cur_h_int_handler差不多
    mt_eint_registration(g_eint_pmic_num,g_cust_eint_mt_pmic_type,mt_pmic_eint_irq,0); //注冊中斷
        wake_up_pmic();
            wake_up_process(pmic_thread_handle);
                pmic_thread_kthread //執行這個函數,前面有分析
    
 
3.單獨分析3
bat_percent_notify_init
    ktime = ktime_set(20, 0); //20s
    hrtimer_init(&bat_percent_notify_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
    bat_percent_notify_timer.function = bat_percent_notify_task;    
    hrtimer_start(&bat_percent_notify_timer, ktime, HRTIMER_MODE_REL);
    bat_percent_notify_thread = kthread_run(bat_percent_notify_handler, 0, "bat_percent_notify_thread");
    
 
電池線程調用函數
bat_percent_notify_handler
    ktime = ktime_set(10, 0);  //10s
    wait_event_interruptible(bat_percent_notify_waiter, (bat_percent_notify_flag == KAL_TRUE));
    bat_per_val=bat_get_ui_percentage(); //得到bat的電量
        if (chr_wake_up_bat == KAL_TRUE)
return BMT_status.SOC;
else
return BMT_status.UI_SOC;
    //如果(沒有充電器&&電池電量保護LEVE = 0&& 電量小於等於15%)
    if( (upmu_get_rgs_chrdet()==0) && (g_battery_percent_level==0) && (bat_per_val<=BAT_PERCENT_LINIT) )
        g_battery_percent_level=1;
        exec_battery_percent_callback(BATTERY_PERCENT_LEVEL_1); //其他模塊通過register_battery_percent_notify注冊回調函數
            battery_percent_callback = bpcb_tb[i].bpcb;  //注冊的回調函數bpcb_tb[i].bpcb;
            battery_percent_callback(battery_percent_level); //調用
    //如果(g_battery_percent_level = 1 && 電量大於15%)
    else if( (g_battery_percent_level==1) && (bat_per_val>BAT_PERCENT_LINIT) )
        g_battery_percent_level=0;
        exec_battery_percent_callback(BATTERY_PERCENT_LEVEL_0); //一樣的回調函數
    hrtimer_start(&bat_percent_notify_timer, ktime, HRTIMER_MODE_REL); //啟動定時器
 
 
定時器執行函數
bat_percent_notify_task
    bat_percent_notify_flag = KAL_TRUE; 
    wake_up_interruptible(&bat_percent_notify_waiter); //喚醒電池線程調用函數
 
 
4.單獨分析4
dlpt_notify_init
    
ktime = ktime_set(30, 0); //30s
 
    hrtimer_init(&dlpt_notify_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
    dlpt_notify_timer.function = dlpt_notify_task;    //定時器執行函數
    hrtimer_start(&dlpt_notify_timer, ktime, HRTIMER_MODE_REL);
    dlpt_notify_thread = kthread_run(dlpt_notify_handler, 0, "dlpt_notify_thread"); //線程執行函數
    pmic_set_register_value(PMIC_RG_UVLO_VTHL,0); //設置低壓鎖定電壓為2.5V
    switch(POWER_UVLO_VOLT_LEVEL) //現在設置是2.6v
        pmic_set_register_value(PMIC_RG_UVLO_VTHL,3);
 
 
低電壓鎖定線程
dlpt_notify_handler
    pre_ui_soc=bat_get_ui_percentage(); //獲取電量
    cur_ui_soc=pre_ui_soc;
    do //下面都是循環
        ktime = ktime_set(10, 0);  //10s
        wait_event_interruptible(dlpt_notify_waiter, (dlpt_notify_flag == KAL_TRUE));
        cur_ui_soc=bat_get_ui_percentage();  //獲取電量
        if (upmu_get_rgs_chrdet())    //如果有充電器
            g_imix_val=get_dlpt_imix_charging();
                zcv_val=PMIC_IMM_GetOneChannelValue(MT6328_AUX_ISENSE_AP,5,1); //電池電壓
                imix_val=(zcv_val-vsys_min_1_val)*1000/ptim_rac_val_avg*9/10; ==》imix值
else
     g_imix_val=get_dlpt_imix();
                //adc and fg--------------------------------------------------------
do_ptim(KAL_FALSE); //得到一些值
                imix=(curr_avg+(volt_avg-g_lbatInt1)*1000/ptim_rac_val_avg)/10; ==>imix值
         if(g_imix_val >= 1)
     exec_dlpt_callback(g_imix_val);    
                dlpt_callback = dlpt_cb_tb[i].dlpt_cb;                
                dlpt_callback(g_dlpt_val);          //執行register_dlpt_notify 注冊的回調函數         
         else
            exec_dlpt_callback(1);
 
定時器執行函數
dlpt_notify_task
    dlpt_notify_flag = KAL_TRUE; 
    wake_up_interruptible(&dlpt_notify_waiter);
 
 
 
//單獨分析5,充電器插拔
 
chrdet_int_handler
    if (!upmu_get_rgs_chrdet())
    boot_mode = get_boot_mode();
    if(boot_mode == KERNEL_POWER_OFF_CHARGING_BOOT || boot_mode == LOW_POWER_OFF_CHARGING_BOOT)
        mt_power_off(); //關機
    pmic_set_register_value(PMIC_RG_USBDL_RST,1); //強制離開usb Down load模式
    do_chrdet_int_task  //在Battery_common.c (kernel-3.10\drivers\power\mediatek)
        if (upmu_is_chr_det() == KAL_TRUE) //==》get_charger_detect_status();mt_usb_is_device
            BMT_status.charger_exist = KAL_TRUE;
        else
            BMT_status.charger_exist = KAL_FALSE;
            if (g_platform_boot_mode == KERNEL_POWER_OFF_CHARGING_BOOT || g_platform_boot_mode == LOW_POWER_OFF_CHARGING_BOOT) //關機充電拔出
                battery_charging_control(CHARGING_CMD_SET_POWER_OFF, NULL); //停止充電
        mt_battery_charger_detect_check(); //檢測充電器
            if (upmu_is_chr_det() == KAL_TRUE) //再次調用upmu_is_chr_det
                BMT_status.charger_exist = KAL_TRUE;
                mt_charger_type_detection(); //檢測是那種充電器插入,在代碼中的電量相關,充電模式第五章
                if ((BMT_status.charger_type == STANDARD_HOST) || (BMT_status.charger_type == CHARGING_HOST))  //如果是這兩種
mt_usb_connect(); //ubs連接
            else
                BMT_status.charger_exist = KAL_FALSE;
BMT_status.charger_type = CHARGER_UNKNOWN;
                mt_usb_disconnect(); //斷開連接
 
 
 
 

    
 
        
        
        
        
    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM