linux-kernel - Fusion F07A-0114-01 触摸屏重置控制器未在 i.MX6 SoC 4.14.98 内核中正确初始化?
问题描述
这是我们旧版 4.14 Linux 内核中触摸屏的驱动程序代码
// SPDX-License-Identifier: GPL-2.0-only
/*
* Fusion touchscreen - provided with the FUSION7_F07A_0102 display.
*
*/
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/reset.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/of_platform.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#define FUSION_XRES 1550
#define FUSION_YRES 950
#define FUSION_REG_DATA_START 0x00
#define FUSION_REG_INFO_LO 0x0e
#define FUSION_REG_INFO_HI 0x0f
#define FUSION_REG_SCAN_COMPLETE 0x11
struct fusion_priv {
struct device *dev;
struct input_dev *input;
struct regmap *regmap;
};
struct fusion_touches {
u16 x1;
u16 y1;
u8 z1;
u8 tip1;
u8 tid1;
u16 x2;
u16 y2;
u8 z2;
u8 tip2;
u8 tid2;
};
static void fusion_touch_complete(struct device *dev, struct regmap *regmap)
{
int i, err;
for (i = 0; i < 3; i++) {
err = regmap_write(regmap, FUSION_REG_SCAN_COMPLETE, 0);
if (!err)
return;
}
dev_err(dev, "touch_complete failed: %d", err);
}
static irqreturn_t fusion_irq(int irq, void *irq_data)
{
struct fusion_priv *priv = irq_data;
struct input_dev *input = priv->input;
struct fusion_touches touches;
u8 td[13];
int err;
/* To ensure data coherency, read the sensor in a single transaction */
err = regmap_bulk_read(priv->regmap, FUSION_REG_DATA_START, td,
sizeof(td));
if (err) {
dev_err(priv->dev, "read block failed: %d", err);
goto done;
}
touches.y1 = td[1] << 8;
touches.y1 |= td[2];
touches.x1 = td[3] << 8;
touches.x1 |= td[4];
touches.z1 = td[5];
touches.tip1 = td[6] & 0x0f;
touches.tid1 = (td[6] & 0xf0) >> 4;
touches.y2 = td[7] << 8;
touches.y2 |= td[8];
touches.x2 = td[9] << 8;
touches.x2 |= td[10];
touches.z2 = td[11];
touches.tip2 = td[12] & 0x0f;
touches.tid2 = (td[12] & 0xf0) >> 4;
touches.x1 = min_t(u16, touches.x1, FUSION_XRES - 1);
touches.y1 = min_t(u16, touches.y1, FUSION_YRES - 1);
touches.x2 = min_t(u16, touches.x2, FUSION_XRES - 1);
touches.y2 = min_t(u16, touches.y2, FUSION_YRES - 1);
if (touches.tip1 == 0 && touches.tip2 == 0) {
/* release */
input_mt_slot(input, 0);
input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
input_mt_slot(input, 1);
input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
} else {
if (touches.tip1) {
input_mt_slot(input, 0);
input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
input_report_abs(input, ABS_MT_POSITION_X, touches.x1);
input_report_abs(input, ABS_MT_POSITION_Y, touches.y1);
input_report_abs(input, ABS_MT_TOUCH_MINOR, touches.z1);
input_report_abs(input, ABS_MT_TOUCH_MAJOR, touches.z1);
input_report_abs(input, ABS_MT_TRACKING_ID,
touches.tid1);
}
if (touches.tip2) {
input_mt_slot(input, 0);
input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
input_report_abs(input, ABS_MT_POSITION_X, touches.x2);
input_report_abs(input, ABS_MT_POSITION_Y, touches.y2);
input_report_abs(input, ABS_MT_TOUCH_MINOR, touches.z2);
input_report_abs(input, ABS_MT_TOUCH_MAJOR, touches.z2);
input_report_abs(input, ABS_MT_TRACKING_ID,
touches.tid2);
}
}
input_mt_report_pointer_emulation(input, false);
input_sync(input);
done:
fusion_touch_complete(priv->dev, priv->regmap);
return IRQ_HANDLED;
}
static const struct regmap_config fusion_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x11,
/* sensor data must be read in a single bulk transaction */
.use_single_rw = false,
};
const static u8 *version_product_info[4] = {
"10Z8", "70Z7", "43Z6", ""
};
static void log_fusion_info(struct device *dev, unsigned int info_hi,
unsigned int info_lo)
{
u8 ver_product, ver_id;
u32 version;
ver_product = (((u8)info_lo) & 0xc0) >> 6;
version = (10 + ((((u32)info_lo)&0x30) >> 4)) * 100000;
version += (((u32)info_lo)&0xf) * 1000;
ver_id = ((u8)(info_hi) & 0x6) >> 1;
version += ((((u32)info_hi) & 0xf8) >> 3) * 10;
version += (((u32)info_hi) & 0x1) + 1; /* 0 is build 1, 1 is build 2 */
dev_info(dev, "Fusion version product %s(%d)",
version_product_info[ver_product], ver_product);
dev_info(dev, "Fusion version id %s(%d)",
ver_id ? "1.4" : "1.0", ver_id);
dev_info(dev, "Fusion version series (%d)", version);
}
static int fusion_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
unsigned int info_lo, info_hi;
struct reset_control *reset;
struct fusion_priv *priv;
struct regmap *regmap;
struct input_dev *input;
int err;
if (client->irq <= 0) {
dev_err(dev, "touchscreen requires an interrupt");
return -EINVAL;
}
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&client->dev, "SMBUS byte data not supported");
return -EIO;
}
reset = devm_reset_control_get(dev, NULL);
if (IS_ERR(reset)) {
dev_err(dev, "no reset controller");
return PTR_ERR(reset);
}
reset_control_assert(reset);
reset_control_deassert(reset);
regmap = devm_regmap_init_i2c(client, &fusion_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
err = regmap_read(regmap, FUSION_REG_INFO_LO, &info_lo);
if (err) {
dev_err(dev, "read failed: %d", err);
return err;
}
err = regmap_read(regmap, FUSION_REG_INFO_HI, &info_hi);
if (err) {
dev_err(dev, "read failed: %d", err);
return err;
}
log_fusion_info(dev, info_hi, info_lo);
input = devm_input_allocate_device(dev);
if (!input)
return -ENOMEM;
input->name = "Fusion Touchscreen";
input->id.bustype = BUS_I2C;
__set_bit(EV_SYN, input->evbit);
__set_bit(EV_KEY, input->evbit);
__set_bit(EV_ABS, input->evbit);
__set_bit(BTN_TOUCH, input->keybit);
/* Multi touch */
input_set_abs_params(input, ABS_MT_POSITION_X, 0, FUSION_XRES - 1,
0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, 0, FUSION_YRES - 1,
0, 0);
err = input_mt_init_slots(input, 2, INPUT_MT_DIRECT);
if (err) {
dev_err(dev, "Unable to set up slots, err: %d\n", err);
return err;
}
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->input = input;
priv->regmap = regmap;
priv->dev = dev;
err = input_register_device(input);
if (err)
return err;
err = devm_request_threaded_irq(dev, client->irq, NULL, fusion_irq,
IRQF_ONESHOT, client->name, priv);
if (err) {
dev_err(dev, "could not request IRQ, err %d", err);
return err;
}
/* clear the irq first. no idea why original driver does this _after_
* enabling the irq.
*/
err = regmap_write(regmap, FUSION_REG_SCAN_COMPLETE, 0);
if (err) {
dev_err(dev, "clear irq failed: %d", err);
return err;
}
return 0;
}
static const struct i2c_device_id fusion_ts_i2c_id[] = {
{ "fusion-ts", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, fusion_ts_i2c_id);
static struct i2c_driver fusion_ts_driver = {
.driver = {
.name = "fusion-ts",
},
.id_table = fusion_ts_i2c_id,
.probe = fusion_ts_probe,
};
module_i2c_driver(fusion_ts_driver);
我认为驱动程序代码中没有完全引用的设备树条目如下:
&i2c1 {
status = "okay";
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1_mercury
&pinctrl_touch_mercury>;
fusion_touch: touch@0x10{
compatible = "fusion-ts";
reg = <0x10>;
interrupts-extended = <&gpio7 12 IRQ_TYPE_EDGE_RISING>;
rst-gpio = <&gpio6 2 GPIO_ACTIVE_HIGH>;
status = "okay";
};
};
问题是触摸屏还不能正常工作。这是内核日志:
fusion-ts 0-0010: no reset controller
--
--
fusion-ts 0-0010: Fusion version id 1.4(1)
fusion-ts 0-0010: Fusion version series (1212241)
input: Fusion Touchscreen as /devices/soc0/soc/2100000.aips-bus/21a0000.i2c/i2c-0/0-0010/input/input2
我应该在哪里寻找让触摸屏工作的地方?
解决方案
推荐阅读
- python - 使用 tf.data 和 mode.fit 时 1DConv 输入的维度出错
- powershell - 调用命令到 DC -msexchhidefromaddresslists
- flask - 如何使用 moto 和 pytest 为烧瓶 REST API 编写单元测试代码?
- workspace - XFCE 工作空间边距在多屏幕设置上不一致
- android - 如何在颤动中存储密钥对?
- c# - 路由声明它在 system.web 中定义,但未找到错误
- r - 如何为 RMarkdown 文档的不同部分设置字体样式和大小?
- powershell - 在文件繁忙或其他错误的情况下,如何在没有交互式对话框的情况下将文件移动到 powershell 中的 RECYCLE.BIN?
- gitlab - 如何从 centos 中完全删除/卸载 gitlab-runner
- sql - 如何从 SQL 条件查询中删除冗余代码