freewing 发表于 2015-5-21 15:25:11

I.MX6Q学习笔记——新版BSP之触摸屏驱动移植

  之所以说是驱动移植是因为之前已经在TQ210、AM335x两个平台上移植过了,因此,仅需要少量修改就可以将驱动移植到imx6q。下面开始触摸驱动移植。本文由技术博主girlkoo进行编写。

  DTS编写

  参考其它DTS的i2c设备写法,我们可以添加如下内容:&i2c1 {
    clock-frequency = <100000>;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_i2c1_2>;
    status = "okay";

    gt811@5d {
      compatible = "gt811,gt811_ts";   
      pinctrl-names = "default";   
      reg = <0x5d>;   
      interrupt-parent = <&gpio1>;   
      interrupts = <9 2>;   
      gpios = <&gpio1 5 0>;   
            
      touchscreen-size-x = <800>;   
      touchscreen-size-y = <480>;   

      touchscreen-swap = <1>;   
      touchscreen-revert-x = <1>;   
      touchscreen-revert-y = <1>;   
    };
};




  添加以上内容后重新编译并烧写DTB。

  驱动编写

  其实移植AM335x的时候就是以DTB方式移植的,因此,除内核api变更的部分需要修改一下,其它代码基本是不需要修改的。驱动代码如下(不含event上报代码):




#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/io.h>

struct gt811_ts_platdata
{
    u32 size_x;
    u32 size_y;
    u32 size_p;
    u32 swap;
    u32 revert_x;
    u32 revert_y;
    u32 reset_pin;
    u32 interrupt_pin;
    u32 ponits_max;
    struct i2c_client *client;
    struct input_dev *input;
    struct work_struct work;
};

static const struct of_device_id gt811_ts_of_match[] = {
    { .compatible = "gt811,gt811_ts", .data = NULL },
    { }
};

static int i2c_write_bytes(struct i2c_client *client, uint8_t *data, int len){
    struct i2c_msg msg;

    msg.flags=!I2C_M_RD;
    msg.addr=client->addr;
    msg.len=len;
    msg.buf=data;

    return i2c_transfer(client->adapter,&msg, 1);
}

static int i2c_read_bytes(struct i2c_client *client, uint8_t *buf, int len){
    struct i2c_msg msgs;

    msgs.flags=!I2C_M_RD;
    msgs.addr=client->addr;
    msgs.len=2;
    msgs.buf=&buf;

    msgs.flags=I2C_M_RD;
    msgs.addr=client->addr;
    msgs.len=len-2;
    msgs.buf=&buf;

    return i2c_transfer(client->adapter,msgs, 2);
}
static void gt811_ts_handler(struct work_struct *work)
{
    struct gt811_ts_platdata *pdata = container_of(work, struct gt811_ts_platdata, work);
    struct device *dev = &pdata->client->dev;
    uint8_t buffer = {0x07, 0x21, 0};
    struct input_mt_pos pos;
    int slots, slot;
    uint8_t count, index, flags, position;

    buffer = 0x0f;
    buffer = 0xff;
    if (i2c_write_bytes(pdata->client,buffer,2) < 0) {
      dev_err(dev, "Failed to write wakeup message.\n");
      goto reenable_irq;
    }

    buffer = 0x07;
    buffer = 0x21;
    if (i2c_read_bytes(pdata->client, buffer, sizeof(buffer)) < 0) {
      dev_err(dev, "Failed to read touch message.\n");
      goto reenable_irq;
    }

    buffer = 0x80;
    buffer = 0x00;
    if (i2c_write_bytes(pdata->client, buffer, 2) < 0) {
      dev_err(dev, "Failed to write sleep message.\n");
      goto reenable_irq;
    }

    buffer = buffer;
    buffer = 0;

    flags = buffer&0x1f;

    count = 0;
    for (index = 0; index < 5 && flags; ++index, flags >>= 1) {
      if (!(flags&0x1)) {
            continue;
      }

      if (index < 3) {
            position = 4 + index * 5;
      }
      else{
            position = 25 + (index - 3) * 5;
      }

      pos.x = (buffer << 8) | buffer;
      pos.y = (buffer << 8) | buffer;
      slots = index;

      if(pdata->swap) {
            swap(pos.x, pos.y);
      }
      if(pdata->revert_x){
            pos.x = pdata->size_x - pos.x;
      }
      if(pdata->revert_y){
            pos.y = pdata->size_y - pos.y;
      }

      ++count;
    }

    // 在这个位置添加event上报代码
    ...

reenable_irq:
    enable_irq(pdata->client->irq);
}

static irqreturn_t gt811_ts_isr(int irq, void *dev_id)
{
    struct gt811_ts_platdata* pdata = (struct gt811_ts_platdata*)dev_id;

    disable_irq_nosync(pdata->client->irq);
    schedule_work(&pdata->work);

    return IRQ_HANDLED;
}

static int gt811_ts_initilize(struct i2c_client *client)
{
    struct device *dev = &client->dev;
    struct gt811_ts_platdata *pdata = (struct gt811_ts_platdata*)i2c_get_clientdata(client);
    int status = 0, count = 0;
    uint8_t version = {0x7, 0x17, 0};
    uint8_t config[] = {
      0x06,0xA2,
      0x12,0x10,0x0E,0x0C,0x0A,0x08,0x06,0x04,0x02,0x00,0xE2,0x53,0xD2,0x53,0xC2,0x53,
      0xB2,0x53,0xA2,0x53,0x92,0x53,0x82,0x53,0x72,0x53,0x62,0x53,0x52,0x53,0x42,0x53,
      0x32,0x53,0x22,0x53,0x12,0x53,0x02,0x53,0xF2,0x53,0x0F,0x13,0x40,0x40,0x40,0x10,
      0x10,0x10,0x0F,0x0F,0x0A,0x35,0x25,0x0C,0x03,0x00,0x05,0x20,0x03,0xE0,0x01,0x00,
      0x00,0x34,0x2C,0x36,0x2E,0x00,0x00,0x03,0x19,0x03,0x08,0x00,0x00,0x00,0x00,0x00,
      0x14,0x10,0xEC,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0x40,
      0x30,0x3C,0x28,0x00,0x00,0x00,0x00,0xC0,0x12,0x01
    };

    config = 480 >> 8;
    config = 480 & 0xff;
    config = 800 >> 8;
    config = 800 & 0xff;

    if (!gpio_is_valid(pdata->reset_pin)) {
      dev_err(dev, "The reset pin number is invalid.\n");
      return -EINVAL;
    }

    count = 3;
    while (count--) {
      gpio_direction_output(pdata->reset_pin, 0);
      msleep(10);
      gpio_direction_output(pdata->reset_pin, 1);
      msleep(100);

      if (i2c_read_bytes(client, version, sizeof(version)) < 0) {
            dev_err(dev, "Failed to get the version of GT811, try again...\n");
            status = -ENODEV;
      }
      else {
            dev_info(dev, "Gt811 detected, version(%04x)...\n", (version<<8)|version);
            status = 0;
            break;
      }
    }

    if (status) {
      return status;
    }

    count = 3;
    while (count--) {
      if (i2c_write_bytes(client, config, sizeof(config)) < 0) {
            dev_err(dev, "Failed to configure the GT811, try again...\n");
            status = -EINVAL;
      }
      else {
            dev_info(dev, "Gt811 configue succeed\n");
            status = 0;
            break;
      }
    }

    return status;
}

static struct gt811_ts_platdata *gt811_ts_parse_devtree(struct i2c_client *client)
{
    struct device *dev = &client->dev;
    struct device_node *node;
    struct gt811_ts_platdata *pdata;
    enum of_gpio_flags flags;

    node = dev->of_node;
    if (!node) {
      dev_err(dev, "The of_node is NULL.\n");
      return ERR_PTR(-ENODEV);
    }

    pdata = devm_kzalloc(dev, sizeof(struct device_node), GFP_KERNEL);
    if (!pdata) {
      dev_err(dev, "No enough memory left.\n");
      return ERR_PTR(-ENOMEM);
    }

    pdata->reset_pin = of_get_gpio_flags(node, 0, &flags);
    if (pdata->reset_pin < 0) {
      dev_err(dev, "Get RST pin failed!\n");
      return ERR_PTR(-EINVAL);
    }

    if (of_property_read_u32(node, "touchscreen-size-x", &pdata->size_x )) {
      dev_err(dev, "Failed to get the touch screen x size.\n");
      return ERR_PTR(-EINVAL);
    }

    if (of_property_read_u32(node, "touchscreen-size-y", &pdata->size_y)) {
      dev_err(dev, "Failed to get the touch screen y size.\n");
      return ERR_PTR(-EINVAL);
    }

    if (of_property_read_u32(node, "touchscreen-size-p", &pdata->size_p)) {
      pdata->size_p = 255;
    }

    if (of_property_read_u32(node, "touchscreen-swap", &pdata->swap)) {
      pdata->swap = 1;
    }

    if (of_property_read_u32(node, "touchscreen-revert-x", &pdata->revert_x)) {
      pdata->revert_x = 1;
    }

    if (of_property_read_u32(node, "touchscreen-revert-y", &pdata->revert_y)) {
      pdata->revert_y = 1;
    }

    return pdata;
}

static int gt811_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    struct device *dev = &client->dev;
    struct gt811_ts_platdata *pdata = dev_get_platdata(dev);
    struct input_dev *input;
    int error = 0;

    if (!of_match_device(of_match_ptr(gt811_ts_of_match), dev)) {
      dev_err(dev, "Failed to match.\n");
      return -EINVAL;
    }

    if (!pdata) {
      pdata = gt811_ts_parse_devtree(client);
      if (IS_ERR(pdata)) {
            dev_err(dev, "Get device data from device tree failed!\n");
            error = -EINVAL;
            goto failed_exit;
      }
    }

    pdata->client = client;

    i2c_set_clientdata(client, pdata);

    error = devm_gpio_request_one(&client->dev, pdata->reset_pin,
                GPIOF_OUT_INIT_HIGH, "gt811_rst_pin");
    if (error < 0) {
      dev_err(dev, "Failed to request gt811 reset pin\n");
      return error;
    }

    input = devm_input_allocate_device(dev);
    if (!input) {
      dev_err(dev, "Failed to allocate input device\n");
      error = -ENOMEM;
      goto pdata_free;
    }

    pdata->input = input;

    input->name = client->name;
    input->id.bustype = BUS_I2C;
    input->id.product = 0xBEEF;
    input->id.vendor=0xDEAD;
    input->dev.parent = &client->dev;

    __set_bit(EV_KEY, input->evbit);
    __set_bit(EV_ABS, input->evbit);
    __set_bit(BTN_TOUCH, input->keybit);
    input_set_abs_params(input, ABS_X, 0, pdata->size_x, 0, 0);
    input_set_abs_params(input, ABS_Y, 0, pdata->size_y, 0, 0);
    input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->size_x, 0, 0);
    input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->size_y, 0, 0);

    error = input_mt_init_slots(input, 5, INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
    if (error) {
      dev_err(dev, "Failed to initialize the multi-touch slots.\n");
      goto input_free;
    }

    input_set_drvdata(input, pdata);

    error = input_register_device(input);
    if (error) {
      dev_err(dev, "Register input device failed!\n");
      goto input_free;
    }

    if (gt811_ts_initilize(client)) {
      dev_err(dev, "Failed to initialize GT811.\n");
    }

    INIT_WORK(&pdata->work, gt811_ts_handler);

    error = devm_request_irq(dev, client->irq, gt811_ts_isr,
                      IRQF_TRIGGER_FALLING, client->name, pdata);
    if (error) {
      dev_err(dev, "Failed to request irq(number:%d)\n", client->irq);
      goto input_free;
    }

    return 0;

input_free:
    devm_kfree(dev, input);
pdata_free:
    devm_kfree(dev, pdata);
failed_exit:
    return error;
}

static int gt811_ts_remove(struct i2c_client *client)
{
    struct gt811_ts_platdata *pdata = (struct gt811_ts_platdata*)i2c_get_clientdata(client);

    devm_free_irq(&client->dev, client->irq, i2c_get_clientdata(client));

    input_unregister_device(pdata->input);

    devm_kfree(&client->dev, pdata);
    return 0;
}

static const struct i2c_device_id gt811_ts_id[] = {
    { "gt811_ts", 0 },
    { }
};

static struct i2c_driver gt811_ts_driver = {
    .driver = {
      .owner= THIS_MODULE,
      .name   = "gt811_ts",
      .of_match_table = of_match_ptr(gt811_ts_of_match),
    },
    .probe      = gt811_ts_probe,
    .remove   = gt811_ts_remove,
    .id_table   = gt811_ts_id,
};

module_i2c_driver(gt811_ts_driver);

MODULE_AUTHOR("girlkoo <nightmeng@gmail.com>");
MODULE_DESCRIPTION("GT811 I2C Touchscreen Driver");
MODULE_LICENSE("GPL");



  编译以上代码得到相应的ko文件,然后将该ko拷贝SD卡的根文件系统内。完整的代码下载链接如下(赚点下载积分^_^):
  http://download.csdn.net/detail/girlkoo/8710677

  测试方法

  我认为最实用的测试方法就是tslib,tslib的配置方法请参考TQ210的移植笔记或者自己网上搜索资料,我这里就不重复了,安装好tslib后先通过ts_calibrate校准触摸屏(实际上电容屏是不需要校准的,仅仅是为了使用tslib),然后运行ts_test并点draw按钮,即可随意画图。下面是实测效果图:
http://img.blog.csdn.net/20150518002737754?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ2lybGtvbw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast  至此,触摸屏驱动就移植完成了。有问题请帮忙指出,有任何疑问欢迎留言讨论。



gefsmile 发表于 2015-6-2 22:48:22

你好,我在使用源码的过程中出现了这个错误:Failed to get the version of GT811, try again...
请问一下,可能是什么原因?

hflw 发表于 2015-10-30 13:16:49

e9的板子,5寸屏,自己制作的根文件系统,自己编译的tslib,为什么ts_calibrate,校准时,没有任何反应,但是运行ts_print_raw很正常。但是我用官方给的文件系统,里面的QT程序运行时,触摸屏运行的也正常。谁遇到这个问题没

山鹰之念 发表于 2015-11-22 15:30:58

hflw 发表于 2015-10-30 13:16
e9的板子,5寸屏,自己制作的根文件系统,自己编译的tslib,为什么ts_calibrate,校准时,没有任何反应,但 ...

哥们问题解决了吗?我也遇到了同样的问题

416604093 发表于 2018-4-13 15:28:25

你好,请问移植过gslX680驱动吗?加入设置触摸事件中断引脚的话,要修改哪些地方呢?
页: [1]
查看完整版本: I.MX6Q学习笔记——新版BSP之触摸屏驱动移植