/* * ELAN HID-I2C TouchScreen driver. * * Copyright (C) 2014 Elan Microelectronics Corporation. * Chuming Zhang * * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include #include #include #include #include #include #include #include #include //#include #include #include #include #include "elan_ts.h" #if defined(CONFIG_FB) static int fb_notifier_callback(struct notifier_block *self,unsigned long event, void *data); #elif defined(CONFIG_HAS_EARLYSUSPEND) static void elan_ts_early_suspend(struct early_suspend *h); static void elan_ts_late_resume(struct early_suspend *h); #endif //define private data struct elan_ts_data *private_ts; unsigned long delay = HZ; /************************key event define**************************/ static const int key_value[] = {KEY_MENU, KEY_HOMEPAGE, KEY_BACK}; void elan_ts_hw_reset(struct ts_chip_hw_info *hw_info) { gpio_set_value(hw_info->rst_gpio, 1); msleep(10); gpio_set_value(hw_info->rst_gpio, 0); msleep(100); gpio_set_value(hw_info->rst_gpio, 1); printk("[elan] elan_ts_hw_reset()\n"); } void elan_switch_irq(struct elan_ts_data *ts, int on) { // struct elan_ts_data *ts = private_ts; dev_err(&ts->client->dev, "[elan] %s enter, irq = %d, on = %d, irq_lock_flag=%d\n", __func__, ts->hw_info.irq_num, on, ts->irq_lock_flag); mutex_lock(&ts->irq_mutex); if (on) { if(ts->irq_lock_flag == 1) { enable_irq(ts->hw_info.irq_num); ts->irq_lock_flag = 0; } } else { if(ts->irq_lock_flag == 0) { disable_irq(ts->hw_info.irq_num); ts->irq_lock_flag = 1; } } mutex_unlock(&ts->irq_mutex); } static int elan_poll_int(void) { int status = 0, retry = 50;//20; do { status = gpio_get_value(private_ts->hw_info.intr_gpio); if (status == 0) break; retry--; msleep(10);//msleep(20); } while (status == 1 && retry > 0); if (status > 0) dev_info(&private_ts->client->dev, "%s: poll interrupt status %s\n",\ __func__, status == 1 ? "high" : "low"); return status == 0 ? 0 : -ETIMEDOUT; } static int elan_i2c_send(const uint8_t *buf, int count) { int ret = -1; int retries = 0; struct i2c_client *client = private_ts->client; struct i2c_adapter *adap = client->adapter; struct i2c_msg msg; msg.addr = client->addr; msg.flags = client->flags & I2C_M_TEN; msg.len = count; msg.buf = (char *)buf; while(retries < 5) { ret = i2c_transfer(adap, &msg, 1); if (ret == 1)break; retries++; } /* * If everything went ok (i.e. 1 msg transmitted), return #bytes * transmitted, else error code. */ return (ret == 1) ? count : ret; } static int elan_i2c_recv(uint8_t *buf, int count) { int ret = -1; int retries = 0; struct i2c_client *client = private_ts->client; struct i2c_adapter *adap = client->adapter; struct i2c_msg msg; msg.addr = client->addr; msg.flags = client->flags & I2C_M_TEN; msg.flags |= I2C_M_RD; msg.len = count; msg.buf = buf; while(retries < 5) { ret = i2c_transfer(adap, &msg, 1); if(ret == 1)break; retries++; } /* * If everything went ok (i.e. 1 msg received), return #bytes received, * else error code. */ return (ret == 1) ? count : ret; } struct elan_i2c_operation elan_ops = { .send = elan_i2c_send, .recv = elan_i2c_recv, .poll = elan_poll_int, }; int elan_ic_status(struct i2c_client *client) { uint8_t checkstatus[HID_CMD_LEN] = {0x04, 0x00, 0x23, 0x00, 0x03, 0x18}; uint8_t buf[HID_RECV_LEN] = {0x00}; int err = 0; struct elan_ts_data *ts = i2c_get_clientdata(client); int retry = 3; /*HID protocol after reset need delay 300ms*/ msleep(100); RETRY: err = ts->ops->send(checkstatus,sizeof(checkstatus)); if (err != sizeof(checkstatus)) { dev_err(&client->dev, "[elan] ERROR: Send get hid hello cmd fail!len=%d\n", err); if((retry--)> 0) goto RETRY; return -1; } err = ts->ops->poll();//elan_poll_int(); if (err) { dev_err(&client->dev, "[elan] ERROR: %s INT status high",__func__); if((retry--) > 0) goto RETRY; return err; } err = ts->ops->recv(buf, sizeof(buf)); if (err != sizeof(buf)) { dev_err(&client->dev, "[elan] ERROR:%s Read Hello Data error\n", __func__); if((retry--) > 0) goto RETRY; return -1; } dev_err(&client->dev, "[elan] FW Mode = 0x%2x\n",buf[4]); if ( HID_FW_NORMAL_MODE == buf[4]) { return COMPARE_UPGRADE; } else if (HID_FW_RECOVERY_MODE == buf[4]) { if (buf[6] != buf[7]) ts->fw_info.fw_bcl = buf[7]; else ts->fw_info.fw_bcl = buf[4]; return FORCED_UPGRADE; }else return UNKNOW_TYPE; } static int get_normal_hello(struct i2c_client *client) { int err = 0; uint8_t buf[8] = { 0 }; uint8_t normal_hello[4] = {NORMAL_FW_NORMAL_MODE,NORMAL_FW_NORMAL_MODE,NORMAL_FW_NORMAL_MODE,NORMAL_FW_NORMAL_MODE}; uint8_t recovery_hello[4] = {NORMAL_FW_NORMAL_MODE,NORMAL_FW_NORMAL_MODE,NORMAL_FW_RECOVERY_MODE,NORMAL_FW_RECOVERY_MODE}; struct elan_ts_data *ts = i2c_get_clientdata(client); err = ts->ops->poll();//elan_poll_int(); if (err) { dev_err(&client->dev, "[elan] ERROR: %s INT status high",__func__); return -1; } err = ts->ops->recv(buf, sizeof(buf)); if (err != sizeof(buf)) { dev_err(&client->dev, "[elan] ERROR:%s Read Hello Data error\n", __func__); return -1; } if( memcmp(buf,normal_hello,sizeof(normal_hello)) == 0) { dev_info(&client->dev, "[elan] hello packet check success!!\n"); return COMPARE_UPGRADE; } else if( memcmp(buf,recovery_hello,sizeof(recovery_hello)) == 0) { dev_info(&client->dev, "[elan] hello packet check faile!!\n"); return FORCED_UPGRADE; } else { dev_info(&client->dev, "[elan] recive hello packet error!!\n"); return UNKNOW_TYPE; } } int elan__hello_packet_handler(struct i2c_client *client, int chip_type) { int ret = 0; struct elan_ts_data *ts = i2c_get_clientdata(client); dev_err(&client->dev, "[elan] chip_type =%d\n", chip_type); if (HID_TYPE_PROTOCOL == chip_type) { ret = elan_ic_status(client); } else if (chip_type == NORMAL_TYPE_PROTOCOL) { ret = get_normal_hello(client); } ts->recover = ret; dev_err(&client->dev, "[elan] ts->recover =%d\n", ts->recover); return ret; } static int elan_ts_get_data(struct i2c_client *client, const uint8_t *wbuf, size_t wsize, uint8_t *rbuf, size_t rsize) { int err = 0; struct elan_ts_data *ts = i2c_get_clientdata(client); if (!wbuf || !rbuf) return -EINVAL; err = ts->ops->send(wbuf, wsize); if(err != wsize) { dev_err(&client->dev, "[elan] %s send cmd faile\n",__func__); err = -1; return err; } err = ts->ops->poll();//elan_poll_int(); if (err != 0) { dev_err(&client->dev, "[elan] %s Int status hight\n",__func__); return err; } err = ts->ops->recv(rbuf,rsize); if (err != rsize) { dev_err(&client->dev, "[elan] %s cmd respone error\n",__func__); err = -1; return err; } else { if (ts->chip_type == HID_TYPE_PROTOCOL) { if ((CMD_S_PKT == rbuf[4])|| (REG_S_PKT == rbuf[4])) return 0; else return -EINVAL; } else { if ((CMD_S_PKT == rbuf[0]) || (REG_S_PKT == rbuf[0])) return 0; else return -EINVAL; } } } static int hid_fw_packet_handler(struct i2c_client *client) { const int pen_osr = 260; /*Ntring=256, Warcon: 260*/ const uint8_t cmd_ver[HID_CMD_LEN] = {0x04,0x00,0x23,0x00,0x03,0x00,0x04,0x53,0x00,0x00,0x01}; const uint8_t cmd_id[HID_CMD_LEN] = {0x04,0x00,0x23,0x00,0x03,0x00,0x04,0x53,0xf0,0x00,0x01}; const uint8_t cmd_bc[HID_CMD_LEN] = {0x04,0x00,0x23,0x00,0x03,0x00,0x04,0x53,0x10,0x00,0x01}; const uint8_t cmd_osr[HID_CMD_LEN] = {0x04,0x00,0x23,0x00,0x03,0x00,0x04,0x53,0xD6,0x00,0x01}; const uint8_t cmd_test_ver[HID_CMD_LEN] = {0x04,0x00,0x23,0x00,0x03,0x00,0x04,0x53,0xe0,0x00,0x01}; const uint8_t cmd_whck_ver[HID_CMD_LEN] = {0x04,0x00,0x23,0x00,0x03,0x00,0x04,0x53,0xd2,0x00,0x01}; const uint8_t cmd_res[HID_CMD_LEN] = {0x04,0x00,0x23,0x00,0x03,0x00,0x04,0x5B,0x00,0x00,0x00,0x00,0x00}; uint8_t rbuf[HID_RECV_LEN] = {0}; int err = 0; int major, minor; struct elan_ts_data *ts = i2c_get_clientdata(client); struct elan_fw_info *fw_info = &ts->fw_info; /*fw version*/ err = elan_ts_get_data(client, cmd_ver, sizeof(cmd_ver), rbuf, sizeof(rbuf)); if ( err ) { dev_err(&client->dev, "[elan] %s get fw version failed\n",__func__); return err; } major = ((rbuf[5] & 0x0f) << 4) | ((rbuf[6] & 0xf0) >> 4); minor = ((rbuf[6] & 0x0f) << 4) | ((rbuf[7] & 0xf0) >> 4); fw_info->fw_ver = major << 8 | minor; /*fw id*/ err = elan_ts_get_data(client, cmd_id, sizeof(cmd_id),rbuf,sizeof(rbuf)); if ( err ) { dev_err(&client->dev, "[elan] %s get fw id failed\n",__func__); return err; } major = ((rbuf[5] & 0x0f) << 4) | ((rbuf[6] & 0xf0) >> 4); minor = ((rbuf[6] & 0x0f) << 4) | ((rbuf[7] & 0xf0) >> 4); fw_info->fw_id = major << 8 | minor; /*get bootcode version*/ err = elan_ts_get_data(client, cmd_bc, sizeof(cmd_bc),rbuf,sizeof(rbuf)); if ( err ) { dev_err(&client->dev, "[elan] %s get bootcode version failed\n",__func__); return err; } major = ((rbuf[5] & 0x0f) << 4) | ((rbuf[6] & 0xf0) >> 4); minor = ((rbuf[6] & 0x0f) << 4) | ((rbuf[7] & 0xf0) >> 4); fw_info->fw_bcv = major << 8 | minor; fw_info->fw_bcl = minor; /*get finger osr*/ err = elan_ts_get_data(client, cmd_osr, sizeof(cmd_osr),rbuf,sizeof(rbuf)); if ( err ) { dev_err(&client->dev, "[elan] %s get finger osr failed\n",__func__); return err; } fw_info->finger_osr = rbuf[7]; /*get trace num*/ err = elan_ts_get_data(client, cmd_res, sizeof(cmd_res),rbuf,sizeof(rbuf)); if ( err ) { dev_err(&client->dev, "[elan] %s get finger osr failed\n",__func__); return err; } // for ic rx = buf[6], tx = buf[7], rx > tx fw_info->rx = rbuf[6]; fw_info->tx = rbuf[7]; /*finger resolution*/ fw_info->finger_xres = (rbuf[6] * 2 - 1) * fw_info->finger_osr; fw_info->finger_yres = (rbuf[7] - 1) * fw_info->finger_osr; /*pen resolution*/ fw_info->pen_xres = (rbuf[6] * 2 - 1) * pen_osr; fw_info->pen_yres = (rbuf[7] - 1) * pen_osr; /*get test ver*/ err = elan_ts_get_data(client, cmd_test_ver, sizeof(cmd_test_ver),rbuf,sizeof(rbuf)); if ( err ) { dev_err(&client->dev, "[elan] %s get test ver failed\n",__func__); return err; } major = ((rbuf[5] & 0x0f) << 4) | ((rbuf[6] & 0xf0) >> 4); minor = ((rbuf[6] & 0x0f) << 4) | ((rbuf[7] & 0xf0) >> 4); fw_info->testsolversion = major << 8 | minor; fw_info->testversion = major; fw_info->solutionversion = minor; /*get whck ver*/ err = elan_ts_get_data(client, cmd_whck_ver, sizeof(cmd_whck_ver),rbuf,sizeof(rbuf)); if ( err ) { dev_err(&client->dev, "[elan] %s get test ver failed\n",__func__); return err; } major = ((rbuf[5] & 0x0f) << 4) | ((rbuf[6] & 0xf0) >> 4); minor = ((rbuf[6] & 0x0f) << 4) | ((rbuf[7] & 0xf0) >> 4); fw_info->whck_ver = major << 8 | minor; dev_info(&client->dev, "[elan] %s fw version:0x%4.4x\n", __func__,fw_info->fw_ver); dev_info(&client->dev, "[elan] %s fw id:0x%4.4x\n", __func__,fw_info->fw_id); dev_info(&client->dev, "[elan] %s bootcode version:0x%4.4x: low byte 0x%2.2x\n", __func__,fw_info->fw_bcv,fw_info->fw_bcl); dev_info(&client->dev, "[elan] %s fw_info->rx, fw_info->tx: %d:%d\n", __func__,fw_info->rx, fw_info->tx); dev_info(&client->dev, "[elan] %s finger x/y resolution:0x%4.4x/0x%4.4x\n", __func__,fw_info->finger_xres,fw_info->finger_yres); dev_info(&client->dev, "[elan] %s pen x/y resolution:0x%4.4x/0x%4.4x\n", __func__,fw_info->pen_xres,fw_info->pen_yres); dev_info(&client->dev, "[elan] %s testsolversion:testversion :0x%4.4x/0x%4.4x\n", __func__,fw_info->testsolversion,fw_info->testversion); dev_info(&client->dev, "[elan] %s solutionversion:whck_ver : 0x%4.4x/0x%4.4x\n", __func__,fw_info->solutionversion,fw_info->whck_ver); return err; } static int normal_fw_packet_handler(struct i2c_client *client) { int err = 0; struct elan_ts_data *ts = i2c_get_clientdata(client); int major, minor; struct elan_fw_info *fw_info = &ts->fw_info; const uint8_t cmd_ver[] = {0x53, 0x00, 0x00, 0x01}; const uint8_t cmd_id[] = {0x53, 0xf0, 0x00, 0x01}; const uint8_t cmd_bc[] = {0x53, 0x10, 0x00, 0x01}; #ifndef TWO_LAYER const uint8_t cmd_x[] = {0x53, 0x60, 0x00, 0x00}; const uint8_t cmd_y[] = {0x53, 0x63, 0x00, 0x00}; uint8_t rbuf[4] = {0x00}; #else const uint8_t cmd_info[] = {0x5B, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t rbuf[17] = {0x00}; #endif /*fw version*/ err = elan_ts_get_data(client, cmd_ver, sizeof(cmd_ver),rbuf,sizeof(rbuf)); if ( err ) { dev_err(&client->dev, "[elan] %s get fw version failed\n",__func__); return err; } major = ((rbuf[1] & 0x0f) << 4) | ((rbuf[2] & 0xf0) >> 4); minor = ((rbuf[2] & 0x0f) << 4) | ((rbuf[3] & 0xf0) >> 4); fw_info->fw_ver = major << 8 | minor; /*fw id*/ err = elan_ts_get_data(client, cmd_id, sizeof(cmd_id),rbuf,sizeof(rbuf)); if ( err ) { dev_err(&client->dev, "[elan] %s get fw id failed\n",__func__); return err; } major = ((rbuf[1] & 0x0f) << 4) | ((rbuf[2] & 0xf0) >> 4); minor = ((rbuf[2] & 0x0f) << 4) | ((rbuf[3] & 0xf0) >> 4); fw_info->fw_id = major << 8 | minor; /*get boocode version*/ err = elan_ts_get_data(client, cmd_bc, sizeof(cmd_bc),rbuf,sizeof(rbuf)); if ( err ) { dev_err(&client->dev, "[elan] %s get bootcode version failed\n",__func__); return err; } major = ((rbuf[1] & 0x0f) << 4) | ((rbuf[2] & 0xf0) >> 4); minor = ((rbuf[2] & 0x0f) << 4) | ((rbuf[3] & 0xf0) >> 4); fw_info->fw_bcv = major << 8 | minor; #ifndef TWO_LAYER err = elan_ts_get_data(client, cmd_x, sizeof(cmd_x),rbuf,sizeof(rbuf)); if ( err ) { dev_err(&client->dev, "[elan] %s get finger xresolution failed\n",__func__); return err; } minor = ((rbuf[2])) | ((rbuf[3] & 0xf0) << 4); fw_info->finger_xres = minor; err = elan_ts_get_data(client, cmd_y, sizeof(cmd_y),rbuf,sizeof(rbuf)); if ( err ) { dev_err(&client->dev, "[elan] %s get finger yresolution failed\n",__func__); return err; } minor = ((rbuf[2])) | ((rbuf[3] & 0xf0) << 4); fw_info->finger_yres = minor; #else err = elan_ts_get_data(client, cmd_info, sizeof(cmd_info),rbuf,sizeof(rbuf)); if ( err ) { dev_err(&client->dev, "[elan] %s get two layer x/y resolution failed\n",__func__); return err; } fw_info->finger_xres = (rbuf[2]+rbuf[6] - 1) * 64; fw_info->finger_yres = (rbuf[3]+rbuf[7] - 1) * 64; #endif dev_info(&client->dev, "[elan] %s fw version:0x%4.4x\n", __func__,fw_info->fw_ver); dev_info(&client->dev, "[elan] %s fw id:0x%4.4x\n", __func__,fw_info->fw_id); dev_info(&client->dev, "[elan] %s bootcode version:0x%4.4x\n", __func__,fw_info->fw_bcv); dev_info(&client->dev, "[elan] %s finger x/y resolution:0x%4.4x/0x%4.4x\n", __func__,fw_info->finger_xres,fw_info->finger_yres); return err; } int elan__fw_packet_handler(struct i2c_client *client) { struct elan_ts_data *ts = i2c_get_clientdata(client); int ret = 0; dev_err(&client->dev, "[elan] fw packet handler chip_type %d\n",ts->chip_type); if (ts->chip_type == HID_TYPE_PROTOCOL) { ret = hid_fw_packet_handler(client); if ( ret ) { dev_err(&client->dev, "[elan] %s HID get fw msg failed\n",__func__); } } else if (ts->chip_type == NORMAL_TYPE_PROTOCOL) { ret = normal_fw_packet_handler(client); if ( ret ) { dev_err(&client->dev, "[elan] %s Normal get fw msg failed\n",__func__); } } return ret; } static int elan_ts_recv_data(struct elan_ts_data *ts, uint8_t *buf) { int rc = 0; uint8_t rbuf[HID_RECV_LEN]={0}; struct elan_report_struct *report = &ts->report; int i = 0; rc = ts->ops->recv(rbuf, sizeof(rbuf)); if ( rc < 0) { dev_err(&ts->client->dev, "[elan] recv report data error [%d] !!\n",rc); return -1; } if (ts->chip_type == HID_TYPE_PROTOCOL) { if (rbuf[2] == HID_FID) { report->finger.fvalid_num = rbuf[62]; report->finger.fbutton_value = rbuf[63]; memcpy(buf,rbuf,67); if (rbuf[62] > 5) { rc = ts->ops->recv(rbuf, sizeof(rbuf)); if (rc != sizeof(rbuf)) { dev_err(&ts->client->dev, "[elan] recv second report data error!!\n"); return -1; } report->finger.fbuf_valid_size = 67*2; memcpy(buf+58,rbuf+3,67-3); } else { report->finger.fbuf_valid_size = 67; } report->finger.fid = HID_FID; report->finger.fsupport_num = 10; report->finger.freport_idx = 3; report->finger.fshift_byte = 11; report->tool_type = ELAN_FINGER; } else if (rbuf[2] == HID_PID) { report->stylus.pid = HID_PID; report->stylus.pbuf_valid_size = rbuf[0]; report->stylus.pbutton_value = 0;//rbuf[13]; report->stylus.preport_idx = 3; report->stylus.tip_status = (rbuf[3] & 0x33) >> 1; report->stylus.inrange_status = rbuf[3] & 0x02; report->stylus.key = rbuf[3] >> 1; // report->stylus.eraser = rbuf[3] >> 1; // report->stylus.inver = rbuf[3] >> 1; // report->stylus.barrel = rbuf[3] >> 1; report->stylus.barrel_tip = rbuf[3]; report->tool_type = ELAN_PEN; memcpy(buf,rbuf,report->stylus.pbuf_valid_size); } } else if (ts->chip_type == NORMAL_TYPE_PROTOCOL) { if (rbuf[0] == NOR2_FID) { report->finger.fid = NOR2_FID; report->finger.fbuf_valid_size = NOR2_SIZE; report->finger.fsupport_num = 2; report->finger.fvalid_num = rbuf[7] & 0x03; report->finger.freport_idx = 1; report->finger.fbits = rbuf[7] & 0x03; } else if(rbuf[0] == NOR5_FID) { report->finger.fid = NOR5_FID; report->finger.fbuf_valid_size = NOR5_SIZE; report->finger.fsupport_num = 5; report->finger.fvalid_num = rbuf[1] & 0x07; report->finger.freport_idx = 2; report->finger.fbits = rbuf[1] >> 3; } else if (rbuf[0] == NOR10_FID) { report->finger.fid = NOR10_FID; report->finger.fbuf_valid_size = NOR10_SIZE; report->finger.fsupport_num = 10; report->finger.fvalid_num = rbuf[2] & 0x0f; report->finger.freport_idx = 3; report->finger.fbits = ((rbuf[2] & 0x30)<<4) | (rbuf[1]); } report->finger.fbutton_value = rbuf[report->finger.fbuf_valid_size - 1]; report->finger.fshift_byte = 3; report->tool_type = ELAN_FINGER; memcpy(buf,rbuf, report->finger.fbuf_valid_size); } if ( report->tool_type == ELAN_PEN) { for(i = 0; i < report->stylus.pbuf_valid_size/8 + 1; i++) { print_log(ts->level,"%02x %02x %02x %02x %02x %02x %02x %02x\n",\ buf[i*8+0],buf[i*8+1],buf[i*8+2],buf[i*8+3],\ buf[i*8+4],buf[i*8+5],buf[i*8+6],buf[i*8+7]); } } else { for(i = 0; i < report->finger.fbuf_valid_size/8 + 1; i++) { print_log(ts->level,"%02x %02x %02x %02x %02x %02x %02x %02x\n",\ buf[i*8+0],buf[i*8+1],buf[i*8+2],buf[i*8+3],\ buf[i*8+4],buf[i*8+5],buf[i*8+6],buf[i*8+7]); } } return rc; } static inline int elan_ts_fparse_xy(uint8_t *data, uint16_t *x, uint16_t *y, const int type) { *x = *y = 0; if (type == HID_FID) { *x = (data[6]); *x <<= 8; *x |= data[5]; *y = (data[10]); *y <<= 8; *y |= data[9]; } else { *x = (data[0] & 0xf0); *x <<= 4; *x |= data[1]; *y = (data[0] & 0x0f); *y <<= 8; *y |= data[2]; } return 0; } static inline int elan_ts_pparse_xy(uint8_t *data, uint16_t *x, uint16_t *y, uint16_t *p) { *x = *y = *p = 0; *x = data[5]; *x <<= 8; *x |= data[4]; *y = data[7]; *y <<= 8; *y |= data[6]; *p = data[9]; *p <<= 8; *p |= data[8]; return 0; } static void elants_a_report(struct elan_ts_data *ts, uint8_t *buf) { struct elan_report_struct *report = &ts->report; struct elan_finger_struct finger = report->finger; struct elan_stylus_struct stylus = report->stylus; int fbits = finger.fbits; int reportid = 0; int valid_num = finger.fvalid_num; uint16_t x = 0, y = 0, p = 0; int fbit = 0; static int pkey = 0; if (report->tool_type == ELAN_FINGER) { for (reportid = 0; reportid < finger.fvalid_num; reportid++ ) { if (finger.fid == HID_FID) { /*hid over i2c protocol*/ fbits = (buf[finger.freport_idx] & 0x03); if (fbits) { fbit = (((buf[finger.freport_idx] & 0xfc) >> 2) - 1); elan_ts_fparse_xy(&buf[finger.freport_idx], &y, &x, finger.fid); x = 800 * x / 2112; y = 1200 * y / 3392; input_report_key(ts->finger_idev, BTN_TOUCH, 1); input_report_key(ts->finger_idev, BTN_TOOL_FINGER, true); input_report_abs(ts->finger_idev, ABS_MT_POSITION_X, x); input_report_abs(ts->finger_idev, ABS_MT_POSITION_Y, y); input_report_abs(ts->finger_idev, ABS_MT_TRACKING_ID, fbit); input_mt_sync(ts->finger_idev); } else valid_num --; finger.freport_idx += 11; } else { /*normal i2c protocol*/ if (fbits & 0x01) { elan_ts_fparse_xy(&buf[finger.freport_idx], &y, &x, finger.fid); input_report_key(ts->finger_idev, BTN_TOUCH, 1); input_report_key(ts->finger_idev, BTN_TOOL_FINGER, true); input_report_abs(ts->finger_idev, ABS_MT_POSITION_X, x); input_report_abs(ts->finger_idev, ABS_MT_POSITION_Y, y); input_report_abs(ts->finger_idev, ABS_MT_TRACKING_ID, reportid); input_mt_sync(ts->finger_idev); }else valid_num--; fbits = fbits >> 1; finger.freport_idx += 3; } } if (!valid_num) { input_report_key(ts->finger_idev, BTN_TOUCH, 0); input_report_key(ts->finger_idev, BTN_TOOL_FINGER, false); input_mt_sync(ts->finger_idev); } input_sync(ts->finger_idev); } else if (report->tool_type == ELAN_PEN) { print_log(ts->level,"[elan] stylus.key %d, pkey %d\n",stylus.key,pkey); if (stylus.key > 0 || !pkey) { switch(stylus.key) { case 2: pkey = BTN_STYLUS; input_report_key(ts->pen_idev, pkey , 1); input_sync(ts->pen_idev); break; case 3: pkey = BTN_STYLUS2; input_report_key(ts->pen_idev, pkey , 1); input_sync(ts->pen_idev); break; case 4: pkey = BTN_STYLUS; input_report_key(ts->pen_idev, pkey , 1); input_sync(ts->pen_idev); break; case 8: pkey = BTN_STYLUS2; input_report_key(ts->pen_idev, pkey , 1); input_sync(ts->pen_idev); break; default: input_report_key(ts->pen_idev, pkey , 0); pkey = 0; input_sync(ts->pen_idev); break; } } print_log(ts->level, "[elan] stylus.tip_status %d, stylus.inrange_status %d\n",\ stylus.tip_status,stylus.inrange_status); if (stylus.inrange_status) { elan_ts_pparse_xy(&buf[0],&y,&x,&p); x = 800 * x / 8580; y = 1200 * y / 13780; input_report_abs(ts->pen_idev, ABS_PRESSURE, p); input_report_abs(ts->pen_idev, ABS_X, x); input_report_abs(ts->pen_idev, ABS_Y, y); dev_info(&ts->client->dev, "[elan] X:Y:P ====%d:%d:%d\n",x,y,p); } input_report_key(ts->pen_idev, BTN_TOUCH, stylus.tip_status); input_report_key(ts->pen_idev, BTN_TOOL_PEN, stylus.tip_status); input_sync(ts->pen_idev); } } static void elants_slot_report(struct elan_ts_data *ts, uint8_t *buf) { struct elan_report_struct *report = &ts->report; struct elan_finger_struct finger = report->finger; struct elan_stylus_struct stylus = report->stylus; uint16_t x = 0, y = 0, p = 0; int16_t x_tilt_raw = 0, y_tilt_raw = 0; int8_t x_tilt = 0, y_tilt = 0; int fbits = finger.fbits; int fprebits = 0; int fbits_tmp = 0; int active = 0; int id = 0, reportid = 0; int num = finger.fvalid_num; static int pkey = 0; if (finger.fid > HID_PID) fbits_tmp = fbits; if (report->tool_type == ELAN_FINGER) { if (finger.fid == HID_FID) { /*hid over i2c protocol*/ for (reportid = 0; reportid < finger.fvalid_num; reportid++ ) { active = (buf[finger.freport_idx] & 0x03); /*id = (((buf[finger.freport_idx] & 0xfc) >> 2) -1);*/ id = (((buf[finger.freport_idx] & 0xfc) >> 2)); elan_ts_fparse_xy(&buf[finger.freport_idx], &x, &y, finger.fid); //lcm x :y = 720 : 1280 tp x: y = 1296:720 x = ts->hw_info.screen_x * x / ts->fw_info.finger_xres; y = ts->hw_info.screen_y * y / ts->fw_info.finger_yres; //x = ts->hw_info.screen_x - x; //y = ts->hw_info.screen_y - y; if (active) { /*finger contact*/ input_mt_slot(ts->finger_idev, id); //input_report_abs(ts->finger_idev, ABS_MT_PRESSURE, 100); input_report_abs(ts->finger_idev, ABS_MT_TOUCH_MAJOR, 100); input_report_abs(ts->finger_idev, ABS_MT_POSITION_X, x); input_report_abs(ts->finger_idev, ABS_MT_POSITION_Y, y); input_mt_report_slot_state(ts->finger_idev, MT_TOOL_FINGER, true); input_report_key(ts->finger_idev, BTN_TOUCH, 1); //dev_info(&ts->client->dev, "[elan] finger X:Y ====%d:%d\n",x,y); } else { /*finger leave*/ input_mt_slot(ts->finger_idev, id); input_mt_report_slot_state(ts->finger_idev, MT_TOOL_FINGER, false); //input_report_key(ts->finger_idev, BTN_TOUCH, 0); num--; } finger.freport_idx += 11; } //input_mt_sync(ts->finger_idev); if(num == 0) input_report_key(ts->finger_idev, BTN_TOUCH, 0); input_sync(ts->finger_idev); } else { /*notmal i2c protocol*/ if (fbits || fprebits) { for (reportid = 0; reportid < finger.fvalid_num; reportid++ ) { if(fbits&0x01){ elan_ts_fparse_xy(&buf[finger.freport_idx], &y, &x, finger.fid); input_mt_slot(ts->finger_idev, reportid); input_mt_report_slot_state(ts->finger_idev, MT_TOOL_FINGER, true); input_report_abs(ts->finger_idev, ABS_MT_POSITION_X, x); input_report_abs(ts->finger_idev, ABS_MT_POSITION_Y, y); } else if(fprebits&0x01){ input_mt_slot(ts->finger_idev, id); input_mt_report_slot_state(ts->finger_idev, MT_TOOL_FINGER, false); } finger.freport_idx += 3; } } fprebits = fbits_tmp; input_sync(ts->finger_idev); } } else if (report->tool_type == ELAN_PEN) { if (stylus.key > 0 || !pkey) { switch(stylus.key) { case 2: pkey = BTN_TOOL_RUBBER; input_report_key(ts->pen_idev, pkey , 1); input_sync(ts->pen_idev); break; case 3: pkey = BTN_TOOL_RUBBER; input_report_key(ts->pen_idev, pkey , 1); input_sync(ts->pen_idev); break; case 4: pkey = BTN_STYLUS; input_report_key(ts->pen_idev, pkey , 1); input_sync(ts->pen_idev); break; case 8: pkey = BTN_STYLUS2; input_report_key(ts->pen_idev, pkey , 1); input_sync(ts->pen_idev); break; default: input_report_key(ts->pen_idev, pkey , 0); pkey = 0; input_sync(ts->pen_idev); break; } } print_log(ts->level, "[elan] stylus.inrange_status = %d, stylus.barrel_tip = %d", \ stylus.inrange_status,stylus.barrel_tip); if(stylus.inrange_status) { elan_ts_pparse_xy(&buf[0],&x,&y,&p); x = ts->hw_info.screen_x * x / ts->fw_info.pen_xres; y = ts->hw_info.screen_y * y / ts->fw_info.pen_yres; //x = ts->hw_info.screen_x - x; //y = ts->hw_info.screen_y - y; x_tilt_raw = (int16_t)((buf[12] << 8) | buf[11]); y_tilt_raw = (int16_t)((buf[14] << 8) | buf[13]); x_tilt = (int8_t)(x_tilt_raw / 100); y_tilt = (int8_t)(y_tilt_raw / 100); input_mt_slot(ts->pen_idev, 0); input_mt_report_slot_state(ts->pen_idev, MT_TOOL_PEN, true); input_report_key(ts->pen_idev, BTN_TOUCH, 1); input_report_abs(ts->pen_idev, ABS_MT_TOOL_TYPE, MT_TOOL_PEN); input_report_abs(ts->pen_idev, ABS_MT_PRESSURE, p); input_report_abs(ts->pen_idev, ABS_MT_POSITION_X, x); input_report_abs(ts->pen_idev, ABS_MT_POSITION_Y, y); input_report_abs(ts->pen_idev, ABS_TILT_X, x_tilt); input_report_abs(ts->pen_idev, ABS_TILT_Y, y_tilt); print_log(ts->level, "[elan] pen X:Y:P:TX:TY ====%d:%d:%d:%d:%d\n", x, y, p, x_tilt, y_tilt); } else { input_mt_slot(ts->pen_idev, 0); input_mt_report_slot_state(ts->pen_idev, MT_TOOL_PEN, false); input_report_key(ts->pen_idev, BTN_TOUCH, 0); dev_info(&ts->client->dev, "[elan] pen relese!!!!"); } input_sync(ts->pen_idev); } } static int report_mbutton(struct input_dev *idev, int button_value) { static int key; switch(button_value) { case 0x01: key = KEY_BACK; input_report_key(idev, key, 1); break; case 0x02: key = KEY_HOMEPAGE; input_report_key(idev, key, 1); break; case 0x03: case 0x04: key = KEY_BACK; input_report_key(idev, key, 1); break; default: if (key != 0) { input_report_key(idev, key, 0); key = 0; } break; } input_sync(idev); return key; } static void elan_ts_hid_report(struct elan_ts_data *ts, uint8_t *buf) { struct elan_report_struct *report = &ts->report; int button = report->finger.fbutton_value; int pbutton = report->stylus.pbutton_value; static int prekey = 0; /*for hid protocol finger contat mutual button or pen contact mutual button*/ /*button priority is higher than other*/ if ((button != 0 && button != 0xFF) || (pbutton != 0 && pbutton != 0xFF)|| (prekey != 0)) { if (ts->report.tool_type == ELAN_FINGER) { prekey = report_mbutton(ts->finger_idev,button); return; } else { prekey = report_mbutton(ts->pen_idev,pbutton); return; } } if (ts->report_type == PROTOCOL_TYPE_B) { elants_slot_report(ts,buf); } else { elants_a_report(ts,buf); } } static void elan_ts_normal_report(struct elan_ts_data *ts, uint8_t *buf) { struct elan_report_struct *report = &ts->report; int button = report->finger.fbutton_value; static int prekey = 0; if ((button != 0 && button != 0xFF) || (prekey != 0)) { prekey = report_mbutton(ts->finger_idev,button); return; } if (ts->report_type == PROTOCOL_TYPE_B) { elants_slot_report(ts,buf); return; } else { elants_a_report(ts,buf); return; } } static void elan_ts_report_data(struct elan_ts_data *ts, uint8_t *buf) { switch (ts->chip_type) { case HID_TYPE_PROTOCOL: elan_ts_hid_report(ts, buf); break; case NORMAL_TYPE_PROTOCOL: elan_ts_normal_report(ts,buf); break; default: dev_err(&ts->client->dev, "[elan] unknow type 0x%2x:0x%2x:0x%2x:0x%2x",\ buf[0],buf[1],buf[2],buf[3]); break; } } static void elan_ts_work_func(struct work_struct *work) { struct elan_ts_data *ts = container_of(work, struct elan_ts_data, ts_work); uint8_t buf[HID_REPORT_MAX_LEN] = {0x00}; int rc = 0; if(gpio_get_value(ts->hw_info.intr_gpio)) { dev_err(&ts->client->dev,"[elan]interrupt jitter\n."); return; } memset(&ts->report, 0, sizeof(ts->report)); rc = elan_ts_recv_data(ts,buf); if (rc < 0) { dev_err(&ts->client->dev,"[elan]recv data error\n."); return; } elan_ts_report_data(ts,buf); return; } static irqreturn_t elan_ts_irq_handler(int irq, void *dev_id) { struct elan_ts_data *ts = (struct elan_ts_data*)dev_id; if (ts->user_handle_irq) { wake_up_interruptible(&ts->elan_userqueue); ts->int_val = 0; return IRQ_HANDLED; } else { queue_work(ts->elan_wq,&ts->ts_work); return IRQ_HANDLED; } } static int elan_request_pen_input_dev(struct elan_ts_data *ts) { int err = 0; ts->pen_idev = input_allocate_device(); if (ts->pen_idev == NULL) { err = -ENOMEM; dev_err(&ts->client->dev, "[elan error] Failed to allocate pen device\n"); return err; } if (ts->report_type == PROTOCOL_TYPE_B) { //input_mt_init_slots(ts->pen_idev, 10); input_mt_init_slots(ts->pen_idev, FINGERS_NUM,INPUT_MT_DIRECT); input_set_abs_params(ts->pen_idev, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0); input_set_abs_params(ts->pen_idev, ABS_MT_POSITION_X, 0, ts->hw_info.screen_x, 0, 0); input_set_abs_params(ts->pen_idev, ABS_MT_POSITION_Y, 0, ts->hw_info.screen_y, 0, 0); input_set_abs_params(ts->pen_idev, ABS_MT_PRESSURE, 0, 4096, 0, 0); input_set_abs_params(ts->pen_idev, ABS_TILT_X, -90, 90, 0, 0); input_set_abs_params(ts->pen_idev, ABS_TILT_Y, -90, 90, 0, 0); } else { __set_bit(BTN_TOOL_PEN, ts->pen_idev->keybit); __set_bit(BTN_TOUCH, ts->pen_idev->keybit); ts->pen_idev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); input_set_abs_params(ts->pen_idev, ABS_X, 0, ts->hw_info.screen_x, 0, 0); input_set_abs_params(ts->pen_idev, ABS_Y, 0, ts->hw_info.screen_y, 0, 0); input_set_abs_params(ts->pen_idev, ABS_PRESSURE, 0, 4096, 0, 0); input_set_abs_params(ts->pen_idev, ABS_TILT_X, -90, 90, 0, 0); input_set_abs_params(ts->pen_idev, ABS_TILT_Y, -90, 90, 0, 0); } ts->pen_idev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) | BIT_MASK(EV_SYN); __set_bit(KEY_BACK, ts->pen_idev->keybit); __set_bit(BTN_TOOL_RUBBER, ts->pen_idev->keybit); __set_bit(BTN_STYLUS, ts->pen_idev->keybit); __set_bit(BTN_STYLUS2, ts->pen_idev->keybit); __set_bit(INPUT_PROP_DIRECT, ts->pen_idev->propbit); __set_bit(BTN_TOUCH, ts->pen_idev->keybit); input_set_abs_params(ts->pen_idev, ABS_MT_TRACKING_ID, 0, 10, 0, 0); ts->pen_idev->name = "elan_pen"; ts->pen_idev->phys = "input/ts"; ts->pen_idev->id.bustype = BUS_I2C; err = input_register_device(ts->pen_idev); if (err) { input_free_device(ts->pen_idev); dev_err(&ts->client->dev, "unable to register pen input device: %d\n", err); return err; } return err; } static int elan_request_finger_input_dev(struct elan_ts_data *ts) { int err = 0; int i = 0; ts->finger_idev = input_allocate_device(); if (ts->finger_idev == NULL) { err = -ENOMEM; dev_err(&ts->client->dev, "[elan] Failed to allocate input device\n"); return err; } ts->finger_idev->evbit[0] = BIT(EV_KEY)|BIT_MASK(EV_REP); /*key setting*/ for (i = 0; i < ARRAY_SIZE(key_value); i++) __set_bit(key_value[i], ts->finger_idev->keybit); ts->finger_idev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); __set_bit(INPUT_PROP_DIRECT, ts->finger_idev->propbit); if (ts->report_type == PROTOCOL_TYPE_B) { //input_mt_init_slots(ts->finger_idev, 10); input_mt_init_slots(ts->finger_idev, FINGERS_NUM,INPUT_MT_DIRECT); input_set_abs_params(ts->finger_idev, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0); } else { __set_bit(BTN_TOOL_FINGER, ts->finger_idev->keybit); } dev_info(&ts->client->dev, "[elan] %s: x resolution: %d, y resolution: %d\n", __func__, ts->fw_info.finger_xres, ts->fw_info.finger_yres); ts->finger_idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); input_set_abs_params(ts->finger_idev, ABS_MT_POSITION_X, 0, ts->hw_info.screen_x, 0, 0); input_set_abs_params(ts->finger_idev, ABS_MT_POSITION_Y, 0, ts->hw_info.screen_y, 0, 0); // input_set_abs_params(ts->finger_idev, ABS_MT_PRESSURE, 0, 255, 0, 0); // input_set_abs_params(ts->finger_idev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); input_set_abs_params(ts->finger_idev, ABS_MT_TRACKING_ID, 0, 255, 0, 0); ts->finger_idev->name = ELAN_TS_NAME; ts->finger_idev->phys = "input/ts"; ts->finger_idev->id.bustype = BUS_I2C; ts->finger_idev->id.vendor = 0x0001; ts->finger_idev->id.product = 0x0002; ts->finger_idev->id.version = 0x0003; err = input_register_device(ts->finger_idev); if (err) { input_free_device(ts->finger_idev); dev_err(&ts->client->dev, "[elan]%s: unable to register %s input device\n", __func__, ts->finger_idev->name); return err; } return 0; } static int elan_ts_register_interrupt(struct elan_ts_data *ts) { int err = 0; err = request_threaded_irq(ts->hw_info.irq_num, NULL, elan_ts_irq_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ELAN_TS_NAME, ts); if (err < 0) dev_err(&ts->client->dev, "[elan] %s: request_irq %d failed,err = %d\n", __func__, ts->client->irq, err); return err; } static void elan_ic_init_work(struct work_struct *work) { int rc = 0; int retry_cnt = 0; struct elan_ts_data *ts = private_ts; struct i2c_client *client = ts->client; /*Get FW MSG: ID,VERSION,X_RES,Y_RES,etc*/ if (ts->recover == COMPARE_UPGRADE) { for (retry_cnt = 0; retry_cnt < 3; retry_cnt++) { rc = elan__fw_packet_handler(client); if (rc < 0) dev_err(&client->dev, "[elan]%s, fw_packet_handler fail, rc = %d\n", __func__, rc); else break; } if (retry_cnt >= 3) { dev_err(&client->dev, "[elan]%s, fw_packet_handler failed,retry out, rc = %d\n", __func__,rc); return; } } else { dev_err(&client->dev, "[elan]%s, fw into recovery mode force update, rc = %d\n", __func__,rc); } #ifdef IAP_PORTION dev_err(&ts->client->dev, "[elan]Start IAP Flow!!!\n"); ts->power_lock = 1; //skip resume / suspend flow elan_check_update_flage(ts); #endif /*finget and pen input event register*/ rc = elan_request_pen_input_dev(ts); if ( rc ) { dev_err(&ts->client->dev, "[elan]: %s pen input event request failed.\n", __func__); goto exit_pen_input_dev_failed; } rc = elan_request_finger_input_dev(ts); if ( rc ) { dev_err(&ts->client->dev, "[elan]: %s finger input event request failed %d.\n", __func__, rc); goto exit_finger_input_dev_failed; } mutex_lock(&ts->irq_mutex); ts->irq_lock_flag = 0; mutex_unlock(&ts->irq_mutex); /*elan irq resgister*/ rc = elan_ts_register_interrupt(private_ts); if ( rc ) { dev_err(&private_ts->client->dev, "[elan]: %s elan_ts_register_interrupt failed %d\n", __func__, rc); goto exit_register_interrupt_failed; } #ifdef IAP_PORTION ts->power_lock = 0; #endif return; exit_register_interrupt_failed: input_unregister_device(ts->finger_idev); exit_finger_input_dev_failed: input_unregister_device(ts->pen_idev); exit_pen_input_dev_failed: return; } static int elan_ts_setup(struct elan_ts_data *ts) { int err = 0; dev_err(&ts->client->dev, "[elan] setup hw reset\n"); /*HW RESET TP and delay 200ms*/ elan_ts_hw_reset(&ts->hw_info); msleep(500); err = elan__hello_packet_handler(ts->client, ts->chip_type); if ( err < 0 ) { dev_err(&ts->client->dev, "[elan error] %s, hello_packet_handler fail,err= %d\n", __func__,err); return err; } else { dev_err(&ts->client->dev, "[elan] %s,ic status = %s", __func__, err == FORCED_UPGRADE ? "recovery":"normal"); } return err; } static int elan_iap_open(struct inode *inode, struct file *filp) { struct elan_ts_data *ts = container_of(((struct miscdevice*)filp->private_data), struct elan_ts_data, firmware); dev_dbg(&ts->client->dev,"%s enter\n", __func__); filp->private_data = ts; // ts->int_val = 1; // ts->user_handle_irq = 1; return 0; } static int elan_iap_release(struct inode *inode, struct file *filp) { dev_info(&private_ts->client->dev,"%s enter", __func__); filp->private_data = NULL; //private_ts->user_handle_irq = 0; //private_ts->int_val = 0; return 0; } static ssize_t elan_iap_write(struct file *filp, const char *buff, size_t count, loff_t *offp) { int ret; char *tmp; struct elan_ts_data *ts = (struct elan_ts_data *)filp->private_data; struct i2c_client *client= ts->client; dev_info(&client->dev,"%s enter", __func__); if (count > 8192){ count = 8192; } tmp = kmalloc(count, GFP_KERNEL); if (tmp == NULL){ return -ENOMEM; } if (copy_from_user(tmp, buff, count)) { return -EFAULT; } ret = elan_i2c_send(tmp, count); if (ret != count){ dev_err(&client->dev, "[elan]elan elan_i2c_send fail, ret=%d \n", ret); } kfree(tmp); return ret; } static ssize_t elan_iap_read(struct file *filp, char *buff, size_t count, loff_t *offp) { char *tmp; int ret; long rc; struct elan_ts_data *ts = (struct elan_ts_data *)filp->private_data; struct i2c_client *client = ts->client; dev_info(&client->dev, "%s enter", __func__); if (count > 8192){ count = 8192; } tmp = kmalloc(count, GFP_KERNEL); if (tmp == NULL){ return -ENOMEM; } if (ts->user_handle_irq == 1) { wait_event_interruptible(ts->elan_userqueue, ts->int_val == 0); } ret = elan_i2c_recv(tmp, count); if (ret != count){ dev_err(&client->dev, "[elan error]elan elan_i2c_recv fail, ret=%d \n", ret); } if (ret == count){ rc = copy_to_user(buff, tmp, count); } if (ts->user_handle_irq == 1) { ts->int_val = 1; } kfree(tmp); return ret; } static long elan_iap_ioctl( struct file *filp, unsigned int cmd, unsigned long arg) { int __user *ip = (int __user *)arg; struct elan_ts_data *ts = (struct elan_ts_data *)filp->private_data; struct i2c_client *client = ts->client; dev_info(&client->dev, "%s enter cmd value %x\n", __func__,cmd); switch (cmd) { case IOCTL_I2C_SLAVE: dev_info(&client->dev, "pre addr is %X\n", client->addr); client->addr = (int __user)arg; dev_info(&client->dev, "new addr is %X\n", client->addr); break; case IOCTL_RESET: elan_ts_hw_reset(&ts->hw_info); break; case IOCTL_IAP_MODE_LOCK: if(private_ts->power_lock == 0){ private_ts->power_lock = 1; elan_switch_irq(ts,0); } break; case IOCTL_IAP_MODE_UNLOCK: if(private_ts->power_lock == 1){ private_ts->power_lock = 0; elan_switch_irq(ts,1); } break; case IOCTL_CHECK_RECOVERY_MODE: return private_ts->recover; break; case IOCTL_ROUGH_CALIBRATE: return elan_ts_calibrate(ts->client); case IOCTL_I2C_INT: put_user(gpio_get_value(ts->hw_info.intr_gpio), ip); break; case IOCTL_USER_HANDLE_IRQ: ts->user_handle_irq = 1; break; case IOCTL_KERN_HANDLE_IRQ: ts->user_handle_irq = 0; break; default: break; } return 0; } static unsigned int elan_iap_poll(struct file *filp, struct poll_table_struct *wait) { int mask = 0; struct elan_ts_data *ts = (struct elan_ts_data *)filp->private_data; dev_info(&ts->client->dev, "[elan] polling int_val = %d\n", ts->int_val); poll_wait(filp,&ts->elan_userqueue, wait); if (ts->int_val == 0) mask |= POLLIN|POLLRDNORM; else if(ts->int_val == 1) mask |= POLLOUT|POLLWRNORM; return mask; } struct file_operations elan_touch_fops = { .open = elan_iap_open, .write = elan_iap_write, .read = elan_iap_read, .release = elan_iap_release, .unlocked_ioctl = elan_iap_ioctl, .compat_ioctl = elan_iap_ioctl, .poll = elan_iap_poll, }; static void elan_touch_node_init(struct elan_ts_data *ts) { elan_sysfs_attri_file(ts); /*creat dev/elan-iap node for fw operation*/ ts->firmware.minor = MISC_DYNAMIC_MINOR; ts->firmware.name = "elan-iap"; ts->firmware.fops = &elan_touch_fops; ts->firmware.mode = S_IFREG|S_IRWXUGO; if (misc_register(&ts->firmware) < 0) dev_err(&ts->client->dev, "misc_register failed!!\n"); ts->p = proc_create("elan-iap", 0664, NULL, (const struct proc_ops *)&elan_touch_fops); if (ts->p == NULL) dev_err(&ts->client->dev, "[elan error] proc_create failed!!\n"); else dev_info(&ts->client->dev, "proc_create ok!!\n"); return; } static void elan_touch_node_deinit(struct elan_ts_data *ts) { elan_sysfs_attri_file_remove(ts); misc_deregister(&ts->firmware); remove_proc_entry("elan-iap", NULL); } /******************************************************* Function: Power on Funtion. Input: ts: elan_ts_data struct. on: bool, true:on, flase:off Output: Executive outcomes. 0: succeed. otherwise: failed *******************************************************/ #if 1 static int elan_ts_power_on(struct elan_ts_data *ts, bool on) { int ret = 0; if (!on) goto power_off; ret = regulator_enable(ts->vdd); if (ret) { dev_err(&ts->client->dev, "Regulator vdd enable failed ret = %d\n",ret); return ret; } #if 0 ret = regulator_enable(ts->vcc_i2c); if (ret) { dev_err(&ts->client->dev, "Regulator vcc_i2c enable failed ret = %d\n",ret); regulator_disable(ts->vdd); } #endif return ret; power_off: ret = regulator_disable(ts->vdd); if (ret) { dev_err(&ts->client->dev, "Regulator vdd disable failed ret = %d\n",ret); return ret; } #if 0 ret = regulator_disable(ts->vcc_i2c); if (ret) { dev_err(&ts->client->dev, "Regulator vcc_i2c disable failed ret = %d\n", ret); ret = regulator_enable(ts->vdd); if (ret) dev_err(&ts->client->dev, "Regulator vdd enable failed ret = %d\n", ret); } #endif return ret; } static int elan_power_initial(struct elan_ts_data *ts) { int ret = 0; ts->vdd = regulator_get(&ts->client->dev, "vdd"); if (IS_ERR(ts->vdd)) { ret = PTR_ERR(ts->vdd); dev_err(&ts->client->dev, "Regulator get failed vdd rc=%d\n", ret); return ret; } #if 0 if (regulator_count_voltages(ts->vdd) > 0) { ret = regulator_set_voltage(ts->vdd,ELAN_VTG_MIN_UV, ELAN_VTG_MAX_UV); if (ret) { dev_err(&ts->client->dev, "Regulator set_vtg failed vdd rc=%d\n", ret); goto reg_vdd_put; } } ts->vcc_i2c = regulator_get(&ts->client->dev, "vcc_i2c"); if (IS_ERR(ts->vcc_i2c)) { ret = PTR_ERR(ts->vcc_i2c); dev_err(&ts->client->dev, "Regulator get failed vcc_i2c rc=%d\n", ret); goto reg_vdd_set_vtg; } if (regulator_count_voltages(ts->vcc_i2c) > 0) { ret = regulator_set_voltage(ts->vcc_i2c, ELAN_I2C_VTG_MIN_UV, ELAN_I2C_VTG_MAX_UV); if (ret) { dev_err(&ts->client->dev, "Regulator set_vtg failed vcc_i2c rc=%d\n", ret); goto reg_vcc_i2c_put; } } #endif return ret; #if 0 reg_vcc_i2c_put: regulator_put(ts->vcc_i2c); reg_vdd_set_vtg: if (regulator_count_voltages(ts->vdd) > 0) regulator_set_voltage(ts->vdd, 0, ELAN_VTG_MAX_UV); reg_vdd_put: regulator_put(ts->vdd); #endif return ret; } static int elan_ts_set_power(struct elan_ts_data *ts, bool on) { int ret = 0; if(!on) { ret = on; goto pwr_deinit; } /*initial power*/ ret = elan_power_initial(ts); if(ret) goto elan_power_init_failed; /*power on*/ ret = elan_ts_power_on(ts,on); if(ret) goto elan_power_on_failed; return ret; elan_power_on_failed: regulator_put(ts->vdd); regulator_put(ts->vcc_i2c); elan_power_init_failed: pwr_deinit: return ret; } #endif /******************************************************* Function: Initial gpio Funtion Input: hw_info: ts_chip_hw_info struct Output: Executive outcomes. 0: succeed. otherwise: failed *******************************************************/ static int elan_ts_gpio_initial(struct ts_chip_hw_info *hw_info) { int ret = 0; printk("[elan] request reset gpio\n"); ret = gpio_request(hw_info->rst_gpio, "tp_reset"); if (ret < 0) { pr_err("%s: request rst_gpio pin failed\n", __func__); goto free_rst_gpio; } gpio_direction_output(hw_info->rst_gpio, 1); printk("[elan] request interrupt gpio\n"); /*set int pin input*/ ret = gpio_request(hw_info->intr_gpio, "tp_irq"); if (ret < 0) { pr_err("%s: request intr_gpio pin failed\n", __func__); goto free_irq_gpio; } gpio_direction_input(hw_info->intr_gpio); hw_info->irq_num = gpio_to_irq(hw_info->intr_gpio); return ret; free_irq_gpio: if (gpio_is_valid(hw_info->intr_gpio)) gpio_free(hw_info->intr_gpio); free_rst_gpio: if (gpio_is_valid(hw_info->rst_gpio)) gpio_free(hw_info->rst_gpio); return ret; } /******************************************************* Function: Get dts gpio num Input: dev: device struct. hw_info: ts_chip_hw_info struct Output: Executive outcomes. 0: succeed. otherwise: failed *******************************************************/ #ifdef CONFIG_OF static int elan_parse_dt(struct device *dev, struct ts_chip_hw_info *chip_hw_info) { int ret = 0; u32 data = 0; //struct device_node *node = NULL; struct elan_ts_data *ts = container_of(chip_hw_info, struct elan_ts_data, hw_info); //u32 lcm_coordinate[2] = {0}; struct device_node *np = dev->of_node; /* node = of_find_compatible_node(NULL, NULL, "elan,ektf"); if(node){ dev_err(&ts->client->dev,"[elan]of_find_compatible_node of : %s\n", "elan,ektf"); return -ENODEV; } */ /*get irq gpio from dts*/ chip_hw_info->intr_gpio = of_get_named_gpio_flags(np, "elan,irq-gpio", 0, NULL); if (!gpio_is_valid(chip_hw_info->intr_gpio)) { dev_err(&ts->client->dev, "[elan] hw_info->intr_gpio invalid\n"); ret = -EINVAL; goto request_intr_gpio_failed; } /*get reset gpio from dts*/ chip_hw_info->rst_gpio = of_get_named_gpio_flags(np, "elan,rst-gpio", 0, NULL); if (!gpio_is_valid(chip_hw_info->rst_gpio)) { dev_err(&ts->client->dev, "[elan] hw_info->rst_gpio invalid\n"); ret = -EINVAL; goto request_rst_gpio_failed; } /*get ic communicate protocol*/ ret = of_property_read_u32(np, "chip_type", &data); if (ret == 0) { ts->chip_type = data; dev_info(&ts->client->dev,"[elan]:chip protocol_type=%s", ts->chip_type == 1 ? "HID IIC":"NORMAL IIC" ); } else { ret = -EINVAL; goto read_chip_type_failed; } /*get report protocol */ ret = of_property_read_u32(np, "report_type", &data); if (ret == 0) { ts->report_type = data; dev_info(&ts->client->dev,"[elan]:report protocol_type=%s", ts->report_type == 1?"B protocol":"A protocol"); } else { ret = -EINVAL;//hw_info->rst_gpio; goto read_report_type_failed; } ts->hw_info.screen_x = 2160; //1728; //2160; ts->hw_info.screen_y = 1440; //2368; //1440 #if 0 /*get lcm coordinate*/ ret = of_property_read_u32_array(np, "lcm_resolution", lcm_coordinate,sizeof(lcm_coordinate)); if (ret == 0) { ts->hw_info.screen_x = lcm_coordinate[0]; ts->hw_info.screen_y = lcm_coordinate[1]; dev_info(&ts->client->dev,"[elan]:LCM RESOLUTION X:Y=%d:%d,", ts->hw_info.screen_x, ts->hw_info.screen_y); } else { ret = -EINVAL;//hw_info->rst_gpio; goto read_lcm_res_failed; } #endif return ret; //read_lcm_res_failed: read_report_type_failed: read_chip_type_failed: if (gpio_is_valid(chip_hw_info->rst_gpio)) gpio_free(chip_hw_info->rst_gpio); request_rst_gpio_failed: if (gpio_is_valid(chip_hw_info->intr_gpio)) gpio_free(chip_hw_info->intr_gpio); request_intr_gpio_failed: return ret; } #endif /******************************************************* Function: Get platform data Funtion Input: ts: elan_ts_data struct. Output: Executive outcomes. 0: succeed. otherwise: failed *******************************************************/ static int elan_ts_hw_initial(struct elan_ts_data *ts) { int ret = 0; struct i2c_client *client = ts->client; struct ts_chip_hw_info *hw_info; hw_info = &(ts->hw_info); #if 0 hw_info = devm_kzalloc(&client->dev,sizeof(struct ts_chip_hw_info), GFP_KERNEL); if (!hw_info) { dev_err(&client->dev, "ETP Failed to allocate memory for hw_info\n"); return -ENOMEM; } else { hw_info = client->dev.platform_data; ts->chip_type = 1; /*1:HID IIC, 0: NORMAL IIC*/ ts->report_type = 1; /*1:B protocol, 0:A protocol*/ } #endif #ifdef CONFIG_OF if (client->dev.of_node) { ret = elan_parse_dt(&client->dev, hw_info); if (ret) return ret; } #endif ts->fw_store_type = FROM_SYS_ETC_FIRMWARE; //define get fw solution ts->user_handle_irq = 0; //ts->irq_lock_flag = 0; //ts->hw_info = *hw_info; ret = elan_ts_gpio_initial(&ts->hw_info); if (ret) dev_err(&client->dev, "gpio initial failed ret = %d\n",ret); dev_err(&client->dev, "[elan] rst = %d, int = %d, irq=%d\n",hw_info->rst_gpio, hw_info->intr_gpio,hw_info->irq_num); dev_err(&client->dev, "[elan] lcm_x = %d, lcm_y = %d\n",hw_info->screen_x, hw_info->screen_y); return ret; } static void elan_ts_hw_deinit(struct elan_ts_data *ts) { regulator_put(ts->vdd); regulator_put(ts->vcc_i2c); if (gpio_is_valid(ts->hw_info.intr_gpio)) gpio_free(ts->hw_info.intr_gpio); if (gpio_is_valid(ts->hw_info.rst_gpio)) gpio_free(ts->hw_info.rst_gpio); } /******************************************************* Function: I2c probe. Input: client: i2c device struct. id: device id. Output: Executive outcomes. 0: succeed. *******************************************************/ static int elan_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { //#define SM_BUS int err; #ifdef SM_BUS union i2c_smbus_data dummy; #endif struct elan_ts_data *ts; int retry = 0; printk("elan %s() %d\n", __func__, __LINE__); /*check i2c bus support fuction*/ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "i2c check functionality error\n"); return -ENXIO; } /*kzalloc struct elan_ts_data memory */ ts = devm_kzalloc(&client->dev, sizeof(struct elan_ts_data), GFP_KERNEL); if (!ts) { dev_err(&client->dev, "%s: allocate elan_ts_data failed", __func__); return -ENOMEM; } printk("elan %s() %d\n", __func__, __LINE__); ts->client = client; i2c_set_clientdata(client, ts); private_ts = ts; /*get hw info and initial*/ err = elan_ts_hw_initial(ts); if(err) { dev_err(&client->dev, "%s hw initial failed\n",__func__); goto free_client_data; } printk("elan %s() %d\n", __func__, __LINE__); /*set power & power on*/ #if 1 err = elan_ts_set_power(ts,1); if (err) { dev_err(&client->dev, "%s power seting failed\n",__func__); goto free_io_port; } msleep(100); #endif printk("elan %s() %d\n", __func__, __LINE__); /*check elan ic in bus or not*/ #ifdef SM_BUS if (i2c_smbus_xfer(client->adapter, client->addr, 0, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) { dev_err(&client->dev, "nothing at this address 0x%x\n", client->addr); goto free_power_set; } #endif /*elan ic transfer initial*/ ts->ops = &elan_ops; printk("elan %s() %d\n", __func__, __LINE__); /*check elan ic status*/ err = elan_ts_setup(ts); if (err < 0) { dev_err(&client->dev, "%s ic initial failed\n",__func__); goto err_no_elan_chip; } /*check rek */ if(COMPARE_UPGRADE == ts->recover) { for (retry = 0; retry < 3; retry++) { err = elan_ts_check_calibrate(ts->client); /*ic reponse rek count,count != 0xff? "ok":"failed" */ if (err) { dev_err(&ts->client->dev, "[elan] check rek failed, retry=%d\n",retry); err = elan_ts_calibrate(ts->client); if (err) { dev_err(&ts->client->dev, "[elan]calibrate failed, retry=%d\n",retry); } else break; } else break; } } /*creat dev node & sysfs node for fw operatrion*/ elan_touch_node_init(ts); printk("elan %s() %d\n", __func__, __LINE__); /*get fw infomation, register input dev, register interrupt*/ INIT_DELAYED_WORK(&ts->init_work, elan_ic_init_work); ts->init_elan_ic_wq = create_singlethread_workqueue("init_elan_ic_wq"); if (IS_ERR(ts->init_elan_ic_wq)) { err = PTR_ERR(ts->init_elan_ic_wq); goto err_ic_init_failed; } queue_delayed_work(ts->init_elan_ic_wq, &ts->init_work, delay); printk("elan %s() %d\n", __func__, __LINE__); /*report work thread*/ ts->elan_wq = create_singlethread_workqueue("elan_wq"); if (IS_ERR(ts->elan_wq)) { err = PTR_ERR(ts->elan_wq); dev_err(&client->dev, "[elan error] failed to create kernel thread: %d\n", err); goto err_create_workqueue_failed; } INIT_WORK(&ts->ts_work, elan_ts_work_func); /*set print log level*/ ts->level = TP_DEBUG; /*initial wait queue for userspace*/ init_waitqueue_head(&ts->elan_userqueue); /*lcm callback resume and suspend*/ #if defined(CONFIG_FB) ts->fb_notif.notifier_call = fb_notifier_callback; err = fb_register_client(&ts->fb_notif); if (err) dev_err(&client->dev,"[FB]Unable to register fb_notifier: %d", err); #elif defined(CONFIG_HAS_EARLYSUSPEND) ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; ts->early_suspend.suspend = elan_ts_early_suspend; ts->early_suspend.resume = elan_ts_late_resume; register_early_suspend(&ts->early_suspend); #endif printk("elan %s() %d probe success!\n", __func__, __LINE__); return err; err_create_workqueue_failed: destroy_workqueue(ts->elan_wq); err_ic_init_failed: destroy_workqueue(ts->init_elan_ic_wq); err_no_elan_chip: #ifdef SM_BUS free_power_set: #endif regulator_put(ts->vdd); regulator_put(ts->vcc_i2c); #if 1 free_io_port: if (gpio_is_valid(ts->hw_info.intr_gpio)) gpio_free(ts->hw_info.intr_gpio); if (gpio_is_valid(ts->hw_info.rst_gpio)) gpio_free(ts->hw_info.rst_gpio); #endif free_client_data: i2c_set_clientdata(client,NULL); return err; } /******************************************************* Function: Elan touchscreen driver release function. Input: client: i2c device struct. Output: Executive outcomes. 0---succeed. *******************************************************/ static void elan_ts_remove(struct i2c_client *client) { struct elan_ts_data *ts = i2c_get_clientdata(client); elan_ts_hw_deinit(ts); elan_touch_node_deinit(ts); input_unregister_device(ts->finger_idev); input_unregister_device(ts->pen_idev); free_irq(ts->hw_info.irq_num,(void *)elan_ts_irq_handler); if (!IS_ERR(ts->init_elan_ic_wq)) { destroy_workqueue(ts->init_elan_ic_wq); } if (!IS_ERR(ts->elan_wq)) { destroy_workqueue(ts->elan_wq); } #if defined(CONFIG_FB) fb_unregister_client(&ts->fb_notif); #endif #ifdef CONFIG_HAS_EARLYSUSPEND unregister_early_suspend(&ts->early_suspend); #endif i2c_set_clientdata(client,NULL); } static void elan_release_point(void) { struct input_dev *fidev; struct input_dev *pidev; int i = 0; if (private_ts->finger_idev && private_ts->pen_idev) { fidev = private_ts->finger_idev; pidev = private_ts->pen_idev; if (private_ts->report_type == PROTOCOL_TYPE_B) { for (i = 0; i < 10; i++) { input_mt_slot(fidev, i); input_mt_report_slot_state(fidev, MT_TOOL_FINGER, 0); } if (private_ts->report.tool_type == ELAN_PEN) { input_mt_slot(pidev, 0); input_mt_report_slot_state(pidev, MT_TOOL_PEN, false); } } else { input_mt_sync(fidev); input_report_key(fidev, BTN_TOUCH, 0); if (private_ts->report.tool_type == ELAN_PEN) { input_mt_sync(pidev); input_report_key(pidev, BTN_TOUCH, 0); } } input_sync(fidev); if (private_ts->report.tool_type == ELAN_PEN) { input_sync(pidev); } } else { dev_err(&private_ts->client->dev, "Noting done\n"); } return; } static int elan_ts_set_power_state(struct i2c_client *client, int state) { int err = 0; struct elan_ts_data *ts = i2c_get_clientdata(client); /*send ic sleep/wake up command*/ uint8_t hid_cmd[HID_CMD_LEN] = {0x04, 0x00, 0x23, 0x00, 0x03, 0x00, 0x04, CMD_W_PKT, 0x50, 0x00, 0x01}; uint8_t cmd[4] = {CMD_W_PKT, 0x50, 0x00, 0x01}; if (ts->chip_type == HID_TYPE_PROTOCOL) { hid_cmd[8] |= (state << 3); err = ts->ops->send(hid_cmd, sizeof(hid_cmd)); if (err != sizeof(hid_cmd)) { err = -EINVAL; goto err_set_power_state; } } else { cmd[1] |= (state << 3); err = ts->ops->send(cmd,sizeof(cmd)); if (err != sizeof(cmd)) { err = -EINVAL; goto err_set_power_state; } } print_log(ts->level, "[elan] set power stats success\n"); return 0; err_set_power_state: return err; } static int elan_ts_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct elan_ts_data *ts = i2c_get_clientdata(client); int err = 0; int retry = RETRY_TIMES; //if do fw upgrade, don't sleep if (ts->power_lock == 0) { dev_err(&client->dev, "[elan] %s suspend flow \n", __func__); elan_switch_irq(ts, 0); try_set_power: // if system would not power off, must do this and check err = elan_ts_set_power_state(ts->client, PWR_STATE_DEEP_SLEEP); if (err) { dev_err(&client->dev, "[elan] set power stats failed err = %d\n", err); if ( (retry --) > 0) goto try_set_power; } /*release finger*/ elan_release_point(); /*power off*/ elan_ts_power_on(ts,false); } else { dev_err(&client->dev, "[elsn] %s Nothing Done!!\n",__func__); } return 0; } static int elan_ts_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct elan_ts_data *ts = i2c_get_clientdata(client); int err = 0; int retry = RETRY_TIMES; /* ** enable irq, set ic status, reset ic **/ if (ts->power_lock == 0) { dev_err(&client->dev, "[elan] reset gpio to resum tp\n"); /*device power on*/ elan_ts_power_on(ts,true); /*delay for ic initial*/ msleep(100); reset_power_state: err = elan_ts_set_power_state(ts->client, PWR_STATE_NORMAL); if (err) { dev_err(&client->dev, "[elan]%s set power stata failed!!\n",__func__); if ((retry--) > 0) goto reset_power_state; else elan_ts_hw_reset(&ts->hw_info); } /*release point*/ elan_release_point(); elan_switch_irq(ts, 1); } else { dev_err(&client->dev, "[elsn] %s Nothing Done!!\n",__func__); } return 0; } /******************************************************* Function: fb_notifier_callback function. Input: self: notifier_block struct. event: unsigned long. data: void Output: 0. *******************************************************/ #if defined(CONFIG_FB) static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) { struct fb_event *evdata = data; int *blank; struct elan_ts_data *ts = container_of(self, struct elan_ts_data, fb_notif); if (evdata && evdata->data && event == FB_EVENT_BLANK && ts && ts->client) { blank = evdata->data; if (*blank == FB_BLANK_UNBLANK) elan_ts_resume(&ts->client->dev); else if (*blank == FB_BLANK_POWERDOWN) elan_ts_suspend(&ts->client->dev); } return 0; } #elif defined(CONFIG_HAS_EARLYSUSPEND) /******************************************************* Function: Early suspend function. Input: h: early_suspend struct. Output: None. *******************************************************/ static void elan_ts_early_suspend(struct early_suspend *h) { struct elan_ts_data *ts; ts = container_of(h, struct elan_ts_data, early_suspend); elan_ts_suspend(&ts->client->dev); } /******************************************************* Function: Late resume function. Input: h: early_suspend struct. Output: None. *******************************************************/ static void elan_ts_late_resume(struct early_suspend *h) { struct elan_ts_data *ts; ts = container_of(h, struct elan_ts_data, early_suspend); elan_ts_resume(&ts->client->dev); } #endif/* !CONFIG_HAS_EARLYSUSPEND && !CONFIG_FB*/ #ifdef CONFIG_PM static const struct dev_pm_ops elan_ts_dev_pm_ops = { #if (!defined(CONFIG_FB) && !defined(CONFIG_HAS_EARLYSUSPEND)) .suspend = elan_ts_suspend, .resume = elan_ts_resume, #endif }; #endif static const struct i2c_device_id elan_ts_id[] = { { ELAN_TS_NAME, 0 }, { } }; #ifdef CONFIG_OF static const struct of_device_id elan_of_match[] = { {.compatible = "elan,ektf"}, {}, }; MODULE_DEVICE_TABLE(of, elan_of_match); #endif static struct i2c_driver elan_ts_driver = { .probe = elan_ts_probe, .remove = elan_ts_remove, .id_table = elan_ts_id, .driver = { .name = ELAN_TS_NAME, #ifdef CONFIG_OF .of_match_table = elan_of_match, #endif #ifdef CONFIG_PM .pm = &elan_ts_dev_pm_ops, #endif }, }; static int __init elan_ts_init(void) { int ret = 0; ret = i2c_add_driver(&elan_ts_driver); return ret; } static void __exit elan_ts_exit(void) { i2c_del_driver(&elan_ts_driver); return; } module_init(elan_ts_init); module_exit(elan_ts_exit); MODULE_DESCRIPTION("ELAN HID-I2C and I2C Touchscreen Driver"); MODULE_AUTHOR("Minger Zhang "); MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);