diff --git a/kernel/drivers/input/touchscreen/synaptics_fw_update.c b/kernel/drivers/input/touchscreen/synaptics_fw_update.c index 4867d1f73c4d..8b6d7c7e368d 100644 --- a/kernel/drivers/input/touchscreen/synaptics_fw_update.c +++ b/kernel/drivers/input/touchscreen/synaptics_fw_update.c @@ -30,7 +30,10 @@ #define DEBUG_FW_UPDATE #define SHOW_PROGRESS -#define FW_IMAGE_NAME "PR12345678.img" +#define FW_IMAGE_NAME "PR1063486-s7301_00000000.img" +#define MAX_FIRMWARE_ID_LEN 10 +#define FORCE_UPDATE false +#define INSIDE_FIRMWARE_UPDATE #define CHECKSUM_OFFSET 0x00 #define BOOTLOADER_VERSION_OFFSET 0x07 @@ -73,6 +76,12 @@ enum flash_command { CMD_ENABLE_FLASH_PROG = 0xF, }; +enum flash_area { + NONE, + UI_FIRMWARE, + CONFIG_AREA +}; + #define SLEEP_MODE_NORMAL (0x00) #define SLEEP_MODE_SENSOR_SLEEP (0x01) #define SLEEP_MODE_RESERVED0 (0x02) @@ -81,9 +90,9 @@ enum flash_command { #define ENABLE_WAIT_MS (1 * 1000) #define WRITE_WAIT_MS (3 * 1000) #define ERASE_WAIT_MS (5 * 1000) +#define RESET_WAIT_MS (500) -#define MIN_SLEEP_TIME_US 50 -#define MAX_SLEEP_TIME_US 100 +#define SLEEP_TIME_US 50 static ssize_t fwu_sysfs_show_image(struct file *data_file, struct kobject *kobj, struct bin_attribute *attributes, @@ -204,6 +213,7 @@ struct f34_flash_properties { struct synaptics_rmi4_fwu_handle { bool initialized; + bool force_update; char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1]; unsigned int image_size; unsigned int data_pos; @@ -231,6 +241,8 @@ struct synaptics_rmi4_fwu_handle { struct synaptics_rmi4_data *rmi4_data; struct f34_flash_control flash_control; struct f34_flash_properties flash_properties; + struct workqueue_struct *fwu_workqueue; + struct delayed_work fwu_work; }; static struct bin_attribute dev_attr_data = { @@ -313,53 +325,6 @@ static void parse_header(struct image_header *header, return; } -static int fwu_check_version(void) -{ - int retval; - unsigned char firmware_id[4]; - unsigned char config_id[4]; - struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client; - - /* device firmware id */ - retval = fwu->fn_ptr->read(fwu->rmi4_data, - fwu->f01_fd.query_base_addr + 18, - firmware_id, - sizeof(firmware_id)); - if (retval < 0) { - dev_err(&i2c_client->dev, - "Failed to read firmware ID (code %d).\n", retval); - return retval; - } - firmware_id[3] = 0; - - dev_info(&i2c_client->dev, "Device firmware ID%d\n", - extract_uint(firmware_id)); - - /* device config id */ - retval = fwu->fn_ptr->read(fwu->rmi4_data, - fwu->f34_fd.ctrl_base_addr, - config_id, - sizeof(config_id)); - if (retval < 0) { - dev_err(&i2c_client->dev, - "Failed to read config ID (code %d).\n", retval); - return retval; - } - - dev_info(&i2c_client->dev, - "Device config ID 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", - config_id[0], config_id[1], config_id[2], config_id[3]); - - /* .img config id */ - dev_info(&i2c_client->dev, - ".img config ID 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", - fwu->config_data[0], - fwu->config_data[1], - fwu->config_data[2], - fwu->config_data[3]); - return 0; -} - static int fwu_read_f01_device_status(struct f01_device_status *status) { int retval; @@ -407,7 +372,7 @@ static int fwu_read_f34_queries(void) return retval; } - dev_info(&i2c_client->dev, "%s perm:%d, bl%d, display:%d\n", + dev_info(&i2c_client->dev, "%s perm:%d, bl:%d, display:%d\n", __func__, fwu->flash_properties.has_perm_config, fwu->flash_properties.has_bl_config, @@ -506,25 +471,13 @@ static int fwu_read_f34_flash_status(void) static int fwu_reset_device(void) { int retval; - unsigned char reset = 0x01; #ifdef DEBUG_FW_UPDATE - dev_info(&fwu->rmi4_data->i2c_client->dev, "Reset device\n"); + dev_info(&fwu->rmi4_data->i2c_client->dev, + "%s: Reset device\n", + __func__); #endif - retval = fwu->fn_ptr->write(fwu->rmi4_data, - fwu->f01_fd.cmd_base_addr, - &reset, - sizeof(reset)); - if (retval < 0) { - dev_err(&fwu->rmi4_data->i2c_client->dev, - "%s: Failed to reset device (addr : 0x%02x)\n", - __func__, fwu->f01_fd.cmd_base_addr); - return retval; - } - - fwu_wait_for_idle(WRITE_WAIT_MS); - retval = fwu->rmi4_data->reset_device(fwu->rmi4_data); if (retval < 0) { dev_err(&fwu->rmi4_data->i2c_client->dev, @@ -539,37 +492,34 @@ static int fwu_write_f34_command(unsigned char cmd) { int retval; + fwu->flash_control.data[0] = cmd; retval = fwu->fn_ptr->write(fwu->rmi4_data, fwu->addr_f34_flash_control, - &cmd, - sizeof(cmd)); + fwu->flash_control.data, + sizeof(fwu->flash_control.data)); if (retval < 0) { dev_err(&fwu->rmi4_data->i2c_client->dev, "%s: Failed to write command 0x%02x\n", - __func__, cmd); + __func__, fwu->flash_control.data[0]); return retval; } return 0; } -static unsigned char fwu_check_flash_status(void) -{ - fwu_read_f34_flash_status(); - return fwu->flash_control.status; -} - static int fwu_wait_for_idle(int timeout_ms) { int count = 0; - int timeout_count = ((timeout_ms * 1000) / MAX_SLEEP_TIME_US) + 1; - + int timeout_count = ((timeout_ms * 1000) / SLEEP_TIME_US) + 1; do { - if (fwu_read_interrupt_status() > 0) + if (fwu->flash_control.command == 0x00) return 0; - usleep_range(MIN_SLEEP_TIME_US, MAX_SLEEP_TIME_US); - count++; - } while (count < timeout_count); + usleep_range(SLEEP_TIME_US, SLEEP_TIME_US + 100); + } while (count++ < timeout_count); + + fwu_read_f34_flash_status(); + if (fwu->flash_control.command == 0x00) + return 0; dev_err(&fwu->rmi4_data->i2c_client->dev, "%s: Timed out waiting for idle status\n", @@ -578,6 +528,133 @@ static int fwu_wait_for_idle(int timeout_ms) return -ETIMEDOUT; } +static enum flash_area fwu_go_nogo(void) +{ + int retval = 0; + int index = 0; + int deviceFirmwareID; + int imageConfigID; + int deviceConfigID; + unsigned long imageFirmwareID; + unsigned char firmware_id[4]; + unsigned char config_id[4]; + char *strptr; + char *imagePR = kzalloc(sizeof(MAX_FIRMWARE_ID_LEN), GFP_KERNEL); + enum flash_area flash_area = NONE; + struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client; + struct f01_device_status f01_device_status; + + if (fwu->force_update) { + flash_area = UI_FIRMWARE; + goto exit; + } + + retval = fwu_read_f01_device_status(&f01_device_status); + if (retval < 0) { + flash_area = NONE; + goto exit; + } + + imagePR = kzalloc(sizeof(MAX_FIRMWARE_ID_LEN), GFP_KERNEL); + + /* Force update firmware when device is in bootloader mode */ + if (f01_device_status.flash_prog) { + dev_info(&i2c_client->dev, + "%s: In flash prog mode\n", + __func__); + flash_area = UI_FIRMWARE; + goto exit; + } + + + /* device firmware id */ + retval = fwu->fn_ptr->read(fwu->rmi4_data, + fwu->f01_fd.query_base_addr + 18, + firmware_id, + sizeof(firmware_id)); + if (retval < 0) { + dev_err(&i2c_client->dev, + "Failed to read firmware ID (code %d).\n", retval); + goto exit; + } + firmware_id[3] = 0; + deviceFirmwareID = extract_uint(firmware_id); + + /* .img firmware id */ + strptr = strstr(FW_IMAGE_NAME, "PR"); + if (!strptr) { + dev_err(&i2c_client->dev, + "No valid PR number (PRxxxxxxx)" \ + "found in image file name...\n"); + goto exit; + } + + strptr += 2; + while (strptr[index] >= '0' && strptr[index] <= '9') { + imagePR[index] = strptr[index]; + index++; + } + imagePR[index] = 0; + + retval = sstrtoul(imagePR, 10, &imageFirmwareID); + if (retval == -EINVAL) { + dev_err(&i2c_client->dev, + "invalid image firmware id...\n"); + goto exit; + } + + dev_info(&i2c_client->dev, + "Device firmware id %d, .img firmware id %d\n", + deviceFirmwareID, + (unsigned int)imageFirmwareID); + if (imageFirmwareID > deviceFirmwareID) { + flash_area = UI_FIRMWARE; + goto exit; + } + + /* device config id */ + retval = fwu->fn_ptr->read(fwu->rmi4_data, + fwu->f34_fd.ctrl_base_addr, + config_id, + sizeof(config_id)); + if (retval < 0) { + dev_err(&i2c_client->dev, + "Failed to read config ID (code %d).\n", retval); + flash_area = NONE; + goto exit; + } + deviceConfigID = extract_uint(config_id); + + dev_info(&i2c_client->dev, + "Device config ID 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", + config_id[0], config_id[1], config_id[2], config_id[3]); + + /* .img config id */ + dev_info(&i2c_client->dev, + ".img config ID 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", + fwu->config_data[0], + fwu->config_data[1], + fwu->config_data[2], + fwu->config_data[3]); + imageConfigID = extract_uint(fwu->config_data); + + if (imageConfigID > deviceConfigID) { + flash_area = CONFIG_AREA; + goto exit; + } + +exit: + kfree(imagePR); + if (flash_area == NONE) + dev_info(&i2c_client->dev, + "Nothing needs to be updated\n"); + else + dev_info(&i2c_client->dev, + "Update %s block\n", + flash_area == UI_FIRMWARE ? "UI FW" : "CONFIG"); + return flash_area; +} + static int fwu_scan_pdt(void) { int retval; @@ -649,16 +726,25 @@ static int fwu_write_blocks(unsigned char *block_ptr, unsigned short block_cnt, int retval; unsigned char block_offset[] = {0, 0}; unsigned short block_num; + struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client; #ifdef SHOW_PROGRESS unsigned int progress = (command == CMD_WRITE_CONFIG_BLOCK) ? 10 : 100; #endif + +#ifdef DEBUG_FW_UPDATE + dev_info(&i2c_client->dev, + "%s: Start to update %s blocks\n", + __func__, + command == CMD_WRITE_CONFIG_BLOCK ? + "config" : "firmware"); +#endif retval = fwu->fn_ptr->write(fwu->rmi4_data, fwu->f34_fd.data_base_addr + BLOCK_NUMBER_OFFSET, block_offset, sizeof(block_offset)); if (retval < 0) { - dev_err(&fwu->rmi4_data->i2c_client->dev, + dev_err(&i2c_client->dev, "%s: Failed to write to block number registers\n", __func__); return retval; @@ -667,20 +753,19 @@ static int fwu_write_blocks(unsigned char *block_ptr, unsigned short block_cnt, for (block_num = 0; block_num < block_cnt; block_num++) { #ifdef SHOW_PROGRESS if (block_num % progress == 0) - dev_info(&fwu->rmi4_data->i2c_client->dev, - "%s: update %s %3d / %3d\n", - __func__, - command == CMD_WRITE_CONFIG_BLOCK ? - "config" : "firmware", - block_num, - block_cnt); + dev_info(&i2c_client->dev, + "%s: update %s %3d / %3d\n", + __func__, + command == CMD_WRITE_CONFIG_BLOCK ? + "config" : "firmware", + block_num, block_cnt); #endif retval = fwu->fn_ptr->write(fwu->rmi4_data, fwu->f34_fd.data_base_addr + BLOCK_DATA_OFFSET, block_ptr, fwu->block_size); if (retval < 0) { - dev_err(&fwu->rmi4_data->i2c_client->dev, + dev_err(&i2c_client->dev, "%s: Failed to write block data (block %d)\n", __func__, block_num); return retval; @@ -688,7 +773,7 @@ static int fwu_write_blocks(unsigned char *block_ptr, unsigned short block_cnt, retval = fwu_write_f34_command(command); if (retval < 0) { - dev_err(&fwu->rmi4_data->i2c_client->dev, + dev_err(&i2c_client->dev, "%s: Failed to write command for block %d\n", __func__, block_num); return retval; @@ -696,30 +781,28 @@ static int fwu_write_blocks(unsigned char *block_ptr, unsigned short block_cnt, retval = fwu_wait_for_idle(WRITE_WAIT_MS); if (retval < 0) { - dev_err(&fwu->rmi4_data->i2c_client->dev, - "%s: Failed to wait for idle status \ - (block %d)\n", - __func__, block_num); + dev_err(&i2c_client->dev, + "%s: Failed to wait for idle status (block %d)\n", + __func__, block_num); return retval; } - retval = fwu_check_flash_status(); - if (retval != 0) { - dev_err(&fwu->rmi4_data->i2c_client->dev, - "%s: Flash block %d status %d\n", + if (fwu->flash_control.status != 0x00) { + dev_err(&i2c_client->dev, + "%s: Flash block %d failed, status 0x%02X\n", __func__, block_num, retval); return -1; } + block_ptr += fwu->block_size; } #ifdef SHOW_PROGRESS - dev_info(&fwu->rmi4_data->i2c_client->dev, - "%s: update %s %3d / %3d\n", - __func__, - command == CMD_WRITE_CONFIG_BLOCK ? - "config" : "firmware", - block_cnt, - block_cnt); + dev_info(&i2c_client->dev, + "%s: update %s %3d / %3d\n", + __func__, + command == CMD_WRITE_CONFIG_BLOCK ? + "config" : "firmware", + block_cnt, block_cnt); #endif return 0; } @@ -741,7 +824,10 @@ static int fwu_write_bootloader_id(void) int retval; #ifdef DEBUG_FW_UPDATE - dev_info(&fwu->rmi4_data->i2c_client->dev, "Write bootloader ID\n"); + dev_info(&fwu->rmi4_data->i2c_client->dev, + "Write bootloader ID 0x%02X 0x%02X\n", + fwu->bootloader_id[0], + fwu->bootloader_id[1]); #endif retval = fwu->fn_ptr->write(fwu->rmi4_data, fwu->f34_fd.data_base_addr + BLOCK_DATA_OFFSET, @@ -789,17 +875,6 @@ static int fwu_enter_flash_prog(void) if (retval < 0) return retval; - retval = fwu_read_f01_device_status(&f01_device_status); - if (retval < 0) - return retval; - - if (!f01_device_status.flash_prog) { - dev_err(&fwu->rmi4_data->i2c_client->dev, - "%s: Program enabled bit not set\n", - __func__); - return -EINVAL; - } - retval = fwu_scan_pdt(); if (retval < 0) return retval; @@ -879,9 +954,12 @@ static int fwu_do_reflash(void) if (retval < 0) return retval; - dev_dbg(&fwu->rmi4_data->i2c_client->dev, - "%s: Idle status detected\n", - __func__); + if (fwu->flash_control.status != 0x00) { + dev_err(&fwu->rmi4_data->i2c_client->dev, + "%s: Erase all command failed, status 0x%02X\n", + __func__, retval); + return -1; + } if (fwu->firmware_data) { retval = fwu_write_firmware(); @@ -900,90 +978,6 @@ static int fwu_do_reflash(void) return retval; } -static int fwu_start_reflash(void) -{ - int retval; - struct image_header header; - const unsigned char *fw_image; - const struct firmware *fw_entry = NULL; - struct f01_device_status f01_device_status; - - pr_notice("%s: Start of reflash process\n", __func__); - - if (fwu->ext_data_source) - fw_image = fwu->ext_data_source; - else { - dev_dbg(&fwu->rmi4_data->i2c_client->dev, - "%s: Requesting firmware image %s\n", - __func__, FW_IMAGE_NAME); - - retval = request_firmware(&fw_entry, FW_IMAGE_NAME, - &fwu->rmi4_data->i2c_client->dev); - if (retval != 0) { - dev_err(&fwu->rmi4_data->i2c_client->dev, - "%s: Firmware image %s not available\n", - __func__, FW_IMAGE_NAME); - retval = -EINVAL; - goto exit; - } - - dev_dbg(&fwu->rmi4_data->i2c_client->dev, - "%s: Firmware image size = %d\n", - __func__, fw_entry->size); - - fw_image = fw_entry->data; - } - - parse_header(&header, fw_image); - - if (header.image_size) - fwu->firmware_data = fw_image + FW_IMAGE_OFFSET; - if (header.config_size) { - fwu->config_data = fw_image + FW_IMAGE_OFFSET + - header.image_size; - } - - fwu->fn_ptr->enable(fwu->rmi4_data, false); - - fwu_check_version(); - - retval = fwu_do_reflash(); - if (retval < 0) { - dev_err(&fwu->rmi4_data->i2c_client->dev, - "%s: Failed to do reflash\n", - __func__); - } - - /* reset device */ - fwu_reset_device(); - - /* check device status */ - retval = fwu_read_f01_device_status(&f01_device_status); - if (retval < 0) - goto exit; - - dev_info(&fwu->rmi4_data->i2c_client->dev, "Device is in %s mode\n", - f01_device_status.flash_prog == 1 ? "bootloader" : "UI"); - if (f01_device_status.flash_prog) - dev_info(&fwu->rmi4_data->i2c_client->dev, "Flash status %d\n", - f01_device_status.status_code); - - if (f01_device_status.flash_prog) { - dev_info(&fwu->rmi4_data->i2c_client->dev, - "%s: Device is in flash prog mode 0x%02X\n", - __func__, f01_device_status.status_code); - retval = 0; - goto exit; - } - fwu->fn_ptr->enable(fwu->rmi4_data, true); - if (fw_entry) - release_firmware(fw_entry); - - pr_notice("%s: End of reflash process\n", __func__); -exit: - return retval; -} - static int fwu_do_write_config(void) { int retval; @@ -1205,6 +1199,110 @@ exit: return retval; } +static int fwu_start_reflash(void) +{ + int retval; + struct image_header header; + const unsigned char *fw_image; + const struct firmware *fw_entry = NULL; + struct f01_device_status f01_device_status; + enum flash_area flash_area; + + pr_notice("%s: Start of reflash process\n", __func__); + + if (fwu->ext_data_source) + fw_image = fwu->ext_data_source; + else { + dev_dbg(&fwu->rmi4_data->i2c_client->dev, + "%s: Requesting firmware image %s\n", + __func__, FW_IMAGE_NAME); + + retval = request_firmware(&fw_entry, FW_IMAGE_NAME, + &fwu->rmi4_data->i2c_client->dev); + if (retval != 0) { + dev_err(&fwu->rmi4_data->i2c_client->dev, + "%s: Firmware image %s not available\n", + __func__, FW_IMAGE_NAME); + retval = -EINVAL; + goto exit; + } + + dev_dbg(&fwu->rmi4_data->i2c_client->dev, + "%s: Firmware image size = %d\n", + __func__, fw_entry->size); + + fw_image = fw_entry->data; + } + + parse_header(&header, fw_image); + + if (header.image_size) + fwu->firmware_data = fw_image + FW_IMAGE_OFFSET; + if (header.config_size) { + fwu->config_data = fw_image + FW_IMAGE_OFFSET + + header.image_size; + } + + if (fwu->ext_data_source) + flash_area = UI_FIRMWARE; + else + flash_area = fwu_go_nogo(); + + switch (flash_area) { + case NONE: + dev_info(&fwu->rmi4_data->i2c_client->dev, + "%s: No need to do reflash.\n", + __func__); + goto exit; + case UI_FIRMWARE: + retval = fwu_do_reflash(); + break; + case CONFIG_AREA: + retval = fwu_do_write_config(); + break; + default: + dev_err(&fwu->rmi4_data->i2c_client->dev, + "%s: Unknown flash area\n", + __func__); + goto exit; + } + + if (retval < 0) { + dev_err(&fwu->rmi4_data->i2c_client->dev, + "%s: Failed to do reflash\n", + __func__); + } + + /* reset device */ + fwu_reset_device(); + + /* check device status */ + retval = fwu_read_f01_device_status(&f01_device_status); + if (retval < 0) + goto exit; + + dev_info(&fwu->rmi4_data->i2c_client->dev, "Device is in %s mode\n", + f01_device_status.flash_prog == 1 ? "bootloader" : "UI"); + if (f01_device_status.flash_prog) + dev_info(&fwu->rmi4_data->i2c_client->dev, "Flash status %d\n", + f01_device_status.status_code); + + if (f01_device_status.flash_prog) { + dev_info(&fwu->rmi4_data->i2c_client->dev, + "%s: Device is in flash prog mode 0x%02X\n", + __func__, f01_device_status.status_code); + retval = 0; + goto exit; + } + + if (fw_entry) + release_firmware(fw_entry); + + pr_notice("%s: End of reflash process\n", __func__); +exit: + return retval; +} + int synaptics_fw_updater(unsigned char *fw_data) { int retval; @@ -1431,6 +1529,11 @@ static void synaptics_rmi4_fwu_attn(struct synaptics_rmi4_data *rmi4_data, return; } +static void synaptics_rmi4_fwu_work(struct work_struct *work) +{ + fwu_start_reflash(); +} + static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data) { int retval; @@ -1497,6 +1600,7 @@ static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data) goto exit_free_mem; fwu->initialized = true; + fwu->force_update = FORCE_UPDATE; retval = sysfs_create_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data); @@ -1519,6 +1623,13 @@ static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data) } } +#ifdef INSIDE_FIRMWARE_UPDATE + fwu->fwu_workqueue = create_singlethread_workqueue("fwu_workqueue"); + INIT_DELAYED_WORK(&fwu->fwu_work, synaptics_rmi4_fwu_work); + queue_delayed_work(fwu->fwu_workqueue, + &fwu->fwu_work, + msecs_to_jiffies(1000)); +#endif return 0; exit_remove_attrs: diff --git a/kernel/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/kernel/drivers/input/touchscreen/synaptics_i2c_rmi4.c index 85530225abd2..76f9155bd49c 100644 --- a/kernel/drivers/input/touchscreen/synaptics_i2c_rmi4.c +++ b/kernel/drivers/input/touchscreen/synaptics_i2c_rmi4.c @@ -347,28 +347,32 @@ static ssize_t synaptics_rmi4_0dbutton_store(struct device *dev, if (rmi4_data->button_0d_enabled == input) return count; - list_for_each_entry(fhandler, &rmi->support_fn_list, link) { - if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) { - ii = fhandler->intr_reg_num; + if (!list_empty(&rmi->support_fn_list)) { + list_for_each_entry(fhandler, &rmi->support_fn_list, link) { + if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) { + ii = fhandler->intr_reg_num; - retval = synaptics_rmi4_i2c_read(rmi4_data, - rmi4_data->f01_ctrl_base_addr + 1 + ii, - &intr_enable, - sizeof(intr_enable)); - if (retval < 0) - return retval; + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f01_ctrl_base_addr + + 1 + ii, + &intr_enable, + sizeof(intr_enable)); + if (retval < 0) + return retval; - if (input == 1) - intr_enable |= fhandler->intr_mask; - else - intr_enable &= ~fhandler->intr_mask; + if (input == 1) + intr_enable |= fhandler->intr_mask; + else + intr_enable &= ~fhandler->intr_mask; - retval = synaptics_rmi4_i2c_write(rmi4_data, - rmi4_data->f01_ctrl_base_addr + 1 + ii, - &intr_enable, - sizeof(intr_enable)); - if (retval < 0) - return retval; + retval = synaptics_rmi4_i2c_write(rmi4_data, + rmi4_data->f01_ctrl_base_addr + + 1 + ii, + &intr_enable, + sizeof(intr_enable)); + if (retval < 0) + return retval; + } } } @@ -637,28 +641,22 @@ static int synaptics_rmi4_f11_abs_report(struct synaptics_rmi4_data *rmi4_data, finger_status, x, y, wx, wy); -#ifdef TYPE_B_PROTOCOL - input_report_abs(rmi4_data->input_dev, - ABS_MT_POSITION_X, x); - input_report_abs(rmi4_data->input_dev, - ABS_MT_POSITION_Y, y); -#ifdef REPORT_2D_W - input_report_abs(rmi4_data->input_dev, - ABS_MT_TOUCH_MAJOR, max(wx, wy)); - input_report_abs(rmi4_data->input_dev, - ABS_MT_TOUCH_MINOR, min(wx, wy)); -#endif -#else + input_report_key(rmi4_data->input_dev, + BTN_TOUCH, 1); + input_report_key(rmi4_data->input_dev, + BTN_TOOL_FINGER, 1); input_report_abs(rmi4_data->input_dev, ABS_MT_POSITION_X, x); input_report_abs(rmi4_data->input_dev, ABS_MT_POSITION_Y, y); + #ifdef REPORT_2D_W input_report_abs(rmi4_data->input_dev, ABS_MT_TOUCH_MAJOR, max(wx, wy)); input_report_abs(rmi4_data->input_dev, ABS_MT_TOUCH_MINOR, min(wx, wy)); #endif +#ifndef TYPE_B_PROTOCOL input_mt_sync(rmi4_data->input_dev); #endif touch_count++; @@ -853,12 +851,14 @@ static int synaptics_rmi4_sensor_report(struct synaptics_rmi4_data *rmi4_data) * Traverse the function handler list and service the source(s) * of the interrupt accordingly. */ - list_for_each_entry(fhandler, &rmi->support_fn_list, link) { - if (fhandler->num_of_data_sources) { - if (fhandler->intr_mask & - intr[fhandler->intr_reg_num]) { - synaptics_rmi4_report_touch(rmi4_data, - fhandler, &touch_count); + if (!list_empty(&rmi->support_fn_list)) { + list_for_each_entry(fhandler, &rmi->support_fn_list, link) { + if (fhandler->num_of_data_sources) { + if (fhandler->intr_mask & + intr[fhandler->intr_reg_num]) { + synaptics_rmi4_report_touch(rmi4_data, + fhandler, &touch_count); + } } } } @@ -1088,8 +1088,8 @@ static int synaptics_rmi4_capacitance_button_map( if (!pdata->capacitance_button_map) { dev_err(&rmi4_data->i2c_client->dev, - "%s: capacitance_button_map is \ - NULL in board file\n", + "%s: capacitance_button_map is" \ + "NULL in board file\n", __func__); return -ENODEV; } else if (!pdata->capacitance_button_map->map) { @@ -1194,6 +1194,63 @@ static int synaptics_rmi4_alloc_fh(struct synaptics_rmi4_fn **fhandler, return 0; } + + /** + * synaptics_rmi4_query_device_info() + * + * Called by synaptics_rmi4_query_device(). + * + */ +static int synaptics_rmi4_query_device_info( + struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + unsigned char f01_query[F01_STD_QUERY_LEN]; + struct synaptics_rmi4_device_info *rmi = &(rmi4_data->rmi4_mod_info); + + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f01_query_base_addr, + f01_query, + sizeof(f01_query)); + if (retval < 0) + return retval; + + /* RMI Version 4.0 currently supported */ + rmi->version_major = 4; + rmi->version_minor = 0; + + rmi->manufacturer_id = f01_query[0]; + rmi->product_props = f01_query[1]; + rmi->product_info[0] = f01_query[2] & MASK_7BIT; + rmi->product_info[1] = f01_query[3] & MASK_7BIT; + rmi->date_code[0] = f01_query[4] & MASK_5BIT; + rmi->date_code[1] = f01_query[5] & MASK_4BIT; + rmi->date_code[2] = f01_query[6] & MASK_5BIT; + rmi->tester_id = ((f01_query[7] & MASK_7BIT) << 8) | + (f01_query[8] & MASK_7BIT); + rmi->serial_number = ((f01_query[9] & MASK_7BIT) << 8) | + (f01_query[10] & MASK_7BIT); + memcpy(rmi->product_id_string, &f01_query[11], 10); + + if (rmi->manufacturer_id != 1) { + dev_err(&rmi4_data->i2c_client->dev, + "%s: Non-Synaptics device found, manufacturer ID = %d\n", + __func__, rmi->manufacturer_id); + } + + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f01_query_base_addr + F01_BUID_ID_OFFSET, + rmi->build_id, + sizeof(rmi->build_id)); + if (retval < 0) { + dev_err(&rmi4_data->i2c_client->dev, + "%s: Failed to read firmware build id (code %d)\n", + __func__, retval); + return retval; + } + return retval; +} + /** * synaptics_rmi4_query_device() * @@ -1214,7 +1271,6 @@ static int synaptics_rmi4_query_device(struct synaptics_rmi4_data *rmi4_data) unsigned char page_number; unsigned char intr_count = 0; unsigned char data_sources = 0; - unsigned char f01_query[F01_STD_QUERY_LEN]; unsigned short pdt_entry_addr; unsigned short intr_addr; struct synaptics_rmi4_f01_device_status status; @@ -1264,6 +1320,11 @@ static int synaptics_rmi4_query_device(struct synaptics_rmi4_data *rmi4_data) rmi4_data->f01_cmd_base_addr = rmi_fd.cmd_base_addr; + retval = + synaptics_rmi4_query_device_info(rmi4_data); + if (retval < 0) + return retval; + retval = synaptics_rmi4_i2c_read(rmi4_data, rmi4_data->f01_data_base_addr, status.data, @@ -1277,7 +1338,17 @@ static int synaptics_rmi4_query_device(struct synaptics_rmi4_data *rmi4_data) status.status_code); goto flash_prog_mode; } - break; + break; + + case SYNAPTICS_RMI4_F34: + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi_fd.ctrl_base_addr, + rmi->config_id, + sizeof(rmi->config_id)); + if (retval < 0) + return retval; + break; + case SYNAPTICS_RMI4_F11: if (rmi_fd.intr_src_count == 0) break; @@ -1335,56 +1406,24 @@ flash_prog_mode: "%s: Number of interrupt registers = %d\n", __func__, rmi4_data->num_of_intr_regs); - retval = synaptics_rmi4_i2c_read(rmi4_data, - rmi4_data->f01_query_base_addr, - f01_query, - sizeof(f01_query)); - if (retval < 0) - return retval; - - /* RMI Version 4.0 currently supported */ - rmi->version_major = 4; - rmi->version_minor = 0; - - rmi->manufacturer_id = f01_query[0]; - rmi->product_props = f01_query[1]; - rmi->product_info[0] = f01_query[2] & MASK_7BIT; - rmi->product_info[1] = f01_query[3] & MASK_7BIT; - rmi->date_code[0] = f01_query[4] & MASK_5BIT; - rmi->date_code[1] = f01_query[5] & MASK_4BIT; - rmi->date_code[2] = f01_query[6] & MASK_5BIT; - rmi->tester_id = ((f01_query[7] & MASK_7BIT) << 8) | - (f01_query[8] & MASK_7BIT); - rmi->serial_number = ((f01_query[9] & MASK_7BIT) << 8) | - (f01_query[10] & MASK_7BIT); - memcpy(rmi->product_id_string, &f01_query[11], 10); - - if (rmi->manufacturer_id != 1) { - dev_err(&rmi4_data->i2c_client->dev, - "%s: Non-Synaptics device found, manufacturer ID = %d\n", - __func__, rmi->manufacturer_id); - } - - retval = synaptics_rmi4_i2c_read(rmi4_data, - rmi4_data->f01_query_base_addr + F01_BUID_ID_OFFSET, - rmi->build_id, - sizeof(rmi->build_id)); - if (retval < 0) - return retval; - memset(rmi4_data->intr_mask, 0x00, sizeof(rmi4_data->intr_mask)); /* * Map out the interrupt bit masks for the interrupt sources * from the registered function handlers. */ - list_for_each_entry(fhandler, &rmi->support_fn_list, link) - data_sources += fhandler->num_of_data_sources; + if (!list_empty(&rmi->support_fn_list)) { + list_for_each_entry(fhandler, &rmi->support_fn_list, link) + data_sources += fhandler->num_of_data_sources; + } if (data_sources) { - list_for_each_entry(fhandler, &rmi->support_fn_list, link) { - if (fhandler->num_of_data_sources) { - rmi4_data->intr_mask[fhandler->intr_reg_num] |= - fhandler->intr_mask; + if (!list_empty(&rmi->support_fn_list)) { + list_for_each_entry(fhandler, + &rmi->support_fn_list, link) { + if (fhandler->num_of_data_sources) { + rmi4_data->intr_mask[fhandler->intr_reg_num] |= + fhandler->intr_mask; + } } } } @@ -1430,12 +1469,14 @@ static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data) msleep(100); - list_for_each_entry(fhandler, &rmi->support_fn_list, link) { - if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) - synaptics_rmi4_f1a_kfree(fhandler); - else - kfree(fhandler->data); - kfree(fhandler); + if (!list_empty(&rmi->support_fn_list)) { + list_for_each_entry(fhandler, &rmi->support_fn_list, link) { + if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) + synaptics_rmi4_f1a_kfree(fhandler); + else + kfree(fhandler->data); + kfree(fhandler); + } } retval = synaptics_rmi4_query_device(rmi4_data); @@ -1534,12 +1575,14 @@ void synaptics_rmi4_new_function(enum exp_fn fn_type, bool insert, exp_fhandler->inserted = false; list_add_tail(&exp_fhandler->link, &exp_fn_list); } else { - list_for_each_entry(exp_fhandler, &exp_fn_list, link) { - if (exp_fhandler->func_init == func_init) { - exp_fhandler->inserted = false; - exp_fhandler->func_init = NULL; - exp_fhandler->func_attn = NULL; - goto exit; + if (!list_empty(&exp_fn_list)) { + list_for_each_entry(exp_fhandler, &exp_fn_list, link) { + if (exp_fhandler->func_init == func_init) { + exp_fhandler->inserted = false; + exp_fhandler->func_init = NULL; + exp_fhandler->func_attn = NULL; + goto exit; + } } } } @@ -1611,7 +1654,7 @@ static int __devinit synaptics_rmi4_probe(struct i2c_client *client, retval = -ENOMEM; goto err_input_device; } -/* + if (platform_data->regulator_en) { rmi4_data->regulator = regulator_get(&client->dev, "vdd"); if (IS_ERR(rmi4_data->regulator)) { @@ -1623,7 +1666,7 @@ static int __devinit synaptics_rmi4_probe(struct i2c_client *client, } regulator_enable(rmi4_data->regulator); } -*/ + rmi4_data->i2c_client = client; rmi4_data->current_page = MASK_8BIT; rmi4_data->board = platform_data; @@ -1652,12 +1695,16 @@ static int __devinit synaptics_rmi4_probe(struct i2c_client *client, rmi4_data->input_dev->name = DRIVER_NAME; rmi4_data->input_dev->phys = INPUT_PHYS_NAME; rmi4_data->input_dev->id.bustype = BUS_I2C; + rmi4_data->input_dev->id.product = SYNAPTICS_RMI4_DRIVER_PRODUCT; + rmi4_data->input_dev->id.version = SYNAPTICS_RMI4_DRIVER_VERSION; rmi4_data->input_dev->dev.parent = &client->dev; input_set_drvdata(rmi4_data->input_dev, rmi4_data); set_bit(EV_SYN, rmi4_data->input_dev->evbit); set_bit(EV_KEY, rmi4_data->input_dev->evbit); set_bit(EV_ABS, rmi4_data->input_dev->evbit); + set_bit(BTN_TOUCH, rmi4_data->input_dev->keybit); + set_bit(BTN_TOOL_FINGER, rmi4_data->input_dev->keybit); #ifdef INPUT_PROP_DIRECT set_bit(INPUT_PROP_DIRECT, rmi4_data->input_dev->propbit); @@ -1681,9 +1728,11 @@ static int __devinit synaptics_rmi4_probe(struct i2c_client *client, #endif f1a = NULL; - list_for_each_entry(fhandler, &rmi->support_fn_list, link) { - if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) - f1a = fhandler->data; + if (!list_empty(&rmi->support_fn_list)) { + list_for_each_entry(fhandler, &rmi->support_fn_list, link) { + if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) + f1a = fhandler->data; + } } if (f1a) { @@ -1775,16 +1824,17 @@ err_query_device: regulator_put(rmi4_data->regulator); } - list_for_each_entry(fhandler, &rmi->support_fn_list, link) { - if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) - synaptics_rmi4_f1a_kfree(fhandler); - else - kfree(fhandler->data); - kfree(fhandler); + if (!list_empty(&rmi->support_fn_list)) { + list_for_each_entry(fhandler, &rmi->support_fn_list, link) { + if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) + synaptics_rmi4_f1a_kfree(fhandler); + else + kfree(fhandler->data); + kfree(fhandler); + } } -/* + err_regulator: -*/ input_free_device(rmi4_data->input_dev); rmi4_data->input_dev = NULL; @@ -1836,12 +1886,14 @@ static int __devexit synaptics_rmi4_remove(struct i2c_client *client) regulator_put(rmi4_data->regulator); } - list_for_each_entry(fhandler, &rmi->support_fn_list, link) { - if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) - synaptics_rmi4_f1a_kfree(fhandler); - else - kfree(fhandler->data); - kfree(fhandler); + if (!list_empty(&rmi->support_fn_list)) { + list_for_each_entry(fhandler, &rmi->support_fn_list, link) { + if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) + synaptics_rmi4_f1a_kfree(fhandler); + else + kfree(fhandler->data); + kfree(fhandler); + } } input_free_device(rmi4_data->input_dev); diff --git a/kernel/drivers/input/touchscreen/synaptics_i2c_rmi4.h b/kernel/drivers/input/touchscreen/synaptics_i2c_rmi4.h index 7ee0a925959a..ecb9b9415e8a 100644 --- a/kernel/drivers/input/touchscreen/synaptics_i2c_rmi4.h +++ b/kernel/drivers/input/touchscreen/synaptics_i2c_rmi4.h @@ -20,7 +20,10 @@ #ifndef _SYNAPTICS_DSX_RMI4_H_ #define _SYNAPTICS_DSX_RMI4_H_ -#define SYNAPTICS_RMI4_DRIVER_VERSION "DSX 1.0" +#define SYNAPTICS_RMI4_DS4 0x0001 +#define SYNAPTICS_RMI4_DS5 0x0002 +#define SYNAPTICS_RMI4_DRIVER_PRODUCT SYNAPTICS_RMI4_DS4 +#define SYNAPTICS_RMI4_DRIVER_VERSION 0x1001 #include #ifdef CONFIG_HAS_EARLYSUSPEND @@ -158,6 +161,7 @@ struct synaptics_rmi4_device_info { unsigned short serial_number; unsigned char product_id_string[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1]; unsigned char build_id[SYNAPTICS_RMI4_BUILD_ID_SIZE]; + unsigned char config_id[3]; struct list_head support_fn_list; };