Input: elan_i2c - add support for multi IC type and iap format
authorDuson Lin <dusonlin@emc.com.tw>
Mon, 8 Jun 2015 23:39:35 +0000 (16:39 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Tue, 9 Jun 2015 00:12:24 +0000 (17:12 -0700)
In order to support multiple IC types for i2c/smbus protocol, add get ic
type command and use this data when checking firmware page count and
signature address.

Signed-off-by: Duson Lin <dusonlin@emc.com.tw>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
drivers/input/mouse/elan_i2c.h
drivers/input/mouse/elan_i2c_core.c
drivers/input/mouse/elan_i2c_i2c.c
drivers/input/mouse/elan_i2c_smbus.c

index 6d5f8a4c1748861b547d218b4eda3ab14de5da5e..ff622a1b0c2c31180c42b01251c01c0c663d8d41 100644 (file)
@@ -33,9 +33,7 @@
 #define ETP_FW_IAP_PAGE_ERR    (1 << 5)
 #define ETP_FW_IAP_INTF_ERR    (1 << 4)
 #define ETP_FW_PAGE_SIZE       64
-#define ETP_FW_VAILDPAGE_COUNT 768
 #define ETP_FW_SIGNATURE_SIZE  6
-#define ETP_FW_SIGNATURE_ADDRESS       0xBFFA
 
 struct i2c_client;
 struct completion;
@@ -58,7 +56,8 @@ struct elan_transport_ops {
                                 bool max_baseliune, u8 *value);
 
        int (*get_version)(struct i2c_client *client, bool iap, u8 *version);
-       int (*get_sm_version)(struct i2c_client *client, u8 *version);
+       int (*get_sm_version)(struct i2c_client *client,
+                             u8* ic_type, u8 *version);
        int (*get_checksum)(struct i2c_client *client, bool iap, u16 *csum);
        int (*get_product_id)(struct i2c_client *client, u8 *id);
 
index fd5068b2542db7d58df4900058376f7285243c1e..b4cfd18cdaca5ef868b01dfcb79b5b6629817e1e 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2013 ELAN Microelectronics Corp.
  *
  * Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw>
- * Version: 1.5.7
+ * Version: 1.5.8
  *
  * 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.8"
 #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];
 
@@ -454,7 +489,7 @@ static ssize_t elan_sysfs_update_fw(struct device *dev,
        }
 
        /* 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,
index a0acbbf83bfd4faaa7d14a09dbe332848dc648e4..683c840c9dd73f31d1279b7db88dfacd1f42b7b0 100644 (file)
@@ -259,7 +259,8 @@ static int elan_i2c_get_version(struct i2c_client *client,
        return 0;
 }
 
-static int elan_i2c_get_sm_version(struct i2c_client *client, u8 *version)
+static int elan_i2c_get_sm_version(struct i2c_client *client,
+                                  u8 *ic_type, u8 *version)
 {
        int error;
        u8 val[3];
@@ -271,6 +272,7 @@ static int elan_i2c_get_sm_version(struct i2c_client *client, u8 *version)
        }
 
        *version = val[0];
+       *ic_type = val[1];
        return 0;
 }
 
index 30ab80dbcdd6e013d6854c63fb7bbe1874169596..ff36a366b2aa1aadbe3c9a7f0e9de3eb687d83c3 100644 (file)
@@ -165,7 +165,8 @@ static int elan_smbus_get_version(struct i2c_client *client,
        return 0;
 }
 
-static int elan_smbus_get_sm_version(struct i2c_client *client, u8 *version)
+static int elan_smbus_get_sm_version(struct i2c_client *client,
+                                    u8 *ic_type, u8 *version)
 {
        int error;
        u8 val[3];
@@ -177,7 +178,8 @@ static int elan_smbus_get_sm_version(struct i2c_client *client, u8 *version)
                return error;
        }
 
-       *version = val[0]; /* XXX Why 0 and not 2 as in IAP/FW versions? */
+       *version = val[0];
+       *ic_type = val[1];
        return 0;
 }