Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: elan_i2c - add support for multi IC type and iap format

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>

authored by

Duson Lin and committed by
Dmitry Torokhov
12018ac3 85919a00

+49 -11
+2 -3
drivers/input/mouse/elan_i2c.h
··· 33 33 #define ETP_FW_IAP_PAGE_ERR (1 << 5) 34 34 #define ETP_FW_IAP_INTF_ERR (1 << 4) 35 35 #define ETP_FW_PAGE_SIZE 64 36 - #define ETP_FW_VAILDPAGE_COUNT 768 37 36 #define ETP_FW_SIGNATURE_SIZE 6 38 - #define ETP_FW_SIGNATURE_ADDRESS 0xBFFA 39 37 40 38 struct i2c_client; 41 39 struct completion; ··· 56 58 bool max_baseliune, u8 *value); 57 59 58 60 int (*get_version)(struct i2c_client *client, bool iap, u8 *version); 59 - int (*get_sm_version)(struct i2c_client *client, u8 *version); 61 + int (*get_sm_version)(struct i2c_client *client, 62 + u8* ic_type, u8 *version); 60 63 int (*get_checksum)(struct i2c_client *client, bool iap, u16 *csum); 61 64 int (*get_product_id)(struct i2c_client *client, u8 *id); 62 65
+40 -5
drivers/input/mouse/elan_i2c_core.c
··· 4 4 * Copyright (c) 2013 ELAN Microelectronics Corp. 5 5 * 6 6 * Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw> 7 - * Version: 1.5.7 7 + * Version: 1.5.8 8 8 * 9 9 * Based on cyapa driver: 10 10 * copyright (c) 2011-2012 Cypress Semiconductor, Inc. ··· 40 40 #include "elan_i2c.h" 41 41 42 42 #define DRIVER_NAME "elan_i2c" 43 - #define ELAN_DRIVER_VERSION "1.5.7" 43 + #define ELAN_DRIVER_VERSION "1.5.8" 44 44 #define ETP_MAX_PRESSURE 255 45 45 #define ETP_FWIDTH_REDUCE 90 46 46 #define ETP_FINGER_WIDTH 15 ··· 83 83 u16 fw_checksum; 84 84 int pressure_adjustment; 85 85 u8 mode; 86 + u8 ic_type; 87 + u16 fw_vaildpage_count; 88 + u16 fw_signature_address; 86 89 87 90 bool irq_wake; 88 91 ··· 93 90 u8 max_baseline; 94 91 bool baseline_ready; 95 92 }; 93 + 94 + static int elan_get_fwinfo(u8 ic_type, u16 *vaildpage_count, 95 + u16 *signature_address) 96 + { 97 + switch(ic_type) { 98 + case 0x09: 99 + *vaildpage_count = 768; 100 + break; 101 + case 0x0D: 102 + *vaildpage_count = 896; 103 + break; 104 + default: 105 + /* unknown ic type clear value */ 106 + *vaildpage_count = 0; 107 + *signature_address = 0; 108 + return -ENXIO; 109 + } 110 + 111 + *signature_address = 112 + (*vaildpage_count * ETP_FW_PAGE_SIZE) - ETP_FW_SIGNATURE_SIZE; 113 + 114 + return 0; 115 + } 96 116 97 117 static int elan_enable_power(struct elan_tp_data *data) 98 118 { ··· 247 221 if (error) 248 222 return error; 249 223 250 - error = data->ops->get_sm_version(data->client, &data->sm_version); 224 + error = data->ops->get_sm_version(data->client, &data->ic_type, 225 + &data->sm_version); 251 226 if (error) 252 227 return error; 253 228 ··· 260 233 &data->pressure_adjustment); 261 234 if (error) 262 235 return error; 236 + 237 + error = elan_get_fwinfo(data->ic_type, &data->fw_vaildpage_count, 238 + &data->fw_signature_address); 239 + if (error) { 240 + dev_err(&data->client->dev, 241 + "unknown ic type %d\n", data->ic_type); 242 + return error; 243 + } 263 244 264 245 return 0; 265 246 } ··· 353 318 iap_start_addr = get_unaligned_le16(&fw->data[ETP_IAP_START_ADDR * 2]); 354 319 355 320 boot_page_count = (iap_start_addr * 2) / ETP_FW_PAGE_SIZE; 356 - for (i = boot_page_count; i < ETP_FW_VAILDPAGE_COUNT; i++) { 321 + for (i = boot_page_count; i < data->fw_vaildpage_count; i++) { 357 322 u16 checksum = 0; 358 323 const u8 *page = &fw->data[i * ETP_FW_PAGE_SIZE]; 359 324 ··· 489 454 } 490 455 491 456 /* Firmware file must match signature data */ 492 - fw_signature = &fw->data[ETP_FW_SIGNATURE_ADDRESS]; 457 + fw_signature = &fw->data[data->fw_signature_address]; 493 458 if (memcmp(fw_signature, signature, sizeof(signature)) != 0) { 494 459 dev_err(dev, "signature mismatch (expected %*ph, got %*ph)\n", 495 460 (int)sizeof(signature), signature,
+3 -1
drivers/input/mouse/elan_i2c_i2c.c
··· 259 259 return 0; 260 260 } 261 261 262 - static int elan_i2c_get_sm_version(struct i2c_client *client, u8 *version) 262 + static int elan_i2c_get_sm_version(struct i2c_client *client, 263 + u8 *ic_type, u8 *version) 263 264 { 264 265 int error; 265 266 u8 val[3]; ··· 272 271 } 273 272 274 273 *version = val[0]; 274 + *ic_type = val[1]; 275 275 return 0; 276 276 } 277 277
+4 -2
drivers/input/mouse/elan_i2c_smbus.c
··· 165 165 return 0; 166 166 } 167 167 168 - static int elan_smbus_get_sm_version(struct i2c_client *client, u8 *version) 168 + static int elan_smbus_get_sm_version(struct i2c_client *client, 169 + u8 *ic_type, u8 *version) 169 170 { 170 171 int error; 171 172 u8 val[3]; ··· 178 177 return error; 179 178 } 180 179 181 - *version = val[0]; /* XXX Why 0 and not 2 as in IAP/FW versions? */ 180 + *version = val[0]; 181 + *ic_type = val[1]; 182 182 return 0; 183 183 } 184 184