/* * MStar MSG21XX touchscreen driver * * Copyright (c) 2006-2012 MStar Semiconductor, Inc. * * Copyright (C) 2012 Bruce Ding * * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 #include #if defined(CONFIG_FB) #include #include #endif #ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR #include #endif /* Constant Value & Variable Definition*/ #define MSTAR_VTG_MIN_UV 2800000 #define MSTAR_VTG_MAX_UV 3300000 #define MSTAR_I2C_VTG_MIN_UV 1800000 #define MSTAR_I2C_VTG_MAX_UV 1800000 #define MAX_BUTTONS 4 #define FT_COORDS_ARR_SIZE 4 #define MSTAR_FW_NAME_MAX_LEN 50 #define MSTAR_CHIPTOP_REGISTER_BANK 0x1E #define MSTAR_CHIPTOP_REGISTER_ICTYPE 0xCC #define MSTAR_INIT_SW_ID 0x7FF #define MSTAR_DEBUG_DIR_NAME "ts_debug" #define MSG_FW_FILE_MAJOR_VERSION(x) \ (((x)->data[0x7f4f] << 8) + ((x)->data[0x7f4e])) #define MSG_FW_FILE_MINOR_VERSION(x) \ (((x)->data[0x7f51] << 8) + ((x)->data[0x7f50])) /* * Note. * Please do not change the below setting. */ #define TPD_WIDTH (2048) #define TPD_HEIGHT (2048) #define PINCTRL_STATE_ACTIVE "pmx_ts_active" #define PINCTRL_STATE_SUSPEND "pmx_ts_suspend" #define PINCTRL_STATE_RELEASE "pmx_ts_release" #define SLAVE_I2C_ID_DBBUS (0xC4>>1) #define DEMO_MODE_PACKET_LENGTH (8) #define TP_PRINT /*store the frimware binary data*/ static unsigned char fw_bin_data[94][1024]; static unsigned int crc32_table[256]; static unsigned short fw_file_major, fw_file_minor; static unsigned short main_sw_id = MSTAR_INIT_SW_ID; static unsigned short info_sw_id = MSTAR_INIT_SW_ID; static unsigned int bin_conf_crc32; struct msg21xx_ts_platform_data { const char *name; char fw_name[MSTAR_FW_NAME_MAX_LEN]; u8 fw_version_major; u8 fw_version_minor; u32 irq_gpio; u32 irq_gpio_flags; u32 reset_gpio; u32 reset_gpio_flags; u32 x_max; u32 y_max; u32 x_min; u32 y_min; u32 panel_minx; u32 panel_miny; u32 panel_maxx; u32 panel_maxy; u32 num_max_touches; u8 ic_type; u32 button_map[MAX_BUTTONS]; u32 num_buttons; u32 hard_reset_delay_ms; u32 post_hard_reset_delay_ms; bool updating_fw; }; /* Touch Data Type Definition */ struct touchPoint_t { unsigned short x; unsigned short y; }; struct touchInfo_t { struct touchPoint_t *point; unsigned char count; unsigned char keycode; }; struct msg21xx_ts_data { struct i2c_client *client; struct input_dev *input_dev; struct msg21xx_ts_platform_data *pdata; struct regulator *vdd; struct regulator *vcc_i2c; bool suspended; #if defined(CONFIG_FB) struct notifier_block fb_notif; #endif struct pinctrl *ts_pinctrl; struct pinctrl_state *pinctrl_state_active; struct pinctrl_state *pinctrl_state_suspend; struct pinctrl_state *pinctrl_state_release; struct mutex ts_mutex; struct touchInfo_t info; }; #if defined(CONFIG_FB) static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data); #endif #ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR static unsigned char bEnableTpProximity; static unsigned char bFaceClosingTp; #endif #ifdef TP_PRINT static int tp_print_proc_read(struct msg21xx_ts_data *ts_data); static void tp_print_create_entry(struct msg21xx_ts_data *ts_data); #endif static void _ReadBinConfig(struct msg21xx_ts_data *ts_data); static unsigned int _CalMainCRC32(struct msg21xx_ts_data *ts_data); static struct mutex msg21xx_mutex; enum EMEM_TYPE_t { EMEM_ALL = 0, EMEM_MAIN, EMEM_INFO, }; /* Function Definition */ static unsigned int _CRC_doReflect(unsigned int ref, signed char ch) { unsigned int value = 0; unsigned int i = 0; for (i = 1; i < (ch + 1); i++) { if (ref & 1) value |= 1 << (ch - i); ref >>= 1; } return value; } static unsigned int _CRC_getValue(unsigned int text, unsigned int prevCRC) { unsigned int ulCRC = prevCRC; ulCRC = (ulCRC >> 8) ^ crc32_table[(ulCRC & 0xFF) ^ text]; return ulCRC; } static void _CRC_initTable(void) { unsigned int magic_number = 0x04c11db7; unsigned int i, j; for (i = 0; i <= 0xFF; i++) { crc32_table[i] = _CRC_doReflect(i, 8) << 24; for (j = 0; j < 8; j++) crc32_table[i] = (crc32_table[i] << 1) ^ (crc32_table[i] & (0x80000000L) ? magic_number : 0); crc32_table[i] = _CRC_doReflect(crc32_table[i], 32); } } static void msg21xx_reset_hw(struct msg21xx_ts_platform_data *pdata) { unsigned int delay; gpio_direction_output(pdata->reset_gpio, 1); gpio_set_value_cansleep(pdata->reset_gpio, 0); /* Note that the RST must be in LOW 10ms at least */ delay = pdata->hard_reset_delay_ms * 1000; usleep_range(delay, delay + 1); gpio_set_value_cansleep(pdata->reset_gpio, 1); /* Enable the interrupt service thread/routine for INT after 50ms */ delay = pdata->post_hard_reset_delay_ms * 1000; usleep_range(delay, delay + 1); } static int read_i2c_seq(struct msg21xx_ts_data *ts_data, unsigned char addr, unsigned char *buf, unsigned short size) { int rc = 0; struct i2c_msg msgs[] = { { .addr = addr, .flags = I2C_M_RD, /* read flag */ .len = size, .buf = buf, }, }; /* If everything went ok (i.e. 1 msg transmitted), return #bytes transmitted, else error code. */ if (ts_data->client != NULL) { rc = i2c_transfer(ts_data->client->adapter, msgs, 1); if (rc < 0) dev_err(&ts_data->client->dev, "%s error %d\n", __func__, rc); } else { dev_err(&ts_data->client->dev, "ts_data->client is NULL\n"); } return rc; } static int write_i2c_seq(struct msg21xx_ts_data *ts_data, unsigned char addr, unsigned char *buf, unsigned short size) { int rc = 0; struct i2c_msg msgs[] = { { .addr = addr, /* * if read flag is undefined, * then it means write flag. */ .flags = 0, .len = size, .buf = buf, }, }; /* * If everything went ok (i.e. 1 msg transmitted), return #bytes * transmitted, else error code. */ if (ts_data->client != NULL) { rc = i2c_transfer(ts_data->client->adapter, msgs, 1); if (rc < 0) dev_err(&ts_data->client->dev, "%s error %d\n", __func__, rc); } else { dev_err(&ts_data->client->dev, "ts_data->client is NULL\n"); } return rc; } static unsigned short read_reg(struct msg21xx_ts_data *ts_data, unsigned char bank, unsigned char addr) { unsigned char tx_data[3] = {0x10, bank, addr}; unsigned char rx_data[2] = {0}; write_i2c_seq(ts_data, SLAVE_I2C_ID_DBBUS, tx_data, sizeof(tx_data)); read_i2c_seq(ts_data, SLAVE_I2C_ID_DBBUS, rx_data, sizeof(rx_data)); return rx_data[1] << 8 | rx_data[0]; } static void write_reg(struct msg21xx_ts_data *ts_data, unsigned char bank, unsigned char addr, unsigned short data) { unsigned char tx_data[5] = {0x10, bank, addr, data & 0xFF, data >> 8}; write_i2c_seq(ts_data, SLAVE_I2C_ID_DBBUS, tx_data, sizeof(tx_data)); } static void write_reg_8bit(struct msg21xx_ts_data *ts_data, unsigned char bank, unsigned char addr, unsigned char data) { unsigned char tx_data[4] = {0x10, bank, addr, data}; write_i2c_seq(ts_data, SLAVE_I2C_ID_DBBUS, tx_data, sizeof(tx_data)); } static void dbbusDWIICEnterSerialDebugMode(struct msg21xx_ts_data *ts_data) { unsigned char data[5]; /* Enter the Serial Debug Mode */ data[0] = 0x53; data[1] = 0x45; data[2] = 0x52; data[3] = 0x44; data[4] = 0x42; write_i2c_seq(ts_data, SLAVE_I2C_ID_DBBUS, data, sizeof(data)); } static void dbbusDWIICStopMCU(struct msg21xx_ts_data *ts_data) { unsigned char data[1]; /* Stop the MCU */ data[0] = 0x37; write_i2c_seq(ts_data, SLAVE_I2C_ID_DBBUS, data, sizeof(data)); } static void dbbusDWIICIICUseBus(struct msg21xx_ts_data *ts_data) { unsigned char data[1]; /* IIC Use Bus */ data[0] = 0x35; write_i2c_seq(ts_data, SLAVE_I2C_ID_DBBUS, data, sizeof(data)); } static void dbbusDWIICIICReshape(struct msg21xx_ts_data *ts_data) { unsigned char data[1]; /* IIC Re-shape */ data[0] = 0x71; write_i2c_seq(ts_data, SLAVE_I2C_ID_DBBUS, data, sizeof(data)); } static unsigned char msg21xx_get_ic_type(struct msg21xx_ts_data *ts_data) { unsigned char ic_type = 0; unsigned char bank; unsigned char addr; msg21xx_reset_hw(ts_data->pdata); dbbusDWIICEnterSerialDebugMode(ts_data); dbbusDWIICStopMCU(ts_data); dbbusDWIICIICUseBus(ts_data); dbbusDWIICIICReshape(ts_data); msleep(300); /* stop mcu */ write_reg_8bit(ts_data, 0x0F, 0xE6, 0x01); /* disable watch dog */ write_reg(ts_data, 0x3C, 0x60, 0xAA55); /* get ic type */ bank = MSTAR_CHIPTOP_REGISTER_BANK; addr = MSTAR_CHIPTOP_REGISTER_ICTYPE; ic_type = (0xff)&(read_reg(ts_data, bank, addr)); if (ic_type != ts_data->pdata->ic_type) ic_type = 0; msg21xx_reset_hw(ts_data->pdata); return ic_type; } static int msg21xx_read_firmware_id(struct msg21xx_ts_data *ts_data) { unsigned char command[3] = { 0x53, 0x00, 0x2A}; unsigned char response[4] = { 0 }; mutex_lock(&msg21xx_mutex); write_i2c_seq(ts_data, ts_data->client->addr, command, sizeof(command)); read_i2c_seq(ts_data, ts_data->client->addr, response, sizeof(response)); mutex_unlock(&msg21xx_mutex); ts_data->pdata->fw_version_major = (response[1]<<8) + response[0]; ts_data->pdata->fw_version_minor = (response[3]<<8) + response[2]; dev_info(&ts_data->client->dev, "major num = %d, minor num = %d\n", ts_data->pdata->fw_version_major, ts_data->pdata->fw_version_minor); return 0; } static int firmware_erase_c33(struct msg21xx_ts_data *ts_data, enum EMEM_TYPE_t emem_type) { /* stop mcu */ write_reg(ts_data, 0x0F, 0xE6, 0x0001); /* disable watch dog */ write_reg_8bit(ts_data, 0x3C, 0x60, 0x55); write_reg_8bit(ts_data, 0x3C, 0x61, 0xAA); /* set PROGRAM password */ write_reg_8bit(ts_data, 0x16, 0x1A, 0xBA); write_reg_8bit(ts_data, 0x16, 0x1B, 0xAB); write_reg_8bit(ts_data, 0x16, 0x18, 0x80); if (emem_type == EMEM_ALL) write_reg_8bit(ts_data, 0x16, 0x08, 0x10); write_reg_8bit(ts_data, 0x16, 0x18, 0x40); msleep(20); /* clear pce */ write_reg_8bit(ts_data, 0x16, 0x18, 0x80); /* erase trigger */ if (emem_type == EMEM_MAIN) write_reg_8bit(ts_data, 0x16, 0x0E, 0x04); /* erase main */ else write_reg_8bit(ts_data, 0x16, 0x0E, 0x08); /* erase all block */ return 0; } static ssize_t firmware_update_c33(struct device *dev, struct device_attribute *attr, const char *buf, size_t size, enum EMEM_TYPE_t emem_type, bool isForce) { unsigned int i, j; unsigned int crc_main, crc_main_tp; unsigned int crc_info, crc_info_tp; unsigned short reg_data = 0; int update_pass = 1; bool fw_upgrade = false; struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev); crc_main = 0xffffffff; crc_info = 0xffffffff; msg21xx_reset_hw(ts_data->pdata); msg21xx_read_firmware_id(ts_data); _ReadBinConfig(ts_data); if ((main_sw_id == info_sw_id) && (_CalMainCRC32(ts_data) == bin_conf_crc32) && (fw_file_major == ts_data->pdata->fw_version_major) && (fw_file_minor > ts_data->pdata->fw_version_minor)) { fw_upgrade = true; } if (!fw_upgrade && !isForce) { dev_dbg(dev, "no need to update\n"); msg21xx_reset_hw(ts_data->pdata); return size; } msg21xx_reset_hw(ts_data->pdata); msleep(300); dbbusDWIICEnterSerialDebugMode(ts_data); dbbusDWIICStopMCU(ts_data); dbbusDWIICIICUseBus(ts_data); dbbusDWIICIICReshape(ts_data); msleep(300); /* erase main */ firmware_erase_c33(ts_data, EMEM_MAIN); msleep(1000); msg21xx_reset_hw(ts_data->pdata); dbbusDWIICEnterSerialDebugMode(ts_data); dbbusDWIICStopMCU(ts_data); dbbusDWIICIICUseBus(ts_data); dbbusDWIICIICReshape(ts_data); msleep(300); /* * Program */ /* polling 0x3CE4 is 0x1C70 */ if ((emem_type == EMEM_ALL) || (emem_type == EMEM_MAIN)) { do { reg_data = read_reg(ts_data, 0x3C, 0xE4); } while (reg_data != 0x1C70); } switch (emem_type) { case EMEM_ALL: write_reg(ts_data, 0x3C, 0xE4, 0xE38F); /* for all-blocks */ break; case EMEM_MAIN: write_reg(ts_data, 0x3C, 0xE4, 0x7731); /* for main block */ break; case EMEM_INFO: write_reg(ts_data, 0x3C, 0xE4, 0x7731); /* for info block */ write_reg_8bit(ts_data, 0x0F, 0xE6, 0x01); write_reg_8bit(ts_data, 0x3C, 0xE4, 0xC5); write_reg_8bit(ts_data, 0x3C, 0xE5, 0x78); write_reg_8bit(ts_data, MSTAR_CHIPTOP_REGISTER_BANK, 0x04, 0x9F); write_reg_8bit(ts_data, MSTAR_CHIPTOP_REGISTER_BANK, 0x05, 0x82); write_reg_8bit(ts_data, 0x0F, 0xE6, 0x00); msleep(100); break; } /* polling 0x3CE4 is 0x2F43 */ do { reg_data = read_reg(ts_data, 0x3C, 0xE4); } while (reg_data != 0x2F43); /* calculate CRC 32 */ _CRC_initTable(); /* total 32 KB : 2 byte per R/W */ for (i = 0; i < 32; i++) { if (i == 31) { fw_bin_data[i][1014] = 0x5A; fw_bin_data[i][1015] = 0xA5; for (j = 0; j < 1016; j++) crc_main = _CRC_getValue(fw_bin_data[i][j], crc_main); } else { for (j = 0; j < 1024; j++) crc_main = _CRC_getValue(fw_bin_data[i][j], crc_main); } for (j = 0; j < 8; j++) write_i2c_seq(ts_data, ts_data->client->addr, &fw_bin_data[i][j * 128], 128); msleep(100); /* polling 0x3CE4 is 0xD0BC */ do { reg_data = read_reg(ts_data, 0x3C, 0xE4); } while (reg_data != 0xD0BC); write_reg(ts_data, 0x3C, 0xE4, 0x2F43); } if ((emem_type == EMEM_ALL) || (emem_type == EMEM_MAIN)) { /* write file done and check crc */ write_reg(ts_data, 0x3C, 0xE4, 0x1380); } msleep(20); if ((emem_type == EMEM_ALL) || (emem_type == EMEM_MAIN)) { /* polling 0x3CE4 is 0x9432 */ do { reg_data = read_reg(ts_data, 0x3C, 0xE4); } while (reg_data != 0x9432); } crc_main = crc_main ^ 0xffffffff; crc_info = crc_info ^ 0xffffffff; if ((emem_type == EMEM_ALL) || (emem_type == EMEM_MAIN)) { /* CRC Main from TP */ crc_main_tp = read_reg(ts_data, 0x3C, 0x80); crc_main_tp = (crc_main_tp << 16) | read_reg(ts_data, 0x3C, 0x82); /* CRC Info from TP */ crc_info_tp = read_reg(ts_data, 0x3C, 0xA0); crc_info_tp = (crc_info_tp << 16) | read_reg(ts_data, 0x3C, 0xA2); } update_pass = 1; if ((emem_type == EMEM_ALL) || (emem_type == EMEM_MAIN)) { if (crc_main_tp != crc_main) update_pass = 0; } if (!update_pass) { dev_err(dev, "update_C33 failed\n"); msg21xx_reset_hw(ts_data->pdata); return 0; } dev_dbg(dev, "update_C33 OK\n"); msg21xx_reset_hw(ts_data->pdata); return size; } static unsigned int _CalMainCRC32(struct msg21xx_ts_data *ts_data) { unsigned int ret = 0; unsigned short reg_data = 0; msg21xx_reset_hw(ts_data->pdata); dbbusDWIICEnterSerialDebugMode(ts_data); dbbusDWIICStopMCU(ts_data); dbbusDWIICIICUseBus(ts_data); dbbusDWIICIICReshape(ts_data); msleep(100); /* Stop MCU */ write_reg(ts_data, 0x0F, 0xE6, 0x0001); /* Stop Watchdog */ write_reg_8bit(ts_data, 0x3C, 0x60, 0x55); write_reg_8bit(ts_data, 0x3C, 0x61, 0xAA); /* cmd */ write_reg(ts_data, 0x3C, 0xE4, 0xDF4C); write_reg(ts_data, MSTAR_CHIPTOP_REGISTER_BANK, 0x04, 0x7d60); /* TP SW reset */ write_reg(ts_data, MSTAR_CHIPTOP_REGISTER_BANK, 0x04, 0x829F); /* MCU run */ write_reg(ts_data, 0x0F, 0xE6, 0x0000); /* polling 0x3CE4 */ do { reg_data = read_reg(ts_data, 0x3C, 0xE4); } while (reg_data != 0x9432); /* Cal CRC Main from TP */ ret = read_reg(ts_data, 0x3C, 0x80); ret = (ret << 16) | read_reg(ts_data, 0x3C, 0x82); dev_dbg(&ts_data->client->dev, "[21xxA]:Current main crc32=0x%x\n", ret); return ret; } static void _ReadBinConfig(struct msg21xx_ts_data *ts_data) { unsigned char dbbus_tx_data[5] = {0}; unsigned char dbbus_rx_data[4] = {0}; unsigned short reg_data = 0; msg21xx_reset_hw(ts_data->pdata); dbbusDWIICEnterSerialDebugMode(ts_data); dbbusDWIICStopMCU(ts_data); dbbusDWIICIICUseBus(ts_data); dbbusDWIICIICReshape(ts_data); msleep(100); /* Stop MCU */ write_reg(ts_data, 0x0F, 0xE6, 0x0001); /* Stop Watchdog */ write_reg_8bit(ts_data, 0x3C, 0x60, 0x55); write_reg_8bit(ts_data, 0x3C, 0x61, 0xAA); /* cmd */ write_reg(ts_data, 0x3C, 0xE4, 0xA4AB); write_reg(ts_data, MSTAR_CHIPTOP_REGISTER_BANK, 0x04, 0x7d60); /* TP SW reset */ write_reg(ts_data, MSTAR_CHIPTOP_REGISTER_BANK, 0x04, 0x829F); /* MCU run */ write_reg(ts_data, 0x0F, 0xE6, 0x0000); /* polling 0x3CE4 */ do { reg_data = read_reg(ts_data, 0x3C, 0xE4); } while (reg_data != 0x5B58); dbbus_tx_data[0] = 0x72; dbbus_tx_data[1] = 0x7F; dbbus_tx_data[2] = 0x55; dbbus_tx_data[3] = 0x00; dbbus_tx_data[4] = 0x04; write_i2c_seq(ts_data, ts_data->client->addr, &dbbus_tx_data[0], 5); read_i2c_seq(ts_data, ts_data->client->addr, &dbbus_rx_data[0], 4); if ((dbbus_rx_data[0] >= 0x30 && dbbus_rx_data[0] <= 0x39) && (dbbus_rx_data[1] >= 0x30 && dbbus_rx_data[1] <= 0x39) && (dbbus_rx_data[2] >= 0x31 && dbbus_rx_data[2] <= 0x39)) { main_sw_id = (dbbus_rx_data[0] - 0x30) * 100 + (dbbus_rx_data[1] - 0x30) * 10 + (dbbus_rx_data[2] - 0x30); } dbbus_tx_data[0] = 0x72; dbbus_tx_data[1] = 0x7F; dbbus_tx_data[2] = 0xFC; dbbus_tx_data[3] = 0x00; dbbus_tx_data[4] = 0x04; write_i2c_seq(ts_data, ts_data->client->addr, &dbbus_tx_data[0], 5); read_i2c_seq(ts_data, ts_data->client->addr, &dbbus_rx_data[0], 4); bin_conf_crc32 = (dbbus_rx_data[0] << 24) | (dbbus_rx_data[1] << 16) | (dbbus_rx_data[2] << 8) | (dbbus_rx_data[3]); dbbus_tx_data[0] = 0x72; dbbus_tx_data[1] = 0x83; dbbus_tx_data[2] = 0x00; dbbus_tx_data[3] = 0x00; dbbus_tx_data[4] = 0x04; write_i2c_seq(ts_data, ts_data->client->addr, &dbbus_tx_data[0], 5); read_i2c_seq(ts_data, ts_data->client->addr, &dbbus_rx_data[0], 4); if ((dbbus_rx_data[0] >= 0x30 && dbbus_rx_data[0] <= 0x39) && (dbbus_rx_data[1] >= 0x30 && dbbus_rx_data[1] <= 0x39) && (dbbus_rx_data[2] >= 0x31 && dbbus_rx_data[2] <= 0x39)) { info_sw_id = (dbbus_rx_data[0] - 0x30) * 100 + (dbbus_rx_data[1] - 0x30) * 10 + (dbbus_rx_data[2] - 0x30); } dev_dbg(&ts_data->client->dev, "[21xxA]:main_sw_id = %d, info_sw_id = %d, bin_conf_crc32 = 0x%x\n", main_sw_id, info_sw_id, bin_conf_crc32); } static ssize_t firmware_update_show(struct device *dev, struct device_attribute *attr, char *buf) { struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev); return snprintf(buf, 3, "%d\n", ts_data->pdata->updating_fw); } static ssize_t firmware_update_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev); ts_data->pdata->updating_fw = true; disable_irq(ts_data->client->irq); size = firmware_update_c33(dev, attr, buf, size, EMEM_MAIN, false); enable_irq(ts_data->client->irq); ts_data->pdata->updating_fw = false; return size; } static DEVICE_ATTR(update, (S_IRUGO | S_IWUSR), firmware_update_show, firmware_update_store); static int prepare_fw_data(struct device *dev) { int count; int i; int ret; const struct firmware *fw = NULL; struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev); ret = request_firmware(&fw, ts_data->pdata->fw_name, dev); if (ret < 0) { dev_err(dev, "Request firmware failed - %s (%d)\n", ts_data->pdata->fw_name, ret); return ret; } count = fw->size / 1024; for (i = 0; i < count; i++) memcpy(fw_bin_data[i], fw->data + (i * 1024), 1024); fw_file_major = MSG_FW_FILE_MAJOR_VERSION(fw); fw_file_minor = MSG_FW_FILE_MINOR_VERSION(fw); dev_dbg(dev, "New firmware: %d.%d", fw_file_major, fw_file_minor); return fw->size; } static ssize_t firmware_update_smart_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int ret; struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev); ret = prepare_fw_data(dev); if (ret < 0) { dev_err(dev, "Request firmware failed -(%d)\n", ret); return ret; } ts_data->pdata->updating_fw = true; disable_irq(ts_data->client->irq); ret = firmware_update_c33(dev, attr, buf, size, EMEM_MAIN, false); if (ret == 0) dev_err(dev, "firmware_update_c33 ret = %d\n", ret); enable_irq(ts_data->client->irq); ts_data->pdata->updating_fw = false; return ret; } static ssize_t firmware_force_update_smart_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int ret; struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev); ret = prepare_fw_data(dev); if (ret < 0) { dev_err(dev, "Request firmware failed -(%d)\n", ret); return ret; } ts_data->pdata->updating_fw = true; disable_irq(ts_data->client->irq); ret = firmware_update_c33(dev, attr, buf, size, EMEM_MAIN, true); if (ret == 0) dev_err(dev, "firmware_update_c33 et = %d\n", ret); enable_irq(ts_data->client->irq); ts_data->pdata->updating_fw = false; return ret; } static DEVICE_ATTR(update_fw, (S_IRUGO | S_IWUSR), firmware_update_show, firmware_update_smart_store); static DEVICE_ATTR(force_update_fw, (S_IRUGO | S_IWUSR), firmware_update_show, firmware_force_update_smart_store); static ssize_t firmware_version_show(struct device *dev, struct device_attribute *attr, char *buf) { struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev); msg21xx_read_firmware_id(ts_data); return snprintf(buf, sizeof(char) * 8, "%03d%03d\n", ts_data->pdata->fw_version_major, ts_data->pdata->fw_version_minor); } static DEVICE_ATTR(version, S_IRUGO, firmware_version_show, NULL); static ssize_t msg21xx_fw_name_show(struct device *dev, struct device_attribute *attr, char *buf) { struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev); return snprintf(buf, MSTAR_FW_NAME_MAX_LEN - 1, "%s\n", ts_data->pdata->fw_name); } static ssize_t msg21xx_fw_name_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev); if (size > MSTAR_FW_NAME_MAX_LEN - 1) return -EINVAL; strlcpy(ts_data->pdata->fw_name, buf, size); if (ts_data->pdata->fw_name[size - 1] == '\n') ts_data->pdata->fw_name[size - 1] = 0; return size; } static DEVICE_ATTR(fw_name, (S_IRUGO | S_IWUSR), msg21xx_fw_name_show, msg21xx_fw_name_store); static ssize_t firmware_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int count = size / 1024; int i; for (i = 0; i < count; i++) memcpy(fw_bin_data[i], buf + (i * 1024), 1024); if (buf != NULL) dev_dbg(dev, "buf[0] = %c\n", buf[0]); return size; } static DEVICE_ATTR(data, S_IWUSR, NULL, firmware_data_store); static ssize_t tp_print_show(struct device *dev, struct device_attribute *attr, char *buf) { struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev); tp_print_proc_read(ts_data); return snprintf(buf, 3, "%d\n", ts_data->suspended); } static ssize_t tp_print_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { return size; } static DEVICE_ATTR(tpp, (S_IRUGO | S_IWUSR), tp_print_show, tp_print_store); #ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR static void _msg_enable_proximity(void) { unsigned char tx_data[4] = {0}; tx_data[0] = 0x52; tx_data[1] = 0x00; tx_data[2] = 0x47; tx_data[3] = 0xa0; mutex_lock(&msg21xx_mutex); write_i2c_seq(ts_data->client->addr, &tx_data[0], 4); mutex_unlock(&msg21xx_mutex); bEnableTpProximity = 1; } static void _msg_disable_proximity(void) { unsigned char tx_data[4] = {0}; tx_data[0] = 0x52; tx_data[1] = 0x00; tx_data[2] = 0x47; tx_data[3] = 0xa1; mutex_lock(&msg21xx_mutex); write_i2c_seq(ts_data->client->addr, &tx_data[0], 4); mutex_unlock(&msg21xx_mutex); bEnableTpProximity = 0; bFaceClosingTp = 0; } static void tsps_msg21xx_enable(int en) { if (en) _msg_enable_proximity(); else _msg_disable_proximity(); } static int tsps_msg21xx_data(void) { return bFaceClosingTp; } #endif static int msg21xx_pinctrl_init(struct msg21xx_ts_data *ts_data) { int retval; /* Get pinctrl if target uses pinctrl */ ts_data->ts_pinctrl = devm_pinctrl_get(&(ts_data->client->dev)); if (IS_ERR_OR_NULL(ts_data->ts_pinctrl)) { retval = PTR_ERR(ts_data->ts_pinctrl); dev_dbg(&ts_data->client->dev, "Target does not use pinctrl %d\n", retval); goto err_pinctrl_get; } ts_data->pinctrl_state_active = pinctrl_lookup_state( ts_data->ts_pinctrl, PINCTRL_STATE_ACTIVE); if (IS_ERR_OR_NULL(ts_data->pinctrl_state_active)) { retval = PTR_ERR(ts_data->pinctrl_state_active); dev_dbg(&ts_data->client->dev, "Can't lookup %s pinstate %d\n", PINCTRL_STATE_ACTIVE, retval); goto err_pinctrl_lookup; } ts_data->pinctrl_state_suspend = pinctrl_lookup_state( ts_data->ts_pinctrl, PINCTRL_STATE_SUSPEND); if (IS_ERR_OR_NULL(ts_data->pinctrl_state_suspend)) { retval = PTR_ERR(ts_data->pinctrl_state_suspend); dev_dbg(&ts_data->client->dev, "Can't lookup %s pinstate %d\n", PINCTRL_STATE_SUSPEND, retval); goto err_pinctrl_lookup; } ts_data->pinctrl_state_release = pinctrl_lookup_state( ts_data->ts_pinctrl, PINCTRL_STATE_RELEASE); if (IS_ERR_OR_NULL(ts_data->pinctrl_state_release)) { retval = PTR_ERR(ts_data->pinctrl_state_release); dev_dbg(&ts_data->client->dev, "Can't lookup %s pinstate %d\n", PINCTRL_STATE_RELEASE, retval); } return 0; err_pinctrl_lookup: devm_pinctrl_put(ts_data->ts_pinctrl); err_pinctrl_get: ts_data->ts_pinctrl = NULL; return retval; } static unsigned char calculate_checksum(unsigned char *msg, int length) { int checksum = 0, i; for (i = 0; i < length; i++) checksum += msg[i]; return (unsigned char)((-checksum) & 0xFF); } static int parse_info(struct msg21xx_ts_data *ts_data) { unsigned char data[DEMO_MODE_PACKET_LENGTH] = {0}; unsigned char checksum = 0; unsigned int x = 0, y = 0; unsigned int x2 = 0, y2 = 0; unsigned int delta_x = 0, delta_y = 0; mutex_lock(&msg21xx_mutex); read_i2c_seq(ts_data, ts_data->client->addr, &data[0], DEMO_MODE_PACKET_LENGTH); mutex_unlock(&msg21xx_mutex); checksum = calculate_checksum(&data[0], (DEMO_MODE_PACKET_LENGTH-1)); dev_dbg(&ts_data->client->dev, "check sum: [%x] == [%x]?\n", data[DEMO_MODE_PACKET_LENGTH-1], checksum); if (data[DEMO_MODE_PACKET_LENGTH-1] != checksum) { dev_err(&ts_data->client->dev, "WRONG CHECKSUM\n"); return -EINVAL; } if (data[0] != 0x52) { dev_err(&ts_data->client->dev, "WRONG HEADER\n"); return -EINVAL; } ts_data->info.keycode = 0xFF; if ((data[1] == 0xFF) && (data[2] == 0xFF) && (data[3] == 0xFF) && (data[4] == 0xFF) && (data[6] == 0xFF)) { if ((data[5] == 0xFF) || (data[5] == 0)) { ts_data->info.keycode = 0xFF; } else if ((data[5] == 1) || (data[5] == 2) || (data[5] == 4) || (data[5] == 8)) { ts_data->info.keycode = data[5] >> 1; dev_dbg(&ts_data->client->dev, "ts_data->info.keycode index %d\n", ts_data->info.keycode); } #ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR else if (bEnableTpProximity && ((data[5] == 0x80) || (data[5] == 0x40))) { if (data[5] == 0x80) bFaceClosingTp = 1; else if (data[5] == 0x40) bFaceClosingTp = 0; return -EINVAL; } #endif else { dev_err(&ts_data->client->dev, "WRONG KEY\n"); return -EINVAL; } } else { x = (((data[1] & 0xF0) << 4) | data[2]); y = (((data[1] & 0x0F) << 8) | data[3]); delta_x = (((data[4] & 0xF0) << 4) | data[5]); delta_y = (((data[4] & 0x0F) << 8) | data[6]); if ((delta_x == 0) && (delta_y == 0)) { ts_data->info.point[0].x = x * ts_data->pdata->x_max / TPD_WIDTH; ts_data->info.point[0].y = y * ts_data->pdata->y_max / TPD_HEIGHT; ts_data->info.count = 1; } else { if (delta_x > 2048) delta_x -= 4096; if (delta_y > 2048) delta_y -= 4096; x2 = (unsigned int)((signed short)x + (signed short)delta_x); y2 = (unsigned int)((signed short)y + (signed short)delta_y); ts_data->info.point[0].x = x * ts_data->pdata->x_max / TPD_WIDTH; ts_data->info.point[0].y = y * ts_data->pdata->y_max / TPD_HEIGHT; ts_data->info.point[1].x = x2 * ts_data->pdata->x_max / TPD_WIDTH; ts_data->info.point[1].y = y2 * ts_data->pdata->y_max / TPD_HEIGHT; ts_data->info.count = ts_data->pdata->num_max_touches; } } return 0; } static void touch_driver_touch_released(struct msg21xx_ts_data *ts_data) { int i; for (i = 0; i < ts_data->pdata->num_max_touches; i++) { input_mt_slot(ts_data->input_dev, i); input_mt_report_slot_state(ts_data->input_dev, MT_TOOL_FINGER, 0); } input_report_key(ts_data->input_dev, BTN_TOUCH, 0); input_report_key(ts_data->input_dev, BTN_TOOL_FINGER, 0); input_sync(ts_data->input_dev); } /* read data through I2C then report data to input sub-system when interrupt occurred */ static irqreturn_t msg21xx_ts_interrupt(int irq, void *dev_id) { int i = 0; static int last_keycode = 0xFF; static int last_count; struct msg21xx_ts_data *ts_data = dev_id; ts_data->info.count = 0; if (0 == parse_info(ts_data)) { if (ts_data->info.keycode != 0xFF) { /* key touch pressed */ if (ts_data->info.keycode < ts_data->pdata->num_buttons) { if (ts_data->info.keycode != last_keycode) { dev_dbg(&ts_data->client->dev, "key touch pressed"); input_report_key(ts_data->input_dev, BTN_TOUCH, 1); input_report_key(ts_data->input_dev, ts_data->pdata->button_map[ ts_data->info.keycode], 1); last_keycode = ts_data->info.keycode; } else { /* pass duplicate key-pressing */ dev_dbg(&ts_data->client->dev, "REPEATED KEY\n"); } } else { dev_dbg(&ts_data->client->dev, "WRONG KEY\n"); } } else { /* key touch released */ if (last_keycode != 0xFF) { dev_dbg(&ts_data->client->dev, "key touch released"); input_report_key(ts_data->input_dev, BTN_TOUCH, 0); input_report_key(ts_data->input_dev, ts_data->pdata->button_map[last_keycode], 0); last_keycode = 0xFF; } } if (ts_data->info.count > 0) { /* point touch pressed */ for (i = 0; i < ts_data->info.count; i++) { input_mt_slot(ts_data->input_dev, i); input_mt_report_slot_state(ts_data->input_dev, MT_TOOL_FINGER, 1); input_report_abs(ts_data->input_dev, ABS_MT_TOUCH_MAJOR, 1); input_report_abs(ts_data->input_dev, ABS_MT_POSITION_X, ts_data->info.point[i].x); input_report_abs(ts_data->input_dev, ABS_MT_POSITION_Y, ts_data->info.point[i].y); } } if (last_count > ts_data->info.count) { for (i = ts_data->info.count; i < ts_data->pdata->num_max_touches; i++) { input_mt_slot(ts_data->input_dev, i); input_mt_report_slot_state(ts_data->input_dev, MT_TOOL_FINGER, 0); } } last_count = ts_data->info.count; input_report_key(ts_data->input_dev, BTN_TOUCH, ts_data->info.count > 0); input_report_key(ts_data->input_dev, BTN_TOOL_FINGER, ts_data->info.count > 0); input_sync(ts_data->input_dev); } return IRQ_HANDLED; } static int msg21xx_ts_power_init(struct msg21xx_ts_data *ts_data, bool init) { int rc; if (init) { ts_data->vdd = regulator_get(&ts_data->client->dev, "vdd"); if (IS_ERR(ts_data->vdd)) { rc = PTR_ERR(ts_data->vdd); dev_err(&ts_data->client->dev, "Regulator get failed vdd rc=%d\n", rc); return rc; } if (regulator_count_voltages(ts_data->vdd) > 0) { rc = regulator_set_voltage(ts_data->vdd, MSTAR_VTG_MIN_UV, MSTAR_VTG_MAX_UV); if (rc) { dev_err(&ts_data->client->dev, "Regulator set_vtg failed vdd rc=%d\n", rc); goto reg_vdd_put; } } ts_data->vcc_i2c = regulator_get(&ts_data->client->dev, "vcc_i2c"); if (IS_ERR(ts_data->vcc_i2c)) { rc = PTR_ERR(ts_data->vcc_i2c); dev_err(&ts_data->client->dev, "Regulator get failed vcc_i2c rc=%d\n", rc); goto reg_vdd_set_vtg; } if (regulator_count_voltages(ts_data->vcc_i2c) > 0) { rc = regulator_set_voltage(ts_data->vcc_i2c, MSTAR_I2C_VTG_MIN_UV, MSTAR_I2C_VTG_MAX_UV); if (rc) { dev_err(&ts_data->client->dev, "Regulator set_vtg failed vcc_i2c rc=%d\n", rc); goto reg_vcc_i2c_put; } } } else { if (regulator_count_voltages(ts_data->vdd) > 0) regulator_set_voltage(ts_data->vdd, 0, MSTAR_VTG_MAX_UV); regulator_put(ts_data->vdd); if (regulator_count_voltages(ts_data->vcc_i2c) > 0) regulator_set_voltage(ts_data->vcc_i2c, 0, MSTAR_I2C_VTG_MAX_UV); regulator_put(ts_data->vcc_i2c); } return 0; reg_vcc_i2c_put: regulator_put(ts_data->vcc_i2c); reg_vdd_set_vtg: if (regulator_count_voltages(ts_data->vdd) > 0) regulator_set_voltage(ts_data->vdd, 0, MSTAR_VTG_MAX_UV); reg_vdd_put: regulator_put(ts_data->vdd); return rc; } static int msg21xx_ts_power_on(struct msg21xx_ts_data *ts_data, bool on) { int rc; if (!on) goto power_off; rc = regulator_enable(ts_data->vdd); if (rc) { dev_err(&ts_data->client->dev, "Regulator vdd enable failed rc=%d\n", rc); return rc; } rc = regulator_enable(ts_data->vcc_i2c); if (rc) { dev_err(&ts_data->client->dev, "Regulator vcc_i2c enable failed rc=%d\n", rc); regulator_disable(ts_data->vdd); } return rc; power_off: rc = regulator_disable(ts_data->vdd); if (rc) { dev_err(&ts_data->client->dev, "Regulator vdd disable failed rc=%d\n", rc); return rc; } rc = regulator_disable(ts_data->vcc_i2c); if (rc) { dev_err(&ts_data->client->dev, "Regulator vcc_i2c disable failed rc=%d\n", rc); rc = regulator_enable(ts_data->vdd); } return rc; } static int msg21xx_ts_gpio_configure(struct msg21xx_ts_data *ts_data, bool on) { int ret = 0; if (!on) goto pwr_deinit; if (gpio_is_valid(ts_data->pdata->irq_gpio)) { ret = gpio_request(ts_data->pdata->irq_gpio, "msg21xx_irq_gpio"); if (ret) { dev_err(&ts_data->client->dev, "Failed to request GPIO[%d], %d\n", ts_data->pdata->irq_gpio, ret); goto err_irq_gpio_req; } ret = gpio_direction_input(ts_data->pdata->irq_gpio); if (ret) { dev_err(&ts_data->client->dev, "Failed to set direction for gpio[%d], %d\n", ts_data->pdata->irq_gpio, ret); goto err_irq_gpio_dir; } gpio_set_value_cansleep(ts_data->pdata->irq_gpio, 1); } else { dev_err(&ts_data->client->dev, "irq gpio not provided\n"); goto err_irq_gpio_req; } if (gpio_is_valid(ts_data->pdata->reset_gpio)) { ret = gpio_request(ts_data->pdata->reset_gpio, "msg21xx_reset_gpio"); if (ret) { dev_err(&ts_data->client->dev, "Failed to request GPIO[%d], %d\n", ts_data->pdata->reset_gpio, ret); goto err_reset_gpio_req; } /* power on TP */ ret = gpio_direction_output( ts_data->pdata->reset_gpio, 1); if (ret) { dev_err(&ts_data->client->dev, "Failed to set direction for GPIO[%d], %d\n", ts_data->pdata->reset_gpio, ret); goto err_reset_gpio_dir; } msleep(100); gpio_set_value_cansleep(ts_data->pdata->reset_gpio, 0); msleep(20); gpio_set_value_cansleep(ts_data->pdata->reset_gpio, 1); msleep(200); } else { dev_err(&ts_data->client->dev, "reset gpio not provided\n"); goto err_reset_gpio_req; } return 0; err_reset_gpio_dir: if (gpio_is_valid(ts_data->pdata->reset_gpio)) gpio_free(ts_data->pdata->irq_gpio); err_reset_gpio_req: err_irq_gpio_dir: if (gpio_is_valid(ts_data->pdata->irq_gpio)) gpio_free(ts_data->pdata->irq_gpio); err_irq_gpio_req: return ret; pwr_deinit: if (gpio_is_valid(ts_data->pdata->irq_gpio)) gpio_free(ts_data->pdata->irq_gpio); if (gpio_is_valid(ts_data->pdata->reset_gpio)) { gpio_set_value_cansleep(ts_data->pdata->reset_gpio, 0); ret = gpio_direction_input(ts_data->pdata->reset_gpio); if (ret) dev_err(&ts_data->client->dev, "Unable to set direction for gpio [%d]\n", ts_data->pdata->reset_gpio); gpio_free(ts_data->pdata->reset_gpio); } return 0; } #ifdef CONFIG_PM static int msg21xx_ts_resume(struct device *dev) { int retval; struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev); if (!ts_data->suspended) { dev_info(dev, "msg21xx_ts already in resume\n"); return 0; } mutex_lock(&ts_data->ts_mutex); retval = msg21xx_ts_power_on(ts_data, true); if (retval) { dev_err(dev, "msg21xx_ts power on failed"); mutex_unlock(&ts_data->ts_mutex); return retval; } if (ts_data->ts_pinctrl) { retval = pinctrl_select_state(ts_data->ts_pinctrl, ts_data->pinctrl_state_active); if (retval < 0) { dev_err(dev, "Cannot get active pinctrl state\n"); mutex_unlock(&ts_data->ts_mutex); return retval; } } retval = msg21xx_ts_gpio_configure(ts_data, true); if (retval) { dev_err(dev, "Failed to put gpios in active state %d", retval); mutex_unlock(&ts_data->ts_mutex); return retval; } enable_irq(ts_data->client->irq); ts_data->suspended = false; mutex_unlock(&ts_data->ts_mutex); return 0; } static int msg21xx_ts_suspend(struct device *dev) { int retval; struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev); if (ts_data->pdata->updating_fw) { dev_info(dev, "Firmware loading in progress\n"); return 0; } if (ts_data->suspended) { dev_info(dev, "msg21xx_ts already in suspend\n"); return 0; } #ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR if (bEnableTpProximity) { dev_dbg(dev, "suspend bEnableTpProximity=%d\n", bEnableTpProximity); return 0; } #endif mutex_lock(&ts_data->ts_mutex); disable_irq(ts_data->client->irq); touch_driver_touch_released(ts_data); if (ts_data->ts_pinctrl) { retval = pinctrl_select_state(ts_data->ts_pinctrl, ts_data->pinctrl_state_suspend); if (retval < 0) { dev_err(dev, "Cannot get idle pinctrl state %d\n", retval); mutex_unlock(&ts_data->ts_mutex); return retval; } } retval = msg21xx_ts_gpio_configure(ts_data, false); if (retval) { dev_err(dev, "Failed to put gpios in idle state %d", retval); mutex_unlock(&ts_data->ts_mutex); return retval; } retval = msg21xx_ts_power_on(ts_data, false); if (retval) { dev_err(dev, "msg21xx_ts power off failed"); mutex_unlock(&ts_data->ts_mutex); return retval; } ts_data->suspended = true; mutex_unlock(&ts_data->ts_mutex); return 0; } #else static int msg21xx_ts_resume(struct device *dev) { return 0; } static int msg21xx_ts_suspend(struct device *dev) { return 0; } #endif static int msg21xx_debug_suspend_set(void *_data, u64 val) { struct msg21xx_ts_data *data = _data; mutex_lock(&data->input_dev->mutex); if (val) msg21xx_ts_suspend(&data->client->dev); else msg21xx_ts_resume(&data->client->dev); mutex_unlock(&data->input_dev->mutex); return 0; } static int msg21xx_debug_suspend_get(void *_data, u64 *val) { struct msg21xx_ts_data *data = _data; mutex_lock(&data->input_dev->mutex); *val = data->suspended; mutex_unlock(&data->input_dev->mutex); return 0; } DEFINE_SIMPLE_ATTRIBUTE(debug_suspend_fops, msg21xx_debug_suspend_get, msg21xx_debug_suspend_set, "%lld\n"); #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 msg21xx_ts_data *ts_data = container_of(self, struct msg21xx_ts_data, fb_notif); if (evdata && evdata->data && event == FB_EVENT_BLANK) { blank = evdata->data; if (*blank == FB_BLANK_UNBLANK) msg21xx_ts_resume(&ts_data->client->dev); else if (*blank == FB_BLANK_POWERDOWN) msg21xx_ts_suspend(&ts_data->client->dev); } return 0; } #endif static int msg21xx_get_dt_coords(struct device *dev, char *name, struct msg21xx_ts_platform_data *pdata) { u32 coords[FT_COORDS_ARR_SIZE]; struct property *prop; struct device_node *np = dev->of_node; int coords_size, rc; prop = of_find_property(np, name, NULL); if (!prop) return -EINVAL; if (!prop->value) return -ENODATA; coords_size = prop->length / sizeof(u32); if (coords_size != FT_COORDS_ARR_SIZE) { dev_err(dev, "invalid %s\n", name); return -EINVAL; } rc = of_property_read_u32_array(np, name, coords, coords_size); if (rc && (rc != -EINVAL)) { dev_err(dev, "Unable to read %s\n", name); return rc; } if (!strcmp(name, "mstar,panel-coords")) { pdata->panel_minx = coords[0]; pdata->panel_miny = coords[1]; pdata->panel_maxx = coords[2]; pdata->panel_maxy = coords[3]; } else if (!strcmp(name, "mstar,display-coords")) { pdata->x_min = coords[0]; pdata->y_min = coords[1]; pdata->x_max = coords[2]; pdata->y_max = coords[3]; } else { dev_err(dev, "unsupported property %s\n", name); return -EINVAL; } return 0; } static int msg21xx_parse_dt(struct device *dev, struct msg21xx_ts_platform_data *pdata) { int rc; struct device_node *np = dev->of_node; struct property *prop; u32 temp_val; rc = msg21xx_get_dt_coords(dev, "mstar,panel-coords", pdata); if (rc && (rc != -EINVAL)) return rc; rc = msg21xx_get_dt_coords(dev, "mstar,display-coords", pdata); if (rc) return rc; rc = of_property_read_u32(np, "mstar,hard-reset-delay-ms", &temp_val); if (!rc) pdata->hard_reset_delay_ms = temp_val; else return rc; rc = of_property_read_u32(np, "mstar,post-hard-reset-delay-ms", &temp_val); if (!rc) pdata->post_hard_reset_delay_ms = temp_val; else return rc; /* reset, irq gpio info */ pdata->reset_gpio = of_get_named_gpio_flags(np, "mstar,reset-gpio", 0, &pdata->reset_gpio_flags); if (pdata->reset_gpio < 0) return pdata->reset_gpio; pdata->irq_gpio = of_get_named_gpio_flags(np, "mstar,irq-gpio", 0, &pdata->irq_gpio_flags); if (pdata->irq_gpio < 0) return pdata->irq_gpio; rc = of_property_read_u32(np, "mstar,ic-type", &temp_val); if (rc && (rc != -EINVAL)) return rc; pdata->ic_type = temp_val; rc = of_property_read_u32(np, "mstar,num-max-touches", &temp_val); if (!rc) pdata->num_max_touches = temp_val; else return rc; prop = of_find_property(np, "mstar,button-map", NULL); if (prop) { pdata->num_buttons = prop->length / sizeof(temp_val); if (pdata->num_buttons > MAX_BUTTONS) return -EINVAL; rc = of_property_read_u32_array(np, "mstar,button-map", pdata->button_map, pdata->num_buttons); if (rc) { dev_err(dev, "Unable to read key codes\n"); return rc; } } return 0; } /* probe function is used for matching and initializing input device */ static int msg21xx_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret = 0, i; struct dentry *temp, *dir; struct input_dev *input_dev; struct msg21xx_ts_data *ts_data; struct msg21xx_ts_platform_data *pdata; if (client->dev.of_node) { pdata = devm_kzalloc(&client->dev, sizeof(struct msg21xx_ts_platform_data), GFP_KERNEL); if (!pdata) return -ENOMEM; ret = msg21xx_parse_dt(&client->dev, pdata); if (ret) { dev_err(&client->dev, "DT parsing failed\n"); return ret; } } else pdata = client->dev.platform_data; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "I2C not supported\n"); return -ENODEV; } ts_data = devm_kzalloc(&client->dev, sizeof(struct msg21xx_ts_data), GFP_KERNEL); if (!ts_data) return -ENOMEM; ts_data->client = client; ts_data->info.point = devm_kzalloc(&client->dev, sizeof(struct touchPoint_t) * pdata->num_max_touches, GFP_KERNEL); if (!ts_data->info.point) { dev_err(&client->dev, "Not enough memory\n"); return -ENOMEM; } /* allocate an input device */ input_dev = input_allocate_device(); if (!input_dev) { ret = -ENOMEM; dev_err(&client->dev, "input device allocation failed\n"); goto err_input_allocate_dev; } input_dev->name = client->name; input_dev->phys = "I2C"; input_dev->dev.parent = &client->dev; input_dev->id.bustype = BUS_I2C; ts_data->input_dev = input_dev; ts_data->client = client; ts_data->pdata = pdata; input_set_drvdata(input_dev, ts_data); i2c_set_clientdata(client, ts_data); ret = msg21xx_ts_power_init(ts_data, true); if (ret) { dev_err(&client->dev, "Mstar power init failed\n"); return ret; } ret = msg21xx_ts_power_on(ts_data, true); if (ret) { dev_err(&client->dev, "Mstar power on failed\n"); goto exit_deinit_power; } ret = msg21xx_pinctrl_init(ts_data); if (!ret && ts_data->ts_pinctrl) { /* * Pinctrl handle is optional. If pinctrl handle is found * let pins to be configured in active state. If not * found continue further without error. */ ret = pinctrl_select_state(ts_data->ts_pinctrl, ts_data->pinctrl_state_active); if (ret < 0) dev_err(&client->dev, "Failed to select %s pinatate %d\n", PINCTRL_STATE_ACTIVE, ret); } ret = msg21xx_ts_gpio_configure(ts_data, true); if (ret) { dev_err(&client->dev, "Failed to configure gpio %d\n", ret); goto exit_gpio_config; } if (msg21xx_get_ic_type(ts_data) == 0) { dev_err(&client->dev, "The current IC is not Mstar\n"); ret = -1; goto err_wrong_ic_type; } mutex_init(&msg21xx_mutex); mutex_init(&ts_data->ts_mutex); /* set the supported event type for input device */ set_bit(EV_ABS, input_dev->evbit); set_bit(EV_SYN, input_dev->evbit); set_bit(EV_KEY, input_dev->evbit); set_bit(BTN_TOUCH, input_dev->keybit); set_bit(BTN_TOOL_FINGER, input_dev->keybit); set_bit(INPUT_PROP_DIRECT, input_dev->propbit); for (i = 0; i < pdata->num_buttons; i++) input_set_capability(input_dev, EV_KEY, pdata->button_map[i]); input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 2, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0); ret = input_mt_init_slots(input_dev, pdata->num_max_touches, 0); if (ret) { dev_err(&client->dev, "Error %d initialising slots\n", ret); goto err_free_mem; } /* register the input device to input sub-system */ ret = input_register_device(input_dev); if (ret < 0) { dev_err(&client->dev, "Unable to register ms-touchscreen input device\n"); goto err_input_reg_dev; } /* version */ if (device_create_file(&client->dev, &dev_attr_version) < 0) { dev_err(&client->dev, "Failed to create device file(%s)!\n", dev_attr_version.attr.name); goto err_create_fw_ver_file; } /* update */ if (device_create_file(&client->dev, &dev_attr_update) < 0) { dev_err(&client->dev, "Failed to create device file(%s)!\n", dev_attr_update.attr.name); goto err_create_fw_update_file; } /* data */ if (device_create_file(&client->dev, &dev_attr_data) < 0) { dev_err(&client->dev, "Failed to create device file(%s)!\n", dev_attr_data.attr.name); goto err_create_fw_data_file; } /* fw name */ if (device_create_file(&client->dev, &dev_attr_fw_name) < 0) { dev_err(&client->dev, "Failed to create device file(%s)!\n", dev_attr_fw_name.attr.name); goto err_create_fw_name_file; } /* smart fw update */ if (device_create_file(&client->dev, &dev_attr_update_fw) < 0) { dev_err(&client->dev, "Failed to create device file(%s)!\n", dev_attr_update_fw.attr.name); goto err_create_update_fw_file; } /* smart fw force update */ if (device_create_file(&client->dev, &dev_attr_force_update_fw) < 0) { dev_err(&client->dev, "Failed to create device file(%s)!\n", dev_attr_force_update_fw.attr.name); goto err_create_force_update_fw_file; } dir = debugfs_create_dir(MSTAR_DEBUG_DIR_NAME, NULL); temp = debugfs_create_file("suspend", S_IRUSR | S_IWUSR, dir, ts_data, &debug_suspend_fops); if (temp == NULL || IS_ERR(temp)) { dev_err(&client->dev, "debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp)); goto free_debug_dir; } #ifdef TP_PRINT tp_print_create_entry(ts_data); #endif ret = request_threaded_irq(client->irq, NULL, msg21xx_ts_interrupt, pdata->irq_gpio_flags | IRQF_ONESHOT, "msg21xx", ts_data); if (ret) goto err_req_irq; disable_irq(client->irq); #if defined(CONFIG_FB) ts_data->fb_notif.notifier_call = fb_notifier_callback; ret = fb_register_client(&ts_data->fb_notif); #endif #ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR tsps_assist_register_callback("msg21xx", &tsps_msg21xx_enable, &tsps_msg21xx_data); #endif dev_dbg(&client->dev, "mstar touch screen registered\n"); enable_irq(client->irq); return 0; err_req_irq: free_irq(client->irq, ts_data); device_remove_file(&client->dev, &dev_attr_data); free_debug_dir: debugfs_remove_recursive(dir); err_create_fw_data_file: device_remove_file(&client->dev, &dev_attr_update); err_create_fw_update_file: device_remove_file(&client->dev, &dev_attr_version); err_create_fw_name_file: device_remove_file(&client->dev, &dev_attr_fw_name); err_create_update_fw_file: device_remove_file(&client->dev, &dev_attr_update_fw); err_create_force_update_fw_file: device_remove_file(&client->dev, &dev_attr_force_update_fw); err_create_fw_ver_file: input_unregister_device(input_dev); err_input_reg_dev: input_free_device(input_dev); input_dev = NULL; err_input_allocate_dev: mutex_destroy(&msg21xx_mutex); mutex_destroy(&ts_data->ts_mutex); err_wrong_ic_type: msg21xx_ts_gpio_configure(ts_data, false); exit_gpio_config: if (ts_data->ts_pinctrl) { if (IS_ERR_OR_NULL(ts_data->pinctrl_state_release)) { devm_pinctrl_put(ts_data->ts_pinctrl); ts_data->ts_pinctrl = NULL; } else { ret = pinctrl_select_state(ts_data->ts_pinctrl, ts_data->pinctrl_state_release); if (ret < 0) dev_err(&ts_data->client->dev, "Cannot get release pinctrl state\n"); } } msg21xx_ts_power_on(ts_data, false); exit_deinit_power: msg21xx_ts_power_init(ts_data, false); err_free_mem: input_free_device(input_dev); return ret; } /* remove function is triggered when the input device is removed from input sub-system */ static int touch_driver_remove(struct i2c_client *client) { int retval = 0; struct msg21xx_ts_data *ts_data = i2c_get_clientdata(client); free_irq(ts_data->client->irq, ts_data); gpio_free(ts_data->pdata->irq_gpio); gpio_free(ts_data->pdata->reset_gpio); if (ts_data->ts_pinctrl) { if (IS_ERR_OR_NULL(ts_data->pinctrl_state_release)) { devm_pinctrl_put(ts_data->ts_pinctrl); ts_data->ts_pinctrl = NULL; } else { retval = pinctrl_select_state(ts_data->ts_pinctrl, ts_data->pinctrl_state_release); if (retval < 0) dev_err(&ts_data->client->dev, "Cannot get release pinctrl state\n"); } } input_unregister_device(ts_data->input_dev); mutex_destroy(&msg21xx_mutex); mutex_destroy(&ts_data->ts_mutex); return retval; } /* The I2C device list is used for matching I2C device and I2C device driver. */ static const struct i2c_device_id touch_device_id[] = { {"msg21xx", 0}, {}, /* should not omitted */ }; static struct of_device_id msg21xx_match_table[] = { { .compatible = "mstar,msg21xx", }, { }, }; MODULE_DEVICE_TABLE(i2c, touch_device_id); static struct i2c_driver touch_device_driver = { .driver = { .name = "ms-msg21xx", .owner = THIS_MODULE, .of_match_table = msg21xx_match_table, }, .probe = msg21xx_ts_probe, .remove = touch_driver_remove, .id_table = touch_device_id, }; module_i2c_driver(touch_device_driver); #ifdef TP_PRINT #include static unsigned short InfoAddr = 0x0F, PoolAddr = 0x10, TransLen = 256; static unsigned char row, units, cnt; static int tp_print_proc_read(struct msg21xx_ts_data *ts_data) { unsigned short i, j; unsigned short left, offset = 0; unsigned char dbbus_tx_data[3] = {0}; unsigned char u8Data; signed short s16Data; int s32Data; char *buf = NULL; left = cnt*row*units; if ((ts_data->suspended == 0) && (InfoAddr != 0x0F) && (PoolAddr != 0x10) && (left > 0)) { buf = kmalloc(left, GFP_KERNEL); if (buf != NULL) { while (left > 0) { dbbus_tx_data[0] = 0x53; dbbus_tx_data[1] = ((PoolAddr + offset) >> 8) & 0xFF; dbbus_tx_data[2] = (PoolAddr + offset) & 0xFF; mutex_lock(&msg21xx_mutex); write_i2c_seq(ts_data, ts_data->client->addr, &dbbus_tx_data[0], 3); read_i2c_seq(ts_data, ts_data->client->addr, &buf[offset], left > TransLen ? TransLen : left); mutex_unlock(&msg21xx_mutex); if (left > TransLen) { left -= TransLen; offset += TransLen; } else { left = 0; } } for (i = 0; i < cnt; i++) { for (j = 0; j < row; j++) { if (units == 1) { u8Data = buf[i * row * units + j * units]; } else if (units == 2) { s16Data = buf[i * row * units + j * units] + (buf[i * row * units + j * units + 1] << 8); } else if (units == 4) { s32Data = buf[i * row * units + j * units] + (buf[i * row * units + j * units + 1] << 8) + (buf[i * row * units + j * units + 2] << 16) + (buf[i * row * units + j * units + 3] << 24); } } } kfree(buf); } } return 0; } static void tp_print_create_entry(struct msg21xx_ts_data *ts_data) { unsigned char dbbus_tx_data[3] = {0}; unsigned char dbbus_rx_data[8] = {0}; dbbus_tx_data[0] = 0x53; dbbus_tx_data[1] = 0x00; dbbus_tx_data[2] = 0x58; mutex_lock(&msg21xx_mutex); write_i2c_seq(ts_data, ts_data->client->addr, &dbbus_tx_data[0], 3); read_i2c_seq(ts_data, ts_data->client->addr, &dbbus_rx_data[0], 4); mutex_unlock(&msg21xx_mutex); InfoAddr = (dbbus_rx_data[1]<<8) + dbbus_rx_data[0]; PoolAddr = (dbbus_rx_data[3]<<8) + dbbus_rx_data[2]; if ((InfoAddr != 0x0F) && (PoolAddr != 0x10)) { msleep(20); dbbus_tx_data[0] = 0x53; dbbus_tx_data[1] = (InfoAddr >> 8) & 0xFF; dbbus_tx_data[2] = InfoAddr & 0xFF; mutex_lock(&msg21xx_mutex); write_i2c_seq(ts_data, ts_data->client->addr, &dbbus_tx_data[0], 3); read_i2c_seq(ts_data, ts_data->client->addr, &dbbus_rx_data[0], 8); mutex_unlock(&msg21xx_mutex); units = dbbus_rx_data[0]; row = dbbus_rx_data[1]; cnt = dbbus_rx_data[2]; TransLen = (dbbus_rx_data[7]<<8) + dbbus_rx_data[6]; if (device_create_file(&ts_data->client->dev, &dev_attr_tpp) < 0) dev_err(&ts_data->client->dev, "Failed to create device file(%s)!\n", dev_attr_tpp.attr.name); } } #endif MODULE_AUTHOR("MStar Semiconductor, Inc."); MODULE_LICENSE("GPL v2");