linux驱动-项目杂记

用于记录项目中乱七八糟的东西,不定期更新,没有排版。

一、G90(mt67850)-SIM卡功能

1、支持双卡,配置config文件

路径:

1
/device/mediateksample/k85v1_64/ProjectConfig.mk

修改参数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
MTK_SIM1_SOCKET_TYPE = 1
MTK_SIM2_SOCKET_TYPE = 1
MTK_SIM_CARD_ONOFF = 2
MTK_SIM_HOT_SWAP = yes
MTK_SIM_HOT_SWAP_COMMON_SLOT = no
MTK_SIM_LOCK_POWER_ON_WRITE_PROTECT = no
MTK_SIM_RECOVERY = yes

MTK_MULTI_SIM_SUPPORT = dsds //一般只需修改这个就好了,其他都是默认配好的,单卡配置成ss

SIM_ME_LOCK_MODE = 3
SIM_REFRESH_RESET_BY_MODEM = yes
MTK_EAP_SIM_AKA = yes
MTK_EXTERNAL_SIM_ONLY_SLOTS = 0
MTK_EXTERNAL_SIM_SUPPORT = no

2、配置dct文件

路径:

1
2
3
4
\vendor\mediatek\proprietary\scripts\dct\DrvGen.exe //dct配置工具
\vendor\mediatek\proprietary\bootable\bootloader\lk\target\k85v1_64\dct\dct\codegen.dws //lk下dct路径
\vendor\mediatek\proprietary\bootable\bootloader\preloader\custom\k85v1_64\dct\dct\codegen.dws //pl下dct路径
\kernel-4.14\drivers\misc\mediatek\dws\mt6785\codegen.dws //kernel下dct路径

配置根据中断检测脚状态来配置

如果插入sim卡为高电平拔出时为低电平则配置 PlugOutPolarity 为低电平
如果插入sim卡为低电平拔出时为高电平则配置 PlugOutPolarity 为高电平

我的为第一种情况因此如下配置:

二、tf卡配置

1、配置中断引脚

1
2
3
4
5
6
7
8
9
路径: /arch/arm64/boot/dts/mediatek/cust_mt6785_msdc.dtsi

具体修改: 原理图使用的 msdc1

host_function = /bits/ 8 <MSDC_SD>;

- cd_level = /bits/ 8 <MSDC_CD_LOW>;
+ cd_level = /bits/ 8 <MSDC_CD_HIGH>; //由于插入tf卡中断检测脚为高这里修改为高电平触发
cd-gpios = <&pio 8 0>;

2、配置下电方式

mt6360 的 sdcard 的下电方式可以配置选择

我的原理图长这样

=-= 我的原理图插入 sd 卡之后,EINT_SD 会被拉高,由于它和 SD_CARD_DET_N_PMU 短接在一起的,因此 SD_CARD_DET_N_PMU 跟着被拉高了,于是满图上图第一种情况 active high,LD05 被拉低。。。。。,sd卡的供电就被拉低了,现象就是插上tf卡供电就掉下来 =w= 导致tf卡没功能。这种情况需要配置为上图的第二种状态 active low,配置如下。

1
2
3
4
5
6
7
路径: drivers/misc/mediatek/pmic/mt6360/ldo/mt6360_ldo_i2c.c
具体修改:

static const struct mt6360_ldo_platform_data def_platform_data = {
- .sdcard_det_en = true,
+ .sdcard_det_en = false,
};

除此之外记得检测卡托,卡托和卡座一定要匹配,不匹配的卡托可能会在插入的过程中短路,导致 pmic 因为自身的保护机制直接关掉对应的 ldo5 引脚供电,这种情况和上面出现的现象是一样的。

三、G90(mt6785)-快充配置

这款芯片是支持快充的,默认没有打开需要手动配置一下

1、快充说明

1) 充电策略

VAT在比较小的时候,转换效率很低:假设VBAT=3.4V,IBAT=3A,当VBUS=7.5V的时候,转换效率为82.7%,当VBUS=12V的时候,转换效率为80.51%,差了接近%2;而当VBAT比较高的时候,转换效率对电压就不会很敏感,在VBAT=4V的情况下,最低一档的转换效率都有86.94%,所以mtk的充电策略:在保证充电功率的情况下,转换效率尽可能的高

2) 温度控制充电

1
2
max_charge_temp = <50>; //大于50°停止充电
max_charge_temp_minux_x_degree = <47>; //从50°降低到47°之后,允许充电

3) 充电检测

手机插入充电线之后,会走一个充电器类型检测,这个检测流程软硬件都有参与,要满足最基本的 BC1.2 协议才会充电,协议规定几种接口,DCP,SDP,CDP都是5v,mtk 有类似的机制在 dual charger 进入 PE40 的时候,会判断当前点量来决定跑不跑 dual charger 快充,涉及 dts 里面

1
pe40_stop_battery_soc,pd_stop_battery_sooc

4) 充电挡位支持

PE快充可以支持三档7v、9v、12v,三选一,

当使用 switch_charger 时没有这种机制,在 85% 电量的时候插入充电器,它一样是跑 switch_charger, 和手机插着充电器从 0% 开始一直充电没有差别

5) mtk 电量计算法

MTK的电量算法是由 driver 和上层的 daemon组成的,
电量变化时 Gauge 的硬件产生中断来通知 driver,
然后由 driver 将电量计算要用的值传到上层 daemon,
上层计算出的 SOC 会用您问题中的 CMD FG_DAEMON_CMD_SET_KERNEL_UISOC 再写到 kernel。

6) 相关参数含义

ICHG = “設定的充電電流”,
AICR = “AICR 保護下允許的最高抽電流”
MIVR = “設定的允許的充電器最低電壓”
IEOC = “設定的截止充電電流”
CV = “設定的Constant Voltage 值”
VSYS = “量測到的 VSYS 值”
VBAT = “测量到的电池电压”
IBAT = “测量到的充电电流”
IBUS = “测量到充电器的电流”
VBUS = “测量到充电器的电压”
soc = 底层电量百分比
uiso = 上层显示电量百分比
CT = 充电器类型

2、打开dts中的相关配置

具体修改:
/kernel-4.14/arch/arm64/boot/dts/mediatek/mt6785.dts b/arch/arm64/boot/dts/mediatek/mt6785.dts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
        charger: charger {
compatible = "mediatek,charger";
algorithm_name = "SwitchCharging";
//修改前
- /* enable_sw_jeita; */
- /* enable_pe_plus; */
- /* enable_pe_2; */
- /* enable_pe_3; */
- /* enable_pe_4; */
//修改后
+ enable_sw_jeita;
+ enable_pe_plus;
+ enable_pe_2;
+ enable_pe_3;
+ enable_pe_4;

enable_type_c;
power_path_support;
enable_dynamic_mivr;
/* common */
battery_cv = <4350000>; //cv 电压,如果想提高快充时间可以适当调高,不过要考虑到电池耐压。
max_charger_voltage = <6500000>;
min_charger_voltage = <4600000>;

/* dynamic mivr */
min_charger_voltage_1 = <4400000>;
min_charger_voltage_2 = <4200000>;
max_dmivr_charger_current = <1400000>;

/* charging current */
usb_charger_current_suspend = <0>;
usb_charger_current_unconfigured = <70000>;
usb_charger_current_configured = <500000>;
usb_charger_current = <500000>;
ac_charger_current = <2050000>; // 普通充电的 ichg
ac_charger_input_current = <2050000>; // ibus
non_std_ac_charger_current = <500000>;
charging_host_charger_current = <1500000>;
apple_1_0a_charger_current = <650000>;
apple_2_1a_charger_current = <800000>;
ta_ac_charger_current = <3000000>; //快充的 ichg

......

/* PD */
pd_vbus_low_bound = <5000000>; //支持的充电最低电压,pd->vbus_l
pd_vbus_upper_bound = <9000000>; //支持的充电最高电压,pd->vbus_h
pd_ichg_level_threshold = <1000000>; /* uA */
pd_stop_battery_soc = <90>; //停止快充电量,gm3 已经舍弃

ibus_err = <14>;
vsys_watt = <5000000>;

kernel-4.14/arch/arm64/boot/dts/mediatek/bat_setting/mt6765_battery_prop.dtsi

1
2
3
4
5
6
7
8
9
10
11
12
13
bat_gm30: battery{
compatible = "mediatek,bat_gm30";
......
/* The ui_soc will keep 100% until SOC drop X percents after unplugged*/
R_FG_VALUE = <(10)>; //rf 电阻用于测量充电流,需要校准
......
ACTIVE_TABLE = <(4)>; //这里要注意一下,我们用到的电池参数table一般为四个
/* Table numbers per battery*/
MULTI_TEMP_GAUGE0 = <(1)>;
/* Multi gauge0 enable*/
#include "mt6785_battery_table.dtsi" // ACTIVE_TABLE 的值就是里面的参数的数组数量。
#include "mt6785_battery_prop_dim2_ext.dtsi"
};

3、修改 kernel 下的 config 文件

1
2
3
4
5
6
7
8
9
/kernel-4.14/arch/arm64/configs/k85v1_64_defconfig b/arch/arm64/configs/k85v1_64_defconfig

CONFIG_ACCDET_EINT_IRQ=y
CONFIG_ACCDET_SUPPORT_EINT0=y
CONFIG_MTK_LENS=y

//增加相关配置
+CONFIG_MTK_PUMP_EXPRESS_PLUS_SUPPORT=y
+CONFIG_MTK_PUMP_EXPRESS_PLUS_20_SUPPORT=y
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/device/mediateksample/k85v1_64/ProjectConfig.mk b/mediateksample/k85v1_64/ProjectConfig.mk

MTK_PROTOCOL2_RAT_CONFIG = L/W/G
MTK_PROTOCOL3_RAT_CONFIG = G

//修改前
-MTK_PUMP_EXPRESS_PLUS_SUPPORT = no
-MTK_PUMP_EXPRESS_PLUS_20_SUPPORT = no

MTK_PUMP_EXPRESS_PLUS_30_SUPPORT = no

//修改后
+MTK_PUMP_EXPRESS_PLUS_20_SUPPORT = yes
+MTK_PUMP_EXPRESS_PLUS_SUPPORT = yes

MTK_PUMP_EXPRESS_SUPPORT = no
MTK_RADIOOFF_POWER_OFF_MD = no
MTK_RAT_WCDMA_PREFERRED = no

4、vendor 目录下修改lk配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/vendor/mediatek/proprietary/bootable/bootloader/lk/project/k85v1_64.mk b/mediatek/proprietary/bootable/bootloader/lk/project/k85v1_64.mk

DEFINES += MTK_NEW_COMBO_EMMC_SUPPORT
DEFINES += MTK_GPT_SCHEME_SUPPORT
MTK_CHARGER_NEW_ARCH := yes

//修改前
-MTK_PUMP_EXPRESS_PLUS_SUPPORT := no

//修改后
+MTK_PUMP_EXPRESS_PLUS_SUPPORT := yes

MTK_CHARGER_INTERFACE := yes
MTK_MT6360_PMU_CHARGER_SUPPORT := yes
MTK_LCM_PHYSICAL_ROTATION = 0

5、mt6360 pd 快充升压逻辑gm3.0

代码调用流程

1
2
3
4
5
6
swchg_select_charging_current_limit
--> mtk_pdc_get_setting //这里判断是否要升压,并获取要设置的电压
--> mtk_pdc_setup //设置当前应当使用的电压
--> adapter_dev_set_cap(info->pd_adapter, MTK_PD,pd->cap.max_mv[idx], pd->cap.ma[idx]); // 设置电压
--> mtk_pdc_get_idx(info, idx, &pd->pd_boost_idx, &pd->pd_buck_idx); // 基于当前设置的电压,更新升压,降压选项

1) 升压算法

pd 的升压逻辑很简单,就是检测当前需要的功耗是否达到了需要升压的高阈值。如果是则升压,如果低于低阈值则降压,否则使用当前电压。

pd_max_watt = 12400000 //升压功耗的高阈值
pd_min_watt = 7900000 // 升压的功耗低阈值
now_max_watt = cap->max_mv[idx] * ibus + chg2_watt; //当前经过计算需要的功耗

升压举例说明:

当前的 idx = 0 使用 5v 充电各个参数如下

idx = selected_idx = 0 //选择 5000
boost_idx = 1 // 选择 9000 ,当前挡位电压下的升压电压
buck_idx = 0 // 选择 5000 ,当前挡位下的降压电压

总结: 当 now_max_watt > pd_max_watt 则选择升压到当前电压的高一级电压,当 now_max_watt < pd_min_watt 则降低一级电压,在中间则保持不变。需要注意的是 chg1_mivr 和 chg2_mivr 也会决定了是否升压,至于这两个的判定条件是啥我也没研究清除,有大佬研究的可以告知一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
int mtk_pdc_get_setting(struct charger_manager *info, int *newvbus, int *newcur,
int *newidx)
{
int ret = 0;
int idx, selected_idx;
unsigned int pd_max_watt, pd_min_watt, now_max_watt;
struct mtk_pdc *pd = &info->pdc;
int ibus = 0, vbus;
int ibat = 0, chg1_ibat = 0, chg2_ibat = 0;
int chg2_watt = 0;
bool boost = false, buck = false;
struct adapter_power_cap *cap = NULL;
unsigned int mivr1 = 0;
unsigned int mivr2 = 0;
bool chg1_mivr = false;
bool chg2_mivr = false;
bool chg2_enable = false;

mtk_pdc_init_table(info); //获取 cap->selected_cap_idx
mtk_pdc_get_reset_idx(info);
mtk_pdc_get_cap_max_watt(info); //当前支持的获取最大的 watt

cap = &pd->cap;

if (cap->nr == 0)
return -1;

if (info->enable_hv_charging == false)
goto reset;

ret = charger_dev_get_ibus(info->chg1_dev, &ibus);
if (ret < 0) {
chr_err("[%s] get ibus fail, keep default voltage\n", __func__);
return -1;
}

if (info->data.parallel_vbus) { //计算出 chg2_watt 一般情况为0
ret = charger_dev_get_ibat(info->chg1_dev, &chg1_ibat);
if (ret < 0)
chr_err("[%s] get ibat fail\n", __func__);

ret = charger_dev_get_ibat(info->chg2_dev, &chg2_ibat);
if (ret < 0) {
ibat = battery_get_bat_current();
chg2_ibat = ibat * 100 - chg1_ibat;
}

if (ibat < 0 || chg2_ibat < 0)
chg2_watt = 0;
else
chg2_watt = chg2_ibat / 1000 * battery_get_bat_voltage()
/ info->data.chg2_eff * 100;

chr_err("[%s] chg2_watt:%d ibat2:%d ibat1:%d ibat:%d\n",
__func__, chg2_watt, chg2_ibat, chg1_ibat, ibat * 100);
}

charger_dev_get_mivr_state(info->chg1_dev, &chg1_mivr);
charger_dev_get_mivr(info->chg1_dev, &mivr1);

if (is_dual_charger_supported(info)) {
charger_dev_is_enabled(info->chg2_dev, &chg2_enable);
if (chg2_enable) {
charger_dev_get_mivr_state(info->chg2_dev, &chg2_mivr);
}
}

vbus = battery_get_vbus();
ibus = ibus / 1000;

if ((chg1_mivr && (vbus < mivr1 / 1000 - 500)) ||
(chg2_mivr && (vbus < mivr2 / 1000 - 500)))
goto reset;

selected_idx = cap->selected_cap_idx; //获取当前的 idx
idx = selected_idx;

if (idx < 0 || idx >= ADAPTER_CAP_MAX_NR)
idx = selected_idx = 0;

pd_max_watt = cap->max_mv[idx] * (cap->ma[idx]
/ 100 * (100 - info->data.ibus_err) - 100); // 高级功耗,一般为固定值从 log 读出为 12400000

now_max_watt = cap->max_mv[idx] * ibus + chg2_watt; //当前经过计算需要的功耗

pd_min_watt = cap->max_mv[pd->pd_buck_idx] * cap->ma[pd->pd_buck_idx] //低级功耗 7900000
/ 100 * (100 - info->data.ibus_err)
- info->data.vsys_watt;

if (pd_min_watt <= 5000000) //pd 快充的最小功耗 5000000
pd_min_watt = 5000000;

printk("pd->pd_boost_idx: %d, pd->pd_buck_idx: %d, selected_idx: %d\n",
pd->pd_boost_idx, pd->pd_buck_idx, selected_idx);

if ((now_max_watt >= pd_max_watt) || chg1_mivr || chg2_mivr) {
printk("1\n");
*newidx = pd->pd_boost_idx; // 选择 pd_boost_idx 也就是升压
boost = true;
} else if (now_max_watt <= pd_min_watt) {
printk("2\n");
*newidx = pd->pd_buck_idx; // 选择 pd_buck_idx 也就是降压
buck = true;
} else {
printk("333\n");
*newidx = selected_idx; // 不变继续当前挡位充电
boost = false;
buck = false;
}

*newvbus = cap->max_mv[*newidx]; //获取对应的电压
*newcur = cap->ma[*newidx]; //获取对应的电流

chr_err("[%s]watt:%d,%d,%d up:%d,%d vbus:%d ibus:%d, mivr:%d,%d\n",
__func__,
pd_max_watt, now_max_watt, pd_min_watt,
boost, buck,
vbus, ibus, chg1_mivr, chg2_mivr);

chr_err("[%s]vbus:%d:%d:%d current:%d idx:%d default_idx:%d\n",
__func__, pd->vbus_h, pd->vbus_l, *newvbus,
*newcur, *newidx, selected_idx);

return 0;

reset:
mtk_pdc_reset(info);
*newidx = pd->pd_reset_idx;
*newvbus = cap->max_mv[*newidx];
*newcur = cap->ma[*newidx];

return 0;
}

2)更新当前挡位下的升压、降压 idx

该函数基于当前的 selected_idx 来更新升压,降压 idx,举例说明:
6360 当前可以供选择的电压挡位如下

max_mv[0] = 5000 ,ma[0] = 3000 //数组下标就是 idx
max_mv[1] = 9000 ,ma[1] = 2660
max_mv[2] = 12000, ma[2] = 2000

maxwatt[i] = max_mv[i] * ma[i]; // 表示功率

maxwatt[0] = 15000000
maxwatt[1] = 23940000
maxwatt[2] = 24000000

pd 支持的范围为 5000 - 9000
第一次插上充电器,默认使用当前挡位为最低档 0 档即设置 5000 mv 充电,同时下面参数也是默认状态 0

idx = selected_idx = 0 //选择 5000
boost_idx = 0 // 选择 5000
buck_idx = 0 // 选择 5000

调用 mtk_pdc_get_idx 更新当前状态更新完状态后如下

idx = selected_idx = 0 //选择 5000
boost_idx = 1 // 选择 9000 ,当前挡位电压下的升压电压
buck_idx = 0 // 选择 5000 ,当前挡位下的降压电压

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/*
更新升压下标 boost_idx

1. 判断 max_mv[0] = 5000 是否在 5000 - 9000 范围内,明显是在的
2. 判断 idx = 0 表示的功耗 maxwatt[idx] 是否小于 maxwatt[0] 明显是相等的
3. 判断 max_mv[1] = 9000 是否在 5000 - 9000 范围内,明显是在的
4. 判断 idx = 0 表示的功耗 maxwatt[idx] 是否小于 maxwatt[1] 明显后者更大,于是更新 idx = 1
5. 判断 max_mv[2] = 12000 是否在 5000 - 9000 范围内,明显不在于是结束

更新 boost_idx 使用当前挡 idx 位下的更高电压即 1

接下来更新降压下标 buck_idx 更新前重新初始化当前下标 idx = selected_idx = 0

1. 判断 max_mv[0] = 5000 是否在 5000 - 9000 范围内,明显是在的
2. 判断 idx = 0 表示的功耗 maxwatt[idx] 是否大于 maxwatt[0] 明显是相等的
3. 判断 max_mv[1] = 9000 是否在 5000 - 9000 范围内,明显是在的
4. 判断 idx = 0 表示的功耗 maxwatt[idx] 是否大于 maxwatt[1] 明显后者更大
5. 判断 max_mv[2] = 12000 是否在 5000 - 9000 范围内,明显不在于是结束

更新 buck_idx 使用当前挡 idx 位下的更低电压即 0
*/
int mtk_pdc_get_idx(struct charger_manager *info, int selected_idx,
int *boost_idx, int *buck_idx)
{
struct mtk_pdc *pd = &info->pdc;
struct adapter_power_cap *cap;
int i = 0;
int idx = 0;

cap = &pd->cap;
idx = selected_idx; //当前设置的电压

if (idx < 0) {
chr_err("[%s] invalid idx:%d\n", __func__, idx);
*boost_idx = 0;
*buck_idx = 0;
return -1;
}

/* get boost_idx */
for (i = 0; i < cap->nr; i++) {

chr_err("min_mv:%d %d %d %d\n",
cap->min_mv[i],
cap->max_mv[i],
pd->vbus_l,
pd->vbus_h);

//判断 cap->mv 支付在 pd 快充支持的电压范围
if (cap->min_mv[i] < pd->vbus_l ||
cap->max_mv[i] < pd->vbus_l) {
chr_err("min_mv error:%d %d %d\n",
cap->min_mv[i],
cap->max_mv[i],
pd->vbus_l);
continue;
}

if (cap->min_mv[i] > pd->vbus_h ||
cap->max_mv[i] > pd->vbus_h) {
chr_err("max_mv error:%d %d %d\n",
cap->min_mv[i],
cap->max_mv[i],
pd->vbus_h);
continue;
}

if (idx == selected_idx) { //如果当前i下标对应的功率更大,则使用更新 idx 使用更大功率表示的下标
if (cap->maxwatt[i] > cap->maxwatt[idx])
idx = i;
} else {
if (cap->maxwatt[i] < cap->maxwatt[idx] &&
cap->maxwatt[i] > cap->maxwatt[selected_idx])
idx = i;
}
}
*boost_idx = idx;
idx = selected_idx;

/* get buck_idx */
for (i = 0; i < cap->nr; i++) {

chr_err("min_mv error:%d %d %d %d\n",
cap->min_mv[i],
cap->max_mv[i],
pd->vbus_l,
pd->vbus_h);

if (cap->min_mv[i] < pd->vbus_l ||
cap->max_mv[i] < pd->vbus_l) {
chr_err("min_mv error:%d %d %d\n",
cap->min_mv[i],
cap->max_mv[i],
pd->vbus_l);
continue;
}

if (cap->min_mv[i] > pd->vbus_h ||
cap->max_mv[i] > pd->vbus_h) {
chr_err("max_mv error:%d %d %d\n",
cap->min_mv[i],
cap->max_mv[i],
pd->vbus_h);
continue;
}

if (idx == selected_idx) { //如果当前i下标对应的功率更小,则使用 i 更新 idx 使用更小功率表示的下标
if (cap->maxwatt[i] < cap->maxwatt[idx])
idx = i;
} else {
if (cap->maxwatt[i] > cap->maxwatt[idx] &&
cap->maxwatt[i] < cap->maxwatt[selected_idx])
idx = i;
}
}
*buck_idx = idx;

return 0;
}

四、G90(mt6785)-功放调试之控制

1、耳机检测代码

G90 的功放和 8788 平台的有点不一样,在插上耳机的时候功放不会自动停止播放,因此在耳机检测的时候手动添加开关功放的使能引脚的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/drivers/misc/mediatek/accdet/mt6359/accdet.c

#if PMIC_ACCDET_KERNEL
static void eint_work_callback(struct work_struct *work)
#else
static void eint_work_callback(void)
#endif
{
pr_info("accdet %s(),DCC EINT func\n", __func__);

if (cur_eint_state == EINT_PIN_PLUG_IN) { //检测到耳机插入跑这里
/* wk, disable vusb LP */
pmic_write(PMIC_RG_LDO_VUSB_HW0_OP_EN_ADDR, 0x8000);
pr_info("%s VUSB LP dis\n", __func__);

pr_info("accdet cur: plug-in, cur_eint_state = %d\n",
cur_eint_state);

amplifier_control_off();/* 关闭功放, 这个函数是自己添加的 */

mutex_lock(&accdet_eint_irq_sync_mutex);
eint_accdet_sync_flag = true;
mutex_unlock(&accdet_eint_irq_sync_mutex);
__pm_wakeup_event(accdet_timer_lock,
jiffies_to_msecs(7 * HZ));

accdet_init();

pr_info("%s VUSB LP dis done\n", __func__);
enable_accdet(0);
} else { //检测到耳机拔出跑这里
pr_info("accdet cur:plug-out, cur_eint_state = %d\n",
cur_eint_state);

amplifier_control_on();/* 打开功放,这个函数是自己添加的 */

mutex_lock(&accdet_eint_irq_sync_mutex);
eint_accdet_sync_flag = false;
accdet_thing_in_flag = false;
mutex_unlock(&accdet_eint_irq_sync_mutex);
if (accdet_dts.moisture_detect_mode != 0x5)
del_timer_sync(&micbias_timer);

/* disable accdet_sw_en=0
*/
pmic_write_clr(PMIC_ACCDET_SW_EN_ADDR,
PMIC_ACCDET_SW_EN_SHIFT);
disable_accdet();
headset_plug_out();
}

#ifdef CONFIG_ACCDET_EINT_IRQ
if (get_moisture_det_en() == 0x1)
recover_moisture_setting(gmoistureID);
else
recover_eint_setting(gmoistureID);
#endif
#ifdef CONFIG_ACCDET_EINT
enable_irq(accdet_irq);
pr_info("accdet %s enable_irq !!\n", __func__);
#endif
}

2、耳机有声音功放没声音

插上耳机 pmu 才有功放信号输出,拔出耳机就没有信号输出,这里的信号指 pmu 端的信号,其实就是外置功放修改,修改如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/device/mediateksample/k85v1_64/ProjectConfig.mk b/mediateksample/k85v1_64/ProjectConfig.mk

MTK_AUDIO_MIC_INVERSE = no
MTK_AUDIO_NUMBER_OF_MIC = 2
MTK_AUDIO_NUMBER_OF_SPEAKER = 1

//修改前
-MTK_AUDIO_SPEAKER_PATH = smartpa_mtk_mt6660

//修改后
+MTK_AUDIO_SPEAKER_PATH = int_hp_buf
MTK_AUDIO_TUNING_TOOL_VERSION = V2.2
MTK_AUDIO_TUNNELING_SUPPORT = no
MTK_AUIDO_MIC_INVERSE = no

3、喇叭尾音

Android系统默认播放停止后3秒会进入Standby模式以节省电源.standby里面有pcm_close接口,会关闭speaker的输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
diff --git a/av/services/audioflinger/AudioFlinger.h b/av/services/audioflinger/AudioFlinger.h
old mode 100644
new mode 100755
index 978d39132..73db1b203
--- a/av/services/audioflinger/AudioFlinger.h
+++ b/av/services/audioflinger/AudioFlinger.h
@@ -97,7 +97,7 @@ class ServerProxy;

// ----------------------------------------------------------------------------

-static const nsecs_t kDefaultStandbyTimeInNsecs = seconds(3);
+static const nsecs_t kDefaultStandbyTimeInNsecs = milliseconds(200);
//MTK_AUDIO_FIX_DEFAULT_DEFECT
static const nsecs_t kDefaultA2dpStandbyTimeInNsecs = milliseconds(500);

四、耳机立体声修改

1
2
vendor/mediatek/proprietary/custom/tb8788p1_64_bsp/hal/audioflinger/audio/audio_custom_exp.h
//在这个文件中增加宏 #define ENABLE_STEREO_SPEAKER

4、 打开 ATCI

1
*#*#3646633#*#*

Log and Debugging -> ATCI -> ALWAYS ENABLE ATCI

喇叭文件频响曲线存放目录
device/mediatek/common/audio_param

三、G90(mt6785)-sensorhub

四、背光能调到黑屏

当打开自动调节背光功能的时候,手动调节设置中背光滚动条将背光设置到最小,屏幕会完全变黑,这种现象可能与lcm的最小亮度有关,可以采用如下方式解决:

1、adb comand设置背光,确定可以使lcm点亮的最小背光值

1
adb shell echo xx >/sys/class/leds/lcd-backlight/brightness    xxbacklight level

2、修改alps/frameworks/base/core/res/res/values/config.xml中如下参数的值为步骤1中所获取的最小背光值

1
2
3
4
5
6
7
8
<!-- Minimum allowable screen brightness to use in a very dark room.
This value sets the floor for the darkest possible auto-brightness
adjustment. It is expected to be somewhat less than the first entry in
config_autoBrightnessLcdBacklightValues so as to allow the user to have
some range of adjustment to dim the screen further than usual in very
dark rooms. The contents of the screen must still be clearly visible
in darkness (although they may not be visible in a bright room). -->
<integer name="config_screenBrightnessDark">1</integer>

五、摄像头

1、摄像头引脚

IOVDD(input output vdd): 负责i2c电压,没有这路电无法读到id,电压一般为 1.8, 少数为2.8内部转化为1.8

DVDD(digital vdd): 用于给数字信号供电,1.2v

AVDD( VDD):用于给 cmos 供电,放大模拟信号,2.8v

PWDN(power wdn): 给摄像头芯片供电,1.8

RESET: 芯片复位信号

MCLK:一般为 24/26MHZ

2、摄像头去掉af

vendor/mediatek/proprietary/custom/mt6785/hal/imgsensor_metadata/gc5035_mipi_raw/config_static_metadata.module.gc5035mipiraw.h

将 MTK_CONTROL_AF_MODE_CONTINUOUS_PICTRUE 改为 MTK_CONTROL_AF_MODE_OFF

同时修改
vendor/mediatek/proprietary/custom/mt6785/hal/lens/src/lenslist.cpp
将对应的配置改为 “Dummy” 如下

1
{S5K3M3_SENSOR_ID, DUMMY_MODULE_ID, AK7371AF_LENS_ID, "Dummy", pAK7371AF_MAIN2_getDefaultData},

3、修改摄像头方向以及mipi通道

vendor\mediatek\proprietary\custom\mt8168\hal\imgsensor_src\cfg_setting_imgsensor.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
static CUSTOM_CFG gCustomCfg[] = {
{
.sensorIdx = IMGSENSOR_SENSOR_IDX_MAIN,
// .mclk = CUSTOM_CFG_MCLK_1,
// .port = CUSTOM_CFG_CSI_PORT_0,
.mclk = CUSTOM_CFG_MCLK_3, //修改mipi通道为 3
.port = CUSTOM_CFG_CSI_PORT_2,
.dir = CUSTOM_CFG_DIR_REAR,
.bitOrder = CUSTOM_CFG_BITORDER_9_2,
.orientation = 90, //设置方向
.horizontalFov = 67,
.verticalFov = 49
},
{
.sensorIdx = IMGSENSOR_SENSOR_IDX_SUB,
// .mclk = CUSTOM_CFG_MCLK_3,
// .port = CUSTOM_CFG_CSI_PORT_2,
.mclk = CUSTOM_CFG_MCLK_1,
.port = CUSTOM_CFG_CSI_PORT_0,
.dir = CUSTOM_CFG_DIR_FRONT,
.bitOrder = CUSTOM_CFG_BITORDER_9_2,
.orientation = 270,
.horizontalFov = 63,
.verticalFov = 40,
.secure = CUSTOM_CFG_SECURE_M0
},
.......
};

4、摄像头连不上cct

请检查是否设置了 SENSOR_OUTPUT_FORMAT_RAW_Gb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
+++ b/drivers/misc/mediatek/imgsensor/src/common/v1_1/s5k5e9_mipi_raw/s5k5e9mipiraw_Sensor.c
@@ -156,7 +156,7 @@ static imgsensor_info_struct imgsensor_info = {
.sensor_interface_type = SENSOR_INTERFACE_TYPE_MIPI,
.mipi_sensor_type = MIPI_OPHY_NCSI2, //0,MIPI_OPHY_NCSI2; 1,MIPI_OPHY_CSI2
.mipi_settle_delay_mode = MIPI_SETTLEDELAY_AUTO,//0,MIPI_SETTLEDELAY_AUTO; 1,MIPI_SETTLEDELAY_MANNUAL
- .sensor_output_dataformat = SENSOR_OUTPUT_FORMAT_RAW_Gb,
+ .sensor_output_dataformat = SENSOR_OUTPUT_FORMAT_RAW_Gr,
.mclk = 24,
.mipi_lane_num = SENSOR_MIPI_2_LANE,
.i2c_addr_table = {0x5a,0x20,0xff},
@@ -165,7 +165,7 @@ static imgsensor_info_struct imgsensor_info = {


static imgsensor_struct imgsensor = {
- .mirror = IMAGE_HV_MIRROR, //mirrorflip information
+ .mirror = IMAGE_NORMAL, //mirrorflip information
.sensor_mode = IMGSENSOR_MODE_INIT, //IMGSENSOR_MODE enum value,record current sensor mode,such as: INIT, Preview, Ca pture, Video,High Speed Video, Slim Video
.shutter = 0x3D0, //current shutter
.gain = 0x100, //current gain

六、adb remount

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
adb reboot bootloader 
echo 等待进入bootloader
pause
fastboot flashing unlock
echo 按照界面提示按小机音量+按键
pause
fastboot reboot
echo 等待开机完成
pause
adb root
pause
adb disable-verity
adb reboot
pause
adb root
adb remount
pause

七、安卓11打开串口log

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
--- a/drivers/misc/mediatek/mtprintk/mtk_printk_ctrl.c
+++ b/drivers/misc/mediatek/mtprintk/mtk_printk_ctrl.c
@@ -34,7 +34,7 @@
#ifdef CONFIG_MTK_ENG_BUILD
int printk_ctrl;
#else
-int printk_ctrl = 1;
+int printk_ctrl = 0;
#endif

module_param_named(disable_uart, printk_ctrl, int, 0644);
@@ -51,7 +51,7 @@ bool mt_get_uartlog_status(void)
void mt_disable_uart(void)
{
/* uart print not always enable */
- if (printk_ctrl != 2)
+ if (printk_ctrl != 0)
printk_ctrl = 1;
}

八、安卓按键映射

1
\out\target\product\tb8168p1_64_bsp\system\usr\keylayout\Generic.kl

九、mtk 平台反汇编 dts

1
out/target/product/tb8788p1_64_bsp/obj/KERNEL_OBJ/scripts/dtc/dtc -I dtb -O dts -o out/target/product/tb8788p1_64_bsp/obj/KERNEL_OBJ/arch/arm64/boot/dts/mediatek/mt6771.dtb

1、dtbo img -> dtb

1
2
./out/host/linux-x86/bin/mkdtimg dump out/target/product/tb8788p1_64_bsp/dtbo-verified.img -b a.0
执行后生成a.0.0

2、dtb->dts

1
2
./out/target/product/tb8788p1_64_bsp/obj/KERNEL_OBJ/scripts/dtc/dtc -I dtb -O dts -o x100.dts a.0.0
执行后生成x100.dts

十、快速打包patch

  1. 将脚本 outdiff 拷贝进需要打包的目录
  2. 运行 git status > a.txt 创建 a.txt 文件
  3. 运行脚本 ./outdiff 创建出 patch 目录 out_diff 该目录有 modified 文件
  4. 对比 a.txt 将新曾文件拷贝进对应目录

十一、打开mtklog

1
adb shell am start -n com.mediatek.mtklogger/com.mediatek.mtklogger.MainActivity

十二、给sys节点权限

1.并非所有的 Linux distributions 都支持 SELinux
目前 SELinux 支持三种模式,分别如下:
enforcing : 强制模式,代表 SELInux 运作中,且已经 正确的开始限制domain/type
permisssive:宽容模式,代表 SELinux 运座钟,不过仅会有警告讯息并不会限制
domain/type的存取。这个模式可以用来运作为 SELinux 的 debug 之用。
disabled: 关闭, SELinux 并没有实际运作

2.查看 SELinux 的模式
get enforcing =》enforcing
在 MTK 的平台下查看 SELinux 的方法是使用 getenforce
如果显示是 enforcing 就说明 SELinux 是打开的
如果显示是 disabled 就说明 SELinux 是关闭

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
第一处修改
system/core/init/selinux.cpp

bool IsEnforcing() {
+ return false; //这里返回false
if (ALLOW_PERMISSIVE_SELINUX) {
return StatusFromCmdline() == SELINUX_ENFORCING;
}


第二处修改
diff --git a/mediateksample/k71v1_64_bsp/init.project.rc b/mediateksample/k71v1_64_bsp/init.project.rc
index 8722a5a5..c87338c3 100755
--- a/mediateksample/k71v1_64_bsp/init.project.rc
+++ b/mediateksample/k71v1_64_bsp/init.project.rc
@@ -35,6 +35,11 @@ on post-fs-data
chmod 0660 /dev/spm
chown system system /dev/spm

+#ADDNODE
+ chmod 0666 /sys/class/led_ctrl/led_ctrl
+ chmod 0666 /sys/class/hall/hall_1
+ chmod 0666 /sys/class/hall/hall_2

十三、安卓11编译相关

1、 Split command build for system product

1)Build system project

1
2
3
4
source build/envsetup.sh
export OUT_DIR=out_sys
lunch sys_mssi_64_ww-eng
make sys_images

2)Partial build

1
2
3
4
5
source build/envsetup.sh
export OUT_DIR=out_sys
lunch sys_mssi_64_ww-eng
mmma system/related/paths
(or make system_module_name, or mm, mmm google default command.)

2、Split command build for vendor product

1)Build vendor project

1
2
3
4
source build/envsetup.sh
export OUT_DIR=out
lunch vnd_k71v1_64_bsp-eng
make vnd_images krn_images

2) Partial build

1
2
3
4
source build/envsetup.sh
export OUT_DIR=out
lunch vnd_k71v1_64_bsp-eng
mmma vendor/related/paths

3、Image post process

1) Normal load

1
python out/target/product/mssi_t_64_cn/images/split_build.py --system-dir out/target/product/mssi_t_64_cn/images --vendor-dir out/target/product/tb8789p2_64/images --kernel-dir out/target/product/tb8789p2_64/images --output-dir out/target/product/tb8789p2_64/merged

2) Normal + OTA

1
2
3
python out_sys/target/product/mssi_64_ww/images/split_build.py --system-dir out_sys/target/product/mssi
_64_ww/images --vendor-dir out/target/product/k71v1_64_bsp/images --kernel-dir out/target/product/k71v1
_64_bsp/images --output-dir output_load --otapackage

3) Normal + CTS

1
2
3
python out_sys/target/product/mssi_64_ww/images/split_build.py --system-dir out_sys/target/product/mssi
_64_ww/images --vendor-dir out/target/product/k71v1_64_bsp/images --kernel-dir out/target/product/k71v1
_64_bsp/images --output-dir output_load --certs-dir $CTS_SECURITY_KEY

4) Normal + OTA + CTS

1
2
3
python out_sys/target/product/mssi_64_ww/images/split_build.py --system-dir out_sys/target/product/mssi
_64_ww/images --vendor-dir out/target/product/k71v1_64_bsp/images --kernel-dir out/target/product/k71v1
_64_bsp/images --output-dir output_load --otapackage --certs-dir $CTS_SECURITY_KEY

5)编译命令

1
source build/envsetup.sh && lunch sys_mssi_t_64_cn-userdebug && make sys_images && lunch vnd_tb8789p2_64-userdebug && make -j24 vnd_images krn_images

十四、linux 查看内存空间

df -h

十五、设置蓝牙开机默认状态

开机设置系统将 wifi 蓝牙 gsensor 默认打开

1
2
3
4
5
vendor/mediatek/proprietary/packages/apps/SettingsProvider/ res/values/defaults.xml
<bool name="def_accelerometer_rotation">true</bool>
<integer name="def_user_rotation">1</integer>
<bool name="def_bluetooth_on">true</bool>
<bool name="def_wifi_on">true</bool>

十六、快速获取设备路径

1
2
3
4
path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
pr_info("%s as %s\n",
dev->name ? dev->name : "Unspecified device",
path ? path : "N/A");

十七、lk 阶段到 kernel 阶段屏幕会闪一下

抓取 mipi 波形发现,mipi 波形从 lk 到 kernel 阶段时波形被拉宽了
最终发现原因如下 lk 阶段直接使用

1
2
3
4
5
6
// 代码路径
mediatek/proprietary/bootable/bootloader/lk/platform/mt6785/ddp_dsi.c

    horizontal_backporch_byte =
          ((dsi_params->horizontal_backporch +
          dsi_params->horizontal_sync_active) * dsiTmpBufBpp - 10);

这个公式计算这里的 horizontal_sync_active = 16 计算出来得到 188
但是 kernel 阶段对 t_hsa 多做了一个处理

1
2
3
4
5
6
7
//代码路径
drivers/misc/mediatek/video/mt6785/dispsys/ddp_dsi.c

t_hsa = ALIGN_TO(t_hsa * dsiTmpBufBpp - 4, 4); // kernel多了这个计算

 ASSERT((t_hbp + t_hsa) * dsiTmpBufBpp > 9);
t_hbp = ALIGN_TO((t_hbp + t_hsa) * dsiTmpBufBpp - 10, 4);

在kernel 多了这个算法使得 t_hsa  从 16 变成了 44, 最终导致 计算结果变成了 272 ,mtk 给的解决方案如下:

1
2
// 修改前面的第三行代码为如下
t_hbp = ALIGN_TO((t_hbp + dsi_params->horizontal_sync_active) * dsiTmpBufBpp - 10, 4);

同时对于行同步型号 hsa,hbp 等都会调用 ALIGN_TO 函数对 4 做取整的操作(mtk 说是和内部设计相关)。因此我们填写参数可以直接将行同步信号填为 4 的整数倍

十八、安卓 11 关闭 lib 库校验

安卓 9 是默认关闭的,在 Android.mk 中增加

1
LOCAL_CHECK_ELF_FILES := false

十九、安卓 9 编译打包 dtbo

1
2
make dtboimage -j8 2>&1 | tee build.log
./vendor/mediatek/proprietary/scripts/sign-image/sign_image.sh

二十、mkt pclk计算

1
params->dsi.PLL_CLOCK  = (vertical_sync_active + vertical_backporch + vertical_frontporch + FRAME_HEIGHT) * (horizontal_sync_active + horizontal_backporch + horizontal_frontporch + FRAME_WIDTH) * fps * 24 / (4 * 2);

二十一、闪屏debug

  1. 排除背光。
    a、 把背光接固定背光,如果仍然闪屏,说明不是背光的问题;
    如果屏不闪,说明是背光问题。
    b、 如果是背光问题,继续分析是否有开AAL功能,如果有开
    AAL功能,请将AAL功能关闭。如果关闭AAL功能后,屏不闪,说明是
    AAL导致的屏闪,请提issue给MTK。如果关闭AAL功能后,屏仍然闪,
    请内部确认贵司是否有在framework层做改动,很多情况是由于改动
    Framework,绕过LightService直接控制背光结点导致的问题。
    c、 其实当定位到是背光的问题了,这个时候就可以提问题给
    MTK了,抓取Mobile log给MTK。
  2. 排除ESD。
    a、如果通过第一步(a)排除说不是背光闪,第二步可以检查是否由于ESD check
    导致的闪屏。可以先关闭ESD功能,看显示是否仍然会闪。如果关闭ESD功能后,lcm不
    再闪动,说明是ESD check导致的闪屏。这个时候就可以提把Mobile log抓过来给MTK看了。
    如果关闭ESD功能后,lcm仍然闪动,说明和ESD check无关。
  3. 其他情况。
    a、如果背光和ESD都给排除了,这个时候是bug的概率比较大。(常见的情况是待机
    的时候不定时的闪屏),抓取Mobilelog过来给MTK check。

二十二、g-sensor 系统不转

1
2
frameworks/base/core/res/res/values/config.xml
<bool name="config_allowAllRotations">true</bool>