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 至此,触摸屏驱动就移植完成了。有问题请帮忙指出,有任何疑问欢迎留言讨论。
你好,我在使用源码的过程中出现了这个错误:Failed to get the version of GT811, try again...
请问一下,可能是什么原因? e9的板子,5寸屏,自己制作的根文件系统,自己编译的tslib,为什么ts_calibrate,校准时,没有任何反应,但是运行ts_print_raw很正常。但是我用官方给的文件系统,里面的QT程序运行时,触摸屏运行的也正常。谁遇到这个问题没 hflw 发表于 2015-10-30 13:16
e9的板子,5寸屏,自己制作的根文件系统,自己编译的tslib,为什么ts_calibrate,校准时,没有任何反应,但 ...
哥们问题解决了吗?我也遇到了同样的问题 你好,请问移植过gslX680驱动吗?加入设置触摸事件中断引脚的话,要修改哪些地方呢?
页:
[1]