悠悠楠杉
i.MX6ULL驱动开发13:电容触摸驱动实践(下)
在上一篇文章中,我们已经完成了i.MX6ULL电容触摸屏驱动的框架搭建和设备树配置。今天,我们将深入实现驱动核心功能,完成从硬件中断到用户空间坐标上报的完整流程。
中断处理机制实现
电容触摸屏通常采用中断方式通知SOC有触摸事件发生。在我们的驱动中,需要正确配置和实现中断处理函数:
c
static irqreturnt ft5x06tsinterrupt(int irq, void *devid)
{
struct ft5x06data *data = devid;
struct input_dev *input = data->input;
u8 buf[32];
int ret, i;
/* 读取触摸点数据 */
ret = ft5x06_read_data(data->client, buf, sizeof(buf));
if (ret < 0) {
dev_err(&data->client->dev, "读取触摸数据失败\n");
goto out;
}
/* 解析多点触控数据 */
for (i = 0; i < FT5X06_MAX_TOUCH_POINTS; i++) {
u8 *touch = &buf[i * FT5X06_TOUCH_STEP + FT5X06_TOUCH_X_H];
if (touch[0] & FT5X06_TOUCH_EVENT_FLAG_PRESS) {
input_mt_slot(input, i);
input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
/* 上报坐标 */
input_report_abs(input, ABS_MT_POSITION_X,
(touch[0] & 0x0F) << 8 | touch[1]);
input_report_abs(input, ABS_MT_POSITION_Y,
(touch[2] & 0x0F) << 8 | touch[3]);
} else if (touch[0] & FT5X06_TOUCH_EVENT_FLAG_RELEASE) {
input_mt_slot(input, i);
input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
}
}
input_sync(input);
out:
return IRQ_HANDLED;
}
输入子系统集成
Linux输入子系统为触摸设备提供了标准接口,我们需要正确配置input_dev:
c
static int ft5x06tsprobe(struct i2cclient *client,
const struct i2cdevice_id *id)
{
// ...初始化代码...
/* 设置输入设备 */
input_dev = devm_input_allocate_device(&client->dev);
if (!input_dev) {
dev_err(&client->dev, "分配输入设备失败\n");
return -ENOMEM;
}
input_dev->name = FT5X06_TS_NAME;
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
/* 设置输入事件 */
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
/* 设置多点触控参数 */
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
0, data->x_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
0, data->y_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
0, 255, 0, 0);
input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR,
0, 255, 0, 0);
/* 注册输入设备 */
ret = input_mt_init_slots(input_dev, FT5X06_MAX_TOUCH_POINTS, 0);
if (ret) {
dev_err(&client->dev, "初始化MT slots失败\n");
return ret;
}
ret = input_register_device(input_dev);
if (ret) {
dev_err(&client->dev, "注册输入设备失败\n");
return ret;
}
// ...其他初始化...
}
设备树配置优化
完整的设备树节点配置应包括中断、复位引脚和电源管理:
dts
&i2c1 {
status = "okay";
ft5x06_ts: touchscreen@38 {
compatible = "edt,edt-ft5x06";
reg = <0x38>;
interrupt-parent = <&gpio1>;
interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
touchscreen-size-x = <800>;
touchscreen-size-y = <480>;
touchscreen-inverted-x;
touchscreen-swapped-x-y;
wakeup-source;
};
};
TSLIB校准与测试
TSLIB是Linux下常用的触摸屏校准和测试工具集,我们需要在系统中配置和使用它:
首先确保内核配置支持evdev输入:
CONFIG_INPUT_EVDEV=y
在目标板上安装TSLIB:
bash opkg install tslib tslib-calibrate tslib-tests
配置环境变量:
bash export TSLIB_TSDEVICE=/dev/input/event1 export TSLIB_CALIBFILE=/etc/pointercal export TSLIB_CONFFILE=/etc/ts.conf export TSLIB_PLUGINDIR=/usr/lib/ts
执行校准:
bash ts_calibrate
测试触摸响应:
bash ts_test
PM电源管理实现
为完善驱动,我们还需要实现电源管理功能:
c
static int __maybeunused ft5x06tssuspend(struct device *dev)
{
struct i2cclient *client = to_i2c_client(dev);
struct ft5x06_data *data = i2c_get_clientdata(client);
/* 禁用中断 */
disable_irq(client->irq);
/* 进入低功耗模式 */
ft5x06_write_reg(client, FT5X06_POWER_MODE_REG, FT5X06_POWER_MODE_SLEEP);
return 0;
}
static int __maybeunused ft5x06tsresume(struct device *dev)
{
struct i2cclient *client = to_i2c_client(dev);
struct ft5x06_data *data = i2c_get_clientdata(client);
/* 从低功耗唤醒 */
ft5x06_write_reg(client, FT5X06_POWER_MODE_REG, FT5X06_POWER_MODE_ACTIVE);
/* 重新初始化芯片 */
ft5x06_chip_init(client);
/* 启用中断 */
enable_irq(client->irq);
return 0;
}
调试技巧
在驱动开发过程中,有效的调试手段至关重要:
使用printk输出调试信息:
c dev_dbg(&client->dev, "坐标: x=%d, y=%d\n", x, y);
通过sysfs导出调试接口:c
static ssizet ft5x06regshow(struct device *dev, struct deviceattribute *attr, char *buf)
{
// 实现读取寄存器值
}
static ssizet ft5x06regstore(struct device *dev,
struct deviceattribute *attr,
const char *buf, size_t count)
{
// 实现写入寄存器值
}
static DEVICEATTR(reg, 0644, ft5x06regshow, ft5x06reg_store);
// 在probe函数中注册
devicecreatefile(&client->dev, &devattrreg);
- 使用内核事件跟踪:
bash cat /sys/kernel/debug/tracing/trace_pipe
常见问题排查
触摸无反应:
- 检查I2C通信是否正常
- 确认中断引脚配置正确
- 验证电源供电稳定
坐标不准确:
- 重新运行ts_calibrate
- 检查设备树中的屏幕尺寸参数
- 确认是否设置了正确的xy反转标志
多点触控失效:
- 确认内核配置了CONFIGINPUTMULTITOUCH
- 检查inputmtinit_slots调用是否正确
- 验证固件支持多点触控
性能优化建议
- 调整中断触发方式,通常边缘触发比电平触发更高效
- 实现触摸点跟踪,减少input_sync调用次数
- 在非活动状态下降低采样率
- 使用DMA进行I2C数据传输(如果支持)