From e5fd91f1ef340da553f7a79da9540c3db711c937 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Tue, 8 Sep 2015 01:01:14 -0300 Subject: Linux-libre 4.2-gnu --- drivers/input/mouse/elan_i2c_core.c | 75 +++++++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 16 deletions(-) (limited to 'drivers/input/mouse/elan_i2c_core.c') diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 7837ba0f8..4ca73013a 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -4,7 +4,7 @@ * Copyright (c) 2013 ELAN Microelectronics Corp. * * Author: 林政維 (Duson Lin) - * Version: 1.5.7 + * Version: 1.5.9 * * Based on cyapa driver: * copyright (c) 2011-2012 Cypress Semiconductor, Inc. @@ -40,7 +40,7 @@ #include "elan_i2c.h" #define DRIVER_NAME "elan_i2c" -#define ELAN_DRIVER_VERSION "1.5.7" +#define ELAN_DRIVER_VERSION "1.5.9" #define ETP_MAX_PRESSURE 255 #define ETP_FWIDTH_REDUCE 90 #define ETP_FINGER_WIDTH 15 @@ -83,6 +83,9 @@ struct elan_tp_data { u16 fw_checksum; int pressure_adjustment; u8 mode; + u8 ic_type; + u16 fw_vaildpage_count; + u16 fw_signature_address; bool irq_wake; @@ -91,6 +94,29 @@ struct elan_tp_data { bool baseline_ready; }; +static int elan_get_fwinfo(u8 ic_type, u16 *vaildpage_count, + u16 *signature_address) +{ + switch(ic_type) { + case 0x09: + *vaildpage_count = 768; + break; + case 0x0D: + *vaildpage_count = 896; + break; + default: + /* unknown ic type clear value */ + *vaildpage_count = 0; + *signature_address = 0; + return -ENXIO; + } + + *signature_address = + (*vaildpage_count * ETP_FW_PAGE_SIZE) - ETP_FW_SIGNATURE_SIZE; + + return 0; +} + static int elan_enable_power(struct elan_tp_data *data) { int repeat = ETP_RETRY_COUNT; @@ -221,7 +247,8 @@ static int elan_query_device_info(struct elan_tp_data *data) if (error) return error; - error = data->ops->get_sm_version(data->client, &data->sm_version); + error = data->ops->get_sm_version(data->client, &data->ic_type, + &data->sm_version); if (error) return error; @@ -234,6 +261,14 @@ static int elan_query_device_info(struct elan_tp_data *data) if (error) return error; + error = elan_get_fwinfo(data->ic_type, &data->fw_vaildpage_count, + &data->fw_signature_address); + if (error) { + dev_err(&data->client->dev, + "unknown ic type %d\n", data->ic_type); + return error; + } + return 0; } @@ -318,7 +353,7 @@ static int __elan_update_firmware(struct elan_tp_data *data, iap_start_addr = get_unaligned_le16(&fw->data[ETP_IAP_START_ADDR * 2]); boot_page_count = (iap_start_addr * 2) / ETP_FW_PAGE_SIZE; - for (i = boot_page_count; i < ETP_FW_VAILDPAGE_COUNT; i++) { + for (i = boot_page_count; i < data->fw_vaildpage_count; i++) { u16 checksum = 0; const u8 *page = &fw->data[i * ETP_FW_PAGE_SIZE]; @@ -403,7 +438,8 @@ static ssize_t elan_sysfs_read_product_id(struct device *dev, struct i2c_client *client = to_i2c_client(dev); struct elan_tp_data *data = i2c_get_clientdata(client); - return sprintf(buf, "%d.0\n", data->product_id); + return sprintf(buf, ETP_PRODUCT_ID_FORMAT_STRING "\n", + data->product_id); } static ssize_t elan_sysfs_read_fw_ver(struct device *dev, @@ -442,19 +478,28 @@ static ssize_t elan_sysfs_update_fw(struct device *dev, { struct elan_tp_data *data = dev_get_drvdata(dev); const struct firmware *fw; + char *fw_name; int error; const u8 *fw_signature; static const u8 signature[] = {0xAA, 0x55, 0xCC, 0x33, 0xFF, 0xFF}; - error = reject_firmware(&fw, ETP_FW_NAME, dev); + /* Look for a firmware with the product id appended. */ + fw_name = kasprintf(GFP_KERNEL, ETP_FW_NAME, data->product_id); + if (!fw_name) { + dev_err(dev, "failed to allocate memory for firmware name\n"); + return -ENOMEM; + } + + dev_info(dev, "requesting fw '%s'\n", fw_name); + error = reject_firmware(&fw, fw_name, dev); + kfree(fw_name); if (error) { - dev_err(dev, "cannot load firmware %s: %d\n", - ETP_FW_NAME, error); + dev_err(dev, "failed to request firmware: %d\n", error); return error; } /* Firmware file must match signature data */ - fw_signature = &fw->data[ETP_FW_SIGNATURE_ADDRESS]; + fw_signature = &fw->data[data->fw_signature_address]; if (memcmp(fw_signature, signature, sizeof(signature)) != 0) { dev_err(dev, "signature mismatch (expected %*ph, got %*ph)\n", (int)sizeof(signature), signature, @@ -726,7 +771,7 @@ static const struct attribute_group *elan_sysfs_groups[] = { */ static void elan_report_contact(struct elan_tp_data *data, int contact_num, bool contact_valid, - bool hover_event, u8 *finger_data) + u8 *finger_data) { struct input_dev *input = data->input; unsigned int pos_x, pos_y; @@ -770,9 +815,7 @@ static void elan_report_contact(struct elan_tp_data *data, input_mt_report_slot_state(input, MT_TOOL_FINGER, true); input_report_abs(input, ABS_MT_POSITION_X, pos_x); input_report_abs(input, ABS_MT_POSITION_Y, data->max_y - pos_y); - input_report_abs(input, ABS_MT_DISTANCE, hover_event); - input_report_abs(input, ABS_MT_PRESSURE, - hover_event ? 0 : scaled_pressure); + input_report_abs(input, ABS_MT_PRESSURE, scaled_pressure); input_report_abs(input, ABS_TOOL_WIDTH, mk_x); input_report_abs(input, ABS_MT_TOUCH_MAJOR, major); input_report_abs(input, ABS_MT_TOUCH_MINOR, minor); @@ -794,14 +837,14 @@ static void elan_report_absolute(struct elan_tp_data *data, u8 *packet) hover_event = hover_info & 0x40; for (i = 0; i < ETP_MAX_FINGERS; i++) { contact_valid = tp_info & (1U << (3 + i)); - elan_report_contact(data, i, contact_valid, hover_event, - finger_data); + elan_report_contact(data, i, contact_valid, finger_data); if (contact_valid) finger_data += ETP_FINGER_DATA_LEN; } input_report_key(input, BTN_LEFT, tp_info & 0x01); + input_report_abs(input, ABS_DISTANCE, hover_event != 0); input_mt_report_pointer_emulation(input, true); input_sync(input); } @@ -877,6 +920,7 @@ static int elan_setup_input_device(struct elan_tp_data *data) input_abs_set_res(input, ABS_Y, data->y_res); input_set_abs_params(input, ABS_PRESSURE, 0, ETP_MAX_PRESSURE, 0, 0); input_set_abs_params(input, ABS_TOOL_WIDTH, 0, ETP_FINGER_WIDTH, 0, 0); + input_set_abs_params(input, ABS_DISTANCE, 0, 1, 0, 0); /* And MT parameters */ input_set_abs_params(input, ABS_MT_POSITION_X, 0, data->max_x, 0, 0); @@ -889,7 +933,6 @@ static int elan_setup_input_device(struct elan_tp_data *data) ETP_FINGER_WIDTH * max_width, 0, 0); input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, ETP_FINGER_WIDTH * min_width, 0, 0); - input_set_abs_params(input, ABS_MT_DISTANCE, 0, 1, 0, 0); data->input = input; -- cgit v1.2.3-54-g00ecf