4 * Copyright (C) 2013 VTL Corporation.
\r
6 * This program is free software; you can redistribute it and/or
\r
7 * modify it under the terms of the GNU General Public License
\r
8 * version 2 as published by the Free Software Foundation.
\r
10 * This program is distributed in the hope that it will be useful, but
\r
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
13 * General Public License for more details.
\r
15 * You should have received a copy of the GNU General Public License
\r
16 * along with this program; if not, write to the Free Software
\r
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
\r
22 #include <linux/kernel.h>
\r
23 #include <linux/timer.h>
\r
24 #include <linux/types.h>
\r
25 #include <linux/module.h>
\r
26 #include <linux/version.h>
\r
27 #include <linux/fs.h>
\r
28 #include <linux/proc_fs.h>
\r
29 #include <asm/uaccess.h>
\r
30 #include <linux/i2c.h>
\r
31 #include <linux/delay.h>
\r
32 #include <linux/interrupt.h>
\r
33 #include <linux/input.h>
\r
34 #include <linux/input/mt.h>
\r
35 #include <linux/gpio.h>
\r
36 #include <linux/sched.h>
\r
37 #include <linux/kthread.h>
\r
38 #include <linux/of_gpio.h>
\r
39 #include <linux/vmalloc.h>
\r
47 #define TS_THREAD_PRIO 90
\r
48 static DECLARE_WAIT_QUEUE_HEAD(waiter);
\r
49 //static struct task_struct *ts_thread = NULL;
\r
50 static unsigned char thread_syn_flag =0;
\r
51 static volatile unsigned char thread_running_flag =0;
\r
54 // ****************************************************************************
\r
55 // Globel or static variables
\r
56 // ****************************************************************************
\r
57 static struct ts_driver g_driver;
\r
58 static int vtl_first_init_flag = 1;
\r
59 struct ts_info g_ts = {
\r
60 .driver = &g_driver,
\r
61 .debug = DEBUG_ENABLE,
\r
63 struct ts_info *pg_ts = &g_ts;
\r
65 static struct i2c_device_id vtl_ts_id[] = {
\r
69 MODULE_DEVICE_TABLE(i2c,vtl_ts_id);
\r
73 static struct i2c_board_info i2c_info[] = {
\r
75 I2C_BOARD_INFO(DRIVER_NAME, 0x01),
\r
76 .platform_data = NULL,
\r
82 // ****************************************************************************
\r
83 // Function declaration
\r
84 // ****************************************************************************
\r
85 unsigned char *gtpfw;
\r
86 static int vtl_ts_config(struct ts_info *ts)
\r
88 struct device *dev = &ts->driver->client->dev;
\r
89 //struct ts_config_info *ts_config_info;
\r
91 struct device_node *np = dev->of_node;
\r
92 enum of_gpio_flags rst_flags;
\r
93 unsigned long irq_flags;
\r
95 struct device_node *tnp;
\r
96 struct property *prop;
\r
98 unsigned int max_num;
\r
99 unsigned char *levels;
\r
102 tnp = of_find_node_by_path("/tp-fw");
\r
104 printk(" error tp_fw not node!!!\n");
\r
107 /* determine the number of brightness levels */
108 prop = of_find_property(tnp, "tp_fw", &length);
\r
110 printk(" error tp_fw not property!!!\n");
\r
114 max_num = length / sizeof(u32);
\r
116 printk(" max-num:%d,length:%d.\n",max_num,length);
\r
118 /* read max_num from DT property */
\r
121 levels = (unsigned char*)vmalloc(max_num);
\r
123 printk("<xiaoyao> error vmalloc failed!!!\n");
\r
127 ret = of_property_read_u8_array_tp(tnp,"tp_fw",levels,max_num);
\r
129 printk(" of_property_read_u8_array failed!!!\n");
\r
134 printk("tp fw error!!!\n");
\r
141 ts->config_info.touch_point_number = TOUCH_POINT_NUM;
\r
142 if(dev->platform_data !=NULL)
\r
149 if (of_property_read_u32(np, "screen_max_x", &val)) {
\r
150 dev_err(&ts->driver->client->dev, "no screen_max_x defined\n");
\r
153 ts->config_info.screen_max_x = val;
\r
155 if (of_property_read_u32(np, "screen_max_y", &val)) {
\r
156 dev_err(&ts->driver->client->dev, "no screen_max_y defined\n");
\r
159 ts->config_info.screen_max_y = val;
\r
161 if (of_property_read_u32(np, "xy_swap", &val)) {
\r
164 ts->config_info.xy_swap = val;
\r
166 if (of_property_read_u32(np, "x_reverse", &val)) {
\r
169 ts->config_info.x_reverse = val;
\r
171 if (of_property_read_u32(np, "y_reverse", &val)) {
\r
174 ts->config_info.y_reverse = val;
\r
176 if (of_property_read_u32(np, "x_mul", &val)) {
\r
179 ts->config_info.x_mul = val;
\r
181 if (of_property_read_u32(np, "y_mul", &val)) {
\r
184 ts->config_info.y_mul = val;
\r
187 if (of_property_read_u32(np, "bin_ver", &val)) {
\r
190 ts->config_info.bin_ver = val;
\r
191 printk("--->>> vtl_ts : xy_swap %d, x_reverse %d, y_reverse %d, x_mul %d, y_mul %d, bin_ver %d\n",
\r
192 ts->config_info.xy_swap,
\r
193 ts->config_info.x_reverse, ts->config_info.y_reverse,
\r
194 ts->config_info.x_mul, ts->config_info.y_mul,
\r
195 ts->config_info.bin_ver);
\r
196 printk("the screen_x is %d , screen_y is %d \n",ts->config_info.screen_max_x,ts->config_info.screen_max_y);
\r
198 ts->config_info.irq_gpio_number = of_get_named_gpio_flags(np, "irq_gpio_number", 0, (enum of_gpio_flags *)&irq_flags);
\r
199 ts->config_info.rst_gpio_number = of_get_named_gpio_flags(np, "rst_gpio_number", 0, &rst_flags);
\r
203 ts->config_info.irq_number = gpio_to_irq(ts->config_info.irq_gpio_number);/* IRQ config*/
\r
205 err = gpio_request(ts->config_info.rst_gpio_number, "vtl_ts_rst");
\r
209 gpio_direction_output(ts->config_info.rst_gpio_number, 1);
\r
210 //gpio_set_value(ts->config_info.rst_gpio_number, 1);
\r
216 struct ts_info * vtl_ts_get_object(void)
\r
223 static void vtl_ts_free_gpio(void)
\r
225 struct ts_info *ts;
\r
229 gpio_free(ts->config_info.rst_gpio_number);
\r
233 void vtl_ts_hw_reset(void)
\r
235 struct ts_info *ts;
\r
239 //gpio_set_value(ts->config_info.rst_gpio_number, 1);
\r
241 gpio_set_value(ts->config_info.rst_gpio_number, 0);
\r
243 gpio_set_value(ts->config_info.rst_gpio_number, 1);
\r
246 chip_solfware_reset(ts->driver->client);//20140306
\r
249 static void vtl_ts_wakeup(void)
\r
251 struct ts_info *ts;
\r
255 gpio_set_value(ts->config_info.rst_gpio_number, 0);
\r
258 gpio_set_value(ts->config_info.rst_gpio_number, 1);
\r
260 chip_solfware_reset(ts->driver->client);//20140306
\r
263 static irqreturn_t vtl_ts_irq(int irq, void *dev)
\r
265 struct ts_info *ts;
\r
270 disable_irq_nosync(ts->config_info.irq_number);// Disable ts interrupt
\r
271 thread_syn_flag=1;
\r
272 wake_up_interruptible(&waiter);
\r
274 return IRQ_HANDLED;
\r
278 static int vtl_ts_read_xy_data(struct ts_info *ts)
\r
280 struct i2c_msg msgs;
\r
285 msgs.addr = ts->driver->client->addr;
\r
286 msgs.flags = 0x01; // 0x00: write 0x01:read
\r
287 msgs.len = sizeof(ts->xy_data.buf);
\r
288 msgs.buf = ts->xy_data.buf;
\r
289 msgs.scl_rate = TS_I2C_SPEED; ///only for rockchip platform
\r
290 ret = i2c_transfer( ts->driver->client->adapter, &msgs, 1);
\r
292 printk("___%s:i2c read xy_data err___\n",__func__);
\r
297 ret = vtl_ts_i2c_read(client,client->addr,ts->xy_data.buf,sizeof(ts->xy_data.buf));
\r
299 printk("___%s:i2c read err___\n",__func__);
\r
306 static void vtl_ts_report_xy_coord(struct ts_info *ts)
\r
311 unsigned int press;
\r
312 unsigned char touch_point_number;
\r
313 static unsigned int release = 0;
\r
314 struct input_dev *input_dev;
\r
315 union ts_xy_data *xy_data;
\r
319 xy_data = &ts->xy_data;
\r
320 input_dev = ts->driver->input_dev;
\r
321 touch_point_number = ts->config_info.touch_point_number;
\r
325 /* report points */
\r
326 sync = 0; press = 0;
\r
327 for ( id = 0; id <touch_point_number; id++ ) //down
\r
329 if ((xy_data->point[id].xhi != 0xFF) && (xy_data->point[id].yhi != 0xFF) &&
\r
330 ( (xy_data->point[id].status == 1) || (xy_data->point[id].status == 2)))
\r
334 printk("--->>> vtl_ts report: xy_swap %d, x_reverse %d, y_reverse %d, x_mul %d, y_mul %d, bin_ver %d\n",
\r
335 ts->config_info.xy_swap,
\r
336 ts->config_info.x_reverse, ts->config_info.y_reverse,
\r
337 ts->config_info.x_mul, ts->config_info.y_mul,
\r
338 ts->config_info.bin_ver);
\r
341 if (ts->config_info.xy_swap == 1) {
\r
342 x = (xy_data->point[id].yhi<<4)|(xy_data->point[id].ylo&0xF);
\r
343 y = (xy_data->point[id].xhi<<4)|(xy_data->point[id].xlo&0xF);
\r
345 x = (xy_data->point[id].xhi<<4)|(xy_data->point[id].xlo&0xF);
\r
346 y = (xy_data->point[id].yhi<<4)|(xy_data->point[id].ylo&0xF);
\r
348 if (ts->config_info.x_reverse)
\r
349 x = ts->config_info.screen_max_x - x;
\r
350 if (ts->config_info.y_reverse)
\r
351 y = ts->config_info.screen_max_y - y;
\r
353 x = ts->config_info.x_mul*x;
\r
354 y = ts->config_info.x_mul*y;
\r
356 //#if(DEBUG_ENABLE)
\r
357 //if((ts->debug)||(DEBUG_ENABLE)){
\r
359 printk("id = %d,status = %d,X = %d,Y = %d\n",xy_data->point[id].id,xy_data->point[id].status,x,y);
\r
360 //XY_DEBUG(xy_data->point[id].id,xy_data->point[id].status,x,y);
\r
363 input_mt_slot(input_dev, xy_data->point[id].id - 1);
\r
364 input_report_abs(input_dev, ABS_MT_TRACKING_ID, xy_data->point[id].id-1);
\r
365 //input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, true);
\r
366 input_report_abs(input_dev, ABS_MT_POSITION_X, x);
\r
367 input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
\r
368 input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, 1);
\r
369 input_report_abs(input_dev, ABS_MT_WIDTH_MAJOR, 1);
\r
371 press |= 0x01 << (xy_data->point[id].id - 1);
\r
377 release &= (release ^ press);//release point flag
\r
379 for ( id = 0; id < touch_point_number; id++ ) //up
\r
381 if ( release & (0x01<<id) )
\r
383 input_mt_slot(input_dev, id);
\r
384 input_report_abs(input_dev, ABS_MT_TRACKING_ID, -1);
\r
392 input_sync(input_dev);
\r
398 int vtl_ts_suspend(struct i2c_client *client, pm_message_t mesg)
\r
400 struct ts_info *ts;
\r
404 if(ts->config_info.ctp_used)
\r
406 vtl_first_init_flag = 0;
\r
407 disable_irq(ts->config_info.irq_number);
\r
408 chip_enter_sleep_mode();
\r
410 for(i=0;i<ts->config_info.touch_point_number;i++)
\r
412 input_mt_slot(ts->driver->input_dev,i);
\r
413 input_report_abs(ts->driver->input_dev, ABS_MT_TRACKING_ID, -1);
\r
414 //input_mt_report_slot_state(ts->driver->input_dev, MT_TOOL_FINGER, false);
\r
416 input_sync(ts->driver->input_dev);
\r
421 int vtl_ts_resume(struct i2c_client *client)
\r
423 struct ts_info *ts;
\r
428 if(ts->config_info.ctp_used)
\r
430 /* Hardware reset */
\r
431 //vtl_ts_hw_reset();
\r
433 for(i=0;i<ts->config_info.touch_point_number;i++)
\r
435 input_mt_slot(ts->driver->input_dev,i);
\r
436 input_report_abs(ts->driver->input_dev, ABS_MT_TRACKING_ID, -1);
\r
437 //input_mt_report_slot_state(ts->driver->input_dev, MT_TOOL_FINGER, false);
\r
439 input_sync(ts->driver->input_dev);
\r
440 if(vtl_first_init_flag==0)
\r
441 enable_irq(ts->config_info.irq_number);
\r
446 static int vtl_ts_early_suspend(struct tp_device *tp)
\r
448 struct ts_info *ts;
\r
453 vtl_ts_suspend(ts->driver->client, PMSG_SUSPEND);
\r
458 static int vtl_ts_early_resume(struct tp_device *tp)
\r
460 struct ts_info *ts;
\r
464 vtl_ts_resume(ts->driver->client);
\r
469 int vtl_ts_remove(struct i2c_client *client)
\r
471 struct ts_info *ts;
\r
476 free_irq(ts->config_info.irq_number, ts);
\r
477 gpio_free(ts->config_info.rst_gpio_number);
\r
478 //vtl_ts_free_gpio();
\r
480 //#ifdef CONFIG_HAS_EARLYSUSPEND
\r
481 //unregister_early_suspend(&ts->driver->early_suspend);
\r
482 tp_unregister_fb(&ts->tp);
\r
484 if(ts->driver->input_dev != NULL)
\r
486 input_unregister_device(ts->driver->input_dev);
\r
487 input_free_device(ts->driver->input_dev);
\r
490 if ( ts->driver->proc_entry != NULL ){
\r
491 remove_proc_entry(DRIVER_NAME, NULL);
\r
494 if(ts->driver->ts_thread != NULL)
\r
496 printk("___kthread stop start___\n");
\r
497 thread_syn_flag=1;
\r
498 wake_up_interruptible(&waiter);
\r
499 kthread_stop(ts->driver->ts_thread);
\r
500 ts->driver->ts_thread = NULL;
\r
501 printk("___kthread stop end___\n");
\r
506 static int vtl_ts_init_input_dev(struct ts_info *ts)
\r
508 struct input_dev *input_dev;
\r
509 struct device *dev;
\r
515 dev = &ts->driver->client->dev;
\r
517 /* allocate input device */
\r
518 ts->driver->input_dev = input_allocate_device();
\r
519 if ( ts->driver->input_dev == NULL ) {
\r
520 dev_err(dev, "Unable to allocate input device for device %s.\n", DRIVER_NAME);
\r
524 input_dev = ts->driver->input_dev;
\r
526 input_dev->name = DRIVER_NAME;
\r
527 input_dev->id.bustype = BUS_I2C;
\r
528 input_dev->id.vendor = 0xaaaa;
\r
529 input_dev->id.product = 0x5555;
\r
530 input_dev->id.version = 0x0001;
\r
532 /* config input device */
\r
533 __set_bit(EV_SYN, input_dev->evbit);
\r
534 __set_bit(EV_KEY, input_dev->evbit);
\r
535 __set_bit(EV_ABS, input_dev->evbit);
\r
538 //set_bit(BTN_TOUCH, input_dev->keybit);//20130923
\r
539 //set_bit(ABS_MT_POSITION_X, input_dev->absbit);//20130923
\r
540 //set_bit(ABS_MT_POSITION_Y, input_dev->absbit);//20130923
\r
542 __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
\r
544 input_mt_init_slots(input_dev, TOUCH_POINT_NUM,0);
\r
545 input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, ts->config_info.screen_max_x, 0, 0);
\r
546 input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, ts->config_info.screen_max_y, 0, 0);
\r
547 input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0,ts->config_info.touch_point_number, 0, 0);
\r
548 input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
\r
549 input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
\r
552 /* register input device */
\r
553 err = input_register_device(input_dev);
\r
555 input_free_device(ts->driver->input_dev);
\r
556 ts->driver->input_dev = NULL;
\r
557 dev_err(dev, "Unable to register input device for device %s.\n", DRIVER_NAME);
\r
565 static int vtl_ts_handler(void *data)
\r
568 struct device *dev;
\r
569 struct ts_info *ts;
\r
570 //struct sched_param param = { .sched_priority = TS_THREAD_PRIO};
\r
572 //sched_setscheduler(current, SCHED_RR, ¶m);
\r
574 ts = (struct ts_info *)data;
\r
575 dev = &ts->driver->client->dev;
\r
578 /* Request platform resources (gpio/interrupt pins) */
\r
579 ret = vtl_ts_config(ts);
\r
582 dev_err(dev, "VTL touch screen config Failed.\n");
\r
583 goto ERR_TS_CONFIG;
\r
592 dev_err(dev, "vtl ts chip init failed.\n");
\r
593 goto ERR_CHIP_INIT;
\r
597 ret = vtl_ts_init_input_dev(ts);
\r
600 dev_err(dev, "init input dev failed.\n");
\r
601 goto ERR_INIT_INPUT;
\r
604 /* Create Proc Entry File */
\r
606 ts->driver->proc_entry = create_proc_entry(DRIVER_NAME, 0666/*S_IFREG | S_IRUGO | S_IWUSR*/, NULL);
\r
607 if ( ts->driver->proc_entry == NULL ) {
\r
608 dev_err(dev, "Failed creating proc dir entry file.\n");
\r
609 goto ERR_PROC_ENTRY;
\r
611 ts->driver->proc_entry->proc_fops = &apk_fops;
\r
614 /* register early suspend */
\r
615 //#ifdef CONFIG_HAS_EARLYSUSPEND
\r
616 //ts->driver->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
\r
617 //ts->driver->early_suspend.suspend = vtl_ts_early_suspend;
\r
618 //ts->driver->early_suspend.resume = vtl_ts_early_resume;
\r
619 //register_early_suspend(&ts->driver->early_suspend);
\r
625 ret = request_irq(ts->config_info.irq_number, vtl_ts_irq, IRQF_TRIGGER_FALLING, DRIVER_NAME, ts);
\r
627 dev_err(dev, "Unable to request irq for device %s.\n", DRIVER_NAME);
\r
630 //disable_irq(pg_ts->config_info.irq_number);
\r
631 ts->config_info.ctp_used =1;
\r
633 ts->tp.tp_resume = vtl_ts_early_resume;
\r
634 ts->tp.tp_suspend = vtl_ts_early_suspend;
\r
635 tp_register_fb(&ts->tp);
\r
637 while (!kthread_should_stop())//while(1)
\r
639 //set_current_state(TASK_INTERRUPTIBLE);
\r
640 wait_event_interruptible(waiter, thread_syn_flag);
\r
641 thread_syn_flag = 0;
\r
642 //set_current_state(TASK_RUNNING);
\r
643 //printk("__state = %x_%x_\n",current->state,ts->driver->ts_thread->state);
\r
644 ret = vtl_ts_read_xy_data(ts);
\r
647 vtl_ts_report_xy_coord(ts);
\r
651 printk("____read xy_data error___\n");
\r
653 // Enable ts interrupt
\r
654 enable_irq(pg_ts->config_info.irq_number);
\r
657 printk("vtl_ts_Kthread exit,%s(%d)\n",__func__,__LINE__);
\r
664 //#ifdef CONFIG_HAS_EARLYSUSPEND
\r
665 //unregister_early_suspend(&ts->driver->early_suspend);
\r
667 tp_unregister_fb(&ts->tp);
\r
668 if ( ts->driver->proc_entry ){
\r
669 remove_proc_entry(DRIVER_NAME, NULL);
\r
670 ts->driver->proc_entry = NULL;
\r
673 /* ERR_PROC_ENTRY: */
\r
674 if(ts->driver->input_dev){
\r
675 input_unregister_device(ts->driver->input_dev);
\r
676 input_free_device(ts->driver->input_dev);
\r
677 ts->driver->input_dev = NULL;
\r
681 gpio_free(ts->config_info.rst_gpio_number);
\r
683 ts->config_info.ctp_used =0;
\r
684 printk("vtl_ts_Kthread exit,%s(%d)\n",__func__,__LINE__);
\r
691 int vtl_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
\r
694 struct ts_info *ts;
\r
695 struct device *dev;
\r
700 ts->driver->client = client;
\r
701 dev = &ts->driver->client->dev;
\r
703 /* Check I2C Functionality */
\r
704 err = i2c_check_functionality(client->adapter, I2C_FUNC_I2C);
\r
706 dev_err(dev, "Check I2C Functionality Failed.\n");
\r
711 //ts->driver->ts_thread = kthread_run(vtl_ts_handler, NULL, DRIVER_NAME);
\r
712 ts->driver->ts_thread = kthread_run(vtl_ts_handler, ts, DRIVER_NAME);
\r
713 if (IS_ERR(ts->driver->ts_thread)) {
\r
714 err = PTR_ERR(ts->driver->ts_thread);
\r
715 ts->driver->ts_thread = NULL;
\r
716 dev_err(dev, "failed to create kernel thread: %d\n", err);
\r
718 //goto ERR_CREATE_TS_THREAD;
\r
721 printk("___%s() end____ \n", __func__);
\r
729 static struct of_device_id vtl_ts_dt_ids[] = {
\r
730 { .compatible = "ct,vtl_ts" },
\r
734 struct i2c_driver vtl_ts_driver = {
\r
737 .owner = THIS_MODULE,
\r
738 .name = DRIVER_NAME,
\r
739 .of_match_table = of_match_ptr(vtl_ts_dt_ids),
\r
741 .id_table = vtl_ts_id,
\r
742 .probe = vtl_ts_probe,
\r
743 //#ifndef CONFIG_HAS_EARLYSUSPEND
\r
744 //.suspend = vtl_ts_suspend,
\r
745 //.resume = vtl_ts_resume,
\r
747 .remove = vtl_ts_remove,
\r
752 int __init vtl_ts_init(void)
\r
755 return i2c_add_driver(&vtl_ts_driver);
\r
758 void __exit vtl_ts_exit(void)
\r
761 i2c_del_driver(&vtl_ts_driver);
\r
764 module_init(vtl_ts_init);
\r
765 module_exit(vtl_ts_exit);
\r
767 MODULE_AUTHOR("yangdechu@vtl.com.cn");
\r
768 MODULE_DESCRIPTION("VTL touchscreen driver for rockchip,V1.0");
\r
769 MODULE_LICENSE("GPL");
\r