1 #include <linux/module.h> 2 #include <linux/init.h> 3 #include <linux/input.h> 4 #include <linux/gpio.h> 5 #include <linux/interrupt.h> 6 #include <linux/i2c.h> 7 #include <linux/slab.h> 8 #include <linux/delay.h> 9 10 #include <plat/gpio-cfg.h> 11 12 #define TS_MAX_WIDTH 800 13 #define TS_MAX_HEIGHT 480 14 15 16 #define TS_INT_GPIO S5PV210_GPH1(6) 17 #define TS_RESET_GPIO S5PV210_GPD0(3) 18 19 20 //設計一個全局的設備對象 21 struct ts_global{ 22 int irqno; 23 int flags; // 中斷觸發方式 24 struct i2c_client *client; //記錄匹配以後的i2c client 25 struct input_dev *inputdev; 26 27 struct work_struct work; //中斷下半部 28 }; 29 30 struct ts_global *gt811_dev; 31 32 33 34 //重寫相似於i2c_master_send()/i2c_master_recv() 35 int gt811_i2c_send(struct i2c_client *client, char *buf, int count) 36 { 37 int ret; 38 39 struct i2c_adapter *adapter = client->adapter; 40 struct i2c_msg msg; 41 42 msg.addr = client->addr; 43 msg.flags = 0; //讀1仍是寫0 44 msg.len = count; 45 msg.buf = buf; 46 //參數1---適配器--來自於i2c client 47 //參數2--數據包 48 //參數3--數據包的個數 49 //返回值--正確返回消息的個數,錯誤返回負數 50 ret = i2c_transfer(adapter, &msg, 1); 51 52 return ret==1?count:ret; 53 54 } 55 56 57 // char rbuf[10] = {0x7, 0x21 /*寄存器地址*/, }; // 後面8個字節用於存放讀取到的數據 58 // gt811_i2c_recv_reg(client , rbuf, 10); 59 int gt811_i2c_recv_reg(struct i2c_client *client, char *buf, int count) 60 { 61 int ret; 62 63 struct i2c_adapter *adapter = client->adapter; 64 struct i2c_msg msg[2]; 65 66 msg[0].addr = client->addr; 67 msg[0].flags = 0; //先寫 68 msg[0].len = 2; //寄存器地址爲16bit 69 msg[0].buf = &buf[0]; 70 71 msg[1].addr = client->addr; 72 msg[1].flags = 1; //後讀 73 msg[1].len = count-2; // 74 msg[1].buf = &buf[2]; 75 76 //參數1---適配器--來自於i2c client 77 //參數2--數據包 78 //參數3--數據包的個數 79 //返回值--正確返回消息的個數,錯誤返回負數 80 ret = i2c_transfer(adapter, msg, 2); 81 82 return ret==2?count-2:ret; 83 84 } 85 86 87 int gt811_init_reg(void) 88 { 89 int ret; 90 91 uint8_t config_info[] = { 92 0x06,0xA2, //寄存器地址 93 94 0x12,0x10,0x0E,0x0C,0x0A,0x08,0x06,0x04,0x02,0x00,0x05,0x55,0x15,0x55,0x25,0x55,\ 95 0x35,0x55,0x45,0x55,0x55,0x55,0x65,0x55,0x75,0x55,0x85,0x55,0x95,0x55,0xA5,0x55,\ 96 0xB5,0x55,0xC5,0x55,0xD5,0x55,0xE5,0x55,0xF5,0x55,0x1B,0x03,0x00,0x00,0x00,0x13,\ 97 0x13,0x13,0x0F,0x0F,0x0A,0x50,0x30,0x0D,0x03,0x00,0x05,0x58,0x02,0x00,0x04,0x00,\ 98 0x00,0x32,0x2C,0x34,0x2E,0x00,0x00,0x04,0x14,0x22,0x04,0x00,0x00,0x00,0x00,0x00,\ 99 0x20,0x14,0xEC,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x30,\ 100 0x25,0x28,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x01\ 101 }; 102 103 config_info[57] &= ~(1<<3); 104 gt811_dev->flags = IRQF_TRIGGER_FALLING; 105 106 config_info[61] = TS_MAX_HEIGHT & 0xff; 107 config_info[62] = TS_MAX_HEIGHT >> 8; 108 109 config_info[63] = TS_MAX_WIDTH& 0xff; 110 config_info[64] = TS_MAX_WIDTH >> 8; 111 112 ret = gt811_i2c_send(gt811_dev->client, config_info, ARRAY_SIZE(config_info)); 113 114 return ret>0?0:ret; 115 116 } 117 118 119 120 void gt811_irq_work(struct work_struct *work) 121 { 122 123 /* 124 1,經過i2c_tranfser(會致使休眠)讀取到座標 125 2, 分析座標 126 3, 上報座標 127 128 */ 129 130 int ret; 131 uint8_t axis_buf[36] = {0x7, 0x21,}; 132 133 ret = gt811_i2c_recv_reg(gt811_dev->client, axis_buf, 36); 134 if(ret < 0) 135 { 136 printk("gt811_i2c_recv_reg error\n"); 137 return; 138 } 139 140 //先進行校驗 141 //先要知道當前是哪幾個點 142 unsigned char temp = axis_buf[2] & 0x1f; // 取低5bit 143 int i; 144 unsigned char soft_chksum = 0; 145 int index; 146 switch(temp) 147 { 148 case 0: //沒有點,表示擡起 149 index = 4; 150 break; 151 case 1: //表示第0點被點 152 index = 9; 153 break; 154 case 2: 155 case 3: //表示第1點被點 156 index = 14; 157 break; 158 159 default: //表示 2, 3, 4點 160 index = 35; 161 break; 162 163 } 164 for(i=2; i<index; i++) 165 soft_chksum += axis_buf[i]; 166 167 if(soft_chksum != axis_buf[index]) 168 { 169 printk("check sum error\n"); 170 return ; 171 } 172 173 // 判斷出當前有幾個點,具體是那幾個點 174 temp = axis_buf[2] & 0x1f; // 取低5bit 175 int pcount = 0 ; //點的個數 176 int pset[5]; //當前被點的點號集合 177 for(i=0; i<5; i++) 178 { 179 if(temp & 1) 180 { 181 pset[pcount++] = i; 182 } 183 temp = temp >> 1; 184 } 185 186 int j; 187 __u16 x; 188 __u16 y; 189 __u8 p; 190 int pindex = 0; 191 if(pcount > 0) 192 { 193 for(j=0; j<pcount; j++) 194 { 195 switch(pset[j]) 196 { 197 case 0: 198 pindex = 4; 199 break; 200 case 1: 201 pindex = 9; 202 break; 203 case 2: 204 pindex = 14; 205 break; 206 case 3: 207 pindex = 19; 208 break; 209 case 4: 210 pindex = 30; 211 break; 212 } 213 if(pset[j] == 3) 214 { 215 x = axis_buf[19]<<8 | axis_buf[26]; 216 y = axis_buf[27]<<8 | axis_buf[28]; 217 p = axis_buf[29]; 218 }else 219 { 220 x = axis_buf[pindex]<<8 | axis_buf[pindex+1]; 221 y = axis_buf[pindex+2]<<8 | axis_buf[pindex+3]; 222 p = axis_buf[pindex+4]; 223 } 224 225 swap(x, y); 226 227 y = 480-y; 228 //printk("x = %d, y = %d, p = %d, id = %d\n", x, y, p, pset[j]); 229 230 input_event(gt811_dev->inputdev, EV_ABS, ABS_MT_POSITION_X, x); 231 input_event(gt811_dev->inputdev, EV_ABS, ABS_MT_POSITION_Y, y); 232 input_event(gt811_dev->inputdev, EV_ABS, ABS_MT_PRESSURE, p); 233 input_event(gt811_dev->inputdev, EV_ABS, ABS_MT_TOUCH_MAJOR, p); 234 input_event(gt811_dev->inputdev, EV_ABS, ABS_MT_TRACKING_ID, pset[j]); 235 input_mt_sync(gt811_dev->inputdev); 236 237 } 238 } 239 //按下和擡起 240 input_report_key(gt811_dev->inputdev, BTN_TOUCH, pcount > 0); 241 input_sync(gt811_dev->inputdev); 242 } 243 244 245 irqreturn_t gt811_irq_svc(int irqno, void *dev_id) 246 { 247 248 249 //啓動下半部--委託 250 schedule_work(>811_dev->work); 251 252 253 return IRQ_HANDLED; 254 } 255 256 257 258 int gt811_drv_probe(struct i2c_client *client, const struct i2c_device_id *id) 259 { 260 int ret; 261 262 gt811_dev = kzalloc(sizeof(struct ts_global), GFP_KERNEL); 263 264 // 0--記錄當前的i2c client 265 gt811_dev->client = client; 266 267 /* 268 4, 硬件初始化: 269 a, 初始化寄存器 270 1, 設置中斷引腳爲懸浮輸入態,RESET設置成GPIO(內部上拉) 271 2, RESET引腳設置成輸出低(開始復位), 延時1ms, 轉成輸入態 272 3, 延遲至少20ms,經過i2c尋址gt811 (確認復位是否成功) 273 4,若是有響應,分一次或者屢次初始化寄存器 274 5,若是沒有響應,重複2步驟 275 b, 申請中斷--request_irq(), 還要用中斷下半部(tasklet, 工做隊列(選擇這個)) 276 | 277 1,經過i2c_tranfser讀取到座標 278 2, 分析座標 279 3, 上報座標 280 281 */ 282 283 gpio_request(TS_INT_GPIO, "ts_int"); 284 gpio_direction_input(TS_INT_GPIO); 285 gpio_free(TS_INT_GPIO); 286 287 gpio_request(TS_RESET_GPIO, "ts_reset"); 288 s3c_gpio_setpull(TS_RESET_GPIO, S3C_GPIO_PULL_UP); 289 mdelay(2); 290 gpio_direction_output(TS_RESET_GPIO, 0); 291 mdelay(1); 292 gpio_direction_input(TS_RESET_GPIO); 293 gpio_free(TS_RESET_GPIO); 294 295 mdelay(25); 296 //經過發送數據給gt811, 看看是否成功 297 char test = 1; 298 ret = i2c_master_send(gt811_dev->client, &test, 1); 299 if(ret < 0) 300 { 301 printk("gt811 reset failed or not found\n"); 302 kfree(gt811_dev); 303 return ret; 304 }else 305 { 306 printk("gt811 reset ok\n"); 307 } 308 309 ret = gt811_init_reg(); 310 if(ret < 0) 311 { 312 printk("gt811_init_reg failed\n"); 313 kfree(gt811_dev); 314 return ret; 315 }else 316 { 317 printk("gt811 init ok\n"); 318 } 319 320 // 4, 硬件初始化,獲取到硬件的數據,上報給input handler 321 //申請中斷 322 //初始化中斷下半部 323 INIT_WORK(>811_dev->work, gt811_irq_work); 324 325 gt811_dev->irqno = gpio_to_irq(TS_INT_GPIO); 326 ret = request_irq(gt811_dev->irqno, gt811_irq_svc, gt811_dev->flags, 327 "ts_eint14", NULL); 328 329 // 1, 構建一個input device 330 gt811_dev->inputdev = input_allocate_device(); 331 332 //爲輸入設備提供額外信息--供用戶查看--/sys/class/input/eventX/device/.. 333 gt811_dev->inputdev->name = "gt811_ts"; 334 gt811_dev->inputdev->phys = "goodix/ts/input0"; 335 gt811_dev->inputdev->uniq = "goodix/gt811"; 336 gt811_dev->inputdev->id.bustype = BUS_I2C; 337 gt811_dev->inputdev->id.vendor = 0xDEAD; 338 gt811_dev->inputdev->id.product = 0x0007; 339 gt811_dev->inputdev->id.version = 0x0001; 340 341 // 2, 初始化 input device 342 // 2.1 設置當前輸入設備可以產生那些類型數據 343 __set_bit(EV_ABS, gt811_dev->inputdev->evbit); 344 __set_bit(EV_KEY, gt811_dev->inputdev->evbit); 345 346 347 // 2.2設置要產生那些按鍵 348 __set_bit(BTN_TOUCH, gt811_dev->inputdev->keybit); 349 __set_bit(KEY_MENU, gt811_dev->inputdev->keybit); 350 __set_bit(KEY_HOME, gt811_dev->inputdev->keybit); 351 __set_bit(KEY_ESC, gt811_dev->inputdev->keybit); 352 353 354 // 2.3 設置要產生那些絕對數據 355 //針對單點 356 __set_bit(ABS_X, gt811_dev->inputdev->absbit); 357 __set_bit(ABS_Y, gt811_dev->inputdev->absbit); 358 __set_bit(ABS_PRESSURE, gt811_dev->inputdev->absbit); 359 360 //針對多點 361 __set_bit(ABS_MT_POSITION_X, gt811_dev->inputdev->absbit); 362 __set_bit(ABS_MT_POSITION_Y, gt811_dev->inputdev->absbit); 363 __set_bit(ABS_MT_PRESSURE, gt811_dev->inputdev->absbit); 364 __set_bit(ABS_MT_TOUCH_MAJOR, gt811_dev->inputdev->absbit); 365 __set_bit(ABS_MT_TRACKING_ID, gt811_dev->inputdev->absbit); 366 367 368 // 2.4 --若是有abs的值,還須要設置abs的最大值和最小值 369 //參數1---設置哪一個設備 370 //參數2--座標 371 //參數3-4;最小值和最大值 372 //參數5-6: 通常填0 373 input_set_abs_params(gt811_dev->inputdev, ABS_X, 0, TS_MAX_WIDTH, 0, 0); 374 input_set_abs_params(gt811_dev->inputdev, ABS_Y, 0, TS_MAX_HEIGHT, 0, 0); 375 input_set_abs_params(gt811_dev->inputdev, ABS_PRESSURE, 0, 16, 0, 0); 376 377 input_set_abs_params(gt811_dev->inputdev, ABS_MT_POSITION_X, 0, TS_MAX_WIDTH, 0, 0); 378 input_set_abs_params(gt811_dev->inputdev, ABS_MT_POSITION_Y, 0, TS_MAX_HEIGHT, 0, 0); 379 input_set_abs_params(gt811_dev->inputdev, ABS_MT_PRESSURE, 0, 16, 0, 0); 380 input_set_abs_params(gt811_dev->inputdev, ABS_MT_TOUCH_MAJOR, 0, 16, 0, 0); 381 input_set_abs_params(gt811_dev->inputdev, ABS_MT_TRACKING_ID, 0, 4, 0, 0); 382 383 // 3, 註冊input device 384 ret = input_register_device(gt811_dev->inputdev); 385 386 387 388 389 390 391 392 return 0; 393 394 } 395 396 397 int gt811_drv_remove(struct i2c_client *client) 398 { 399 400 input_unregister_device(gt811_dev->inputdev); 401 input_free_device(gt811_dev->inputdev); 402 403 cancel_work_sync(>811_dev->work); 404 free_irq(gt811_dev->irqno, NULL); 405 406 kfree(gt811_dev); 407 408 return 0; 409 } 410 411 412 const struct i2c_device_id gt811_id_table[] = { 413 {"gt811_i2c_ts", 0x811}, 414 {} 415 }; 416 417 418 struct i2c_driver gt811_i2c_drv = { 419 .probe = gt811_drv_probe, 420 .remove = gt811_drv_remove, 421 .driver = { 422 .name = "gt811_drv", 423 }, 424 .id_table = gt811_id_table, 425 426 }; 427 428 429 430 431 static int __init gt811_drv_init(void) 432 { 433 //註冊一個i2c driver 434 return i2c_add_driver(>811_i2c_drv); 435 436 } 437 438 439 static void __exit gt811_drv_exit(void) 440 { 441 442 i2c_del_driver(>811_i2c_drv); 443 } 444 445 module_init(gt811_drv_init); 446 module_exit(gt811_drv_exit); 447 MODULE_LICENSE("GPL");
1 CROSS_COMPILE = arm-none-linux-gnueabi- 2 CC = $(CROSS_COMPILE)gcc 3 4 #指定內核源碼路徑 5 KERNEL_DIR = /home/kernel/linux-3.0.8 6 CUR_DIR = $(shell pwd) 7 8 MYAPP = ts_app 9 10 MODULE = gt811_i2c_drv 11 12 all: 13 #讓make進入內核源碼編譯,同時將當前目錄中的c程序做爲內核模塊一塊兒編譯 14 make -C $(KERNEL_DIR) M=$(CUR_DIR) modules 15 ifneq ($(MYAPP), ) 16 $(CC) -o $(MYAPP) $(MYAPP).c 17 endif 18 19 clean: 20 #刪除上面編譯生成的文件 21 make -C $(KERNEL_DIR) M=$(CUR_DIR) clean 22 rm -rf $(MYAPP) 23 24 install: 25 cp *.ko $(MYAPP) /opt/rootfs/drv_module 26 27 #指定當前目錄下哪一個文件做爲內核模塊編 28 obj-m += $(MODULE).o
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <unistd.h> 5 #include <sys/types.h> 6 #include <sys/stat.h> 7 #include <fcntl.h> 8 #include <sys/ioctl.h> 9 #include <linux/input.h> 10 11 12 int main(void) 13 { 14 15 int fd; 16 int ret; 17 18 struct input_event package; 19 20 21 fd = open("/dev/event0",O_RDWR); 22 if(fd < 0) 23 { 24 perror("open"); 25 exit(1); 26 } 27 28 while(1) 29 { 30 bzero(&package,sizeof(package)); 31 ret = read(fd, &package,sizeof(package)); 32 if(ret < 0) 33 { 34 perror("read"); 35 exit(1); 36 } 37 //拆包 38 if(package.type == EV_KEY) 39 { 40 if(package.code == KEY_DOWN) 41 { 42 if(package.value) 43 { 44 printf("<app>-- KEY_DOWN pressed\n"); 45 }else 46 { 47 printf("<app>-- KEY_DOWN up\n"); 48 } 49 } 50 if(package.code == KEY_POWER) 51 { 52 if(package.value) 53 { 54 printf("<app>-- KEY_POWER pressed\n"); 55 }else 56 { 57 printf("<app>-- KEY_POWER up\n"); 58 } 59 } 60 } 61 62 63 if(package.type == EV_ABS) 64 { 65 switch(package.code) 66 { 67 case ABS_MT_POSITION_X: 68 printf(" x = %d ", package.value); 69 break; 70 case ABS_MT_POSITION_Y: 71 printf(" y = %d ", package.value); 72 break; 73 case ABS_MT_PRESSURE: 74 printf(" p = %d ", package.value); 75 break; 76 case ABS_MT_TRACKING_ID: 77 printf(" id = %d \n", package.value); 78 break; 79 80 } 81 } 82 } 83 84 close(fd); 85 86 return 0; 87 }