static int goodix_ts_power(struct gt818_ts_data * ts, int on) { int ret = -1; struct gt818_platform_data *pdata = ts->client->dev.platform_data; unsigned char i2c_control_buf[3] = {0x06,0x92,0x01}; //suspend cmd if(ts != NULL && !ts->use_irq) return -2; switch(on) { case 0: i2c_pre_cmd(ts); // set the io port high level to avoid level change which might stop gt818 from sleeping gpio_direction_output(pdata->gpio_reset, 1); gpio_direction_output(pdata->gpio_pendown, 1); msleep(5); ret = i2c_write_bytes(ts->client, i2c_control_buf, 3); if(ret < 0) { printk(KERN_INFO"**gt818 suspend fail**\n"); } else { //printk(KERN_INFO"**gt818 suspend**\n"); ret = 0; } // i2c_end_cmd(ts); return ret; case 1: gpio_pull_updown(pdata->gpio_pendown, 1); gpio_direction_output(pdata->gpio_pendown, 0); msleep(1); gpio_direction_output(pdata->gpio_pendown, 1); msleep(1); gpio_direction_input(pdata->gpio_pendown); gpio_pull_updown(pdata->gpio_pendown, 0); /* msleep(2); gpio_pull_updown(pdata->gpio_reset, 1); gpio_direction_output(pdata->gpio_reset, 0); msleep(2); gpio_direction_input(pdata->gpio_reset); gpio_pull_updown(pdata->gpio_reset, 0); msleep(30); */ msleep(1); ret = i2c_pre_cmd(ts); //printk(KERN_INFO"**gt818 reusme**\n"); ret = i2c_end_cmd(ts); return ret; default: printk(KERN_DEBUG "%s: Cant't support this command.", gt818_ts_name); return -EINVAL; } }
static u8 clear_mix_flag(struct goodix_ts_data *ts) { s32 i = 0; u8 buf[3]; buf[0] = 0x14; buf[1] = 0x00; buf[2] = 0x80; for (i = 0; i < 5; i++) { if (i2c_write_bytes(ts->client, buf, 3) > 0) { break; } } i2c_end_cmd(ts); if (i >= 5) { DEBUG_UPDATE("Clear mix flag failed!\n"); return fail; } return success; }
static u8 get_ic_msg(struct goodix_ts_data *ts, u16 addr, u8* msg, s32 len) { s32 i = 0; msg[0] = addr >> 8 & 0xff; msg[1] = addr & 0xff; for (i = 0; i < 5; i++) { if (i2c_read_bytes(ts->client, msg, ADDR_LENGTH + len) > 0) { break; } } i2c_end_cmd(ts); if (i >= 5) { DEBUG_UPDATE("Read data from 0x%02x%02x failed!\n", msg[0], msg[1]); return fail; } return success; }
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; }
static void goodix_ts_work_func(struct work_struct *work) { u8 touch_status[8*MAX_FINGER_NUM + 18] = {READ_TOUCH_ADDR_H, READ_TOUCH_ADDR_L, 0}; u8 *key_value = NULL; u8 *point_data = NULL; static u8 finger_last[MAX_FINGER_NUM + 1]={0}; u8 finger_current[MAX_FINGER_NUM + 1] = {0}; u8 coor_data[6*MAX_FINGER_NUM] = {0}; static u8 last_key = 0; u8 finger = 0; u8 key = 0; unsigned int count = 0; unsigned int position = 0; int temp = 0; int x = 0, y = 0 , pressure; u16 *coor_point; int syn_flag = 0; struct gt818_ts_data *ts = container_of(work, struct gt818_ts_data, work); i2c_pre_cmd(ts); i2c_read_bytes(ts->client, touch_status, sizeof(touch_status)/sizeof(touch_status[0])); i2c_end_cmd(ts); //judge whether the data is ready if((touch_status[2] & 0x30) != 0x20) { printk("%s:DATA_NO_READY\n", __func__); goto DATA_NO_READY; } //judge whether it is large area touch if(touch_status[13] & 0x0f) { goto DATA_NO_READY; } ts->bad_data = 0; finger = touch_status[2] & 0x07; key_value = touch_status + 15; key = key_value[2] & 0x0f; if(finger > 0) { point_data = key_value + 3; for(position = 0; position < (finger*8); position += 8) { temp = point_data[position]; //printk("track:%d\n", temp); if(temp < (MAX_FINGER_NUM + 1)) { finger_current[temp] = 1; for(count = 0; count < 6; count++) { coor_data[(temp - 1) * 6 + count] = point_data[position+1+count]; } } else { //dev_err(&(ts->client->dev),"Track Id error:%d\n ",); ts->bad_data = 1; ts->retry++; goto XFER_ERROR; } } } else { for(position = 1; position < MAX_FINGER_NUM+1; position++) { finger_current[position] = 0; } } coor_point = (u16 *)coor_data; for(position = 1; position < MAX_FINGER_NUM + 1; position++) { if((finger_current[position] == 0) && (finger_last[position] != 0)) { //printk("<<<<<<<<<<<<<<<<<<<%s:positon:%d (%d,%d)\n", __func__, position,last_x,last_y); //printk("<<<%d , %d ",finger_current[position],finger_last[position]); //input_mt_slot(ts->input_dev, position); //input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true); //input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0); //input_report_abs(ts->input_dev, ABS_MT_POSITION_X, last_x[position]); //input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, last_y[position]); //input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 100); //input_mt_sync(ts->input_dev); input_mt_slot(ts->input_dev, position); input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false); syn_flag = 1; } else if(finger_current[position]) { x = (*(coor_point+3*(position-1)))*SCREEN_MAX_WIDTH/(TOUCH_MAX_WIDTH); y = (*(coor_point+3*(position-1)+1))*SCREEN_MAX_HEIGHT/(TOUCH_MAX_HEIGHT); pressure = (*(coor_point+3*(position-1)+2)); if(x < SCREEN_MAX_WIDTH){ x = SCREEN_MAX_WIDTH - x; } if(y < SCREEN_MAX_HEIGHT){ // y = SCREEN_MAX_HEIGHT-y; } //printk(">>>>>>>>>>>>>>>>>%s:positon:%d (%d,%d)\n", __func__, position,x,y); input_mt_slot(ts->input_dev, position); input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true); input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 1); input_report_abs(ts->input_dev, ABS_MT_PRESSURE, pressure); input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x); input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y); last_x[position] = x; last_y[position] = y; //input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, pressure); //input_mt_sync(ts->input_dev); syn_flag = 1; } } input_sync(ts->input_dev); #ifdef HAVE_TOUCH_KEY if((last_key == 0) && (key == 0)){ goto NO_KEY_PRESS; } else{ syn_flag = 1; switch(key){ case 1: key = 4; break; case 2: key = 3; break; case 4: key = 2; break; case 8: key = 1; break; default: key = 0; break; } if(key != 0){ input_report_key(ts->input_dev, gt818_key_array[key - 1], 1); } else{ input_report_key(ts->input_dev, gt818_key_array[last_key - 1], 0); } last_key = key; } #endif NO_KEY_PRESS: if(syn_flag){ input_sync(ts->input_dev); } for(position = 1; position < MAX_FINGER_NUM + 1; position++) { finger_last[position] = finger_current[position]; } DATA_NO_READY: XFER_ERROR: // i2c_end_cmd(ts); if(ts->use_irq) enable_irq(ts->client->irq); }
static u8 get_ic_fw_msg(struct goodix_ts_data *ts) { s32 ret = 0; s32 i = 0; u8 buf[32]; if (fail == clear_mix_flag(ts)) { return fail; } //Get the mask version in rom of IC if (fail == get_ic_msg(ts, READ_MSK_VER_ADDR_H << 8 | READ_MSK_VER_ADDR_L, buf, 4)) { DEBUG_UPDATE("Read mask version failed!\n"); return fail; } memcpy(update_msg.ic_fw_msg.msk_ver, &buf[ADDR_LENGTH], 4); DEBUG_UPDATE("IC The mask version in rom is %c%c%c%c.\n", update_msg.ic_fw_msg.msk_ver[0],update_msg.ic_fw_msg.msk_ver[1], update_msg.ic_fw_msg.msk_ver[2],update_msg.ic_fw_msg.msk_ver[3]); #if 1 //Get the firmware msg in IC, include firmware version and checksum flag for (i = 0; i < 2; i++) { if (fail == get_ic_msg(ts, READ_FW_MSG_ADDR_H<< 8 | READ_FW_MSG_ADDR_L, buf, 4)) { DEBUG_UPDATE("Get firmware msg in IC error.\n"); return fail; } update_msg.force_update = buf[ADDR_LENGTH]; if (i == 0 && update_msg.force_update == 0xAA) { DEBUG_UPDATE("The check sum in ic is error.\n"); DEBUG_UPDATE("IC will be reset.\n"); DEBUG_UPDATE("If the check sum is still error,\n "); DEBUG_UPDATE("The IC will be updated by force.\n"); guitar_reset(10); continue; //msleep(100); } break; } //ic_fw_msg.type = buf[ADDR_LENGTH + 1]; update_msg.ic_fw_msg.version = buf[ADDR_LENGTH + 2] << 8 | buf[ADDR_LENGTH + 3]; DEBUG_UPDATE("IC VID:0x%x\n", (int)update_msg.ic_fw_msg.version); DEBUG_UPDATE("IC force update:%x\n", update_msg.force_update); #endif //Cuts the frequency buf[0] = 0x15; buf[1] = 0x22; buf[2] = 0x18; ret = i2c_write_bytes(ts->client, buf, 3); if (ret <= 0) { return fail; } i2c_end_cmd(ts); //Get the pid at 0x4011 in nvram if (fail == get_ic_msg(ts, 0x4011, buf, 1)) { DEBUG_UPDATE("Read pid failed!\n"); return fail; } update_msg.ic_fw_msg.type = buf[ADDR_LENGTH]; DEBUG_UPDATE("IC PID:%x\n", update_msg.ic_fw_msg.type); // guitar_reset(10); return success; }