關於MTK android平台使用PMIC的調試

PMIC是power management IC的縮寫,中文是電源管理集成電路,主要特點是高集成度,將擁傳統的多路輸出電源封裝在一顆晶片內,使得多電源應用場景高效率更高,體積更小。

CPU系統中,我們經常用到的PMIC。如手機,平板,機頂盒設計,智能語音音箱設計,大型工控設備設計等,下面是關於在MTK平台mt6371的調試。

我們在移植外設得時候,經常需要使用得PMIC來控制系統時鐘得輸出,如客戶外接NFC設備時,如果想要使用co-clock方案,需要打開PMIC提供的clock buffer:XO_NFC。由於默認XO_NFC是關閉的,需要客戶修改代碼來打開。
 
 
1、vendor\mediatek\proprietary\bootable\bootloader\preloader\platform\\src\drivers\Clkbuf_ctl.c 

#define PMIC_CW00_INIT_VAL 0x4E1D --> 改成0x4EDD

2、kernel-4.9\drivers\misc\mediatek\base\power\clkbuf_v1\\Mtk_clkbuf_hw.c
void clk_buf_post_init(void)
{
#ifndef CONFIG_NFC_CHIP_SUPPORT --> 請將此處改為#if 0
/* no need to use XO_NFC if no NFC */
clk_buf_ctrl_internal(CLK_BUF_NFC, false);
#endif
}​

我們可以使用Dump命令來檢查clkbuf是不是設置正確,可以參考一下dump說明。

cat /sys/kernel/clk_buf/clk_buf_ctrl

dump 出的結果如下:
XO_SOC SW(1)/HW(2) CTL: 2, Dis(0)/En(1): 1, RS: 1
XO_WCN SW(1)/HW(2) CTL: 1, Dis(0)/En(1): 1, RS: 1
XO_NFC SW(1)/HW(2) CTL: 0, Dis(0)/En(1): 0, RS: 0 //此處還是看RS是否為1,1則有enable信號,0則沒有。
XO_CEL SW(1)/HW(2) CTL: 2, Dis(0)/En(1): 1, RS: 1
XO_AUD SW(1)/HW(2) CTL: 0, Dis(0)/En(1): 0, RS: 0
XO_PD SW(1)/HW(2) CTL: 0, Dis(0)/En(1): 0, RS: 0
XO_EXT SW(1)/HW(2) CTL: 0, Dis(0)/En(1): 0, RS: 0
.********** clock buffer debug info **********
DCXO_CW00=0x4e1d //此處用於檢查XO_BUF3的設定是否正確,如果NFC要用,一般要設為0X4EDD.
DCXO_CW01=0x6d55
DCXO_CW02=0x3aee
DCXO_CW03=0x842b
DCXO_CW04=0xff88
DCXO_CW05=0xdd40
DCXO_CW06=0x2318
DCXO_CW07=0x8ffe
DCXO_CW08=0x46be
DCXO_CW09=0x8f
DCXO_CW10=0xef50
DCXO_CW11=0x8000
DCXO_CW12=0x8a75
DCXO_CW13=0x98e9
DCXO_CW14=0x82b5
DCXO_CW15=0xa2aa
DCXO_CW16=0x9455
DCXO_CW17=0x7773
DCXO_CW18=0x7
DCXO_CW19=0x9887
pmic-srclkeni3(srclken_conn)=0x0
CLK_BUF1_STATUS=2
CLK_BUF2_STATUS=1
CLK_BUF3_STATUS=0
CLK_BUF4_STATUS=2
CLK_BUF5_STATUS=0
CLK_BUF6_STATUS=0
CLK_BUF7_STATUS=0
CLK_BUF1_DRIVING_CURRENT=1
CLK_BUF2_DRIVING_CURRENT=1
CLK_BUF3_DRIVING_CURRENT=1
CLK_BUF4_DRIVING_CURRENT=1
CLK_BUF5_DRIVING_CURRENT=1
CLK_BUF6_DRIVING_CURRENT=1
CLK_BUF7_DRIVING_CURRENT=1
buf01mode = WCN_BUF24_EN(0x3), en_m = sw disable(0)
buf03mode = CEL_BUF24_EN(0x3), en_m = sw enable(1)
DCXO_CONN_ADR0/WDATA0/ADR1/WDATA1=0x44a 0 44a 1
DCXO_NFC_ADR0/WDATA0/ADR1/WDATA1=0x78c 100 78a 100
DCXO_ENABLE=0x3, flight mode = 0 bblpm = 0
PMIC_CLKBUF_DRV_CURR (1/2/3/4/6/7)= 1 1 1 1 3 1
.********** clock buffer command help **********
PMIC switch on/off: echo pmic en1 en2 en3 en4 en5 en6 en7 > /sys/kernel/clk_buf/clk_buf_ctrl
 

Android R 如何對pmic進行讀寫操作

 
確認有需求對pmic進行讀寫的設備是否為pmic的子設備,確認方法:
查看pmic dts文件,是否為子設備結點,比如:
mt6357-accdet的設備定義:

&main_pmic {
pmic_accdet: pmic_accdet {

compatible = "mediatek,mt6357-accdet";



如果確認是pmic子設備,可以按照方案1,進行。
如果不是pmic子設備,應該按照方案2,執行。

方案1:
1.include頭文件,到目標文件
#include <linux/mfd/mt6397/core.h>
#include <linux/regmap.h>

2.定義:struct mt6397_chip *chip; 建議定義為全局變量

3.在probe函數中,添加:
chip = dev_get_drvdata(pdev->dev.parent);

也許對應函數的probe,pdev定義不同,目前示例的pdev定義為platform_device
比如:static int mt6357_gauge_probe(struct platform_device *pdev)

4.寄存器讀寫

讀操作:
int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)

參數填寫方式:regmap_read(chip->regmap,address,val)

參數1,為固定格式如上.
參數2為address:查詢reg地址,文件路徑示例 /kernel-4.19/include/linux/mfd/mt6357/registers.h
參數3:讀取出來的值,要保存的變量,注意是地址傳入。

寫操作:

int regmap_write(struct regmap *map, unsigned int reg, unsigned int val)
參數填寫方式:regmap_read(chip->regmap,address,val)

參數1,為固定格式如上.
參數2為address:查詢reg地址,文件路徑示例 /kernel-4.19/include/linux/mfd/mt6357/registers.h
參數3:寫一個整數值就好。



如果僅更新某個bit,可以用如下方式:
regmap_update_bits(map, reg, mask, val)

相關定義:
#define regmap_update_bits(map, reg, mask, val) \
regmap_update_bits_base(map, reg, mask, val, NULL, false, false)


示例:

regmap_update_bits(chip->regmap,address,mask,val)
參數1:為上面固定格式
參數2:address查詢reg地址,文件路徑示例 /kernel-4.19/include/linux/mfd/mt6357/registers.h
參數3:mask,即要更新的bit
參數4,更新的val

比如更新bit 11的值為1,此時可以這樣寫:
regmap_update_bits(chip->regmap,address,1<< 11,1<< 11);//11可以理解為shift
方案2:

如果需要操作pmic reg的device不是pmic的子設備,那麼在方案1中的第3步,就不能使用,需要做如下調整:
相關定義和封裝,可以參考,charger相關格式:
/kernel-4.19/drivers/power/supply/mtk_charger_intf.c

int disable_hw_ovp(struct mtk_charger *info, int en)
{
struct device_node *pmic_node;
struct platform_device *pmic_pdev;
struct mt6397_chip *chip;
struct regmap *regmap;

pmic_node = of_parse_phandle(info->pdev->dev.of_node, "pmic", 0);首先從dts裡面解析PMIC相關node
if (!pmic_node) {
chr_err("get pmic_node fail\n");
return -1;
}

pmic_pdev = of_find_device_by_node(pmic_node);再找到相關device
if (!pmic_pdev) {
chr_err("get pmic_pdev fail\n");
return -1;
}
chip = dev_get_drvdata(&(pmic_pdev->dev));最後獲取相關chip指針

if (!chip) {
chr_err("get chip fail\n");
return -1;
}

regmap = chip->regmap;此時,就可以拿到如方案1的regmap了。


//這個函數是charger的rd做了一個封裝
pmic_set_register_value(regmap,
PMIC_RG_VCDT_HV_EN_ADDR,
PMIC_RG_VCDT_HV_EN_SHIFT,
PMIC_RG_VCDT_HV_EN_MASK,
en);

return 0;
}


相關封裝函數:
static void pmic_set_register_value(struct regmap *map,
unsigned int addr,
unsigned int mask,
unsigned int shift,
unsigned int val)
{
regmap_update_bits(map,
addr,
mask << shift,
val << shift);
}

★博文內容均由個人提供,與平台無關,如有違法或侵權,請與網站管理員聯繫。

★文明上網,請理性發言。內容一周內被舉報5次,發文人進小黑屋喔~

評論