Input: elan_i2c - add product IDs FW names
[firefly-linux-kernel-4.4.55.git] / drivers / input / mouse / elan_i2c_core.c
index 7ce8bfe22d7eeb2672804b2303692635df5be9fc..62641f2adaf74d2a3e5ba2473ac00b9a8984cb28 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2013 ELAN Microelectronics Corp.
  *
  * Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw>
- * Version: 1.5.6
+ * Version: 1.5.9
  *
  * Based on cyapa driver:
  * copyright (c) 2011-2012 Cypress Semiconductor, Inc.
@@ -40,8 +40,7 @@
 #include "elan_i2c.h"
 
 #define DRIVER_NAME            "elan_i2c"
-#define ELAN_DRIVER_VERSION    "1.5.6"
-#define ETP_PRESSURE_OFFSET    25
+#define ELAN_DRIVER_VERSION    "1.5.9"
 #define ETP_MAX_PRESSURE       255
 #define ETP_FWIDTH_REDUCE      90
 #define ETP_FINGER_WIDTH       15
@@ -53,6 +52,7 @@
 #define ETP_REPORT_ID_OFFSET   2
 #define ETP_TOUCH_INFO_OFFSET  3
 #define ETP_FINGER_DATA_OFFSET 4
+#define ETP_HOVER_INFO_OFFSET  30
 #define ETP_MAX_REPORT_LEN     34
 
 /* The main device structure */
@@ -81,8 +81,11 @@ struct elan_tp_data {
        u8                      sm_version;
        u8                      iap_version;
        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;
@@ -99,7 +125,7 @@ static int elan_enable_power(struct elan_tp_data *data)
        error = regulator_enable(data->vcc);
        if (error) {
                dev_err(&data->client->dev,
-                       "Failed to enable regulator: %d\n", error);
+                       "failed to enable regulator: %d\n", error);
                return error;
        }
 
@@ -111,6 +137,7 @@ static int elan_enable_power(struct elan_tp_data *data)
                msleep(30);
        } while (--repeat > 0);
 
+       dev_err(&data->client->dev, "failed to enable power: %d\n", error);
        return error;
 }
 
@@ -125,7 +152,7 @@ static int elan_disable_power(struct elan_tp_data *data)
                        error = regulator_disable(data->vcc);
                        if (error) {
                                dev_err(&data->client->dev,
-                                       "Failed to disable regulator: %d\n",
+                                       "failed to disable regulator: %d\n",
                                        error);
                                /* Attempt to power the chip back up */
                                data->ops->power_control(data->client, true);
@@ -138,6 +165,7 @@ static int elan_disable_power(struct elan_tp_data *data)
                msleep(30);
        } while (--repeat > 0);
 
+       dev_err(&data->client->dev, "failed to disable power: %d\n", error);
        return error;
 }
 
@@ -196,7 +224,6 @@ static int elan_initialize(struct elan_tp_data *data)
                if (!error)
                        return 0;
 
-               repeat--;
                msleep(30);
        } while (--repeat > 0);
 
@@ -220,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;
 
@@ -228,6 +256,19 @@ static int elan_query_device_info(struct elan_tp_data *data)
        if (error)
                return error;
 
+       error = data->ops->get_pressure_adjustment(data->client,
+                                                  &data->pressure_adjustment);
+       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;
 }
 
@@ -312,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];
 
@@ -397,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,
@@ -436,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 = request_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 = request_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,
@@ -720,13 +771,13 @@ static const struct attribute_group *elan_sysfs_groups[] = {
  */
 static void elan_report_contact(struct elan_tp_data *data,
                                int contact_num, bool contact_valid,
-                               u8 *finger_data)
+                               bool hover_event, u8 *finger_data)
 {
        struct input_dev *input = data->input;
        unsigned int pos_x, pos_y;
        unsigned int pressure, mk_x, mk_y;
-       unsigned int area_x, area_y, major, minor, new_pressure;
-
+       unsigned int area_x, area_y, major, minor;
+       unsigned int scaled_pressure;
 
        if (contact_valid) {
                pos_x = ((finger_data[0] & 0xf0) << 4) |
@@ -755,15 +806,18 @@ static void elan_report_contact(struct elan_tp_data *data,
                major = max(area_x, area_y);
                minor = min(area_x, area_y);
 
-               new_pressure = pressure + ETP_PRESSURE_OFFSET;
-               if (new_pressure > ETP_MAX_PRESSURE)
-                       new_pressure = ETP_MAX_PRESSURE;
+               scaled_pressure = pressure + data->pressure_adjustment;
+
+               if (scaled_pressure > ETP_MAX_PRESSURE)
+                       scaled_pressure = ETP_MAX_PRESSURE;
 
                input_mt_slot(input, contact_num);
                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_PRESSURE, new_pressure);
+               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_TOOL_WIDTH, mk_x);
                input_report_abs(input, ABS_MT_TOUCH_MAJOR, major);
                input_report_abs(input, ABS_MT_TOUCH_MINOR, minor);
@@ -779,11 +833,14 @@ static void elan_report_absolute(struct elan_tp_data *data, u8 *packet)
        u8 *finger_data = &packet[ETP_FINGER_DATA_OFFSET];
        int i;
        u8 tp_info = packet[ETP_TOUCH_INFO_OFFSET];
-       bool contact_valid;
+       u8 hover_info = packet[ETP_HOVER_INFO_OFFSET];
+       bool contact_valid, hover_event;
 
+       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, finger_data);
+               elan_report_contact(data, i, contact_valid, hover_event,
+                                   finger_data);
 
                if (contact_valid)
                        finger_data += ETP_FINGER_DATA_LEN;
@@ -877,6 +934,7 @@ 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;
 
@@ -1084,16 +1142,18 @@ static int __maybe_unused elan_resume(struct device *dev)
        }
 
        error = elan_enable_power(data);
-       if (error)
+       if (error) {
                dev_err(dev, "power up when resuming failed: %d\n", error);
+               goto err;
+       }
 
        error = elan_initialize(data);
        if (error)
                dev_err(dev, "initialize when resuming failed: %d\n", error);
 
+err:
        enable_irq(data->client->irq);
-
-       return 0;
+       return error;
 }
 
 static SIMPLE_DEV_PM_OPS(elan_pm_ops, elan_suspend, elan_resume);