记录 音量按键波形异常 的问题现象、排查过程、修改方案和验证方法。
MT8781 音量减按键异常:KPROW0 固定拉低与 KPCOL0 输入检测方案
1. 问题背景
MT8781 项目中出现了音量减按键异常问题。
根据硬件原理图,音量减按键并不是独立的 GPIO 按键,而是由 keypad 矩阵中的两根信号线组合实现:
Volume Down = KPROW0 + KPCOL0
MT8781/MT6789 平台对应的 pinmux 关系如下:
GPIO68 = KPROW0
GPIO66 = KPCOL0
因此,音量减按键涉及以下两根信号线:
| 信号 | GPIO | 功能 |
|---|---|---|
KPROW0 | GPIO68 | Keypad Row |
KPCOL0 | GPIO66 | Keypad Column |
2. 原始问题分析
正常的 keypad 矩阵按键需要同时配置 Row 和 Column,并通过 keypad 驱动周期性扫描来识别按键事件。
但当前项目并未采用完整的 keypad Row/Column 扫描方案,而是参考其他项目使用以下 workaround:
GPIO68 / KPROW0:固定输出低电平
GPIO66 / KPCOL0:作为输入检测
采用该方案后,音量减按键的检测过程如下:
按下音量减按键
↓
KPCOL0 与 KPROW0 导通
↓
KPROW0 已固定为低电平
↓
KPCOL0 被拉低
↓
Keypad 驱动检测到按键事件
因此,该问题不能仅通过配置 KPCOL0 解决。
从硬件连接来看,音量减按键实际依赖:
KPROW0 + KPCOL0
如果只配置:
GPIO66 = KPCOL0
而没有为:
GPIO68 = KPROW0
提供稳定的低电平,那么按键按下后,KPCOL0 不一定能够被有效拉低,可能出现以下异常:
- 音量减按键无效;
- 按键检测不稳定;
KPCOL0波形异常;- 偶发漏键或误触发。
3. DTS 修改方案
3.1 新增 gpio_key_rom pinctrl 状态
在 &pio 节点中新增 gpio_key_rom,将 GPIO68 配置为普通 GPIO,并固定输出低电平。
&pio {
gpio_key_rom: key_low {
pins_cmd_dat {
pinmux = <PINMUX_GPIO68__FUNC_GPIO68>;
slew-rate = <1>;
output-low;
};
};
};
各项配置说明如下:
| 配置项 | 含义 |
|---|---|
PINMUX_GPIO68__FUNC_GPIO68 | 将 GPIO68 配置为普通 GPIO 功能 |
slew-rate = <1> | 配置 GPIO 输出边沿速率 |
output-low | 将 GPIO68 配置为输出,并固定输出低电平 |
3.2 在 Panel 节点中绑定 key_rom
在 Panel 节点中绑定该 pinctrl 状态:
pinctrl-names = "key_rom";
pinctrl-0 = <&gpio_key_rom>;
如果 Panel 节点原本已经存在其他 pinctrl 状态,例如 LCM 电源、复位或 Bias 相关 GPIO,则不能直接覆盖原有配置,而应在原有配置基础上追加 key_rom。
示例:
pinctrl-names = "xxx", "xxx", "key_rom";
pinctrl-x = <&gpio_key_rom>;
注意:这里的
pinctrl-x需要根据key_rom在pinctrl-names中的实际索引填写。
例如,原始配置为:
pinctrl-names = "lcm_rst_low", "lcm_rst_high";
pinctrl-0 = <&lcm_rst_low>;
pinctrl-1 = <&lcm_rst_high>;
新增 key_rom 后,应修改为:
pinctrl-names = "lcm_rst_low", "lcm_rst_high", "key_rom";
pinctrl-0 = <&lcm_rst_low>;
pinctrl-1 = <&lcm_rst_high>;
pinctrl-2 = <&gpio_key_rom>;
不能直接删除或替换原有的 Panel pinctrl 配置,否则可能影响屏幕上电、复位以及 Bias 时序。
3.3 Keypad 侧配置 KPCOL0
Keypad 侧仅配置 GPIO66 为 KPCOL0,并将其作为输入信号进行检测。
&keypad {
pinctrl-names = "default";
pinctrl-0 = <&kpd_pins_default>;
};
&pio {
kpd_pins_default: kpdgpiodefault {
pins_cmd_dat {
pinmux = <PINMUX_GPIO66__FUNC_KPCOL0>;
bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
input-enable;
input-schmitt-enable;
};
};
};
各项配置说明如下:
| 配置项 | 含义 |
|---|---|
PINMUX_GPIO66__FUNC_KPCOL0 | 将 GPIO66 配置为 KPCOL0 功能 |
bias-pull-up | 为输入信号配置上拉 |
input-enable | 使能 GPIO 输入功能 |
input-schmitt-enable | 使能施密特输入,提高输入信号的抗干扰能力 |
4. Panel 驱动修改方案
仅在 DTS 中定义 gpio_key_rom,不一定能够保证该状态被自动选中并生效。
因此,需要在 Panel 驱动中主动获取 pinctrl,并选择名为 key_rom 的状态。
在 Panel Probe 阶段增加以下逻辑:
ctx->pinctrl = devm_pinctrl_get(dev);
if (IS_ERR(ctx->pinctrl)) {
dev_info(dev, "cannot get panel pinctrl %ld\n",
PTR_ERR(ctx->pinctrl));
ctx->pinctrl = NULL;
} else {
ctx->gpio_key_rom =
pinctrl_lookup_state(ctx->pinctrl, "key_rom");
if (IS_ERR(ctx->gpio_key_rom)) {
dev_info(dev, "cannot find pinctrl key_rom %ld\n",
PTR_ERR(ctx->gpio_key_rom));
ctx->gpio_key_rom = NULL;
} else {
pinctrl_select_state(ctx->pinctrl,
ctx->gpio_key_rom);
}
}
该段代码的执行流程如下:
Panel Probe
↓
获取 Panel 节点对应的 pinctrl
↓
查找名称为 key_rom 的 pinctrl state
↓
选择 key_rom 状态
↓
GPIO68 被配置为普通 GPIO
↓
GPIO68 固定输出低电平
5. 核心结论
本问题的本质是:
音量减按键在硬件上由 KPROW0 + KPCOL0 共同构成
当前项目没有采用完整的 keypad Row/Column 扫描方式,而是采用以下 workaround:
GPIO68 / KPROW0:固定输出低电平
GPIO66 / KPCOL0:作为 Keypad 输入检测
最终的按键检测路径如下:
按下音量减按键
↓
KPROW0 与 KPCOL0 导通
↓
GPIO68 / KPROW0 已固定输出低电平
↓
GPIO66 / KPCOL0 被拉低
↓
Keypad 驱动检测到音量减按键事件
因此,本次修改必须同时满足两个条件:
- GPIO68 必须稳定输出低电平;
- GPIO66 必须正确配置为
KPCOL0输入检测。
只配置其中一侧,无法保证音量减按键正常工作。
6. 注意事项
6.1 GPIO68 不再作为正常的 KPROW0 扫描线使用
在本方案中,GPIO68 被配置为:
普通 GPIO 输出低电平
因此,GPIO68 不再作为标准 keypad Row 扫描线使用。
如果后续需要恢复完整的 keypad 矩阵扫描方案,则需要重新配置:
GPIO68 = KPROW0
GPIO66 = KPCOL0
并由 keypad 驱动统一管理 Row 和 Column 的扫描逻辑。
6.2 不要覆盖 Panel 原有的 pinctrl 配置
如果 Panel 节点已经存在其他 pinctrl 状态,例如:
lcm_rst_low
lcm_rst_high
bias_en_low
bias_en_high
新增 key_rom 时必须采用追加方式,不能替换原有配置。
错误覆盖可能导致以下问题:
覆盖 Panel 原有 pinctrl
↓
LCM 电源、复位或 Bias 配置丢失
↓
屏幕上电时序异常
↓
可能出现不开机、白屏、花屏等问题
6.3 确认 pinctrl_select_state() 是否真正执行
虽然 DTS 中配置了:
pinctrl-names = "key_rom";
pinctrl-0 = <&gpio_key_rom>;
但该状态是否真正生效,还需要确认驱动是否执行了:
pinctrl_select_state(ctx->pinctrl, ctx->gpio_key_rom);
建议通过 Kernel Log 检查是否出现以下异常:
cannot get panel pinctrl
cannot find pinctrl key_rom
如果没有出现上述报错,并且音量减按键恢复正常,则说明 key_rom 状态已经正确获取并生效。
6.4 建议检查 pinctrl_select_state() 返回值
为了进一步确认 pinctrl 状态是否选择成功,可以保存并检查 pinctrl_select_state() 的返回值。
示例:
int ret;
ret = pinctrl_select_state(ctx->pinctrl, ctx->gpio_key_rom);
if (ret < 0)
dev_info(dev, "failed to select key_rom state: %d\n", ret);
这样可以避免出现以下情况:
成功查找到 key_rom
↓
pinctrl_select_state() 执行失败
↓
GPIO68 实际未切换为输出低电平
7. 验证方法与结果
7.1 功能验证
合入修改后,音量减按键恢复正常。
验证结论如下:
GPIO68 固定输出低电平生效
GPIO66 / KPCOL0 能够检测到低电平变化
Keypad 驱动能够正常上报音量减按键事件
音量减按键功能恢复
7.2 建议验证项目
除基本按键功能外,建议同时检查以下内容:
| 验证项目 | 预期结果 |
|---|---|
| 单次按下音量减 | 正常减少一级音量 |
| 连续点击音量减 | 无漏键、无重复触发 |
| 长按音量减 | 音量连续下降 |
| 音量加按键 | 功能不受影响 |
| 电源键及其他按键 | 功能不受影响 |
| 设备休眠后唤醒 | 音量减仍可正常使用 |
| 重启设备 | GPIO68 低电平配置仍能正常生效 |
| 屏幕显示 | 无白屏、花屏或上电异常 |
8. 推荐提交说明
8.1 简短英文版本
dts: configure GPIO68 low to fix volume down key issue
8.2 简短中文版本
配置 GPIO68 输出低电平,修复音量减按键异常
8.3 完整提交说明
MT8781 音量减按键由 KPROW0 和 KPCOL0 共同构成。
当前项目未使用完整的 keypad Row/Column 扫描方案,
而是参考其他项目的 workaround:
- 将 GPIO68/KPROW0 配置为普通 GPIO,并固定输出低电平;
- 将 GPIO66/KPCOL0 配置为 keypad 输入检测。
按下音量减按键时,KPROW0 与 KPCOL0 导通,
GPIO66/KPCOL0 被 GPIO68/KPROW0 拉低,
从而使 keypad 驱动能够正常检测并上报音量减按键事件。