blob: dce9dee01066b47a20f6f38c75dfbc48a08d2cc1 [file] [log] [blame]
Alexandra Chin669d27c2012-12-24 15:42:30 +08001/*
2 * Synaptics RMI4 touchscreen driver
3 *
4 * Copyright (C) 2012 Synaptics Incorporated
5 *
6 * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
7 * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 */
19
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/slab.h>
23#include <linux/i2c.h>
24#include <linux/interrupt.h>
25#include <linux/delay.h>
26#include <linux/input.h>
27#include <linux/firmware.h>
Amy Malocheafcecb22013-04-16 18:43:22 -070028#include <linux/string.h>
Alexandra Chin669d27c2012-12-24 15:42:30 +080029#include <linux/input/synaptics_dsx.h>
30#include "synaptics_i2c_rmi4.h"
31
Alexandra Chin669d27c2012-12-24 15:42:30 +080032#define SHOW_PROGRESS
Alexandra Chind5591a62013-02-07 12:59:15 -080033#define MAX_FIRMWARE_ID_LEN 10
34#define FORCE_UPDATE false
35#define INSIDE_FIRMWARE_UPDATE
Alexandra Chin669d27c2012-12-24 15:42:30 +080036
Alexandra Chin669d27c2012-12-24 15:42:30 +080037#define FW_IMAGE_OFFSET 0x100
Alexandra Chin400f26e2013-07-25 11:58:17 -070038/* 0 to ignore flash block check to speed up flash time */
39#define CHECK_FLASH_BLOCK_STATUS 1
Alexandra Chin669d27c2012-12-24 15:42:30 +080040
41#define REG_MAP (1 << 0)
42#define UNLOCKED (1 << 1)
43#define HAS_CONFIG_ID (1 << 2)
44#define HAS_PERM_CONFIG (1 << 3)
45#define HAS_BL_CONFIG (1 << 4)
46#define HAS_DISP_CONFIG (1 << 5)
47#define HAS_CTRL1 (1 << 6)
48
Amy Maloched9bf0d92013-06-19 17:19:23 -070049#define RMI4_INFO_MAX_LEN 200
50
51#define RMI4_STORE_TS_INFO(buf, id, rev, fw_ver) \
52 snprintf(buf, RMI4_INFO_MAX_LEN, \
53 "controller\t= synaptics\n" \
54 "model\t\t= %d rev %d\n" \
55 "fw_ver\t\t= %d\n", id, rev, fw_ver)
56
Amy Malocheafcecb22013-04-16 18:43:22 -070057enum falsh_config_area {
58 UI_CONFIG_AREA = 0x00,
59 PERM_CONFIG_AREA = 0x01,
60 BL_CONFIG_AREA = 0x02,
61 DISP_CONFIG_AREA = 0x03
62};
Alexandra Chin669d27c2012-12-24 15:42:30 +080063
64enum flash_command {
65 CMD_WRITE_FW_BLOCK = 0x2,
66 CMD_ERASE_ALL = 0x3,
Alexandra Chin823a2f52013-07-29 16:09:52 -070067 CMD_WRITE_LOCKDOWN_BLOCK = 0x4,
Alexandra Chin669d27c2012-12-24 15:42:30 +080068 CMD_READ_CONFIG_BLOCK = 0x5,
69 CMD_WRITE_CONFIG_BLOCK = 0x6,
70 CMD_ERASE_CONFIG = 0x7,
Amy Malocheafcecb22013-04-16 18:43:22 -070071 CMD_READ_SENSOR_ID = 0x8,
Alexandra Chin669d27c2012-12-24 15:42:30 +080072 CMD_ERASE_BL_CONFIG = 0x9,
73 CMD_ERASE_DISP_CONFIG = 0xA,
Amy Malocheafcecb22013-04-16 18:43:22 -070074 CMD_ENABLE_FLASH_PROG = 0xF
Alexandra Chin669d27c2012-12-24 15:42:30 +080075};
76
Alexandra Chind5591a62013-02-07 12:59:15 -080077enum flash_area {
78 NONE,
79 UI_FIRMWARE,
Amy Maloche2c4c48c2013-05-01 20:06:23 -070080 CONFIG_AREA,
81 MISMATCH
Alexandra Chind5591a62013-02-07 12:59:15 -080082};
83
Amy Malocheafcecb22013-04-16 18:43:22 -070084enum image_file_option {
85 OPTION_BUILD_INFO = 0,
86 OPTION_CONTAIN_BOOTLOADER = 1,
87};
88
Alexandra Chin400f26e2013-07-25 11:58:17 -070089enum flash_offset {
90 OFFSET_BOOTLOADER_ID,
91 OFFSET_FLASH_PROPERTIES,
92 OFFSET_BLOCK_SIZE,
93 OFFSET_FW_BLOCK_COUNT,
94 OFFSET_BLOCK_NUMBER,
95 OFFSET_BLOCK_DATA,
96 OFFSET_FLASH_CONTROL,
97 OFFSET_FLASH_STATUS
98};
99
Alexandra Chin823a2f52013-07-29 16:09:52 -0700100enum flash_update_mode {
101 NORMAL = 1,
102 FORCE = 2,
103 LOCKDOWN = 8
104};
105
Alexandra Chin669d27c2012-12-24 15:42:30 +0800106#define SLEEP_MODE_NORMAL (0x00)
107#define SLEEP_MODE_SENSOR_SLEEP (0x01)
108#define SLEEP_MODE_RESERVED0 (0x02)
109#define SLEEP_MODE_RESERVED1 (0x03)
110
111#define ENABLE_WAIT_MS (1 * 1000)
112#define WRITE_WAIT_MS (3 * 1000)
113#define ERASE_WAIT_MS (5 * 1000)
Alexandra Chind5591a62013-02-07 12:59:15 -0800114#define RESET_WAIT_MS (500)
Alexandra Chin669d27c2012-12-24 15:42:30 +0800115
Alexandra Chin400f26e2013-07-25 11:58:17 -0700116#define SLEEP_TIME_US 100
Alexandra Chin669d27c2012-12-24 15:42:30 +0800117
Alexandra Chin669d27c2012-12-24 15:42:30 +0800118static int fwu_wait_for_idle(int timeout_ms);
119
Amy Malocheafcecb22013-04-16 18:43:22 -0700120struct image_header_data {
121 union {
122 struct {
123 /* 0x00-0x0F */
124 unsigned char file_checksum[4];
125 unsigned char reserved_04;
126 unsigned char reserved_05;
127 unsigned char options_firmware_id:1;
128 unsigned char options_contain_bootloader:1;
129 unsigned char options_reserved:6;
130 unsigned char bootloader_version;
131 unsigned char firmware_size[4];
132 unsigned char config_size[4];
133 /* 0x10-0x1F */
134 unsigned char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE];
Amy Maloche2c4c48c2013-05-01 20:06:23 -0700135 unsigned char pkg_id_lsb;
136 unsigned char pkg_id_msb;
137 unsigned char pkg_id_rev_lsb;
138 unsigned char pkg_id_rev_msb;
Amy Malocheafcecb22013-04-16 18:43:22 -0700139 unsigned char product_info[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE];
140 /* 0x20-0x2F */
141 unsigned char reserved_20_2f[0x10];
142 /* 0x30-0x3F */
143 unsigned char ds_firmware_id[0x10];
144 /* 0x40-0x4F */
145 unsigned char ds_customize_info[10];
146 unsigned char reserved_4a_4f[6];
147 /* 0x50-0x53*/
148 unsigned char firmware_id[4];
149 } __packed;
Amy Maloche2c4c48c2013-05-01 20:06:23 -0700150 unsigned char data[0x54];
Amy Malocheafcecb22013-04-16 18:43:22 -0700151 };
152};
153
Alexandra Chin823a2f52013-07-29 16:09:52 -0700154struct image_content {
155 bool is_contain_build_info;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800156 unsigned int checksum;
157 unsigned int image_size;
158 unsigned int config_size;
159 unsigned char options;
160 unsigned char bootloader_version;
161 unsigned char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1];
162 unsigned char product_info[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE];
Amy Maloche2c4c48c2013-05-01 20:06:23 -0700163 u16 package_id;
164 u16 package_revision_id;
Amy Malocheafcecb22013-04-16 18:43:22 -0700165 unsigned int firmware_id;
Alexandra Chin823a2f52013-07-29 16:09:52 -0700166 const unsigned char *firmware_data;
167 const unsigned char *config_data;
168 const unsigned char *lockdown_data;
169 unsigned short lockdown_block_count;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800170};
171
172struct pdt_properties {
173 union {
174 struct {
175 unsigned char reserved_1:6;
176 unsigned char has_bsr:1;
177 unsigned char reserved_2:1;
178 } __packed;
179 unsigned char data[1];
180 };
181};
182
183struct f01_device_status {
184 union {
185 struct {
186 unsigned char status_code:4;
187 unsigned char reserved:2;
188 unsigned char flash_prog:1;
189 unsigned char unconfigured:1;
190 } __packed;
191 unsigned char data[1];
192 };
193};
194
195struct f01_device_control {
196 union {
197 struct {
198 unsigned char sleep_mode:2;
199 unsigned char nosleep:1;
200 unsigned char reserved:2;
201 unsigned char charger_connected:1;
202 unsigned char report_rate:1;
203 unsigned char configured:1;
204 } __packed;
205 unsigned char data[1];
206 };
207};
208
209struct f34_flash_control {
210 union {
Alexandra Chin400f26e2013-07-25 11:58:17 -0700211 /* version 0 */
Alexandra Chin669d27c2012-12-24 15:42:30 +0800212 struct {
Alexandra Chin400f26e2013-07-25 11:58:17 -0700213 unsigned char command_v0:4;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800214 unsigned char status:3;
215 unsigned char program_enabled:1;
216 } __packed;
Alexandra Chin400f26e2013-07-25 11:58:17 -0700217 /* version 1 */
218 struct {
219 unsigned char command_v1:6;
220 unsigned char reserved:2;
221 } __packed;
222 unsigned char data[1];
223 };
224};
225
226struct f34_flash_status {
227 union {
228 struct {
229 unsigned char status:6;
230 unsigned char reserved:1;
231 unsigned char program_enabled:1;
232 } __packed;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800233 unsigned char data[1];
234 };
235};
236
237struct f34_flash_properties {
238 union {
239 struct {
240 unsigned char regmap:1;
241 unsigned char unlocked:1;
242 unsigned char has_configid:1;
243 unsigned char has_perm_config:1;
244 unsigned char has_bl_config:1;
245 unsigned char has_display_config:1;
246 unsigned char has_blob_config:1;
247 unsigned char reserved:1;
248 } __packed;
249 unsigned char data[1];
250 };
251};
252
253struct synaptics_rmi4_fwu_handle {
254 bool initialized;
Alexandra Chind5591a62013-02-07 12:59:15 -0800255 bool force_update;
Alexandra Chin823a2f52013-07-29 16:09:52 -0700256 bool do_lockdown;
Alexandra Chin400f26e2013-07-25 11:58:17 -0700257 bool interrupt_flag;
258 bool polling_mode;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800259 char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1];
260 unsigned int image_size;
261 unsigned int data_pos;
262 unsigned char intr_mask;
263 unsigned char bootloader_id[2];
264 unsigned char productinfo1;
265 unsigned char productinfo2;
266 unsigned char *ext_data_source;
267 unsigned char *read_config_buf;
268 const unsigned char *firmware_data;
269 const unsigned char *config_data;
Alexandra Chin823a2f52013-07-29 16:09:52 -0700270 const unsigned char *lockdown_data;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800271 unsigned short block_size;
272 unsigned short fw_block_count;
273 unsigned short config_block_count;
Alexandra Chin823a2f52013-07-29 16:09:52 -0700274 unsigned short lockdown_block_count;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800275 unsigned short perm_config_block_count;
276 unsigned short bl_config_block_count;
277 unsigned short disp_config_block_count;
278 unsigned short config_size;
279 unsigned short config_area;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800280 unsigned short addr_f01_interrupt_register;
Alexandra Chin823a2f52013-07-29 16:09:52 -0700281 const unsigned char *data_buffer;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800282 struct synaptics_rmi4_fn_desc f01_fd;
283 struct synaptics_rmi4_fn_desc f34_fd;
284 struct synaptics_rmi4_exp_fn_ptr *fn_ptr;
285 struct synaptics_rmi4_data *rmi4_data;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800286 struct f34_flash_properties flash_properties;
Alexandra Chind5591a62013-02-07 12:59:15 -0800287 struct workqueue_struct *fwu_workqueue;
288 struct delayed_work fwu_work;
Alexandra Chin823a2f52013-07-29 16:09:52 -0700289 char image_name[NAME_BUFFER_SIZE];
290 struct image_content image_content;
Amy Maloched9bf0d92013-06-19 17:19:23 -0700291 char *ts_info;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800292};
293
294static struct synaptics_rmi4_fwu_handle *fwu;
295
Alexandra Chind9e204d2013-07-25 15:23:01 -0700296DECLARE_COMPLETION(fwu_remove_complete);
Alexandra Chin669d27c2012-12-24 15:42:30 +0800297
298static unsigned int extract_uint(const unsigned char *ptr)
299{
300 return (unsigned int)ptr[0] +
301 (unsigned int)ptr[1] * 0x100 +
302 (unsigned int)ptr[2] * 0x10000 +
303 (unsigned int)ptr[3] * 0x1000000;
304}
305
Amy Malocheafcecb22013-04-16 18:43:22 -0700306static unsigned int extract_uint_be(const unsigned char *ptr)
307{
308 return (unsigned int)ptr[3] +
309 (unsigned int)ptr[2] * 0x100 +
310 (unsigned int)ptr[1] * 0x10000 +
311 (unsigned int)ptr[0] * 0x1000000;
312}
313
Amy Maloched9bf0d92013-06-19 17:19:23 -0700314static void synaptics_rmi4_update_debug_info(void)
315{
316 unsigned char pkg_id[4];
317 unsigned int build_id;
318 struct synaptics_rmi4_device_info *rmi;
319 /* read device package id */
320 fwu->fn_ptr->read(fwu->rmi4_data,
321 fwu->f01_fd.query_base_addr + 17,
322 pkg_id,
323 sizeof(pkg_id));
324 rmi = &(fwu->rmi4_data->rmi4_mod_info);
325
326 build_id = (unsigned int)rmi->build_id[0] +
327 (unsigned int)rmi->build_id[1] * 0x100 +
328 (unsigned int)rmi->build_id[2] * 0x10000;
329
330 RMI4_STORE_TS_INFO(fwu->ts_info, pkg_id[1] << 8 | pkg_id[0],
331 pkg_id[3] << 8 | pkg_id[2], build_id);
332}
333
Alexandra Chin823a2f52013-07-29 16:09:52 -0700334static void parse_header(void)
Alexandra Chin669d27c2012-12-24 15:42:30 +0800335{
Alexandra Chin823a2f52013-07-29 16:09:52 -0700336 struct image_content *img = &fwu->image_content;
337 struct image_header_data *data =
338 (struct image_header_data *)fwu->data_buffer;
339 img->checksum = extract_uint(data->file_checksum);
340 img->bootloader_version = data->bootloader_version;
341 img->image_size = extract_uint(data->firmware_size);
342 img->config_size = extract_uint(data->config_size);
343 memcpy(img->product_id, data->product_id,
Amy Malocheafcecb22013-04-16 18:43:22 -0700344 sizeof(data->product_id));
Alexandra Chin823a2f52013-07-29 16:09:52 -0700345 img->product_id[sizeof(data->product_id)] = 0;
Amy Maloche2c4c48c2013-05-01 20:06:23 -0700346
Alexandra Chin823a2f52013-07-29 16:09:52 -0700347 img->product_id[sizeof(data->product_info)] = 0;
348 memcpy(img->product_info, data->product_info,
Amy Malocheafcecb22013-04-16 18:43:22 -0700349 sizeof(data->product_info));
350
Alexandra Chin823a2f52013-07-29 16:09:52 -0700351 img->is_contain_build_info =
Amy Malocheafcecb22013-04-16 18:43:22 -0700352 (data->options_firmware_id == (1 << OPTION_BUILD_INFO));
Alexandra Chin823a2f52013-07-29 16:09:52 -0700353
354 if (img->is_contain_build_info) {
Sarada Prasanna Garnayakfe94fe52013-11-12 19:50:24 +0530355 img->package_id = (data->pkg_id_msb << 8) |
Amy Maloche2c4c48c2013-05-01 20:06:23 -0700356 data->pkg_id_lsb;
Alexandra Chin823a2f52013-07-29 16:09:52 -0700357 img->package_revision_id = (data->pkg_id_rev_msb << 8) |
Amy Maloche2c4c48c2013-05-01 20:06:23 -0700358 data->pkg_id_rev_lsb;
359 dev_info(&fwu->rmi4_data->i2c_client->dev,
360 "%s Package ID %d Rev %d\n", __func__,
Alexandra Chin823a2f52013-07-29 16:09:52 -0700361 img->package_id, img->package_revision_id);
Amy Maloche2c4c48c2013-05-01 20:06:23 -0700362
Alexandra Chin823a2f52013-07-29 16:09:52 -0700363 img->firmware_id = extract_uint(data->firmware_id);
Amy Malocheafcecb22013-04-16 18:43:22 -0700364 dev_info(&fwu->rmi4_data->i2c_client->dev,
365 "%s Firwmare build id %d\n", __func__,
Alexandra Chin823a2f52013-07-29 16:09:52 -0700366 img->firmware_id);
Amy Malocheafcecb22013-04-16 18:43:22 -0700367 }
Alexandra Chin669d27c2012-12-24 15:42:30 +0800368
Amy Maloche2c4c48c2013-05-01 20:06:23 -0700369 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
Alexandra Chin669d27c2012-12-24 15:42:30 +0800370 "Firwmare size %d, config size %d\n",
Alexandra Chin823a2f52013-07-29 16:09:52 -0700371 img->image_size,
372 img->config_size);
373
374 /* get UI firmware offset */
375 if (img->image_size)
376 img->firmware_data = fwu->data_buffer + FW_IMAGE_OFFSET;
377 /* get config offset*/
378 if (img->config_size)
379 img->config_data = fwu->data_buffer + FW_IMAGE_OFFSET +
380 img->image_size;
381 /* get lockdown offset*/
382 switch (img->bootloader_version) {
383 case 3:
384 case 4:
385 img->lockdown_block_count = 4;
386 break;
387 case 5:
388 case 6:
389 img->lockdown_block_count = 5;
390 break;
391 default:
392 dev_warn(&fwu->rmi4_data->i2c_client->dev,
393 "%s: Not support lockdown in " \
394 "bootloader version V%d\n",
395 __func__, img->bootloader_version);
396 img->lockdown_data = NULL;
397 }
398
399 img->lockdown_data = fwu->data_buffer +
400 FW_IMAGE_OFFSET -
401 img->lockdown_block_count * fwu->block_size;
402
403 fwu->lockdown_block_count = img->lockdown_block_count;
404 fwu->lockdown_data = img->lockdown_data;
405 fwu->config_data = img->config_data;
406 fwu->firmware_data = img->firmware_data;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800407 return;
408}
409
Alexandra Chin669d27c2012-12-24 15:42:30 +0800410static int fwu_read_f01_device_status(struct f01_device_status *status)
411{
412 int retval;
413
414 retval = fwu->fn_ptr->read(fwu->rmi4_data,
415 fwu->f01_fd.data_base_addr,
416 status->data,
417 sizeof(status->data));
418 if (retval < 0) {
419 dev_err(&fwu->rmi4_data->i2c_client->dev,
420 "%s: Failed to read F01 device status\n",
421 __func__);
422 return retval;
423 }
424
425 return 0;
426}
427
Alexandra Chin400f26e2013-07-25 11:58:17 -0700428static unsigned short fwu_get_address(enum flash_offset type)
429{
430 int offset;
431 unsigned short addr = 0;
432 struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client;
433
434 switch (type) {
435 case OFFSET_BOOTLOADER_ID:
436 offset = 0;
437 addr = fwu->f34_fd.query_base_addr + offset;
438 break;
439 case OFFSET_FLASH_PROPERTIES:
440 offset = ((fwu->f34_fd.version == 0) ? 2 : 1);
441 addr = fwu->f34_fd.query_base_addr + offset;
442 break;
443 case OFFSET_BLOCK_SIZE:
444 offset = ((fwu->f34_fd.version == 0) ? 3 : 2);
445 addr = fwu->f34_fd.query_base_addr + offset;
446 break;
447 case OFFSET_FW_BLOCK_COUNT:
448 offset = ((fwu->f34_fd.version == 0) ? 5 : 3);
449 addr = fwu->f34_fd.query_base_addr + offset;
450 break;
451 case OFFSET_BLOCK_NUMBER:
452 offset = 0;
453 addr = fwu->f34_fd.data_base_addr + offset;
454 break;
455 case OFFSET_BLOCK_DATA:
456 offset = ((fwu->f34_fd.version == 0) ? 2 : 1);
457 addr = fwu->f34_fd.data_base_addr + offset;
458 break;
459 case OFFSET_FLASH_CONTROL:
460 offset = ((fwu->f34_fd.version == 0) ?
461 2 + (fwu->block_size) : 2);
462 addr = fwu->f34_fd.data_base_addr + offset;
463 break;
464 case OFFSET_FLASH_STATUS:
465 if (fwu->f34_fd.version == 1) {
466 offset = 3;
467 addr = fwu->f34_fd.data_base_addr + offset;
468 } else if (fwu->f34_fd.version == 0) {
469 dev_warn(&i2c_client->dev,
470 "%s: F$34 version 0 does not contain " \
471 "flash status register\n",
472 __func__);
473 }
474 break;
475 default:
476 dev_err(&i2c_client->dev,
477 "%s: Unknown flash offset (%d)\n",
478 __func__, type);
479 break;
480 }
481 return addr;
482}
483
Alexandra Chin669d27c2012-12-24 15:42:30 +0800484static int fwu_read_f34_queries(void)
485{
486 int retval;
487 unsigned char count = 4;
488 unsigned char buf[10];
489 struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client;
490
491 retval = fwu->fn_ptr->read(fwu->rmi4_data,
Alexandra Chin400f26e2013-07-25 11:58:17 -0700492 fwu_get_address(OFFSET_BOOTLOADER_ID),
Alexandra Chin669d27c2012-12-24 15:42:30 +0800493 fwu->bootloader_id,
494 sizeof(fwu->bootloader_id));
495 if (retval < 0) {
496 dev_err(&i2c_client->dev,
497 "%s: Failed to read bootloader ID\n",
498 __func__);
499 return retval;
500 }
501
502 retval = fwu->fn_ptr->read(fwu->rmi4_data,
Alexandra Chin400f26e2013-07-25 11:58:17 -0700503 fwu_get_address(OFFSET_FLASH_PROPERTIES),
Alexandra Chin669d27c2012-12-24 15:42:30 +0800504 fwu->flash_properties.data,
505 sizeof(fwu->flash_properties.data));
506 if (retval < 0) {
507 dev_err(&i2c_client->dev,
508 "%s: Failed to read flash properties\n",
509 __func__);
510 return retval;
511 }
512
Alexandra Chind5591a62013-02-07 12:59:15 -0800513 dev_info(&i2c_client->dev, "%s perm:%d, bl:%d, display:%d\n",
Alexandra Chin669d27c2012-12-24 15:42:30 +0800514 __func__,
515 fwu->flash_properties.has_perm_config,
516 fwu->flash_properties.has_bl_config,
517 fwu->flash_properties.has_display_config);
518
519 if (fwu->flash_properties.has_perm_config)
520 count += 2;
521
522 if (fwu->flash_properties.has_bl_config)
523 count += 2;
524
525 if (fwu->flash_properties.has_display_config)
526 count += 2;
527
528 retval = fwu->fn_ptr->read(fwu->rmi4_data,
Alexandra Chin400f26e2013-07-25 11:58:17 -0700529 fwu_get_address(OFFSET_BLOCK_SIZE),
Alexandra Chin669d27c2012-12-24 15:42:30 +0800530 buf,
531 2);
532 if (retval < 0) {
533 dev_err(&i2c_client->dev,
534 "%s: Failed to read block size info\n",
535 __func__);
536 return retval;
537 }
538
539 batohs(&fwu->block_size, &(buf[0]));
540
541 retval = fwu->fn_ptr->read(fwu->rmi4_data,
Alexandra Chin400f26e2013-07-25 11:58:17 -0700542 fwu_get_address(OFFSET_FW_BLOCK_COUNT),
Alexandra Chin669d27c2012-12-24 15:42:30 +0800543 buf,
544 count);
545 if (retval < 0) {
546 dev_err(&i2c_client->dev,
Alexandra Chin400f26e2013-07-25 11:58:17 -0700547 "%s: Failed to read block count info\n",
548 __func__);
Alexandra Chin669d27c2012-12-24 15:42:30 +0800549 return retval;
550 }
551
552 batohs(&fwu->fw_block_count, &(buf[0]));
553 batohs(&fwu->config_block_count, &(buf[2]));
554
555 count = 4;
556
557 if (fwu->flash_properties.has_perm_config) {
558 batohs(&fwu->perm_config_block_count, &(buf[count]));
559 count += 2;
560 }
561
562 if (fwu->flash_properties.has_bl_config) {
563 batohs(&fwu->bl_config_block_count, &(buf[count]));
564 count += 2;
565 }
566
567 if (fwu->flash_properties.has_display_config)
568 batohs(&fwu->disp_config_block_count, &(buf[count]));
569
Alexandra Chin669d27c2012-12-24 15:42:30 +0800570 return 0;
571}
572
573static int fwu_read_interrupt_status(void)
574{
575 int retval;
576 unsigned char interrupt_status;
577 retval = fwu->fn_ptr->read(fwu->rmi4_data,
578 fwu->addr_f01_interrupt_register,
579 &interrupt_status,
580 sizeof(interrupt_status));
581 if (retval < 0) {
582 dev_err(&fwu->rmi4_data->i2c_client->dev,
583 "%s: Failed to read flash status\n",
584 __func__);
585 return retval;
586 }
587 return interrupt_status;
588}
589
Alexandra Chin400f26e2013-07-25 11:58:17 -0700590static int fwu_read_f34_flash_status(unsigned char *status)
Alexandra Chin669d27c2012-12-24 15:42:30 +0800591{
592 int retval;
Alexandra Chin400f26e2013-07-25 11:58:17 -0700593 struct f34_flash_control flash_control;
594 struct f34_flash_status flash_status;
595
596 if (fwu->f34_fd.version == 1) {
597 retval = fwu->fn_ptr->read(fwu->rmi4_data,
598 fwu_get_address(OFFSET_FLASH_STATUS),
599 flash_status.data,
600 sizeof(flash_status.data));
601 if (retval < 0) {
602 dev_err(&fwu->rmi4_data->i2c_client->dev,
Alexandra Chin669d27c2012-12-24 15:42:30 +0800603 "%s: Failed to read flash status\n",
604 __func__);
Alexandra Chin400f26e2013-07-25 11:58:17 -0700605 return -EIO;
606 }
607 *status = flash_status.status;
608 } else {
609 retval = fwu->fn_ptr->read(fwu->rmi4_data,
610 fwu_get_address(OFFSET_FLASH_CONTROL),
611 flash_control.data,
612 sizeof(flash_control.data));
613 if (retval < 0) {
614 dev_err(&fwu->rmi4_data->i2c_client->dev,
615 "%s: Failed to read flash status\n",
616 __func__);
617 return -EIO;
618 }
619 *status = flash_control.status;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800620 }
621 return 0;
622}
623
624static int fwu_reset_device(void)
625{
626 int retval;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800627
Amy Maloche2c4c48c2013-05-01 20:06:23 -0700628 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
Alexandra Chind5591a62013-02-07 12:59:15 -0800629 "%s: Reset device\n",
630 __func__);
Alexandra Chin669d27c2012-12-24 15:42:30 +0800631
Alexandra Chin669d27c2012-12-24 15:42:30 +0800632 retval = fwu->rmi4_data->reset_device(fwu->rmi4_data);
633 if (retval < 0) {
634 dev_err(&fwu->rmi4_data->i2c_client->dev,
635 "%s: Failed to reset core driver after reflash\n",
636 __func__);
637 return retval;
638 }
Alexandra Chin400f26e2013-07-25 11:58:17 -0700639
640 fwu->polling_mode = false;
641
Alexandra Chin669d27c2012-12-24 15:42:30 +0800642 return 0;
643}
644
645static int fwu_write_f34_command(unsigned char cmd)
646{
647 int retval;
Alexandra Chin400f26e2013-07-25 11:58:17 -0700648 struct f34_flash_control flash_control;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800649
Alexandra Chin400f26e2013-07-25 11:58:17 -0700650 flash_control.data[0] = cmd;
651 fwu->interrupt_flag = false;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800652 retval = fwu->fn_ptr->write(fwu->rmi4_data,
Alexandra Chin400f26e2013-07-25 11:58:17 -0700653 fwu_get_address(OFFSET_FLASH_CONTROL),
654 flash_control.data,
655 sizeof(flash_control.data));
Alexandra Chin669d27c2012-12-24 15:42:30 +0800656 if (retval < 0) {
657 dev_err(&fwu->rmi4_data->i2c_client->dev,
658 "%s: Failed to write command 0x%02x\n",
Alexandra Chin400f26e2013-07-25 11:58:17 -0700659 __func__, flash_control.data[0]);
Alexandra Chin669d27c2012-12-24 15:42:30 +0800660 return retval;
661 }
662 return 0;
663}
664
Alexandra Chin669d27c2012-12-24 15:42:30 +0800665static int fwu_wait_for_idle(int timeout_ms)
666{
667 int count = 0;
Alexandra Chind5591a62013-02-07 12:59:15 -0800668 int timeout_count = ((timeout_ms * 1000) / SLEEP_TIME_US) + 1;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800669 do {
Alexandra Chin400f26e2013-07-25 11:58:17 -0700670 if (fwu->interrupt_flag)
Alexandra Chin669d27c2012-12-24 15:42:30 +0800671 return 0;
Alexandra Chin400f26e2013-07-25 11:58:17 -0700672 if (fwu->polling_mode)
673 if (fwu->intr_mask & fwu_read_interrupt_status())
674 return 0;
675 usleep_range(SLEEP_TIME_US, SLEEP_TIME_US + 1);
Alexandra Chind5591a62013-02-07 12:59:15 -0800676 } while (count++ < timeout_count);
677
Alexandra Chin400f26e2013-07-25 11:58:17 -0700678 if (fwu->intr_mask & fwu_read_interrupt_status()) {
679 fwu->polling_mode = true;
680 dev_info(&fwu->rmi4_data->i2c_client->dev,
681 "%s: Switch to polling mode\n",
682 __func__);
Alexandra Chind5591a62013-02-07 12:59:15 -0800683 return 0;
Alexandra Chin400f26e2013-07-25 11:58:17 -0700684 }
Alexandra Chin669d27c2012-12-24 15:42:30 +0800685
686 dev_err(&fwu->rmi4_data->i2c_client->dev,
687 "%s: Timed out waiting for idle status\n",
688 __func__);
689
690 return -ETIMEDOUT;
691}
692
Alexandra Chin823a2f52013-07-29 16:09:52 -0700693static enum flash_area fwu_go_nogo(void)
Alexandra Chind5591a62013-02-07 12:59:15 -0800694{
695 int retval = 0;
696 int index = 0;
697 int deviceFirmwareID;
698 int imageConfigID;
699 int deviceConfigID;
700 unsigned long imageFirmwareID;
701 unsigned char firmware_id[4];
702 unsigned char config_id[4];
Amy Maloche2c4c48c2013-05-01 20:06:23 -0700703 unsigned char pkg_id[4];
Alexandra Chind5591a62013-02-07 12:59:15 -0800704 char *strptr;
705 char *imagePR = kzalloc(sizeof(MAX_FIRMWARE_ID_LEN), GFP_KERNEL);
706 enum flash_area flash_area = NONE;
707 struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client;
708 struct f01_device_status f01_device_status;
Alexandra Chin823a2f52013-07-29 16:09:52 -0700709 struct image_content *img = &fwu->image_content;
Alexandra Chind5591a62013-02-07 12:59:15 -0800710
711 if (fwu->force_update) {
712 flash_area = UI_FIRMWARE;
713 goto exit;
714 }
715
Alexandra Chin823a2f52013-07-29 16:09:52 -0700716 if (img->is_contain_build_info) {
Amy Maloche2c4c48c2013-05-01 20:06:23 -0700717 /* if package id does not match, do not update firmware */
718 fwu->fn_ptr->read(fwu->rmi4_data,
719 fwu->f01_fd.query_base_addr + 17,
720 pkg_id,
721 sizeof(pkg_id));
722
Alexandra Chin823a2f52013-07-29 16:09:52 -0700723 if (img->package_id != ((pkg_id[1] << 8) | pkg_id[0])) {
Amy Maloche2c4c48c2013-05-01 20:06:23 -0700724 flash_area = MISMATCH;
725 goto exit;
726 }
Alexandra Chin823a2f52013-07-29 16:09:52 -0700727 if (img->package_revision_id !=
Amy Maloche2c4c48c2013-05-01 20:06:23 -0700728 ((pkg_id[3] << 8) | pkg_id[2])) {
729 flash_area = MISMATCH;
730 goto exit;
731 }
732 }
733
Alexandra Chin400f26e2013-07-25 11:58:17 -0700734 /* check firmware size */
Alexandra Chin823a2f52013-07-29 16:09:52 -0700735 if (fwu->fw_block_count*fwu->block_size != img->image_size) {
Alexandra Chin400f26e2013-07-25 11:58:17 -0700736 dev_err(&i2c_client->dev,
737 "%s: firmware size of device (%d) != .img (%d)\n",
738 __func__,
739 fwu->config_block_count * fwu->block_size,
Alexandra Chin823a2f52013-07-29 16:09:52 -0700740 img->image_size);
Alexandra Chin400f26e2013-07-25 11:58:17 -0700741 flash_area = NONE;
742 goto exit;
743 }
744
745 /* check config size */
Alexandra Chin823a2f52013-07-29 16:09:52 -0700746 if (fwu->config_block_count*fwu->block_size != img->config_size) {
Alexandra Chin400f26e2013-07-25 11:58:17 -0700747 dev_err(&i2c_client->dev,
748 "%s: config size of device (%d) != .img (%d)\n",
749 __func__,
750 fwu->config_block_count * fwu->block_size,
Alexandra Chin823a2f52013-07-29 16:09:52 -0700751 img->config_size);
Alexandra Chin400f26e2013-07-25 11:58:17 -0700752 flash_area = NONE;
753 goto exit;
754 }
755
Alexandra Chind5591a62013-02-07 12:59:15 -0800756 retval = fwu_read_f01_device_status(&f01_device_status);
757 if (retval < 0) {
758 flash_area = NONE;
759 goto exit;
760 }
761
Alexandra Chind5591a62013-02-07 12:59:15 -0800762 /* Force update firmware when device is in bootloader mode */
763 if (f01_device_status.flash_prog) {
764 dev_info(&i2c_client->dev,
765 "%s: In flash prog mode\n",
766 __func__);
767 flash_area = UI_FIRMWARE;
768 goto exit;
769 }
770
Alexandra Chind5591a62013-02-07 12:59:15 -0800771 /* device firmware id */
772 retval = fwu->fn_ptr->read(fwu->rmi4_data,
773 fwu->f01_fd.query_base_addr + 18,
774 firmware_id,
775 sizeof(firmware_id));
776 if (retval < 0) {
777 dev_err(&i2c_client->dev,
Amy Malocheafcecb22013-04-16 18:43:22 -0700778 "%s: Failed to read firmware ID (code %d).\n",
779 __func__, retval);
Alexandra Chind5591a62013-02-07 12:59:15 -0800780 goto exit;
781 }
782 firmware_id[3] = 0;
783 deviceFirmwareID = extract_uint(firmware_id);
784
785 /* .img firmware id */
Alexandra Chin823a2f52013-07-29 16:09:52 -0700786 if (img->is_contain_build_info) {
Alexandra Chind5591a62013-02-07 12:59:15 -0800787 dev_err(&i2c_client->dev,
Amy Malocheafcecb22013-04-16 18:43:22 -0700788 "%s: Image option contains build info.\n",
789 __func__);
Alexandra Chin823a2f52013-07-29 16:09:52 -0700790 imageFirmwareID = img->firmware_id;
Amy Malocheafcecb22013-04-16 18:43:22 -0700791 } else {
Alexandra Chin823a2f52013-07-29 16:09:52 -0700792 if (!fwu->image_name) {
793 dev_info(&i2c_client->dev,
794 "%s: Unknown image file name\n",
795 __func__);
796 flash_area = UI_FIRMWARE;
797 goto exit;
798 }
799 strptr = strnstr(fwu->image_name, "PR",
800 sizeof(fwu->image_name));
Amy Malocheafcecb22013-04-16 18:43:22 -0700801 if (!strptr) {
802 dev_err(&i2c_client->dev,
803 "No valid PR number (PRxxxxxxx)" \
804 "found in image file name...\n");
805 goto exit;
806 }
807
808 strptr += 2;
809 while (strptr[index] >= '0' && strptr[index] <= '9') {
810 imagePR[index] = strptr[index];
811 index++;
812 }
813 imagePR[index] = 0;
814
815 retval = kstrtoul(imagePR, 10, &imageFirmwareID);
816 if (retval == -EINVAL) {
817 dev_err(&i2c_client->dev,
818 "invalid image firmware id...\n");
819 goto exit;
820 }
Alexandra Chind5591a62013-02-07 12:59:15 -0800821 }
822
Amy Malocheafcecb22013-04-16 18:43:22 -0700823 dev_dbg(&i2c_client->dev,
Alexandra Chind5591a62013-02-07 12:59:15 -0800824 "Device firmware id %d, .img firmware id %d\n",
825 deviceFirmwareID,
826 (unsigned int)imageFirmwareID);
827 if (imageFirmwareID > deviceFirmwareID) {
828 flash_area = UI_FIRMWARE;
829 goto exit;
Alexandra Chinc556cf02013-03-19 17:46:05 -0700830 } else if (imageFirmwareID < deviceFirmwareID) {
831 flash_area = NONE;
832 dev_info(&i2c_client->dev,
Amy Malocheafcecb22013-04-16 18:43:22 -0700833 "%s: Img fw is older than device fw. Skip fw update.\n",
834 __func__);
Alexandra Chinc556cf02013-03-19 17:46:05 -0700835 goto exit;
Alexandra Chind5591a62013-02-07 12:59:15 -0800836 }
837
838 /* device config id */
839 retval = fwu->fn_ptr->read(fwu->rmi4_data,
840 fwu->f34_fd.ctrl_base_addr,
841 config_id,
842 sizeof(config_id));
843 if (retval < 0) {
844 dev_err(&i2c_client->dev,
Amy Malocheafcecb22013-04-16 18:43:22 -0700845 "%s: Failed to read config ID (code %d).\n",
846 __func__, retval);
Alexandra Chind5591a62013-02-07 12:59:15 -0800847 flash_area = NONE;
848 goto exit;
849 }
Amy Malocheafcecb22013-04-16 18:43:22 -0700850 deviceConfigID = extract_uint_be(config_id);
Alexandra Chind5591a62013-02-07 12:59:15 -0800851
Amy Malocheafcecb22013-04-16 18:43:22 -0700852 dev_dbg(&i2c_client->dev,
Alexandra Chind5591a62013-02-07 12:59:15 -0800853 "Device config ID 0x%02X, 0x%02X, 0x%02X, 0x%02X\n",
854 config_id[0], config_id[1], config_id[2], config_id[3]);
855
856 /* .img config id */
Amy Malocheafcecb22013-04-16 18:43:22 -0700857 dev_dbg(&i2c_client->dev,
Alexandra Chind5591a62013-02-07 12:59:15 -0800858 ".img config ID 0x%02X, 0x%02X, 0x%02X, 0x%02X\n",
859 fwu->config_data[0],
860 fwu->config_data[1],
861 fwu->config_data[2],
862 fwu->config_data[3]);
Amy Malocheafcecb22013-04-16 18:43:22 -0700863 imageConfigID = extract_uint_be(fwu->config_data);
864
865 dev_dbg(&i2c_client->dev,
866 "%s: Device config ID %d, .img config ID %d\n",
867 __func__, deviceConfigID, imageConfigID);
Alexandra Chind5591a62013-02-07 12:59:15 -0800868
869 if (imageConfigID > deviceConfigID) {
870 flash_area = CONFIG_AREA;
871 goto exit;
872 }
Alexandra Chind5591a62013-02-07 12:59:15 -0800873exit:
874 kfree(imagePR);
Amy Maloche2c4c48c2013-05-01 20:06:23 -0700875 if (flash_area == MISMATCH)
876 dev_info(&i2c_client->dev,
877 "%s: Package ID indicates mismatch of firmware and" \
878 " controller compatibility\n", __func__);
879 else if (flash_area == NONE)
Alexandra Chind5591a62013-02-07 12:59:15 -0800880 dev_info(&i2c_client->dev,
Amy Malocheafcecb22013-04-16 18:43:22 -0700881 "%s: Nothing needs to be updated\n", __func__);
Alexandra Chind5591a62013-02-07 12:59:15 -0800882 else
883 dev_info(&i2c_client->dev,
Amy Malocheafcecb22013-04-16 18:43:22 -0700884 "%s: Update %s block\n", __func__,
Alexandra Chind5591a62013-02-07 12:59:15 -0800885 flash_area == UI_FIRMWARE ? "UI FW" : "CONFIG");
886 return flash_area;
887}
888
Alexandra Chin669d27c2012-12-24 15:42:30 +0800889static int fwu_scan_pdt(void)
890{
891 int retval;
892 unsigned char ii;
893 unsigned char intr_count = 0;
894 unsigned char intr_off;
895 unsigned char intr_src;
896 unsigned short addr;
897 bool f01found = false;
898 bool f34found = false;
899 struct synaptics_rmi4_fn_desc rmi_fd;
900
Amy Maloche2c4c48c2013-05-01 20:06:23 -0700901 dev_dbg(&fwu->rmi4_data->i2c_client->dev, "Scan PDT\n");
Alexandra Chin669d27c2012-12-24 15:42:30 +0800902
903 for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
904 retval = fwu->fn_ptr->read(fwu->rmi4_data,
905 addr,
906 (unsigned char *)&rmi_fd,
907 sizeof(rmi_fd));
908 if (retval < 0)
909 return retval;
910
911 if (rmi_fd.fn_number) {
912 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
913 "%s: Found F%02x\n",
914 __func__, rmi_fd.fn_number);
915 switch (rmi_fd.fn_number) {
916 case SYNAPTICS_RMI4_F01:
917 f01found = true;
918 fwu->f01_fd = rmi_fd;
919 fwu->addr_f01_interrupt_register =
920 fwu->f01_fd.data_base_addr + 1;
921 break;
922 case SYNAPTICS_RMI4_F34:
923 f34found = true;
924 fwu->f34_fd = rmi_fd;
925 fwu->intr_mask = 0;
926 intr_src = rmi_fd.intr_src_count;
927 intr_off = intr_count % 8;
928 for (ii = intr_off;
929 ii < ((intr_src & MASK_3BIT) +
930 intr_off);
931 ii++)
932 fwu->intr_mask |= 1 << ii;
933 break;
934 }
935 } else
936 break;
937
938 intr_count += (rmi_fd.intr_src_count & MASK_3BIT);
939 }
940
941 if (!f01found || !f34found) {
942 dev_err(&fwu->rmi4_data->i2c_client->dev,
943 "%s: Failed to find both F01 and F34\n",
944 __func__);
945 return -EINVAL;
946 }
947
948 fwu_read_interrupt_status();
949 return 0;
950}
951
952static int fwu_write_blocks(unsigned char *block_ptr, unsigned short block_cnt,
953 unsigned char command)
954{
955 int retval;
Alexandra Chin400f26e2013-07-25 11:58:17 -0700956 unsigned char flash_status;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800957 unsigned char block_offset[] = {0, 0};
958 unsigned short block_num;
Alexandra Chin400f26e2013-07-25 11:58:17 -0700959 unsigned short addr_block_data = fwu_get_address(OFFSET_BLOCK_DATA);
960 unsigned short addr_block_num = fwu_get_address(OFFSET_BLOCK_NUMBER);
Alexandra Chind5591a62013-02-07 12:59:15 -0800961 struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800962#ifdef SHOW_PROGRESS
Alexandra Chin823a2f52013-07-29 16:09:52 -0700963 unsigned int progress;
964 unsigned char command_str[10];
965 switch (command) {
966 case CMD_WRITE_CONFIG_BLOCK:
967 progress = 10;
968 strlcpy(command_str, "config", 10);
969 break;
970 case CMD_WRITE_FW_BLOCK:
971 progress = 100;
972 strlcpy(command_str, "firmware", 10);
973 break;
974 case CMD_WRITE_LOCKDOWN_BLOCK:
975 progress = 1;
976 strlcpy(command_str, "lockdown", 10);
977 break;
978 default:
979 progress = 1;
980 strlcpy(command_str, "unknown", 10);
981 break;
982 }
Alexandra Chin669d27c2012-12-24 15:42:30 +0800983#endif
Alexandra Chind5591a62013-02-07 12:59:15 -0800984
Amy Maloche2c4c48c2013-05-01 20:06:23 -0700985 dev_dbg(&i2c_client->dev,
Alexandra Chind5591a62013-02-07 12:59:15 -0800986 "%s: Start to update %s blocks\n",
987 __func__,
Alexandra Chin823a2f52013-07-29 16:09:52 -0700988 command_str);
Alexandra Chin669d27c2012-12-24 15:42:30 +0800989 retval = fwu->fn_ptr->write(fwu->rmi4_data,
Alexandra Chin400f26e2013-07-25 11:58:17 -0700990 addr_block_num,
Alexandra Chin669d27c2012-12-24 15:42:30 +0800991 block_offset,
992 sizeof(block_offset));
993 if (retval < 0) {
Alexandra Chind5591a62013-02-07 12:59:15 -0800994 dev_err(&i2c_client->dev,
Alexandra Chin669d27c2012-12-24 15:42:30 +0800995 "%s: Failed to write to block number registers\n",
996 __func__);
997 return retval;
998 }
999
1000 for (block_num = 0; block_num < block_cnt; block_num++) {
1001#ifdef SHOW_PROGRESS
1002 if (block_num % progress == 0)
Alexandra Chind5591a62013-02-07 12:59:15 -08001003 dev_info(&i2c_client->dev,
1004 "%s: update %s %3d / %3d\n",
1005 __func__,
Alexandra Chin823a2f52013-07-29 16:09:52 -07001006 command_str,
Alexandra Chind5591a62013-02-07 12:59:15 -08001007 block_num, block_cnt);
Alexandra Chin669d27c2012-12-24 15:42:30 +08001008#endif
1009 retval = fwu->fn_ptr->write(fwu->rmi4_data,
Alexandra Chin400f26e2013-07-25 11:58:17 -07001010 addr_block_data,
Alexandra Chin669d27c2012-12-24 15:42:30 +08001011 block_ptr,
1012 fwu->block_size);
1013 if (retval < 0) {
Alexandra Chind5591a62013-02-07 12:59:15 -08001014 dev_err(&i2c_client->dev,
Alexandra Chin669d27c2012-12-24 15:42:30 +08001015 "%s: Failed to write block data (block %d)\n",
1016 __func__, block_num);
1017 return retval;
1018 }
1019
1020 retval = fwu_write_f34_command(command);
1021 if (retval < 0) {
Alexandra Chind5591a62013-02-07 12:59:15 -08001022 dev_err(&i2c_client->dev,
Alexandra Chin669d27c2012-12-24 15:42:30 +08001023 "%s: Failed to write command for block %d\n",
1024 __func__, block_num);
1025 return retval;
1026 }
1027
1028 retval = fwu_wait_for_idle(WRITE_WAIT_MS);
1029 if (retval < 0) {
Alexandra Chind5591a62013-02-07 12:59:15 -08001030 dev_err(&i2c_client->dev,
1031 "%s: Failed to wait for idle status (block %d)\n",
1032 __func__, block_num);
Alexandra Chin669d27c2012-12-24 15:42:30 +08001033 return retval;
1034 }
1035
Alexandra Chin400f26e2013-07-25 11:58:17 -07001036 #if CHECK_FLASH_BLOCK_STATUS
1037 retval = fwu_read_f34_flash_status(&flash_status);
1038 if (retval < 0) {
Alexandra Chind5591a62013-02-07 12:59:15 -08001039 dev_err(&i2c_client->dev,
Alexandra Chin400f26e2013-07-25 11:58:17 -07001040 "%s: Failed to read flash status (block %d)\n",
1041 __func__, block_num);
Shantanu Jain41f0d472013-01-04 12:14:37 +05301042 return retval;
Alexandra Chin669d27c2012-12-24 15:42:30 +08001043 }
Alexandra Chin400f26e2013-07-25 11:58:17 -07001044 if (flash_status != 0x00) {
1045 dev_err(&i2c_client->dev,
1046 "%s: Flash block %d failed, status 0x%02X\n",
1047 __func__, block_num, flash_status);
1048 return -EINVAL;
1049 }
1050 #endif
Alexandra Chin669d27c2012-12-24 15:42:30 +08001051 block_ptr += fwu->block_size;
1052 }
1053#ifdef SHOW_PROGRESS
Alexandra Chind5591a62013-02-07 12:59:15 -08001054 dev_info(&i2c_client->dev,
1055 "%s: update %s %3d / %3d\n",
1056 __func__,
Alexandra Chin823a2f52013-07-29 16:09:52 -07001057 command_str,
Alexandra Chind5591a62013-02-07 12:59:15 -08001058 block_cnt, block_cnt);
Alexandra Chin669d27c2012-12-24 15:42:30 +08001059#endif
1060 return 0;
1061}
1062
1063static int fwu_write_firmware(void)
1064{
1065 return fwu_write_blocks((unsigned char *)fwu->firmware_data,
1066 fwu->fw_block_count, CMD_WRITE_FW_BLOCK);
1067}
1068
1069static int fwu_write_configuration(void)
1070{
1071 return fwu_write_blocks((unsigned char *)fwu->config_data,
1072 fwu->config_block_count, CMD_WRITE_CONFIG_BLOCK);
1073}
1074
Alexandra Chin823a2f52013-07-29 16:09:52 -07001075static int fwu_write_lockdown_block(void)
1076{
1077 return fwu_write_blocks((unsigned char *)fwu->lockdown_data,
1078 fwu->lockdown_block_count, CMD_WRITE_LOCKDOWN_BLOCK);
1079}
1080
Alexandra Chin669d27c2012-12-24 15:42:30 +08001081static int fwu_write_bootloader_id(void)
1082{
1083 int retval;
1084
Amy Maloche2c4c48c2013-05-01 20:06:23 -07001085 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
Alexandra Chind5591a62013-02-07 12:59:15 -08001086 "Write bootloader ID 0x%02X 0x%02X\n",
1087 fwu->bootloader_id[0],
1088 fwu->bootloader_id[1]);
Amy Maloche2c4c48c2013-05-01 20:06:23 -07001089
Alexandra Chin669d27c2012-12-24 15:42:30 +08001090 retval = fwu->fn_ptr->write(fwu->rmi4_data,
Alexandra Chin400f26e2013-07-25 11:58:17 -07001091 fwu_get_address(OFFSET_BLOCK_DATA),
Alexandra Chin669d27c2012-12-24 15:42:30 +08001092 fwu->bootloader_id,
1093 sizeof(fwu->bootloader_id));
1094 if (retval < 0) {
1095 dev_err(&fwu->rmi4_data->i2c_client->dev,
1096 "%s: Failed to write bootloader ID\n",
1097 __func__);
1098 return retval;
1099 }
1100
1101 return 0;
1102}
1103
Alexandra Chin823a2f52013-07-29 16:09:52 -07001104static int fwu_enter_flash_prog(bool force)
Alexandra Chin669d27c2012-12-24 15:42:30 +08001105{
1106 int retval;
1107 struct f01_device_status f01_device_status;
1108 struct f01_device_control f01_device_control;
1109
Amy Maloche2c4c48c2013-05-01 20:06:23 -07001110 dev_dbg(&fwu->rmi4_data->i2c_client->dev, "Enter bootloader mode\n");
1111
Alexandra Chin669d27c2012-12-24 15:42:30 +08001112 retval = fwu_read_f01_device_status(&f01_device_status);
1113 if (retval < 0)
1114 return retval;
1115
Amy Malochecb78b1d2013-08-27 16:34:11 -07001116 if (force) {
1117 dev_info(&fwu->rmi4_data->i2c_client->dev,
1118 "%s: Force to enter flash prog mode\n",
1119 __func__);
1120 } else if (f01_device_status.flash_prog) {
Alexandra Chin669d27c2012-12-24 15:42:30 +08001121 dev_info(&fwu->rmi4_data->i2c_client->dev,
1122 "%s: Already in flash prog mode\n",
1123 __func__);
1124 return 0;
1125 }
1126
1127 retval = fwu_write_bootloader_id();
1128 if (retval < 0)
1129 return retval;
1130
1131 retval = fwu_write_f34_command(CMD_ENABLE_FLASH_PROG);
1132 if (retval < 0)
1133 return retval;
1134
1135 retval = fwu_wait_for_idle(ENABLE_WAIT_MS);
1136 if (retval < 0)
1137 return retval;
1138
Alexandra Chin669d27c2012-12-24 15:42:30 +08001139 retval = fwu_scan_pdt();
1140 if (retval < 0)
1141 return retval;
1142
1143 retval = fwu_read_f01_device_status(&f01_device_status);
1144 if (retval < 0)
1145 return retval;
1146
1147 if (!f01_device_status.flash_prog) {
1148 dev_err(&fwu->rmi4_data->i2c_client->dev,
1149 "%s: Not in flash prog mode\n",
1150 __func__);
1151 return -EINVAL;
1152 }
1153
1154 retval = fwu_read_f34_queries();
1155 if (retval < 0)
1156 return retval;
1157
1158 retval = fwu->fn_ptr->read(fwu->rmi4_data,
1159 fwu->f01_fd.ctrl_base_addr,
1160 f01_device_control.data,
1161 sizeof(f01_device_control.data));
1162 if (retval < 0) {
1163 dev_err(&fwu->rmi4_data->i2c_client->dev,
1164 "%s: Failed to read F01 device control\n",
1165 __func__);
1166 return retval;
1167 }
1168
1169 f01_device_control.nosleep = true;
1170 f01_device_control.sleep_mode = SLEEP_MODE_NORMAL;
1171
1172 retval = fwu->fn_ptr->write(fwu->rmi4_data,
1173 fwu->f01_fd.ctrl_base_addr,
1174 f01_device_control.data,
1175 sizeof(f01_device_control.data));
1176 if (retval < 0) {
1177 dev_err(&fwu->rmi4_data->i2c_client->dev,
1178 "%s: Failed to write F01 device control\n",
1179 __func__);
1180 return retval;
1181 }
Alexandra Chin400f26e2013-07-25 11:58:17 -07001182 fwu->polling_mode = false;
Alexandra Chin669d27c2012-12-24 15:42:30 +08001183 return retval;
1184}
1185
Alexandra Chin669d27c2012-12-24 15:42:30 +08001186static int fwu_do_write_config(void)
1187{
1188 int retval;
1189
Alexandra Chin823a2f52013-07-29 16:09:52 -07001190 retval = fwu_enter_flash_prog(false);
Alexandra Chin669d27c2012-12-24 15:42:30 +08001191 if (retval < 0)
1192 return retval;
1193
1194 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
1195 "%s: Entered flash prog mode\n",
1196 __func__);
1197
1198 if (fwu->config_area == PERM_CONFIG_AREA) {
1199 fwu->config_block_count = fwu->perm_config_block_count;
1200 goto write_config;
1201 }
1202
1203 retval = fwu_write_bootloader_id();
1204 if (retval < 0)
1205 return retval;
1206
1207 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
1208 "%s: Bootloader ID written\n",
1209 __func__);
1210
1211 switch (fwu->config_area) {
1212 case UI_CONFIG_AREA:
1213 retval = fwu_write_f34_command(CMD_ERASE_CONFIG);
1214 break;
1215 case BL_CONFIG_AREA:
1216 retval = fwu_write_f34_command(CMD_ERASE_BL_CONFIG);
1217 fwu->config_block_count = fwu->bl_config_block_count;
1218 break;
1219 case DISP_CONFIG_AREA:
1220 retval = fwu_write_f34_command(CMD_ERASE_DISP_CONFIG);
1221 fwu->config_block_count = fwu->disp_config_block_count;
1222 break;
1223 }
1224 if (retval < 0)
1225 return retval;
1226
1227 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
1228 "%s: Erase command written\n",
1229 __func__);
1230
1231 retval = fwu_wait_for_idle(ERASE_WAIT_MS);
1232 if (retval < 0)
1233 return retval;
1234
1235 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
1236 "%s: Idle status detected\n",
1237 __func__);
1238
1239write_config:
1240 retval = fwu_write_configuration();
1241 if (retval < 0)
1242 return retval;
1243
1244 pr_notice("%s: Config written\n", __func__);
1245
1246 return retval;
1247}
1248
1249static int fwu_start_write_config(void)
1250{
1251 int retval;
Alexandra Chin823a2f52013-07-29 16:09:52 -07001252 int block_count;
Alexandra Chin669d27c2012-12-24 15:42:30 +08001253
1254 switch (fwu->config_area) {
1255 case UI_CONFIG_AREA:
Alexandra Chin823a2f52013-07-29 16:09:52 -07001256 block_count = fwu->config_block_count;
Alexandra Chin669d27c2012-12-24 15:42:30 +08001257 break;
1258 case PERM_CONFIG_AREA:
1259 if (!fwu->flash_properties.has_perm_config)
1260 return -EINVAL;
Alexandra Chin823a2f52013-07-29 16:09:52 -07001261 block_count = fwu->perm_config_block_count;
Alexandra Chin669d27c2012-12-24 15:42:30 +08001262 break;
1263 case BL_CONFIG_AREA:
1264 if (!fwu->flash_properties.has_bl_config)
1265 return -EINVAL;
Alexandra Chin823a2f52013-07-29 16:09:52 -07001266 block_count = fwu->bl_config_block_count;
Alexandra Chin669d27c2012-12-24 15:42:30 +08001267 break;
1268 case DISP_CONFIG_AREA:
1269 if (!fwu->flash_properties.has_display_config)
1270 return -EINVAL;
Alexandra Chin823a2f52013-07-29 16:09:52 -07001271 block_count = fwu->disp_config_block_count;
Alexandra Chin669d27c2012-12-24 15:42:30 +08001272 break;
1273 default:
1274 return -EINVAL;
1275 }
1276
Alexandra Chin823a2f52013-07-29 16:09:52 -07001277 if (fwu->image_size == block_count*fwu->block_size) {
1278 dev_info(&fwu->rmi4_data->i2c_client->dev,
1279 "%s: write config from config file\n",
1280 __func__);
1281 fwu->config_data = fwu->data_buffer;
1282 } else {
1283 parse_header();
Alexandra Chin669d27c2012-12-24 15:42:30 +08001284 }
1285
1286 pr_notice("%s: Start of write config process\n", __func__);
1287
1288 retval = fwu_do_write_config();
1289 if (retval < 0) {
1290 dev_err(&fwu->rmi4_data->i2c_client->dev,
1291 "%s: Failed to write config\n",
1292 __func__);
1293 }
1294
1295 fwu->rmi4_data->reset_device(fwu->rmi4_data);
1296
1297 pr_notice("%s: End of write config process\n", __func__);
1298
1299 return retval;
1300}
1301
Alexandra Chin823a2f52013-07-29 16:09:52 -07001302static int fwu_do_write_lockdown(bool reset)
1303{
1304 int retval;
1305
1306 pr_notice("%s: Start of lockdown process\n", __func__);
1307
1308 retval = fwu_enter_flash_prog(false);
1309 if (retval < 0)
1310 return retval;
1311
1312 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
1313 "%s: Entered flash prog mode\n",
1314 __func__);
1315
1316 if (fwu->flash_properties.unlocked == 0) {
1317 dev_err(&fwu->rmi4_data->i2c_client->dev,
1318 "%s: Device has been locked!\n",
1319 __func__);
1320 if (reset)
1321 goto exit;
1322 else
1323 return -EINVAL;
1324 }
1325
1326 retval = fwu_write_lockdown_block();
1327 if (retval < 0)
1328 return retval;
1329
1330 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
1331 "%s:Lockdown device\n",
1332 __func__);
1333
1334exit:
1335 if (reset)
1336 retval = fwu->rmi4_data->reset_device(fwu->rmi4_data);
1337 else
1338 retval = fwu_enter_flash_prog(true);
1339
1340 if (retval < 0)
1341 return retval;
1342
1343 pr_notice("%s: End of lockdown process\n", __func__);
1344
1345 return retval;
1346}
1347
1348static int fwu_start_write_lockdown(void)
1349{
1350 parse_header();
1351 return fwu_do_write_lockdown(true);
1352}
1353
Alexandra Chin669d27c2012-12-24 15:42:30 +08001354static int fwu_do_read_config(void)
1355{
1356 int retval;
1357 unsigned char block_offset[] = {0, 0};
1358 unsigned short block_num;
1359 unsigned short block_count;
1360 unsigned short index = 0;
1361
Alexandra Chin669d27c2012-12-24 15:42:30 +08001362 switch (fwu->config_area) {
1363 case UI_CONFIG_AREA:
1364 block_count = fwu->config_block_count;
1365 break;
1366 case PERM_CONFIG_AREA:
1367 if (!fwu->flash_properties.has_perm_config) {
1368 retval = -EINVAL;
1369 goto exit;
1370 }
1371 block_count = fwu->perm_config_block_count;
1372 break;
1373 case BL_CONFIG_AREA:
1374 if (!fwu->flash_properties.has_bl_config) {
1375 retval = -EINVAL;
1376 goto exit;
1377 }
1378 block_count = fwu->bl_config_block_count;
1379 break;
1380 case DISP_CONFIG_AREA:
1381 if (!fwu->flash_properties.has_display_config) {
1382 retval = -EINVAL;
1383 goto exit;
1384 }
1385 block_count = fwu->disp_config_block_count;
1386 break;
1387 default:
1388 retval = -EINVAL;
1389 goto exit;
1390 }
1391
1392 fwu->config_size = fwu->block_size * block_count;
1393
1394 kfree(fwu->read_config_buf);
1395 fwu->read_config_buf = kzalloc(fwu->config_size, GFP_KERNEL);
1396
1397 block_offset[1] |= (fwu->config_area << 5);
1398
1399 retval = fwu->fn_ptr->write(fwu->rmi4_data,
Alexandra Chin400f26e2013-07-25 11:58:17 -07001400 fwu_get_address(OFFSET_BLOCK_NUMBER),
Alexandra Chin669d27c2012-12-24 15:42:30 +08001401 block_offset,
1402 sizeof(block_offset));
1403 if (retval < 0) {
1404 dev_err(&fwu->rmi4_data->i2c_client->dev,
1405 "%s: Failed to write to block number registers\n",
1406 __func__);
1407 goto exit;
1408 }
1409
1410 for (block_num = 0; block_num < block_count; block_num++) {
1411 retval = fwu_write_f34_command(CMD_READ_CONFIG_BLOCK);
1412 if (retval < 0) {
1413 dev_err(&fwu->rmi4_data->i2c_client->dev,
1414 "%s: Failed to write read config command\n",
1415 __func__);
1416 goto exit;
1417 }
1418
1419 retval = fwu_wait_for_idle(WRITE_WAIT_MS);
1420 if (retval < 0) {
1421 dev_err(&fwu->rmi4_data->i2c_client->dev,
1422 "%s: Failed to wait for idle status\n",
1423 __func__);
1424 goto exit;
1425 }
1426
1427 retval = fwu->fn_ptr->read(fwu->rmi4_data,
Alexandra Chin400f26e2013-07-25 11:58:17 -07001428 fwu_get_address(OFFSET_BLOCK_DATA),
Alexandra Chin669d27c2012-12-24 15:42:30 +08001429 &fwu->read_config_buf[index],
1430 fwu->block_size);
1431 if (retval < 0) {
1432 dev_err(&fwu->rmi4_data->i2c_client->dev,
1433 "%s: Failed to read block data (block %d)\n",
1434 __func__, block_num);
1435 goto exit;
1436 }
1437
1438 index += fwu->block_size;
1439 }
1440
1441exit:
Alexandra Chin823a2f52013-07-29 16:09:52 -07001442 return retval;
1443}
1444
1445static int fwu_do_reflash(void)
1446{
1447 int retval;
1448 unsigned char flash_status;
1449
1450 if (fwu->do_lockdown) {
1451 retval = fwu_do_write_lockdown(false);
1452 if (retval < 0)
1453 dev_warn(&fwu->rmi4_data->i2c_client->dev,
1454 "%s: Skip lockdown process.\n",
1455 __func__);
1456 }
1457 retval = fwu_enter_flash_prog(false);
1458 if (retval < 0)
1459 return retval;
1460 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
1461 "%s: Entered flash prog mode\n",
1462 __func__);
1463
1464 retval = fwu_write_bootloader_id();
1465 if (retval < 0)
1466 return retval;
1467
1468 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
1469 "%s: Bootloader ID written\n",
1470 __func__);
1471
1472 retval = fwu_write_f34_command(CMD_ERASE_ALL);
1473 if (retval < 0)
1474 return retval;
1475
1476 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
1477 "%s: Erase all command written\n",
1478 __func__);
1479
Amy Malochecb78b1d2013-08-27 16:34:11 -07001480 if (fwu->polling_mode)
1481 msleep(100);
1482
Alexandra Chin823a2f52013-07-29 16:09:52 -07001483 retval = fwu_wait_for_idle(ERASE_WAIT_MS);
1484 if (retval < 0)
1485 return retval;
1486
1487 retval = fwu_read_f34_flash_status(&flash_status);
1488 if (retval < 0)
1489 return retval;
1490 if (flash_status != 0x00) {
1491 dev_err(&fwu->rmi4_data->i2c_client->dev,
1492 "%s: Erase all command failed, status 0x%02X\n",
1493 __func__, flash_status);
1494 return -EINVAL;
1495 }
1496
1497 if (fwu->firmware_data) {
1498 retval = fwu_write_firmware();
1499 if (retval < 0)
1500 return retval;
1501 pr_notice("%s: Firmware programmed\n", __func__);
1502 }
1503
1504 if (fwu->config_data) {
1505 retval = fwu_write_configuration();
1506 if (retval < 0)
1507 return retval;
1508 pr_notice("%s: Configuration programmed\n", __func__);
1509 }
Alexandra Chin669d27c2012-12-24 15:42:30 +08001510
1511 return retval;
1512}
1513
Alexandra Chind5591a62013-02-07 12:59:15 -08001514static int fwu_start_reflash(void)
1515{
Amy Malocheafcecb22013-04-16 18:43:22 -07001516 int retval = 0;
Alexandra Chind5591a62013-02-07 12:59:15 -08001517 const struct firmware *fw_entry = NULL;
1518 struct f01_device_status f01_device_status;
1519 enum flash_area flash_area;
1520
1521 pr_notice("%s: Start of reflash process\n", __func__);
1522
1523 if (fwu->ext_data_source)
Alexandra Chin823a2f52013-07-29 16:09:52 -07001524 dev_info(&fwu->rmi4_data->i2c_client->dev,
1525 "%s Load .img file from commandline.\n",
1526 __func__);
Alexandra Chind5591a62013-02-07 12:59:15 -08001527 else {
Alexandra Chin400f26e2013-07-25 11:58:17 -07001528 if (strnlen(fwu->rmi4_data->fw_image_name,
1529 NAME_BUFFER_SIZE) == 0) {
1530 dev_err(&fwu->rmi4_data->i2c_client->dev,
1531 "Firmware image name not given, "\
1532 "skipping update\n");
1533 return 0;
1534 }
1535
1536 if (strnlen(fwu->rmi4_data->fw_image_name, NAME_BUFFER_SIZE) ==
1537 NAME_BUFFER_SIZE) {
1538 dev_err(&fwu->rmi4_data->i2c_client->dev,
1539 "Firmware image name exceeds max length " \
1540 "(%d), skipping update\n", NAME_BUFFER_SIZE);
1541 return 0;
1542 }
1543
Alexandra Chin823a2f52013-07-29 16:09:52 -07001544 snprintf(fwu->image_name, NAME_BUFFER_SIZE, "%s",
Amy Malocheafcecb22013-04-16 18:43:22 -07001545 fwu->rmi4_data->fw_image_name);
1546 dev_info(&fwu->rmi4_data->i2c_client->dev,
1547 "%s: Requesting firmware image %s\n",
Alexandra Chin823a2f52013-07-29 16:09:52 -07001548 __func__, fwu->image_name);
Alexandra Chind5591a62013-02-07 12:59:15 -08001549
Amy Malochecb835832013-03-26 18:06:05 -07001550 retval = request_firmware(&fw_entry,
Alexandra Chin823a2f52013-07-29 16:09:52 -07001551 fwu->image_name,
Alexandra Chind5591a62013-02-07 12:59:15 -08001552 &fwu->rmi4_data->i2c_client->dev);
1553 if (retval != 0) {
1554 dev_err(&fwu->rmi4_data->i2c_client->dev,
1555 "%s: Firmware image %s not available\n",
Amy Malochecb835832013-03-26 18:06:05 -07001556 __func__,
Alexandra Chin823a2f52013-07-29 16:09:52 -07001557 fwu->image_name);
Amy Malocheb494b9a2013-05-13 18:01:53 -07001558 return -EINVAL;
Alexandra Chind5591a62013-02-07 12:59:15 -08001559 }
1560
1561 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
Himanshu Aggarwal27f73562014-01-16 19:30:41 +05301562 "%s: Firmware image size = %zu\n",
Alexandra Chind5591a62013-02-07 12:59:15 -08001563 __func__, fw_entry->size);
1564
Alexandra Chin823a2f52013-07-29 16:09:52 -07001565 fwu->data_buffer = fw_entry->data;
Alexandra Chind5591a62013-02-07 12:59:15 -08001566 }
1567
Alexandra Chin823a2f52013-07-29 16:09:52 -07001568 parse_header();
1569 flash_area = fwu_go_nogo();
Alexandra Chin400f26e2013-07-25 11:58:17 -07001570
1571 if (fwu->rmi4_data->sensor_sleep) {
1572 dev_err(&fwu->rmi4_data->i2c_client->dev,
1573 "%s: Sensor sleeping\n",
1574 __func__);
Alexandra Chin823a2f52013-07-29 16:09:52 -07001575 retval = -ENODEV;
1576 goto exit;
Alexandra Chin400f26e2013-07-25 11:58:17 -07001577 }
1578 fwu->rmi4_data->stay_awake = true;
Alexandra Chind5591a62013-02-07 12:59:15 -08001579
1580 switch (flash_area) {
1581 case NONE:
Amy Maloche2c4c48c2013-05-01 20:06:23 -07001582 case MISMATCH:
1583 retval = 0;
Alexandra Chind5591a62013-02-07 12:59:15 -08001584 dev_info(&fwu->rmi4_data->i2c_client->dev,
1585 "%s: No need to do reflash.\n",
1586 __func__);
1587 goto exit;
1588 case UI_FIRMWARE:
1589 retval = fwu_do_reflash();
1590 break;
1591 case CONFIG_AREA:
1592 retval = fwu_do_write_config();
1593 break;
1594 default:
1595 dev_err(&fwu->rmi4_data->i2c_client->dev,
1596 "%s: Unknown flash area\n",
1597 __func__);
Alexandra Chin823a2f52013-07-29 16:09:52 -07001598 retval = -EINVAL;
Alexandra Chind5591a62013-02-07 12:59:15 -08001599 goto exit;
1600 }
1601
Alexandra Chin823a2f52013-07-29 16:09:52 -07001602 if (retval < 0)
Alexandra Chind5591a62013-02-07 12:59:15 -08001603 dev_err(&fwu->rmi4_data->i2c_client->dev,
1604 "%s: Failed to do reflash\n",
1605 __func__);
Alexandra Chind5591a62013-02-07 12:59:15 -08001606
1607 /* reset device */
1608 fwu_reset_device();
1609
1610 /* check device status */
1611 retval = fwu_read_f01_device_status(&f01_device_status);
1612 if (retval < 0)
1613 goto exit;
1614
1615 dev_info(&fwu->rmi4_data->i2c_client->dev, "Device is in %s mode\n",
1616 f01_device_status.flash_prog == 1 ? "bootloader" : "UI");
1617 if (f01_device_status.flash_prog)
1618 dev_info(&fwu->rmi4_data->i2c_client->dev, "Flash status %d\n",
1619 f01_device_status.status_code);
1620
1621 if (f01_device_status.flash_prog) {
1622 dev_info(&fwu->rmi4_data->i2c_client->dev,
1623 "%s: Device is in flash prog mode 0x%02X\n",
1624 __func__, f01_device_status.status_code);
Alexandra Chind5591a62013-02-07 12:59:15 -08001625 }
1626
Amy Malocheb494b9a2013-05-13 18:01:53 -07001627exit:
Alexandra Chind5591a62013-02-07 12:59:15 -08001628 if (fw_entry)
1629 release_firmware(fw_entry);
1630
1631 pr_notice("%s: End of reflash process\n", __func__);
Alexandra Chin400f26e2013-07-25 11:58:17 -07001632 fwu->rmi4_data->stay_awake = false;
Alexandra Chind5591a62013-02-07 12:59:15 -08001633 return retval;
1634}
1635
Alexandra Chin823a2f52013-07-29 16:09:52 -07001636int synaptics_fw_updater(void)
Alexandra Chin669d27c2012-12-24 15:42:30 +08001637{
1638 int retval;
1639
1640 if (!fwu)
1641 return -ENODEV;
1642
1643 if (!fwu->initialized)
1644 return -ENODEV;
1645
Amy Malocheb494b9a2013-05-13 18:01:53 -07001646 fwu->rmi4_data->fw_updating = true;
Amy Maloche986863d2013-06-10 15:13:57 -07001647 if (fwu->rmi4_data->suspended == true) {
Amy Malocheb494b9a2013-05-13 18:01:53 -07001648 fwu->rmi4_data->fw_updating = false;
1649 dev_err(&fwu->rmi4_data->i2c_client->dev,
1650 "Cannot start fw upgrade while device is in suspend\n");
1651 return -EBUSY;
1652 }
1653
Alexandra Chin669d27c2012-12-24 15:42:30 +08001654 fwu->config_area = UI_CONFIG_AREA;
1655
1656 retval = fwu_start_reflash();
Amy Malocheb494b9a2013-05-13 18:01:53 -07001657 fwu->rmi4_data->fw_updating = false;
Alexandra Chin669d27c2012-12-24 15:42:30 +08001658
Amy Maloched9bf0d92013-06-19 17:19:23 -07001659 synaptics_rmi4_update_debug_info();
1660
Alexandra Chin669d27c2012-12-24 15:42:30 +08001661 return retval;
1662}
1663EXPORT_SYMBOL(synaptics_fw_updater);
1664
1665static ssize_t fwu_sysfs_show_image(struct file *data_file,
1666 struct kobject *kobj, struct bin_attribute *attributes,
1667 char *buf, loff_t pos, size_t count)
1668{
1669 struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
1670
1671 if (count < fwu->config_size) {
1672 dev_err(&rmi4_data->i2c_client->dev,
Himanshu Aggarwal27f73562014-01-16 19:30:41 +05301673 "%s: Not enough space (%zu bytes) in buffer\n",
Alexandra Chin669d27c2012-12-24 15:42:30 +08001674 __func__, count);
1675 return -EINVAL;
1676 }
1677
1678 memcpy(buf, fwu->read_config_buf, fwu->config_size);
1679
1680 return fwu->config_size;
1681}
1682
1683static ssize_t fwu_sysfs_store_image(struct file *data_file,
1684 struct kobject *kobj, struct bin_attribute *attributes,
1685 char *buf, loff_t pos, size_t count)
1686{
1687 memcpy((void *)(&fwu->ext_data_source[fwu->data_pos]),
1688 (const void *)buf,
1689 count);
1690
Alexandra Chin823a2f52013-07-29 16:09:52 -07001691 fwu->data_buffer = fwu->ext_data_source;
Alexandra Chin669d27c2012-12-24 15:42:30 +08001692 fwu->data_pos += count;
1693
1694 return count;
1695}
1696
Alexandra Chin823a2f52013-07-29 16:09:52 -07001697static ssize_t fwu_sysfs_image_name_store(struct device *dev,
Amy Malocheb494b9a2013-05-13 18:01:53 -07001698 struct device_attribute *attr, const char *buf, size_t count)
1699{
1700 struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
1701 char *strptr;
1702
1703 if (count >= NAME_BUFFER_SIZE) {
1704 dev_err(&rmi4_data->i2c_client->dev,
1705 "Input over %d characters long\n", NAME_BUFFER_SIZE);
1706 return -EINVAL;
1707 }
1708
1709 strptr = strnstr(buf, ".img",
1710 count);
1711 if (!strptr) {
1712 dev_err(&rmi4_data->i2c_client->dev,
1713 "Input is not valid .img file\n");
1714 return -EINVAL;
1715 }
1716
1717 strlcpy(rmi4_data->fw_image_name, buf, count);
1718 return count;
1719}
1720
Alexandra Chin823a2f52013-07-29 16:09:52 -07001721static ssize_t fwu_sysfs_image_name_show(struct device *dev,
Amy Malocheb494b9a2013-05-13 18:01:53 -07001722 struct device_attribute *attr, char *buf)
1723{
1724 if (strnlen(fwu->rmi4_data->fw_image_name, NAME_BUFFER_SIZE) > 0)
1725 return snprintf(buf, PAGE_SIZE, "%s\n",
1726 fwu->rmi4_data->fw_image_name);
1727 else
1728 return snprintf(buf, PAGE_SIZE, "No firmware name given\n");
1729}
1730
Amy Maloche5e0360e2013-05-01 13:31:57 -07001731static ssize_t fwu_sysfs_force_reflash_store(struct device *dev,
1732 struct device_attribute *attr, const char *buf, size_t count)
1733{
1734 int retval;
1735 unsigned int input;
1736 struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
1737
1738 if (sscanf(buf, "%u", &input) != 1) {
1739 retval = -EINVAL;
1740 goto exit;
1741 }
1742
1743 if (input != 1) {
1744 retval = -EINVAL;
1745 goto exit;
1746 }
Alexandra Chin823a2f52013-07-29 16:09:52 -07001747 if (LOCKDOWN)
1748 fwu->do_lockdown = true;
Amy Maloche5e0360e2013-05-01 13:31:57 -07001749
1750 fwu->force_update = true;
Alexandra Chin823a2f52013-07-29 16:09:52 -07001751 retval = synaptics_fw_updater();
Amy Maloche5e0360e2013-05-01 13:31:57 -07001752 if (retval < 0) {
1753 dev_err(&rmi4_data->i2c_client->dev,
1754 "%s: Failed to do reflash\n",
1755 __func__);
1756 goto exit;
1757 }
1758
1759 retval = count;
1760
1761exit:
1762 kfree(fwu->ext_data_source);
1763 fwu->ext_data_source = NULL;
Alexandra Chin823a2f52013-07-29 16:09:52 -07001764 fwu->force_update = FORCE_UPDATE;
Amy Maloche37a75b72013-08-06 13:27:50 -07001765 fwu->do_lockdown = rmi4_data->board->do_lockdown;
Amy Maloche5e0360e2013-05-01 13:31:57 -07001766 return retval;
1767}
1768
Alexandra Chin669d27c2012-12-24 15:42:30 +08001769static ssize_t fwu_sysfs_do_reflash_store(struct device *dev,
1770 struct device_attribute *attr, const char *buf, size_t count)
1771{
1772 int retval;
1773 unsigned int input;
1774 struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
1775
1776 if (sscanf(buf, "%u", &input) != 1) {
1777 retval = -EINVAL;
1778 goto exit;
1779 }
1780
Alexandra Chin823a2f52013-07-29 16:09:52 -07001781 if (input & LOCKDOWN) {
1782 fwu->do_lockdown = true;
1783 input &= ~LOCKDOWN;
1784 }
1785
1786 if ((input != NORMAL) && (input != FORCE)) {
1787 retval = -EINVAL;
1788 goto exit;
1789 }
1790
1791 if (input == FORCE)
1792 fwu->force_update = true;
1793
1794 retval = synaptics_fw_updater();
1795 if (retval < 0) {
1796 dev_err(&rmi4_data->i2c_client->dev,
1797 "%s: Failed to do reflash\n",
1798 __func__);
1799 goto exit;
1800 }
1801
1802 retval = count;
1803
1804exit:
1805 kfree(fwu->ext_data_source);
1806 fwu->ext_data_source = NULL;
1807 fwu->force_update = FORCE_UPDATE;
Amy Maloche37a75b72013-08-06 13:27:50 -07001808 fwu->do_lockdown = rmi4_data->board->do_lockdown;
Alexandra Chin823a2f52013-07-29 16:09:52 -07001809 return retval;
1810}
1811
1812static ssize_t fwu_sysfs_write_lockdown_store(struct device *dev,
1813 struct device_attribute *attr, const char *buf, size_t count)
1814{
1815 int retval;
1816 unsigned int input;
1817 struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
1818
1819 if (sscanf(buf, "%u", &input) != 1) {
1820 retval = -EINVAL;
1821 goto exit;
1822 }
1823
Alexandra Chin669d27c2012-12-24 15:42:30 +08001824 if (input != 1) {
1825 retval = -EINVAL;
1826 goto exit;
1827 }
1828
Alexandra Chin823a2f52013-07-29 16:09:52 -07001829 retval = fwu_start_write_lockdown();
Alexandra Chin669d27c2012-12-24 15:42:30 +08001830 if (retval < 0) {
1831 dev_err(&rmi4_data->i2c_client->dev,
Alexandra Chin823a2f52013-07-29 16:09:52 -07001832 "%s: Failed to write lockdown block\n",
Alexandra Chin669d27c2012-12-24 15:42:30 +08001833 __func__);
1834 goto exit;
1835 }
1836
1837 retval = count;
1838
1839exit:
1840 kfree(fwu->ext_data_source);
1841 fwu->ext_data_source = NULL;
Alexandra Chin823a2f52013-07-29 16:09:52 -07001842 fwu->force_update = FORCE_UPDATE;
Amy Maloche37a75b72013-08-06 13:27:50 -07001843 fwu->do_lockdown = rmi4_data->board->do_lockdown;
Alexandra Chin669d27c2012-12-24 15:42:30 +08001844 return retval;
1845}
1846
1847static ssize_t fwu_sysfs_write_config_store(struct device *dev,
1848 struct device_attribute *attr, const char *buf, size_t count)
1849{
1850 int retval;
1851 unsigned int input;
1852 struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
1853
1854 if (sscanf(buf, "%u", &input) != 1) {
1855 retval = -EINVAL;
1856 goto exit;
1857 }
1858
1859 if (input != 1) {
1860 retval = -EINVAL;
1861 goto exit;
1862 }
1863
1864 retval = fwu_start_write_config();
1865 if (retval < 0) {
1866 dev_err(&rmi4_data->i2c_client->dev,
1867 "%s: Failed to write config\n",
1868 __func__);
1869 goto exit;
1870 }
1871
1872 retval = count;
1873
1874exit:
1875 kfree(fwu->ext_data_source);
1876 fwu->ext_data_source = NULL;
1877 return retval;
1878}
1879
1880static ssize_t fwu_sysfs_read_config_store(struct device *dev,
1881 struct device_attribute *attr, const char *buf, size_t count)
1882{
1883 int retval;
1884 unsigned int input;
1885 struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
1886
1887 if (sscanf(buf, "%u", &input) != 1)
1888 return -EINVAL;
1889
1890 if (input != 1)
1891 return -EINVAL;
1892
1893 retval = fwu_do_read_config();
1894 if (retval < 0) {
1895 dev_err(&rmi4_data->i2c_client->dev,
1896 "%s: Failed to read config\n",
1897 __func__);
1898 return retval;
1899 }
1900
1901 return count;
1902}
1903
1904static ssize_t fwu_sysfs_config_area_store(struct device *dev,
1905 struct device_attribute *attr, const char *buf, size_t count)
1906{
1907 int retval;
Abinaya P96429972014-01-27 17:41:29 +05301908 unsigned short config_area;
1909 struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
Alexandra Chin669d27c2012-12-24 15:42:30 +08001910
Abinaya P96429972014-01-27 17:41:29 +05301911 retval = kstrtou16(buf, 10, &config_area);
Alexandra Chin669d27c2012-12-24 15:42:30 +08001912 if (retval)
1913 return retval;
1914
Abinaya P96429972014-01-27 17:41:29 +05301915 if (config_area < 0x00 || config_area > 0x03) {
1916 dev_err(&rmi4_data->i2c_client->dev,
1917 "%s: Incorrect value of config_area\n",
1918 __func__);
1919 return -EINVAL;
1920 }
1921
Alexandra Chin669d27c2012-12-24 15:42:30 +08001922 fwu->config_area = config_area;
1923
1924 return count;
1925}
1926
1927static ssize_t fwu_sysfs_image_size_store(struct device *dev,
1928 struct device_attribute *attr, const char *buf, size_t count)
1929{
1930 int retval;
1931 unsigned long size;
1932 struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
1933
Shantanu Jain41f0d472013-01-04 12:14:37 +05301934 retval = kstrtoul(buf, 10, &size);
Alexandra Chin669d27c2012-12-24 15:42:30 +08001935 if (retval)
1936 return retval;
1937
1938 fwu->image_size = size;
1939 fwu->data_pos = 0;
1940
1941 kfree(fwu->ext_data_source);
1942 fwu->ext_data_source = kzalloc(fwu->image_size, GFP_KERNEL);
1943 if (!fwu->ext_data_source) {
1944 dev_err(&rmi4_data->i2c_client->dev,
1945 "%s: Failed to alloc mem for image data\n",
1946 __func__);
1947 return -ENOMEM;
1948 }
1949
1950 return count;
1951}
1952
1953static ssize_t fwu_sysfs_block_size_show(struct device *dev,
1954 struct device_attribute *attr, char *buf)
1955{
1956 return snprintf(buf, PAGE_SIZE, "%u\n", fwu->block_size);
1957}
1958
1959static ssize_t fwu_sysfs_firmware_block_count_show(struct device *dev,
1960 struct device_attribute *attr, char *buf)
1961{
1962 return snprintf(buf, PAGE_SIZE, "%u\n", fwu->fw_block_count);
1963}
1964
1965static ssize_t fwu_sysfs_configuration_block_count_show(struct device *dev,
1966 struct device_attribute *attr, char *buf)
1967{
1968 return snprintf(buf, PAGE_SIZE, "%u\n", fwu->config_block_count);
1969}
1970
1971static ssize_t fwu_sysfs_perm_config_block_count_show(struct device *dev,
1972 struct device_attribute *attr, char *buf)
1973{
1974 return snprintf(buf, PAGE_SIZE, "%u\n", fwu->perm_config_block_count);
1975}
1976
1977static ssize_t fwu_sysfs_bl_config_block_count_show(struct device *dev,
1978 struct device_attribute *attr, char *buf)
1979{
1980 return snprintf(buf, PAGE_SIZE, "%u\n", fwu->bl_config_block_count);
1981}
1982
1983static ssize_t fwu_sysfs_disp_config_block_count_show(struct device *dev,
1984 struct device_attribute *attr, char *buf)
1985{
1986 return snprintf(buf, PAGE_SIZE, "%u\n", fwu->disp_config_block_count);
1987}
1988
Amy Maloched25bd8c2013-01-25 12:34:31 -08001989static ssize_t fwu_sysfs_config_id_show(struct device *dev,
1990 struct device_attribute *attr, char *buf)
1991{
Amy Maloche581f7402013-02-19 16:29:37 -08001992 unsigned char config_id[4];
Amy Maloched25bd8c2013-01-25 12:34:31 -08001993 /* device config id */
1994 fwu->fn_ptr->read(fwu->rmi4_data,
1995 fwu->f34_fd.ctrl_base_addr,
1996 config_id,
1997 sizeof(config_id));
1998
1999 return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n",
2000 config_id[0], config_id[1], config_id[2], config_id[3]);
2001}
2002
Amy Maloche2c4c48c2013-05-01 20:06:23 -07002003static ssize_t fwu_sysfs_package_id_show(struct device *dev,
2004 struct device_attribute *attr, char *buf)
2005{
2006 unsigned char pkg_id[4];
2007 /* read device package id */
2008 fwu->fn_ptr->read(fwu->rmi4_data,
2009 fwu->f01_fd.query_base_addr + 17,
2010 pkg_id,
2011 sizeof(pkg_id));
2012
2013 return snprintf(buf, PAGE_SIZE, "%d rev %d\n",
2014 (pkg_id[1] << 8) | pkg_id[0],
2015 (pkg_id[3] << 8) | pkg_id[2]);
2016}
2017
Amy Maloched9bf0d92013-06-19 17:19:23 -07002018static int synaptics_rmi4_debug_dump_info(struct seq_file *m, void *v)
2019{
2020 seq_printf(m, "%s\n", fwu->ts_info);
2021
2022 return 0;
2023}
2024
2025static int debugfs_dump_info_open(struct inode *inode, struct file *file)
2026{
2027 return single_open(file, synaptics_rmi4_debug_dump_info,
2028 inode->i_private);
2029}
2030
2031static const struct file_operations debug_dump_info_fops = {
2032 .owner = THIS_MODULE,
2033 .open = debugfs_dump_info_open,
2034 .read = seq_read,
2035 .release = single_release,
2036};
2037
Alexandra Chin669d27c2012-12-24 15:42:30 +08002038static void synaptics_rmi4_fwu_attn(struct synaptics_rmi4_data *rmi4_data,
2039 unsigned char intr_mask)
2040{
Alexandra Chinb2d3aea2013-09-24 11:58:02 -07002041 if (!fwu)
2042 return;
2043
Alexandra Chin669d27c2012-12-24 15:42:30 +08002044 if (fwu->intr_mask & intr_mask)
Alexandra Chin400f26e2013-07-25 11:58:17 -07002045 fwu->interrupt_flag = true;
Alexandra Chin669d27c2012-12-24 15:42:30 +08002046
2047 return;
2048}
2049
Amy Malocheb494b9a2013-05-13 18:01:53 -07002050static struct bin_attribute dev_attr_data = {
2051 .attr = {
2052 .name = "data",
Amy Maloche8b99ec92013-06-24 17:13:42 -07002053 .mode = (S_IRUGO | S_IWUSR | S_IWGRP),
Amy Malocheb494b9a2013-05-13 18:01:53 -07002054 },
2055 .size = 0,
2056 .read = fwu_sysfs_show_image,
2057 .write = fwu_sysfs_store_image,
2058};
2059
2060static struct device_attribute attrs[] = {
Amy Maloche8b99ec92013-06-24 17:13:42 -07002061 __ATTR(fw_name, S_IRUGO | S_IWUSR | S_IWGRP,
Alexandra Chin823a2f52013-07-29 16:09:52 -07002062 fwu_sysfs_image_name_show,
2063 fwu_sysfs_image_name_store),
Himanshu Aggarwalbed231a2013-12-03 19:16:09 +05302064 __ATTR(force_update_fw, S_IWUSR | S_IWGRP,
2065 NULL,
Amy Malocheb494b9a2013-05-13 18:01:53 -07002066 fwu_sysfs_force_reflash_store),
Himanshu Aggarwalbed231a2013-12-03 19:16:09 +05302067 __ATTR(update_fw, S_IWUSR | S_IWGRP,
2068 NULL,
Amy Malocheb494b9a2013-05-13 18:01:53 -07002069 fwu_sysfs_do_reflash_store),
Himanshu Aggarwalbed231a2013-12-03 19:16:09 +05302070 __ATTR(writeconfig, S_IWUSR | S_IWGRP,
2071 NULL,
Amy Malocheb494b9a2013-05-13 18:01:53 -07002072 fwu_sysfs_write_config_store),
Himanshu Aggarwalbed231a2013-12-03 19:16:09 +05302073 __ATTR(writelockdown, S_IWUSR | S_IWGRP,
2074 NULL,
Alexandra Chin823a2f52013-07-29 16:09:52 -07002075 fwu_sysfs_write_lockdown_store),
Himanshu Aggarwalbed231a2013-12-03 19:16:09 +05302076 __ATTR(readconfig, S_IWUSR | S_IWGRP,
2077 NULL,
Amy Malocheb494b9a2013-05-13 18:01:53 -07002078 fwu_sysfs_read_config_store),
Himanshu Aggarwalbed231a2013-12-03 19:16:09 +05302079 __ATTR(configarea, S_IWUSR | S_IWGRP,
2080 NULL,
Amy Malocheb494b9a2013-05-13 18:01:53 -07002081 fwu_sysfs_config_area_store),
Himanshu Aggarwalbed231a2013-12-03 19:16:09 +05302082 __ATTR(imagesize, S_IWUSR | S_IWGRP,
2083 NULL,
Amy Malocheb494b9a2013-05-13 18:01:53 -07002084 fwu_sysfs_image_size_store),
2085 __ATTR(blocksize, S_IRUGO,
2086 fwu_sysfs_block_size_show,
2087 synaptics_rmi4_store_error),
2088 __ATTR(fwblockcount, S_IRUGO,
2089 fwu_sysfs_firmware_block_count_show,
2090 synaptics_rmi4_store_error),
2091 __ATTR(configblockcount, S_IRUGO,
2092 fwu_sysfs_configuration_block_count_show,
2093 synaptics_rmi4_store_error),
2094 __ATTR(permconfigblockcount, S_IRUGO,
2095 fwu_sysfs_perm_config_block_count_show,
2096 synaptics_rmi4_store_error),
2097 __ATTR(blconfigblockcount, S_IRUGO,
2098 fwu_sysfs_bl_config_block_count_show,
2099 synaptics_rmi4_store_error),
2100 __ATTR(dispconfigblockcount, S_IRUGO,
2101 fwu_sysfs_disp_config_block_count_show,
2102 synaptics_rmi4_store_error),
2103 __ATTR(config_id, S_IRUGO,
2104 fwu_sysfs_config_id_show,
2105 synaptics_rmi4_store_error),
Amy Maloche2c4c48c2013-05-01 20:06:23 -07002106 __ATTR(package_id, S_IRUGO,
2107 fwu_sysfs_package_id_show,
2108 synaptics_rmi4_store_error),
Amy Malocheb494b9a2013-05-13 18:01:53 -07002109};
2110
2111
Alexandra Chind5591a62013-02-07 12:59:15 -08002112static void synaptics_rmi4_fwu_work(struct work_struct *work)
2113{
2114 fwu_start_reflash();
2115}
2116
Alexandra Chin669d27c2012-12-24 15:42:30 +08002117static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data)
2118{
2119 int retval;
2120 unsigned char attr_count;
2121 struct pdt_properties pdt_props;
Amy Maloched9bf0d92013-06-19 17:19:23 -07002122 struct dentry *temp;
Alexandra Chin669d27c2012-12-24 15:42:30 +08002123
2124 fwu = kzalloc(sizeof(*fwu), GFP_KERNEL);
2125 if (!fwu) {
2126 dev_err(&rmi4_data->i2c_client->dev,
2127 "%s: Failed to alloc mem for fwu\n",
2128 __func__);
Alexandra Chinb2d3aea2013-09-24 11:58:02 -07002129 retval = -ENOMEM;
Alexandra Chin669d27c2012-12-24 15:42:30 +08002130 goto exit;
2131 }
2132
2133 fwu->fn_ptr = kzalloc(sizeof(*(fwu->fn_ptr)), GFP_KERNEL);
2134 if (!fwu->fn_ptr) {
2135 dev_err(&rmi4_data->i2c_client->dev,
2136 "%s: Failed to alloc mem for fn_ptr\n",
2137 __func__);
2138 retval = -ENOMEM;
2139 goto exit_free_fwu;
2140 }
2141
2142 fwu->rmi4_data = rmi4_data;
2143 fwu->fn_ptr->read = rmi4_data->i2c_read;
2144 fwu->fn_ptr->write = rmi4_data->i2c_write;
2145 fwu->fn_ptr->enable = rmi4_data->irq_enable;
2146
2147 retval = fwu->fn_ptr->read(rmi4_data,
2148 PDT_PROPS,
2149 pdt_props.data,
2150 sizeof(pdt_props.data));
2151 if (retval < 0) {
2152 dev_dbg(&rmi4_data->i2c_client->dev,
2153 "%s: Failed to read PDT properties, assuming 0x00\n",
2154 __func__);
Alexandra Chinb2d3aea2013-09-24 11:58:02 -07002155 goto exit_free_mem;
Alexandra Chin669d27c2012-12-24 15:42:30 +08002156 } else if (pdt_props.has_bsr) {
2157 dev_err(&rmi4_data->i2c_client->dev,
2158 "%s: Reflash for LTS not currently supported\n",
2159 __func__);
Alexandra Chinb2d3aea2013-09-24 11:58:02 -07002160 retval = -EINVAL;
Alexandra Chin669d27c2012-12-24 15:42:30 +08002161 goto exit_free_mem;
2162 }
2163
2164 retval = fwu_scan_pdt();
2165 if (retval < 0)
2166 goto exit_free_mem;
2167
2168 fwu->productinfo1 = rmi4_data->rmi4_mod_info.product_info[0];
2169 fwu->productinfo2 = rmi4_data->rmi4_mod_info.product_info[1];
2170
2171 memcpy(fwu->product_id, rmi4_data->rmi4_mod_info.product_id_string,
2172 SYNAPTICS_RMI4_PRODUCT_ID_SIZE);
2173 fwu->product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE] = 0;
2174
2175 dev_dbg(&rmi4_data->i2c_client->dev,
2176 "%s: F01 product info: 0x%04x 0x%04x\n",
2177 __func__, fwu->productinfo1, fwu->productinfo2);
2178 dev_dbg(&rmi4_data->i2c_client->dev,
2179 "%s: F01 product ID: %s\n",
2180 __func__, fwu->product_id);
2181
2182 retval = fwu_read_f34_queries();
2183 if (retval < 0)
2184 goto exit_free_mem;
2185
2186 fwu->initialized = true;
Alexandra Chind5591a62013-02-07 12:59:15 -08002187 fwu->force_update = FORCE_UPDATE;
Amy Maloche37a75b72013-08-06 13:27:50 -07002188 fwu->do_lockdown = rmi4_data->board->do_lockdown;
Alexandra Chin823a2f52013-07-29 16:09:52 -07002189 fwu->initialized = true;
Alexandra Chin400f26e2013-07-25 11:58:17 -07002190 fwu->polling_mode = false;
Alexandra Chin669d27c2012-12-24 15:42:30 +08002191
Amy Maloche4d54ac42013-06-11 12:09:44 -07002192 retval = sysfs_create_bin_file(&rmi4_data->i2c_client->dev.kobj,
Alexandra Chin669d27c2012-12-24 15:42:30 +08002193 &dev_attr_data);
2194 if (retval < 0) {
2195 dev_err(&rmi4_data->i2c_client->dev,
2196 "%s: Failed to create sysfs bin file\n",
2197 __func__);
2198 goto exit_free_mem;
2199 }
2200
2201 for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
Amy Maloche4d54ac42013-06-11 12:09:44 -07002202 retval = sysfs_create_file(&rmi4_data->i2c_client->dev.kobj,
Alexandra Chin669d27c2012-12-24 15:42:30 +08002203 &attrs[attr_count].attr);
2204 if (retval < 0) {
2205 dev_err(&rmi4_data->i2c_client->dev,
2206 "%s: Failed to create sysfs attributes\n",
2207 __func__);
2208 retval = -ENODEV;
2209 goto exit_remove_attrs;
2210 }
2211 }
2212
Amy Maloched9bf0d92013-06-19 17:19:23 -07002213 temp = debugfs_create_file("dump_info", S_IRUSR | S_IWUSR,
2214 fwu->rmi4_data->dir, fwu->rmi4_data,
2215 &debug_dump_info_fops);
2216 if (temp == NULL || IS_ERR(temp)) {
2217 dev_err(&rmi4_data->i2c_client->dev,
2218 "%s: Failed to create debugfs dump info file\n",
2219 __func__);
2220 retval = PTR_ERR(temp);
2221 goto exit_remove_attrs;
2222 }
2223
2224 fwu->ts_info = kzalloc(RMI4_INFO_MAX_LEN, GFP_KERNEL);
2225 if (!fwu->ts_info) {
2226 dev_err(&rmi4_data->i2c_client->dev, "Not enough memory\n");
2227 goto exit_free_ts_info;
2228 }
2229
2230 synaptics_rmi4_update_debug_info();
2231
Alexandra Chind5591a62013-02-07 12:59:15 -08002232#ifdef INSIDE_FIRMWARE_UPDATE
2233 fwu->fwu_workqueue = create_singlethread_workqueue("fwu_workqueue");
2234 INIT_DELAYED_WORK(&fwu->fwu_work, synaptics_rmi4_fwu_work);
2235 queue_delayed_work(fwu->fwu_workqueue,
2236 &fwu->fwu_work,
2237 msecs_to_jiffies(1000));
2238#endif
Alexandra Chinc556cf02013-03-19 17:46:05 -07002239
Alexandra Chin669d27c2012-12-24 15:42:30 +08002240 return 0;
Amy Maloched9bf0d92013-06-19 17:19:23 -07002241exit_free_ts_info:
2242 debugfs_remove(temp);
Alexandra Chin669d27c2012-12-24 15:42:30 +08002243exit_remove_attrs:
Alexandra Chin823a2f52013-07-29 16:09:52 -07002244 for (attr_count--; attr_count >= 0; attr_count--) {
2245 sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
2246 &attrs[attr_count].attr);
2247 }
Alexandra Chin669d27c2012-12-24 15:42:30 +08002248
Alexandra Chin823a2f52013-07-29 16:09:52 -07002249 sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
Alexandra Chin669d27c2012-12-24 15:42:30 +08002250
2251exit_free_mem:
2252 kfree(fwu->fn_ptr);
2253
2254exit_free_fwu:
2255 kfree(fwu);
Alexandra Chin823a2f52013-07-29 16:09:52 -07002256 fwu = NULL;
Alexandra Chin669d27c2012-12-24 15:42:30 +08002257
2258exit:
Alexandra Chinb2d3aea2013-09-24 11:58:02 -07002259 return retval;
Alexandra Chin669d27c2012-12-24 15:42:30 +08002260}
2261
2262static void synaptics_rmi4_fwu_remove(struct synaptics_rmi4_data *rmi4_data)
2263{
2264 unsigned char attr_count;
2265
2266 sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
2267
2268 for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
2269 sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
2270 &attrs[attr_count].attr);
2271 }
2272
Alexandra Chin823a2f52013-07-29 16:09:52 -07002273 kfree(fwu->read_config_buf);
Alexandra Chin669d27c2012-12-24 15:42:30 +08002274 kfree(fwu->fn_ptr);
2275 kfree(fwu);
2276
Alexandra Chind9e204d2013-07-25 15:23:01 -07002277 complete(&fwu_remove_complete);
Alexandra Chin669d27c2012-12-24 15:42:30 +08002278
2279 return;
2280}
2281
2282static int __init rmi4_fw_update_module_init(void)
2283{
2284 synaptics_rmi4_new_function(RMI_FW_UPDATER, true,
2285 synaptics_rmi4_fwu_init,
2286 synaptics_rmi4_fwu_remove,
2287 synaptics_rmi4_fwu_attn);
2288 return 0;
2289}
2290
2291static void __exit rmi4_fw_update_module_exit(void)
2292{
Alexandra Chin669d27c2012-12-24 15:42:30 +08002293 synaptics_rmi4_new_function(RMI_FW_UPDATER, false,
2294 synaptics_rmi4_fwu_init,
2295 synaptics_rmi4_fwu_remove,
2296 synaptics_rmi4_fwu_attn);
Alexandra Chind9e204d2013-07-25 15:23:01 -07002297 wait_for_completion(&fwu_remove_complete);
Alexandra Chin669d27c2012-12-24 15:42:30 +08002298 return;
2299}
2300
2301module_init(rmi4_fw_update_module_init);
2302module_exit(rmi4_fw_update_module_exit);
2303
2304MODULE_AUTHOR("Synaptics, Inc.");
2305MODULE_DESCRIPTION("RMI4 FW Update Module");
Alexandra Chinbd1dac22013-02-22 12:33:19 -08002306MODULE_LICENSE("GPL v2");