//重新唤醒 static int goodix_ts_resume(struct i2c_client *client) { int ret; struct goodix_ts_data *ts = i2c_get_clientdata(client); struct goodix_i2c_rmi_platform_data *pdata = client->dev.platform_data; if (ts->power) { ret = ts->power(1); if (ret < 0) printk(KERN_ERR "goodix_ts_resume power on failed\n"); }else if(pdata->gpio_shutdown){ gpio_direction_output(pdata->gpio_shutdown, 0); mdelay(10); goodix_init_panel(ts); gpio_direction_input(pdata ->gpio_irq); gpio_enable_edge_int(gpio_to_idx(pdata ->gpio_irq), pdata->irq_edge, client->irq - INT_GPIO_0); } if (ts->use_irq) enable_irq(client->irq); if (!ts->use_irq) hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); return 0; }
static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret = 0; int retry=0; struct gt818_ts_data *ts; struct gt818_platform_data *pdata; dev_info(&client->dev,"Install touch driver.\n"); printk("gt818: Install touch driver.\n"); //Check I2C function if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "Must have I2C_FUNC_I2C.\n"); ret = -ENODEV; goto err_check_functionality_failed; } ts = kzalloc(sizeof(*ts), GFP_KERNEL); if (ts == NULL) { ret = -ENOMEM; goto err_alloc_data_failed; } i2c_connect_client = client; //used by Guitar_Update pdata = client->dev.platform_data; ts->client = client; i2c_set_clientdata(client, ts); //init int and reset ports ret = gpio_request(pdata->gpio_pendown, "TS_INT"); //Request IO if (ret){ dev_err(&client->dev, "Failed to request GPIO:%d, ERRNO:%d\n",(int)pdata->gpio_pendown, ret); goto err_gpio_request_failed; } rk29_mux_api_set(pdata->pendown_iomux_name, pdata->pendown_iomux_mode); gpio_direction_input(pdata->gpio_pendown); gpio_pull_updown(pdata->gpio_pendown, 0); ret = gpio_request(pdata->gpio_reset, "gt818_resetPin"); if(ret){ dev_err(&client->dev, "failed to request resetPin GPIO%d\n", pdata->gpio_reset); goto err_gpio_request_failed; } rk29_mux_api_set(pdata->resetpin_iomux_name, pdata->resetpin_iomux_mode); #if 1 for(retry = 0; retry < 4; retry++) { gpio_pull_updown(pdata->gpio_reset, 1); gpio_direction_output(pdata->gpio_reset, 0); msleep(1); //delay at least 1ms gpio_direction_input(pdata->gpio_reset); gpio_pull_updown(pdata->gpio_reset, 0); msleep(25); //delay at least 20ms ret = i2c_pre_cmd(ts); if (ret > 0) break; msleep(50); } if(ret <= 0) { dev_err(&client->dev, "Warnning: I2C communication might be ERROR!\n"); goto err_i2c_failed; } #endif for(retry = 0; retry < 3; retry++) { ret = goodix_init_panel(ts); dev_info(&client->dev,"the config ret is :%d\n", ret); msleep(20); if(ret < 0) //Initiall failed continue; else break; } if(ret < 0) { ts->bad_data = 1; goto err_init_godix_ts; } goodix_read_version(ts); INIT_WORK(&ts->work, goodix_ts_work_func); //init work_struct ts->input_dev = input_allocate_device(); if (ts->input_dev == NULL) { ret = -ENOMEM; dev_dbg(&client->dev,"goodix_ts_probe: Failed to allocate input device\n"); goto err_input_dev_alloc_failed; } //ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ; //ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); //ts->input_dev->absbit[0] = BIT_MASK(ABS_MT_POSITION_X) | BIT_MASK(ABS_MT_POSITION_Y) | // BIT_MASK(ABS_MT_TOUCH_MAJOR) | BIT_MASK(ABS_MT_WIDTH_MAJOR); // for android #ifdef HAVE_TOUCH_KEY for(retry = 0; retry < MAX_KEY_NUM; retry++) { input_set_capability(ts->input_dev, EV_KEY, gt818_key_array[retry]); } #endif snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&client->dev)); snprintf(ts->name, sizeof(ts->name), "gt818-touchscreen"); ts->input_dev->name = "gt818_ts";//ts->name; ts->input_dev->phys = ts->phys; ts->input_dev->dev.parent = &client->dev; ts->input_dev->id.bustype = BUS_I2C; ts->input_dev->id.vendor = 0xDEAD; ts->input_dev->id.product = 0xBEEF; ts->input_dev->id.version = 10427; //screen firmware version __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); __set_bit(EV_ABS, ts->input_dev->evbit); #ifdef GOODIX_MULTI_TOUCH input_mt_init_slots(ts->input_dev, MAX_FINGER_NUM); //input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, SCREEN_MAX_WIDTH, 0, 0); input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, SCREEN_MAX_HEIGHT, 0, 0); //input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, MAX_FINGER_NUM, 0, 0); input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0); #else input_set_abs_params(ts->input_dev, ABS_X, 0, SCREEN_MAX_HEIGHT, 0, 0); input_set_abs_params(ts->input_dev, ABS_Y, 0, SCREEN_MAX_WIDTH, 0, 0); input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 255, 0, 0); #endif ret = input_register_device(ts->input_dev); if (ret) { dev_err(&client->dev,"Probe: Unable to register %s input device\n", ts->input_dev->name); goto err_input_register_device_failed; } ts->bad_data = 0; // 16finger_list.length = 0; client->irq = gpio_to_irq(pdata->gpio_pendown); //If not defined in client if (client->irq) { #if INT_TRIGGER==0 #define GT801_PLUS_IRQ_TYPE IRQ_TYPE_EDGE_RISING #elif INT_TRIGGER==1 #define GT801_PLUS_IRQ_TYPE IRQ_TYPE_EDGE_FALLING #elif INT_TRIGGER==2 #define GT801_PLUS_IRQ_TYPE IRQ_TYPE_LEVEL_LOW #elif INT_TRIGGER==3 #define GT801_PLUS_IRQ_TYPE IRQ_TYPE_LEVEL_HIGH #endif ret = request_irq(client->irq, goodix_ts_irq_handler, GT801_PLUS_IRQ_TYPE, client->name, ts); if (ret != 0) { dev_err(&client->dev,"Cannot allocate ts INT!ERRNO:%d\n", ret); gpio_direction_input(pdata->gpio_pendown); gpio_free(pdata->gpio_pendown); goto err_gpio_request_failed; } else { disable_irq(client->irq); ts->use_irq = 1; dev_dbg(&client->dev,"Reques EIRQ %d succesd on GPIO:%d\n", client->irq, pdata->gpio_pendown); } } err_gpio_request_failed: ts->power = goodix_ts_power; #ifdef CONFIG_HAS_EARLYSUSPEND ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; ts->early_suspend.suspend = goodix_ts_early_suspend; ts->early_suspend.resume = goodix_ts_late_resume; register_early_suspend(&ts->early_suspend); #endif dev_info(&client->dev,"Start %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "interrupt" : "polling"); if (ts->use_irq) { enable_irq(client->irq); } else { hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ts->timer.function = goodix_ts_timer_func; hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); } i2c_end_cmd(ts); return 0; err_init_godix_ts: i2c_end_cmd(ts); if(ts->use_irq) { ts->use_irq = 0; free_irq(client->irq,ts); gpio_direction_input(pdata->gpio_pendown); gpio_free(pdata->gpio_pendown); } else hrtimer_cancel(&ts->timer); err_input_register_device_failed: input_free_device(ts->input_dev); err_input_dev_alloc_failed: i2c_set_clientdata(client, NULL); err_i2c_failed: kfree(ts); err_alloc_data_failed: err_check_functionality_failed: return ret; }
/******************************************************* 功能: 触摸屏探测函数 在注册驱动时调用(要求存在对应的client); 用于IO,中断等资源申请;设备注册;触摸屏初始化等工作 参数: client:待驱动的设备结构体 id:设备ID return: 执行结果码,0表示正常执行 ********************************************************/ static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct goodix_ts_data *ts; int ret = 0; int retry=0; int count=0; struct goodix_i2c_rmi_platform_data *pdata = client->dev.platform_data; int INT_PORT = pdata ->gpio_irq; int SHUTDOWN_PORT = pdata->gpio_shutdown; if (!SHUTDOWN_PORT || !INT_PORT) { ret = -1; printk(KERN_ALERT "goodix platform data error\n"); goto err_check_functionality_failed ; } dev_dbg(&client->dev,"Install touchscreen driver for guitar.\n"); //Check I2C function ret = gpio_request(SHUTDOWN_PORT, "TS_SHUTDOWN"); //Request IO if (ret < 0) { printk(KERN_ALERT "Failed to request GPIO:%d, ERRNO:%d\n",(int)SHUTDOWN_PORT,ret); goto err_check_functionality_failed; } gpio_direction_output(SHUTDOWN_PORT, 0); //Touchscreen is waiting to wakeup ret = gpio_get_value(SHUTDOWN_PORT); if (ret) { printk(KERN_ALERT "Cannot set touchscreen to work.\n"); goto err_check_functionality_failed; } //waite guitar start if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "System need I2C function.\n"); ret = -ENODEV; goto err_check_functionality_failed; } i2c_connect_client = client; //used by Guitar Updating. msleep(16); for(retry=0; retry < 5; retry++) { ret =i2c_write_bytes(client, NULL, 0); //Test i2c. if (ret > 0) break; } if(ret < 0) { dev_err(&client->dev, "Warnning: I2C connection might be something wrong!\n"); ret = -ENOSYS; goto err_i2c_failed; } // gpio_set_value(SHUTDOWN_PORT, 1); //suspend ts = kzalloc(sizeof(*ts), GFP_KERNEL); if (ts == NULL) { ret = -ENOMEM; goto err_alloc_data_failed; } INIT_WORK(&ts->work, goodix_ts_work_func); ts->client = client; i2c_set_clientdata(client, ts); ts->input_dev = input_allocate_device(); if (ts->input_dev == NULL) { ret = -ENOMEM; dev_dbg(&client->dev," In File:%s Function:%s Failed to allocate input device\n", __FILE__, __func__); goto err_input_dev_alloc_failed; } ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ; ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); ts->input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y); // for android //#ifdef GOODIX_MULTI_TOUCH //used by android 1.x for multi-touch, not realized //ts->input_dev->absbit[0]=BIT(ABS_HAT0X) |BIT(ABS_HAT0Y); //ts->input_dev->keybit[BIT_WORD(BTN_2)] = BIT_MASK(BTN_2); //#endif input_set_abs_params(ts->input_dev, ABS_X, 0, pdata->xmax, 0, 0); input_set_abs_params(ts->input_dev, ABS_Y, 0, pdata->ymax, 0, 0); input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 255, 0, 0); #ifdef GOODIX_MULTI_TOUCH input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0); input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, pdata->xmax, 0, 0); input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, pdata->ymax, 0, 0); #endif sprintf(ts->phys, "input/ts)"); ts->input_dev->name = s3c_ts_name; ts->input_dev->phys = ts->phys; ts->input_dev->id.bustype = BUS_I2C; ts->input_dev->id.vendor = 0xDEAD; ts->input_dev->id.product = 0xBEEF; ts->input_dev->id.version = 10427; finger_list.length = 0; ret = input_register_device(ts->input_dev); if (ret) { dev_err(&client->dev,"Probe: Unable to register %s input device\n", ts->input_dev->name); goto err_input_register_device_failed; } gpio_set_value(SHUTDOWN_PORT, 1); msleep(100); gpio_set_value(SHUTDOWN_PORT, 0); msleep(100); goodix_init_panel(ts); goodix_read_version(ts); msleep(500); struct device *dev = &client->dev; sysfs_create_group(&dev->kobj, &goodix_attr_group); dev_set_drvdata(dev, ts); ts->init_finished = 0; ts->use_irq = 0; ts->retry=0; ts->bad_data = 0; if (client->irq) { ret = gpio_request(INT_PORT, "TS_INT"); //Request IO if (ret < 0) { dev_err(&client->dev, "Failed to request GPIO:%d, ERRNO:%d\n",(int)INT_PORT,ret); goto err_gpio_request_failed; } /* set input mode */ gpio_direction_input(INT_PORT); gpio_enable_edge_int(gpio_to_idx(INT_PORT), pdata->irq_edge, client->irq - INT_GPIO_0); ret = request_irq(client->irq, goodix_ts_irq_handler, pdata->irq_edge ? IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING, client->name, ts); if (ret != 0) { dev_err(&client->dev,"Can't allocate touchscreen's interrupt!ERRNO:%d\n", ret); gpio_free( INT_PORT); goto err_gpio_request_failed; } else { // disable_irq(client->irq); ts->use_irq = 1; dev_info(&client->dev,"Reques EIRQ %d succesd on GPIO:%d\n",client->irq,INT_PORT); } } err_gpio_request_failed: if (!ts->use_irq) { hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ts->timer.function = goodix_ts_timer_func; hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); } #ifdef CONFIG_HAS_EARLYSUSPEND ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; ts->early_suspend.suspend = goodix_ts_early_suspend; ts->early_suspend.resume = goodix_ts_late_resume; register_early_suspend(&ts->early_suspend); #endif dev_info(&client->dev,"Start %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "Interrupt" : "Polling\n"); return 0; err_init_godix_ts: if(ts->use_irq) free_irq(client->irq,ts); gpio_request(INT_PORT,"TS_INT"); gpio_free(INT_PORT); err_input_register_device_failed: input_free_device(ts->input_dev); err_input_dev_alloc_failed: i2c_set_clientdata(client, NULL); kfree(ts); err_i2c_failed: gpio_direction_input(SHUTDOWN_PORT); gpio_free(SHUTDOWN_PORT); err_alloc_data_failed: err_check_functionality_failed: return ret; }
/******************************************************* 功能: 触摸屏工作函数 由中断触发,接受1组坐标数据,校验后再分析输出 参数: ts: client私有数据结构体 return: 执行结果码,0表示正常执行 ********************************************************/ static void goodix_ts_work_func(struct work_struct *work) { uint8_t point_data[35]={ 0 }; static uint8_t finger_bit=0; uint8_t finger=0; int ret=-1; unsigned int pressure[MAX_FINGER_NUM]; int pos[MAX_FINGER_NUM][2]; int position =0; int count = 0, read_position = 0; int check_sum = 0; struct goodix_ts_data *ts = container_of(work, struct goodix_ts_data, work); struct goodix_i2c_rmi_platform_data *pdata = ts->client->dev.platform_data; int SHUTDOWN_PORT = pdata->gpio_shutdown; if (gpio_get_value(SHUTDOWN_PORT)) { printk(KERN_ALERT "Guitar stop working.The data is invalid. \n"); goto NO_ACTION; } start_read_i2c: //if i2c transfer is failed, let it restart less than 10 times if( ts->retry > 9) { if(!ts->use_irq) //ts->timer.state = HRTIMER_STATE_INACTIVE; hrtimer_cancel(&ts->timer); dev_info(&(ts->client->dev), "Because of transfer error, Guitar's driver stop working.\n"); return ; } if(ts->bad_data) msleep(16); ret=i2c_read_bytes(ts->client, point_data, 35); if(ret <= 0) { dev_err(&(ts->client->dev),"I2C transfer error. Number:%d\n ", ret); ts->bad_data = 1; ts->retry++; goodix_init_panel(ts); goto start_read_i2c; } ts->bad_data = 0; //The bit indicate which fingers pressed down switch(point_data[1]& 0x1f) { case 0: case 1: for(count=1; count<8; count++) check_sum += (int)point_data[count]; if((check_sum%256) != point_data[8]) goto XFER_ERROR; break; case 2: case 3: for(count=1; count<13;count++) check_sum += (int)point_data[count]; if((check_sum%256) != point_data[13]) goto XFER_ERROR; break; default: //(point_data[1]& 0x1f) > 3 for(count=1; count<34;count++) check_sum += (int)point_data[count]; if((check_sum%256) != point_data[34]) goto XFER_ERROR; } point_data[1]&=0x1f; finger = finger_bit^point_data[1]; if(finger == 0 && point_data[1] == 0) goto NO_ACTION; //no fingers and no action else if(finger == 0) //the same as last time goto BIT_NO_CHANGE; //check which point(s) DOWN or UP for(position = 0; (finger !=0)&& (position < MAX_FINGER_NUM); position++) { if((finger&0x01) == 1) //current bit is 1? { //NO.postion finger is change if(((finger_bit>>position)&0x01)==1) //NO.postion finger is UP set_up_point(&finger_list, position); else add_point(&finger_list, position); } finger>>=1; }
static int guitar_update_proc(void *v_ts) { s32 ret; u32 retry = 100; u32 i = 0; struct goodix_ts_data* ts = NULL; u8* data = NULL; u8* ic_nvram = NULL; st_fw_head fw_head; u8 buf[32]; ts = (struct goodix_ts_data*)v_ts; data = kzalloc(UPDATE_DATA_LENGTH, GFP_KERNEL); if (NULL == data) { DEBUG_UPDATE("data failed apply for memory.\n"); return fail; } ic_nvram = kzalloc(UPDATE_DATA_LENGTH, GFP_KERNEL); if (NULL == ic_nvram) { DEBUG_UPDATE("ic_nvram failed apply for memory.\n"); goto app_mem_failed; } DEBUG_UPDATE("Apply for memory successfully.memory size: %d.\n", UPDATE_DATA_LENGTH); msleep(1000); DEBUG_UPDATE("Updating...\n"); if (fail == load_update_file(ts, &fw_head, &data[2], NULL)) { DEBUG_UPDATE("Load file data failed!\n"); goto load_failed; } DEBUG_UPDATE("Load file data successfully!\n"); if (ts->use_irq) { if(!ts->irq_is_disable) { disable_irq(ts->client->irq); } ts->irq_is_disable = 2; } for (i = 0; i < 5; i++) { if (fail == guitar_update_mode(ts)) { DEBUG_UPDATE("Next try![Enter update mode]\n"); continue; } else { DEBUG_UPDATE("Set update mode successfully.\n"); break; } } if (i >= 5) { DEBUG_UPDATE("Set update mode failed.\n"); return fail; } retry = 0; while(retry++ < 5) { if (fail == guitar_update_firmware(ts, &fw_head, &data[2])) { DEBUG_UPDATE("Update firmware failed.\n"); continue; } DEBUG_UPDATE("Update firmware successfully.\n"); //while(1) // simulation store operation failed if (fail == guitar_nvram_store(ts)) { DEBUG_UPDATE("Store nvram failed.\n"); continue; } msleep(100); if (fail == get_ic_msg(ts, 0x1201, buf, 1)) { DEBUG_UPDATE("Read NVRCS failed.(Store)\n"); continue; } if (buf[ADDR_LENGTH] & 0x01) { DEBUG_UPDATE("Check NVRCS(0x%02x) failed.(Store)\n", buf[ADDR_LENGTH]); continue; } DEBUG_UPDATE("Store nvram successfully.\n"); if (fail == guitar_nvram_recall(ts)) { DEBUG_UPDATE("Recall nvram failed.\n"); continue; } msleep(5); if (fail == get_ic_msg(ts, 0x1201, buf, 1)) { DEBUG_UPDATE("Read NVRCS failed.(Recall)\n"); continue; } if (buf[ADDR_LENGTH] & 0x02) { DEBUG_UPDATE("Check NVRCS(0x%02x) failed.(Recall)\n", buf[ADDR_LENGTH]); continue; } DEBUG_UPDATE("Recall nvram successfully.\n"); ic_nvram[0] = fw_head.st_addr[0]; ic_nvram[1] = fw_head.st_addr[1]; for ( i = 0; i < 10; i++) { ret = i2c_read_bytes(ts->client, ic_nvram, ADDR_LENGTH + fw_head.lenth); if (ret <= 0) { continue; } break; } if (i >= 10) { DEBUG_UPDATE("Read nvram failed!\n"); continue; } DEBUG_UPDATE("Read nvram successfully!\n"); if (false == is_equal(&data[2], &ic_nvram[2], fw_head.lenth)) { DEBUG_UPDATE("Nvram not equal!\n"); continue; } DEBUG_UPDATE("Check nvram by byte successfully!\n"); if (update_msg.gt_loc > 0) { DEBUG_UPDATE("Location:%d, Ret:%d.\n", (s32)update_msg.gt_loc, (s32)ret); memset(buf, 0, sizeof(buf)); ret = update_msg.file->f_op->write(update_msg.file, buf, 6, &update_msg.gt_loc); if (ret < 0) { DEBUG_UPDATE("Didn't clear the focre update flag in file.\n"); } else { DEBUG_UPDATE("Clear the focre update flag in file.Location:%d, Ret:%d.\n", (s32)update_msg.gt_loc, (s32)ret); } } DEBUG_UPDATE("Update successfully!\n"); break; } set_fs(update_msg.old_fs); filp_close(update_msg.file, NULL); guitar_leave_update_mode(); DEBUG_UPDATE("Leave update mode!\n"); //Reset guitar DEBUG_UPDATE("Reset IC and send config!\n"); guitar_reset(10); for (i = 0; i < 3; i++) { if (fail == goodix_init_panel(ts, 1)) { msleep(10); continue; } break; } if (i >= 3) { DEBUG_UPDATE("Send config data failed.\n"); } msleep(10); if (ts->use_irq) { ts->irq_is_disable = 0; enable_irq(ts->client->irq); } load_failed: kfree(ic_nvram); app_mem_failed: kfree(data); if (retry < 5) { return success; } DEBUG_UPDATE("Update failed!\n"); return fail; }
static int gt811_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret; int retry; const char irq_table[2] = {IRQ_TYPE_EDGE_FALLING,IRQ_TYPE_EDGE_RISING}; fs210_ts_dev =kmalloc(sizeof(struct ts_device), GFP_KERNEL); if(!fs210_ts_dev->ts_client){ printk(KERN_ERR "malloc failed!\n"); return -ENOMEM; } fs210_ts_dev->ts_client =client; INIT_WORK(&fs210_ts_dev->work, goodix_ts_work_func); /*1.硬件相关的操作 */ /*1.1 管脚申请*/ ret=gpio_request(SHUTDOWN_PORT,"reset"); if (ret < 0) { dev_err(&client->dev, "Failed to request RESET GPIO:%d, ERRNO:%d\n",(int)SHUTDOWN_PORT,ret); goto err0; } //一定要上拉 s3c_gpio_setpull(SHUTDOWN_PORT, S3C_GPIO_PULL_UP); //gpio_direction_input(SHUTDOWN_PORT); /*1.2 复位触摸屏 */ for(retry=0;retry <= 10; retry++) { gpio_direction_output(SHUTDOWN_PORT,0); msleep(1); gpio_direction_input(SHUTDOWN_PORT); msleep(100); printk(KERN_INFO "num_adatper =%d\n",client->adapter->nr); ret =i2c_write_byte(&test_data, 1); //Test I2C connection. if (ret > 0) break; dev_info(&client->dev, "GT811 I2C TEST FAILED!Please check the HARDWARE connect\n"); } if(ret <= 0) { dev_err(&client->dev, "Warnning: I2C communication might be ERROR!\n"); goto err1; } /*1.2 初始化触摸屏*/ for(retry=0; retry<3; retry++) { /*初始化触摸屏面板*/ ret=goodix_init_panel(fs210_ts_dev); msleep(2); if(ret != 0) //Initiall failed continue; else break; } if(ret!= 0) { //ts->bad_data=1; //标志位 goto err1; } /*1.3 触摸屏中断要进行注册*/ /*1.3.1 申请GPIO管脚*/ ret = gpio_request(INT_PORT, "TS_INT"); //Request IO if (ret < 0) { dev_err(&client->dev, "Failed to request GPIO:%d, ERRNO:%d\n",(int)INT_PORT,ret); goto err1; } /*1.3.2 获取中断号*/ client->irq =gpio_to_irq(INT_PORT); /*1.3.3 申请中断, */ ret = request_irq(client->irq, goodix_ts_irq_handler,irq_table[fs210_ts_dev->int_trigger_type], client->name, fs210_ts_dev); if (ret != 0) { dev_err(&client->dev,"Cannot allocate ts INT!ERRNO:%d\n", ret); gpio_direction_input(INT_PORT); gpio_free(INT_PORT); goto err1; } /*2.分配input_dev结构体*/ fs210_ts_dev->ts_input =input_allocate_device(); if(!fs210_ts_dev->ts_input){ printk(KERN_ERR "malloc failed!\n"); ret =-ENOMEM; goto err0; } /*3.设置input_dev结构体*/ /*3.1 设置能产生哪类事件*/ //set_bit(EV_SYN,fs210_ts_dev->ts_input->evbit); set_bit(EV_KEY,fs210_ts_dev->ts_input->evbit); set_bit(EV_ABS,fs210_ts_dev->ts_input->evbit); /*3.2 设置能产生哪些事件*/ set_bit(BTN_TOUCH,fs210_ts_dev->ts_input->keybit); input_set_capability(fs210_ts_dev->ts_input,EV_KEY,KEY_BACK); input_set_capability(fs210_ts_dev->ts_input,EV_ABS,ABS_X); //set_bit(ABS_X, fs210_ts_dev->ts_input->absbit); set_bit(ABS_Y, fs210_ts_dev->ts_input->absbit); set_bit(ABS_PRESSURE, fs210_ts_dev->ts_input->absbit); /*3.3 设置绝对位移的各种参数*/ input_set_abs_params(fs210_ts_dev->ts_input, ABS_X, 0, fs210_ts_dev->abs_x_max, 0, 0); input_set_abs_params(fs210_ts_dev->ts_input, ABS_Y, 0, fs210_ts_dev->abs_y_max, 0, 0); input_set_abs_params(fs210_ts_dev->ts_input, ABS_PRESSURE, 0, 255, 0, 0); #ifdef GOODIX_MULTI_TOUCH input_set_abs_params(fs210_ts_dev->ts_input, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); input_set_abs_params(fs210_ts_dev->ts_input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); input_set_abs_params(fs210_ts_dev->ts_input, ABS_MT_POSITION_X, 0, fs210_ts_dev->abs_x_max, 0, 0); input_set_abs_params(fs210_ts_dev->ts_input, ABS_MT_POSITION_Y, 0, fs210_ts_dev->abs_y_max, 0, 0); #endif /*4.注册input_dev*/ ret=input_register_device(fs210_ts_dev->ts_input); if(ret){ printk(KERN_ERR "register input_dev failed!\n"); ret =-EINVAL; goto err2; } return 0; err3: input_unregister_device(fs210_ts_dev->ts_input); err2: gpio_free(INT_PORT); input_free_device(fs210_ts_dev->ts_input); err1: gpio_free(SHUTDOWN_PORT); err0: kfree(fs210_ts_dev); return ret; }
/******************************************************* 功能: 触摸屏探测函数 在注册驱动时调用(要求存在对应的client); 用于IO,中断等资源申请;设备注册;触摸屏初始化等工作 参数: client:待驱动的设备结构体 id:设备ID return: 执行结果码,0表示正常执行 ********************************************************/ static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct goodix_ts_data *ts; int ret = 0; int retry=0; int count=0; FNC_ENTERY; struct goodix_i2c_platform_data *pdata; dev_dbg(&client->dev,"Install touchscreen driver for guitar.\n"); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "System need I2C function.\n"); ret = -ENODEV; goto err_check_functionality_failed; } if (!(((board_version == 1)&&(hw_version == 0))||(board_version == 0))) { printk("%s: system hardware version:%d, GOODIX touchscreen is unsupported!!!\n", __func__, hw_version); ret = -1; goto err_check_functionality_failed; } ts = kzalloc(sizeof(*ts), GFP_KERNEL); if (ts == NULL) { ret = -ENOMEM; goto err_alloc_data_failed; } /* 获取预定义资源 */ pdata = client->dev.platform_data; if(pdata != NULL) { //ts->gpio_shutdown = pdata->gpio_shutdown; //ts->gpio_irq = pdata->gpio_irq; //use as s3c_gpio_cfgpin(ts->gpio_shutdown, pdata->shutdown_cfg); /* output */ } #ifdef SHUTDOWN_PORT ts->gpio_shutdown = SHUTDOWN_PORT; if(ts->gpio_shutdown) { //ret = gpio_request(ts->gpio_shutdown, "TS_SHUTDOWN"); //Request IO if (ret < 0) { printk(KERN_ALERT "Failed to request GPIO:%d, ERRNO:%d\n", ts->gpio_shutdown, ret); goto err_gpio_request; } gpio_direction_output(ts->gpio_shutdown, 0); //Touchscreen is waiting to wake up ret = gpio_get_value(ts->gpio_shutdown); if (ret) { printk(KERN_ALERT "Cannot set touchscreen to work.\n"); goto err_i2c_failed; } ts->use_shutdown = 1; msleep(25); //waiting for initialization of Guitar. } #endif RESETPIN_CFG; RESETPIN_SET1; mdelay(200); RESETPIN_SET0; mdelay(200); i2c_connect_client = client; //used by Guitar Updating. //TODO: used to set speed of i2c transfer. Must change as your paltform. // s3c24xx_set_i2c_clockrate(client->adapter, 250, &count); //set i2c <=250kHz dev_dbg(&client->dev, "i2c set frequency:%dkHz.\n", count); #if 0 for(retry=0; retry < 5; retry++) { ret=i2c_read_bytes(ts->client,version_data, GT80X_VERSION_LENGTH); ret =i2c_write_bytes(client, NULL, 0); //Test i2c. if (ret > 0) break; } if(ret < 0) { dev_err(&client->dev, "Warnning: I2C connection might be something wrong!\n"); goto err_i2c_failed; } #endif if(ts->use_shutdown) gpio_set_value(ts->gpio_shutdown, 1); //suspend INIT_WORK(&ts->work, goodix_ts_work_func); ts->client = client; i2c_set_clientdata(client, ts); pdata = client->dev.platform_data; ts->input_dev = input_allocate_device(); if (ts->input_dev == NULL) { ret = -ENOMEM; dev_dbg(&client->dev,"Failed to allocate input device\n"); goto err_input_dev_alloc_failed; } ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ; #ifndef GOODIX_MULTI_TOUCH ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); ts->input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y); input_set_abs_params(ts->input_dev, ABS_X, 0, SCREEN_MAX_HEIGHT, 0, 0); input_set_abs_params(ts->input_dev, ABS_Y, 0, SCREEN_MAX_WIDTH, 0, 0); input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 255, 0, 0); #else //ts->input_dev->absbit[0] = BIT_MASK(ABS_MT_TRACKING_ID) | ts->input_dev->absbit[0] = BIT_MASK(ABS_MT_TOUCH_MAJOR)| BIT_MASK(ABS_MT_WIDTH_MAJOR) | BIT_MASK(ABS_MT_POSITION_X) | BIT_MASK(ABS_MT_POSITION_Y); // for android input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, SCREEN_MAX_HEIGHT, 0, 0); input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, SCREEN_MAX_WIDTH, 0, 0); //input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, MAX_FINGER_NUM-1, 0, 0); #endif sprintf(ts->phys, "input/ts)"); ts->input_dev->name = s3c_ts_name; ts->input_dev->phys = ts->phys; ts->input_dev->id.bustype = BUS_I2C; ts->input_dev->id.vendor = 0xDEAD; ts->input_dev->id.product = 0xBEEF; ts->input_dev->id.version = 0x1103; finger_list.length = 0; ret = input_register_device(ts->input_dev); if (ret) { dev_err(&client->dev,"Probe: Unable to register %s input device\n", ts->input_dev->name); goto err_input_register_device_failed; } ts->use_irq = 1; //ts->use_irq = 0; ts->retry = 0; ts->bad_data = 0; #if defined(INT_PORT) ts->gpio_irq = INT_PORT; client->irq=TS_INT; //If not define in client if (client->irq) { #ifdef CONFIG_MACH_EMEV writel(readl(CHG_PULL1)|0xC000, CHG_PULL1); gpio_direction_input(irq_to_gpio(client->irq)); #endif //ret = gpio_request(ts->gpio_irq, "TS_INT"); //Request IO if (ret < 0) { dev_err(&client->dev, "Failed to request GPIO:%d, ERRNO:%d\n", ts->gpio_irq, ret); goto err_int_request_failed; } // ret = s3c_gpio_cfgpin(ts->gpio_irq, INT_CFG); //Set IO port function ret = request_irq(client->irq, goodix_ts_irq_handler , IRQ_TYPE_EDGE_RISING, "GoodixIRQ", ts); if (ret != 0) { dev_err(&client->dev,"Can't allocate touchscreen's interrupt%d!ERRNO:%d\n",client->irq, ret); gpio_direction_input(ts->gpio_irq); gpio_free(ts->gpio_irq); goto err_int_request_failed; } else { disable_irq(client->irq); ts->use_irq = 1; dev_dbg(&client->dev,"Reques EIRQ %d succesd on GPIO:%d\n",client->irq, ts->gpio_irq); } } #endif err_int_request_failed: if (!ts->use_irq) { hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ts->timer.function = goodix_ts_timer_func; hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); } flush_workqueue(goodix_wq); if(ts->use_shutdown) { gpio_set_value(ts->gpio_shutdown, 0); #ifdef SHUTDOWN_PORT ts->power = goodix_ts_power; #endif msleep(30); } ret = goodix_init_panel(ts); if(ret != 0) goto err_init_godix_ts; if(ts->use_irq) enable_irq(client->irq); goodix_read_version(ts); //msleep(500); #ifdef CONFIG_HAS_EARLYSUSPEND ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; ts->early_suspend.suspend = goodix_ts_early_suspend; ts->early_suspend.resume = goodix_ts_late_resume; register_early_suspend(&ts->early_suspend); #endif dev_dbg(&client->dev,"Start %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "Interrupt" : "Polling"); return 0; err_init_godix_ts: if(ts->use_irq) { free_irq(client->irq,ts); gpio_free(ts->gpio_irq); } err_input_register_device_failed: input_free_device(ts->input_dev); err_input_dev_alloc_failed: i2c_set_clientdata(client, NULL); err_i2c_failed: if(ts->use_shutdown) { gpio_direction_input(ts->gpio_shutdown); gpio_free(ts->gpio_shutdown); } err_gpio_request: kfree(ts); err_alloc_data_failed: err_check_functionality_failed: return ret; }
/******************************************************* 功能: 触摸屏工作函数 由中断触发,接受1组坐标数据,校验后再分析输出 参数: ts: client私有数据结构体 return: 执行结果码,0表示正常执行 ********************************************************/ static void goodix_ts_work_func(struct work_struct *work) { static uint8_t finger_bit=0; //last time fingers' state struct point_data * p = NULL; uint8_t read_position = 0; uint8_t point_data[READ_BYTES_NUM]={ 0 }; uint8_t finger=0; //record which finger is changed uint8_t check_sum = 0; int ret = -1; int count = 0; struct goodix_ts_data *ts = container_of(work, struct goodix_ts_data, work); if (ts->use_shutdown && gpio_get_value(ts->gpio_shutdown)) goto NO_ACTION; //The data is invalid. //if i2c-transfer is failed, let it restart less than 10 times. FOR DEBUG. /* if( ts->retry > 9) { if(!ts->use_irq && (ts->timer.state != HRTIMER_STATE_INACTIVE)) hrtimer_cancel(&ts->timer); dev_info(&(ts->client->dev), "Because of transfer error, %s stop working.\n",s3c_ts_name); ts->bad_data = 1; return ; } */ ret=i2c_read_bytes(ts->client, point_data, sizeof(point_data)); if(ret <= 0) { dev_dbg(&(ts->client->dev),"I2C transfer error. ERROR Number:%d\n ", ret); ts->retry++; if(ts->power) { ts->power(ts, 0); ts->power(ts, 1); } else { goodix_init_panel(ts); msleep(260); } goto XFER_ERROR; } //如果能够保证在INT中断后及时的读取坐标数据,可以不进行校验 if(!ts->use_irq) { switch(point_data[1]& 0x1f) { case 0: break; case 1: for(count=1; count<8; count++) check_sum += (int)point_data[count]; read_position = 8; break; case 2: case 3: for(count=1; count<13;count++) check_sum += (int)point_data[count]; read_position = 13; break; default: //(point_data[1]& 0x1f) > 3 for(count=1; count<34;count++) check_sum += (int)point_data[count]; read_position = 34; } if(check_sum != point_data[read_position]) goto XFER_ERROR; } //The bits indicate which fingers pressed down point_data[1]&=0x1f; finger = finger_bit^point_data[1]; if(finger == 0 && point_data[1] == 0) goto NO_ACTION; //no fingers and no action else if(finger == 0) //the same as last time goto BIT_NO_CHANGE; //check which point(s) DOWN or UP analyse_points(&finger_list, finger_bit, finger); if(finger_list.head == NULL) goto NO_ACTION; else dev_dbg(&ts->client->dev, "fingers count:%d\n", finger_list.length); BIT_NO_CHANGE: for(p = finger_list.head; p != NULL; p = p->next) { if(p->state == FLAG_UP) { p->x = p->y = 0; p->pressure = 0; continue; } if(p->id < 3) read_position = p->id*5+3; else read_position = 29; if(p->id != 3) { p->x = (unsigned int) (point_data[read_position]<<8) + (unsigned int)( point_data[read_position+1]); p->y = (unsigned int)(point_data[read_position+2]<<8) + (unsigned int) (point_data[read_position+3]); p->pressure = point_data[read_position+4]; } #if MAX_FINGER_NUM > 3 else { p->x = (unsigned int) (point_data[18]<<8) + (unsigned int)( point_data[25]); p->y = (unsigned int)(point_data[26]<<8) + (unsigned int) (point_data[27]); p->pressure = point_data[28]; } #endif // 将触摸屏的坐标映射到LCD坐标上. 触摸屏短边为X轴,LCD坐标一般长边为X轴,可能需要调整原点位置 p->x = (TOUCH_MAX_WIDTH - p->x)*SCREEN_MAX_WIDTH/TOUCH_MAX_WIDTH;//y if (board_version == 0){ p->y = p->y*SCREEN_MAX_HEIGHT/TOUCH_MAX_HEIGHT;//x } else if (board_version == 1) { p->y = (TOUCH_MAX_HEIGHT - p->y)*SCREEN_MAX_HEIGHT/TOUCH_MAX_HEIGHT;//x } swap(p->x, p->y); } #ifndef GOODIX_MULTI_TOUCH if(finger_list.head->state == FLAG_DOWN) { input_report_abs(ts->input_dev, ABS_X, finger_list.head->x); input_report_abs(ts->input_dev, ABS_Y, finger_list.head.y); } input_report_abs(ts->input_dev, ABS_PRESSURE, finger_list.head->pressure); input_report_key(ts->input_dev, BTN_TOUCH, finger_list.head->state); #else /* ABS_MT_TOUCH_MAJOR is used as ABS_MT_PRESSURE in android. */ for(p = finger_list.head; p != NULL; p = p->next) { if(p->state == FLAG_DOWN) { input_report_abs(ts->input_dev, ABS_MT_POSITION_X, p->x); input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, p->y); } //input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, p->id); input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, p->pressure); input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, p->pressure); //printk("ID:%d.\n", p->id); input_mt_sync(ts->input_dev); } #endif input_sync(ts->input_dev); delete_points(&finger_list); finger_bit = point_data[1]&0x1f; //restore last presse state. XFER_ERROR: NO_ACTION: if(ts->use_irq) enable_irq(ts->client->irq); }