首页 > 解决方案 > 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

我应该在哪里寻找让触摸屏工作的地方?

Fusion 7寸触摸屏初始化

标签: linux-kerneltouchscreen

解决方案


推荐阅读