static void ft5x0x_ts_release(void) { struct ft5x0x_ts_data *data = i2c_get_clientdata(this_client); #ifdef FT5X0X_MULTI_TOUCH input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, 0); input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 0); input_report_key(data->input_dev, BTN_TOUCH, 0); #else input_report_abs(data->input_dev, ABS_PRESSURE, 0); input_report_key(data->input_dev, BTN_TOUCH, 0); #endif input_sync(data->input_dev); } static int ft5x0x_read_data(void) { struct ft5x0x_ts_data *data = i2c_get_clientdata(this_client); struct ts_event *event = &data->event; u32 buf[32] = {0}; int ret = -1; #ifdef FT5X0X_MULTI_TOUCH ret = ft5x0x_i2c_rxdata(buf, 31); #else ret = ft5x0x_i2c_rxdata(buf, 7); #endif if (ret < 0) { printk("%s read_data i2c_rxdata failed: %d\n", __func__, ret); } memset(event, 0, sizeof(struct ts_event)); event->touch_point = buf[2] & 0x07; if (event->touch_point == 0) { ft5x0x_ts_release(); return 1; } #ifdef FT5X0X_MULTI_TOUCH switch (event->touch_point) { case 5: event->x5 = (s16)(buf[0x1b] & 0x0F)<<8 | (s16)buf[0x1c]; event->y5 = (s16)(buf[0x1d] & 0x0F)<<8 | (s16)buf[0x1e]; case 4: event->x4 = (s16)(buf[0x15] & 0x0F)<<8 | (s16)buf[0x16]; event->y4 = (s16)(buf[0x17] & 0x0F)<<8 | (s16)buf[0x18]; case 3: event->x3 = (s16)(buf[0x0f] & 0x0F)<<8 | (s16)buf[0x10]; event->y3 = (s16)(buf[0x11] & 0x0F)<<8 | (s16)buf[0x12]; case 2: event->x2 = (s16)(buf[9] & 0x0F)<<8 | (s16)buf[10]; event->y2 = (s16)(buf[11] & 0x0F)<<8 | (s16)buf[12]; case 1: event->x1 = (s16)(buf[3] & 0x0F)<<8 | (s16)buf[4]; event->y1 = (s16)(buf[5] & 0x0F)<<8 | (s16)buf[6]; break; default: return -1; } #else if (event->touch_point == 1) { event->x1 = (s16)(buf[3] & 0x0F)<<8 | (s16)buf[4]; event->y1 = (s16)(buf[5] & 0x0F)<<8 | (s16)buf[6]; } #endif event->pressure = 200; return 0; } static void ft5x0x_reprot_value(void) { struct ft5x0x_ts_data *data = i2c_get_clientdata(this_client); struct ts_event *event = &data->event; #ifdef FT5X0X_MULTI_TOUCH switch(event->touch_point) { case 5: input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure); input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x5); input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y5); input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, event->pressure); input_mt_sync(data->input_dev); case 4: input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure); input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x4); input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y4); input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, event->pressure); input_mt_sync(data->input_dev); case 3: input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure); input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x3); input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y3); input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, event->pressure); input_mt_sync(data->input_dev); case 2: input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure); input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x2); input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y2); input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, event->pressure); input_mt_sync(data->input_dev); case 1: input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure); input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x1); input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y1); input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, event->pressure); input_mt_sync(data->input_dev); break; default: break; } #else if (event->touch_point == 1) { input_report_abs(data->input_dev, ABS_X, event->x1); input_report_abs(data->input_dev, ABS_Y, event->y1); input_report_abs(data->input_dev, ABS_PRESSURE, event->pressure); } input_report_key(data->input_dev, BTN_TOUCH, 1); #endif input_sync(data->input_dev); #ifdef FT5X0X_MULTI_TOUCH printk(" >>> Point[0] point:(%d, %d), ABS_MT_TOUCH_MAJOR: %d, ABS_MT_WIDTH_MAJOR: %d >>>\n", event->x1, event->y1, event->pressure, event->pressure); printk(" >>> Point[1] point:(%d, %d), ABS_MT_TOUCH_MAJOR: %d, ABS_MT_WIDTH_MAJOR: %d >>>\n", event->x2, event->y2, event->pressure, event->pressure); printk(" >>> Point[2] point:(%d, %d), ABS_MT_TOUCH_MAJOR: %d, ABS_MT_WIDTH_MAJOR: %d >>>\n", event->x3, event->y3, event->pressure, event->pressure); printk(" >>> Point[3] point:(%d, %d), ABS_MT_TOUCH_MAJOR: %d, ABS_MT_WIDTH_MAJOR: %d >>>\n", event->x4, event->y4, event->pressure, event->pressure); printk(" >>> Point[4] point:(%d, %d), ABS_MT_TOUCH_MAJOR: %d, ABS_MT_WIDTH_MAJOR: %d >>>\n", event->x5, event->y5, event->pressure, event->pressure); printk("\n"); #else printk(" >>> one point:(%d, %d), ABS_PRESSURE: %d, BTN_TOUCH: %d >>>\n", event->x1, event->y1, event->pressure, 1); #endif } static void ft5x0x_ts_pen_irq_work(struct work_struct *work) { int ret = -1; ret = ft5x0x_read_data(); if (ret == 0) ft5x0x_report_value(); } static interrupt_r ft5x0x_ts_interrupt(int irq, void *dev_id) { struct ft5x0x_ts_data *ft5x0x_ts = dev_id; if (!work_pending(&ft5x0x_ts->pen_irq_work)) queue_work(ft5x0x_ts->ts_workqueue, &ft5x0x_ts->pen_irq_work); return IRQ_HANDLED; } #ifdef CONFIG_HAS_EARLYSUSPEND static void ft5x0x_ts_suspend(struct early_suspend *handler) { struct ft5x0x_ts_data *ft5x0x_ts; ts = container_of(handler, struct ft5x0x_ts_data, early_suspend); disable_irq(this_client->irq); cancel_workqueue(ft5x0x_ts->pen_irq_work); flush_workqueue(ft5x0x_ts->ts_workqueue); ft5x0x_write_reg(FT5X0X_REG_PMODE, PMODE_MONITOR); printk("[FST] %s\n", __func__); } static void ft5x0x_ts_resume(struct early_suspend *handler) { ventana_touchscreen_reset(); enable_irq(this_client->irq); ft5x0x_write_reg(FT5X0X_REG_PMODE, PMODE_ACTIVE); printk("[FST] %s\n", __func__); } #endif static int ft5x0x_ts_probe(struct i2c_client *client, const struct i2c_device_id, *id) { int err = 0; struct ft5x0x_ts_data *ft5x0x_ts; struct input_dev *input_dev; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { err = -ENODEV; goto exit_i2c_check_functionality; } ft5x0x_ts = kzalloc(sizeof(ft5x0x_ts_data), GPL_KERNEL); if (!ft5x0x_ts) { err = -ENOMEM; goto exit_alloc_data; } this_client = client; i2c_set_clientdata(client, ft5x0x_ts); INIT_WORK(&ft5x0x_ts->pen_event_work, ft5x0x_ts_pen_irq_work); ft5x0x_ts->ts_workqueue = create_siglethread_workqueue(dev_name(&client->dev)); if (!ft5x0x_ts->ts_workqueue) { err = -ESRCH; goto exit_create_siglethread; } err = request_irq(client->irq, ft5x0x_ts_interrupt, IRQF_TRIGGER_FALLING, "ft5x0x-irq", ft5x0x_ts); if (err < 0) { dev_err(&client->dev, "ft5x0x_ts_probe: request irq failed\n"); goto exit_irq_request; } disable_irq(this_client-irq); input_dev = input_allocate_device(); if (!input_dev) { err = -ENOMEM; dev_err(&client-dev, "ft5x0x_ts_probe: failed alloc input device\n"); } ft5x0x_ts->input_dev = input_dev; input_dev->name = FT5X0X_NAME; set_bit(EV_ABS, input_dev->evbit); set_bit(EV_KEY, input_dev->evbit); set_bit(BTN_TOUCH, input_dev->keybit); #ifdef FT5X0X_MULTI_TOUCH set_bit(ABS_MT_TOUCH_MAJOR, input_dev->absbit); set_bit(ABS_MT_POSITION_X, input_dev->absbit); set_bit(ABS_MT_POSITION_Y, input_dev->absbit); set_bit(ABS_MT_WIDTH_MAJOR, input_dev->absbit); input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, SCREEN_MAX_X, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, SCREEN_MAX_Y, 0, 0); input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, PRESS_MAX, 0, 0); input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, 200, 0, 0); #else set_bit(ABS_X, input_dev->absbit); set_bit(ABS_Y, input_dev->absbit); set_bit(ABS_PRESSURE, input_dev->absbit); set_bit(BTN_TOUCH, input_dev->keybit); input_set_abs_params(input_dev, ABS_X, 0, SCREEN_MAX_X, 0, 0); input_set_abs_params(input_dev, ABS_Y, 0, SCREEN_MAX_Y, 0, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, PRESS_MAX, 0 , 0); err = input_register_device(input_dev); if (err) { dev_err(&client->dev, "ft5x0x_ts_probe: failed to register input device: %s\n", dev_name(&client->dev)); goto exit_input_register_device; } #endif #ifdef CONFIG_HAS_EARLYSUSPEND ft5x0x_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; ft5x0x_ts->early_suspend.suspend = ft5x0x_ts_suspend; ft5x0x_ts->early_suspend.resume = ft5x0x_ts_resume; register_early_suspend(ft5x0x_ts->early_suspend); #endif msleep(50); //Get some register information uc_reg_value = ft5x0x_read_fw_ver(); printk("[FST] Firmware version = 0x%sx\n", uc_reg_value); //Auto calibration err = ft5x0x_write_reg(CALIBRATION_REG, 0x00); if (err) printk("[FST] Auto calibration failed.\n"); else printk("[FST] Auto calibration successfully.\n"); //Config the run mode of TPM, reg - 0xa7 : auto calibration - 0x04 ft5x0x_write_reg(FT5X0X_REG_STATE, 0x00); printk("[FST] Auto calibration during running.\n"); enable_irq(this_client->irq); return 0; exit_input_register_device: input_free_device(input_dev); exit_alloc_data: free_irq(client->irq, ft5x0x_ts); exit_irq_request: exit_create_siglethread: i2c_set_clientdata(client, NULL); exit_alloc_data: exit_i2c_check_functionality: return err; } static int __devexit ft5x0x_ts_remove(struct i2c_client *client) { struct ft5x0x_ts_data *ft5x0x_ts = i2c_get_clientdata(client); #ifdef CONFIG_HAS_EARLYSUSPEND unregister_early_suspend(&ft5x0x_ts->early_suspend); #endif free_irq(client->irq, ft5x0x_ts); input_unregister_device(ft5x0x_ts->input_dev); kfree(ft5x0x_ts); cancel_work_sync(&ft5x0x_ts->pen_event_work); destroy_workqueue(ft5x0x_ts->ts_workqueue); i2c_set_cleintdata(client, NULL); return 0; } static const struct i2c_device_id ft5x0x_ts_id[] = { {FT5X0X_NAME, 0} }; MODULE_DEVICE_TABLE(i2c, ft5x0x_id); static struct i2c_driver ft5x0x_ts_driver = { .probe = ft5x0x_ts_probe, .remove = __devexit_p(ft5x0x_ts_remove), .id_table = ft5x0x_ts_id, .driver = { .name = FT5X0X_TS, .owner = THIS_MODULE, }, }; static int __init ft5x0x_ts_init(void) { int ret; ret = i2c_add_driver(&ft5x0x_ts_driver); return ret; } static void __exit ft5x0x_ts_exit(void) { i2c_delete_driver(&ft5x0x_ts_driver); } module_init(ft5x0x_ts_init); module_exit(ft5x0x_ts_exit);