转载自:http://blog.csdn.net/lizuobin2/article/details/55264211
开发板:tiny4412SDK + S702 + 4GB Flash
要移植的内核版本:Linux-4.4.0 (支持device tree)
u-boot版本:友善之臂自带的 U-Boot 2010.12
busybox版本:busybox 1.25
友善之臂提供的资料中,触摸屏驱动采用的是一线触控,但是保留了i2c接口,驱动芯片为FT5406,本文主要实现 i2c 接口的触摸屏驱动。
首先,分析下 FT5406 的基本电路接口:
基本都是通用的接口,如 I2C 接口,INT,WAKE,RST。如图:
以上可知,我们在驱动中必须定义一个中断口,来启动接收触摸数据,一个gpio脚来复位FT5406。wake:主要靠cpu发送一个唤醒指令给FT5406。
查看tiny4412原理图
再次,需确认FT5406的从地址,以便于I2C访问得到。这个可以根据FT5406数据手册查找到.
可知从地址高位必须为:3,低位必须根据 i2ccon 设定的值来确定,这点很奇怪。
我这边找到的从地址为:0x38
i2ccon 暂时未找到出处,可以用 i2c tools 探测一下
/mnt # ./i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- 38 -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
基本的东西确认好后,剩下的就是根据FT5406数据手册上的指令,开始写驱动了。
在此之前,我们先了解下驱动如何实现电容屏的多点触摸,其实很简单,主要需要
触摸屏IC FT5406 能够捕获多点数据,这点电容屏基本多能支持到捕获2点以上,而FT5406 可以捕获5个触摸点,编写驱动时,只要去获取这几个点的数据,然后上报就行。格式如图:
解释:
- 02h : 捕获的触摸点个数
- 03h- 1eh :对应每个点的x,y坐标数值。
- touch id 表示触点编号,对应于typeB的slot
驱动参考:Ft6236.c (drivers\input\touchscreen)
touch_demo{
compatible = "tiny4412,touch_demo";
interrupts = <6 0>;
interrupt-parent = <&gpx1>;
status = "okay";
};
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
&i2c_1{
status = "okay";
touch@38{
compatible = "tiny4412,touch";
reg = <0x38>;
};
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/of_gpio.h>
#define uchar unsigned char
static void touch_read_handler(struct work_struct *work);
DECLARE_WORK(touch_read_work, touch_read_handler);
static struct i2c_client *touch_client;
static struct input_dev *touch_dev;
static int irq;
static void touch_read(unsigned char sAddr, unsigned char *buf, unsigned int len)
{
struct i2c_msg msg[2];
int i, ret;
unsigned char address;
for (i = 0; i < len; i++)
{
/* 先写入要读取的寄存器地址 */
address = sAddr + i;
msg[0].addr = touch_client->addr; /* 目的 */
msg[0].buf = &address; /* 源 */
msg[0].len = 1; /* 地址=1 byte */
msg[0].flags = 0; /* 表示写 */
/* 然后启动读操作 */
msg[1].addr = touch_client->addr; /* 源 */
msg[1].buf = &buf[i]; /* 目的 */
msg[1].len = 1; /* 数据=1 byte */
msg[1].flags = I2C_M_RD; /* 表示读 */
ret = i2c_transfer(touch_client->adapter, msg, 2);
if (ret < 0)
{
printk("i2c_transfer eror\n");
}
mdelay(10);
}
}
static void touch_read_handler(struct work_struct *work)
{
unsigned char buf[13];
unsigned char touches, i, event, id;
unsigned short x, y;
bool act;
/* read tp resister by i2c */
touch_read(0x00, buf, 13);
/* number of touch points */
touches = buf[2] & 0x0f;
//printk("point num %d\n", touches);
if (touches > 2) {
printk("%s touch read touches error\n",__func__);
touches = 2;
}
for (i = 0; i < touches; i++) {
y = ((buf[5 + i * 6] & 0x0f) << 8) | buf[6 + i * 6];
x = ((buf[3 + i * 6] & 0x0f) << 8) | buf[4 + i * 6];
//printk("%d point x:%08d y:%08d\n", i, x, y);
event = buf[3 + i * 6] >> 6; //event flags
id = buf[5 + i * 6] >> 4; //touch id
//printk("event %d id %d\n", event, id);
//down or contact
act = (event == 0x00 || event == 0x02);
input_mt_slot(touch_dev, id);
input_mt_report_slot_state(touch_dev, MT_TOOL_FINGER, act);
//if up return
if (!act)
continue;
input_report_abs(touch_dev, ABS_MT_POSITION_X, x);
input_report_abs(touch_dev, ABS_MT_POSITION_Y, y);
}
input_mt_sync_frame(touch_dev);
input_sync(touch_dev);
}
static irqreturn_t touch_isr(int irq, void *dev_id)
{
schedule_work(&touch_read_work);
return IRQ_HANDLED;
}
static int touch_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
unsigned char buf;
int ret;
touch_client = client;
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
touch_read(0xa3, &buf, 1);
printk("Chip vendor ID %x\n", buf);
touch_read(0xa6, &buf, 1);
printk("Firmware ID %x\n", buf);
touch_read(0xa8, &buf, 1);
printk("CTPM Vendor ID %x\n", buf);
touch_read(0x00, &buf, 1);
printk("DEVIDE_MODE %x\n", buf);
touch_read(0x80, &buf, 1);
printk("ID_G_THGROUP. %x\n", buf);
touch_read(0x88, &buf, 1);
printk("ID_G_PERIODACTIVE. %x\n", buf);
touch_dev = input_allocate_device();
if (touch_dev == NULL)
{
printk("%s, allocate input device, error\n", __func__);
return -1;
}
//告诉input能够支持哪些事件
input_set_abs_params(touch_dev, ABS_MT_POSITION_X, 0, 800, 0, 0);
input_set_abs_params(touch_dev, ABS_MT_POSITION_Y, 0, 480, 0, 0);
ret = input_mt_init_slots(touch_dev, 2, INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
if (ret)
{
printk("%s, input_mt_init_slots error\n", __func__);
return ret;
}
touch_dev->name = "touch";
touch_dev->id.bustype = BUS_I2C;
touch_dev->dev.parent = &(touch_client)->dev;
ret = input_register_device(touch_dev);
if (ret)
{
printk("%s, register input device, error\n", __func__);
return ret;
}
printk("irq is %d\n", irq);
ret = devm_request_threaded_irq(&touch_client->dev, irq, touch_isr, NULL, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "touch1", NULL);
if (ret < 0)
{
printk("failed to request_irq %d\n", ret);
}
return 0;
}
static int touch_remove(struct i2c_client *client)
{
return 0;
}
static const struct i2c_device_id touch_id_table[] =
{
{ "touch", 0 },
{}
};
/* 1. 分配/设置i2c_driver */
static struct i2c_driver touch_driver =
{
.driver = {
.name = "touch",
.owner = THIS_MODULE,
},
.probe = touch_probe,
.remove = touch_remove,
.id_table = touch_id_table,
};
static int int_demo_remove(struct platform_device *pdev) {
printk("%s enter.\n", __func__);
return 0;
}
static int int_demo_probe(struct platform_device *pdev) {
irq = platform_get_irq(pdev, 0);
printk("int_demo_probe %d\n", irq);
return 0;
}
static const struct of_device_id touch_demo_dt_ids[] = {
{ .compatible = "tiny4412,touch_demo", },
{},
};
MODULE_DEVICE_TABLE(of, touch_demo_dt_ids);
static struct platform_driver touch_demo_driver = {
.driver = {
.name = "touch_demo",
.of_match_table = of_match_ptr(touch_demo_dt_ids),
},
.probe = int_demo_probe,
.remove = int_demo_remove,
};
static int touch_drv_init(void)
{
int ret;
/* 1.注册平台设备驱动 */
ret = platform_driver_register(&touch_demo_driver);
if (ret)
printk(KERN_ERR "int demo: probe failed: %d\n", ret);
/* 2. 注册i2c_driver */
i2c_add_driver(&touch_driver);
return 0;
}
static void touch_drv_exit(void)
{
i2c_del_driver(&touch_driver);
platform_driver_unregister(&touch_demo_driver);
}
module_init(touch_drv_init);
module_exit(touch_drv_exit);
MODULE_LICENSE("GPL");
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253