blob: 349b020a90a65811de3dab22137ae5bb70c18d1e [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
32#define DEBUG_FW_UPDATE
33#define SHOW_PROGRESS
Alexandra Chind5591a62013-02-07 12:59:15 -080034#define MAX_FIRMWARE_ID_LEN 10
35#define FORCE_UPDATE false
36#define INSIDE_FIRMWARE_UPDATE
Alexandra Chin669d27c2012-12-24 15:42:30 +080037
Alexandra Chin669d27c2012-12-24 15:42:30 +080038#define FW_IMAGE_OFFSET 0x100
Alexandra Chin669d27c2012-12-24 15:42:30 +080039
40#define BOOTLOADER_ID_OFFSET 0
41#define FLASH_PROPERTIES_OFFSET 2
42#define BLOCK_SIZE_OFFSET 3
43#define FW_BLOCK_COUNT_OFFSET 5
44
45#define REG_MAP (1 << 0)
46#define UNLOCKED (1 << 1)
47#define HAS_CONFIG_ID (1 << 2)
48#define HAS_PERM_CONFIG (1 << 3)
49#define HAS_BL_CONFIG (1 << 4)
50#define HAS_DISP_CONFIG (1 << 5)
51#define HAS_CTRL1 (1 << 6)
52
53#define BLOCK_NUMBER_OFFSET 0
54#define BLOCK_DATA_OFFSET 2
55
Amy Malocheafcecb22013-04-16 18:43:22 -070056#define NAME_BUFFER_SIZE 128
57
58enum falsh_config_area {
59 UI_CONFIG_AREA = 0x00,
60 PERM_CONFIG_AREA = 0x01,
61 BL_CONFIG_AREA = 0x02,
62 DISP_CONFIG_AREA = 0x03
63};
Alexandra Chin669d27c2012-12-24 15:42:30 +080064
65enum flash_command {
66 CMD_WRITE_FW_BLOCK = 0x2,
67 CMD_ERASE_ALL = 0x3,
68 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,
80 CONFIG_AREA
81};
82
Amy Malocheafcecb22013-04-16 18:43:22 -070083enum image_file_option {
84 OPTION_BUILD_INFO = 0,
85 OPTION_CONTAIN_BOOTLOADER = 1,
86};
87
Alexandra Chin669d27c2012-12-24 15:42:30 +080088#define SLEEP_MODE_NORMAL (0x00)
89#define SLEEP_MODE_SENSOR_SLEEP (0x01)
90#define SLEEP_MODE_RESERVED0 (0x02)
91#define SLEEP_MODE_RESERVED1 (0x03)
92
93#define ENABLE_WAIT_MS (1 * 1000)
94#define WRITE_WAIT_MS (3 * 1000)
95#define ERASE_WAIT_MS (5 * 1000)
Alexandra Chind5591a62013-02-07 12:59:15 -080096#define RESET_WAIT_MS (500)
Alexandra Chin669d27c2012-12-24 15:42:30 +080097
Amy Malocheafcecb22013-04-16 18:43:22 -070098#define POLLING_MODE 0
99
Alexandra Chind5591a62013-02-07 12:59:15 -0800100#define SLEEP_TIME_US 50
Alexandra Chin669d27c2012-12-24 15:42:30 +0800101
102static ssize_t fwu_sysfs_show_image(struct file *data_file,
103 struct kobject *kobj, struct bin_attribute *attributes,
104 char *buf, loff_t pos, size_t count);
105
106static ssize_t fwu_sysfs_store_image(struct file *data_file,
107 struct kobject *kobj, struct bin_attribute *attributes,
108 char *buf, loff_t pos, size_t count);
109
Amy Maloche5e0360e2013-05-01 13:31:57 -0700110static ssize_t fwu_sysfs_force_reflash_store(struct device *dev,
111 struct device_attribute *attr, const char *buf, size_t count);
112
Alexandra Chin669d27c2012-12-24 15:42:30 +0800113static ssize_t fwu_sysfs_do_reflash_store(struct device *dev,
114 struct device_attribute *attr, const char *buf, size_t count);
115
116static ssize_t fwu_sysfs_write_config_store(struct device *dev,
117 struct device_attribute *attr, const char *buf, size_t count);
118
119static ssize_t fwu_sysfs_read_config_store(struct device *dev,
120 struct device_attribute *attr, const char *buf, size_t count);
121
122static ssize_t fwu_sysfs_config_area_store(struct device *dev,
123 struct device_attribute *attr, const char *buf, size_t count);
124
125static ssize_t fwu_sysfs_image_size_store(struct device *dev,
126 struct device_attribute *attr, const char *buf, size_t count);
127
128static ssize_t fwu_sysfs_block_size_show(struct device *dev,
129 struct device_attribute *attr, char *buf);
130
131static ssize_t fwu_sysfs_firmware_block_count_show(struct device *dev,
132 struct device_attribute *attr, char *buf);
133
134static ssize_t fwu_sysfs_configuration_block_count_show(struct device *dev,
135 struct device_attribute *attr, char *buf);
136
137static ssize_t fwu_sysfs_perm_config_block_count_show(struct device *dev,
138 struct device_attribute *attr, char *buf);
139
140static ssize_t fwu_sysfs_bl_config_block_count_show(struct device *dev,
141 struct device_attribute *attr, char *buf);
142
143static ssize_t fwu_sysfs_disp_config_block_count_show(struct device *dev,
144 struct device_attribute *attr, char *buf);
145
Amy Maloched25bd8c2013-01-25 12:34:31 -0800146static ssize_t fwu_sysfs_config_id_show(struct device *dev,
147 struct device_attribute *attr, char *buf);
148
Alexandra Chin669d27c2012-12-24 15:42:30 +0800149static int fwu_wait_for_idle(int timeout_ms);
150
Amy Malocheafcecb22013-04-16 18:43:22 -0700151struct image_header_data {
152 union {
153 struct {
154 /* 0x00-0x0F */
155 unsigned char file_checksum[4];
156 unsigned char reserved_04;
157 unsigned char reserved_05;
158 unsigned char options_firmware_id:1;
159 unsigned char options_contain_bootloader:1;
160 unsigned char options_reserved:6;
161 unsigned char bootloader_version;
162 unsigned char firmware_size[4];
163 unsigned char config_size[4];
164 /* 0x10-0x1F */
165 unsigned char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE];
166 unsigned char reserved_1a;
167 unsigned char reserved_1b;
168 unsigned char reserved_1c;
169 unsigned char reserved_1d;
170 unsigned char product_info[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE];
171 /* 0x20-0x2F */
172 unsigned char reserved_20_2f[0x10];
173 /* 0x30-0x3F */
174 unsigned char ds_firmware_id[0x10];
175 /* 0x40-0x4F */
176 unsigned char ds_customize_info[10];
177 unsigned char reserved_4a_4f[6];
178 /* 0x50-0x53*/
179 unsigned char firmware_id[4];
180 } __packed;
181 unsigned char data[54];
182 };
183};
184
Alexandra Chin669d27c2012-12-24 15:42:30 +0800185struct image_header {
186 unsigned int checksum;
187 unsigned int image_size;
188 unsigned int config_size;
189 unsigned char options;
190 unsigned char bootloader_version;
191 unsigned char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1];
192 unsigned char product_info[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE];
Amy Malocheafcecb22013-04-16 18:43:22 -0700193 unsigned int firmware_id;
194 bool is_contain_build_info;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800195};
196
197struct pdt_properties {
198 union {
199 struct {
200 unsigned char reserved_1:6;
201 unsigned char has_bsr:1;
202 unsigned char reserved_2:1;
203 } __packed;
204 unsigned char data[1];
205 };
206};
207
208struct f01_device_status {
209 union {
210 struct {
211 unsigned char status_code:4;
212 unsigned char reserved:2;
213 unsigned char flash_prog:1;
214 unsigned char unconfigured:1;
215 } __packed;
216 unsigned char data[1];
217 };
218};
219
220struct f01_device_control {
221 union {
222 struct {
223 unsigned char sleep_mode:2;
224 unsigned char nosleep:1;
225 unsigned char reserved:2;
226 unsigned char charger_connected:1;
227 unsigned char report_rate:1;
228 unsigned char configured:1;
229 } __packed;
230 unsigned char data[1];
231 };
232};
233
234struct f34_flash_control {
235 union {
236 struct {
237 unsigned char command:4;
238 unsigned char status:3;
239 unsigned char program_enabled:1;
240 } __packed;
241 unsigned char data[1];
242 };
243};
244
245struct f34_flash_properties {
246 union {
247 struct {
248 unsigned char regmap:1;
249 unsigned char unlocked:1;
250 unsigned char has_configid:1;
251 unsigned char has_perm_config:1;
252 unsigned char has_bl_config:1;
253 unsigned char has_display_config:1;
254 unsigned char has_blob_config:1;
255 unsigned char reserved:1;
256 } __packed;
257 unsigned char data[1];
258 };
259};
260
261struct synaptics_rmi4_fwu_handle {
262 bool initialized;
Alexandra Chind5591a62013-02-07 12:59:15 -0800263 bool force_update;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800264 char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1];
265 unsigned int image_size;
266 unsigned int data_pos;
267 unsigned char intr_mask;
268 unsigned char bootloader_id[2];
269 unsigned char productinfo1;
270 unsigned char productinfo2;
271 unsigned char *ext_data_source;
272 unsigned char *read_config_buf;
273 const unsigned char *firmware_data;
274 const unsigned char *config_data;
275 unsigned short block_size;
276 unsigned short fw_block_count;
277 unsigned short config_block_count;
278 unsigned short perm_config_block_count;
279 unsigned short bl_config_block_count;
280 unsigned short disp_config_block_count;
281 unsigned short config_size;
282 unsigned short config_area;
283 unsigned short addr_f34_flash_control;
284 unsigned short addr_f01_interrupt_register;
285 struct synaptics_rmi4_fn_desc f01_fd;
286 struct synaptics_rmi4_fn_desc f34_fd;
287 struct synaptics_rmi4_exp_fn_ptr *fn_ptr;
288 struct synaptics_rmi4_data *rmi4_data;
289 struct f34_flash_control flash_control;
290 struct f34_flash_properties flash_properties;
Alexandra Chind5591a62013-02-07 12:59:15 -0800291 struct workqueue_struct *fwu_workqueue;
292 struct delayed_work fwu_work;
Amy Malocheafcecb22013-04-16 18:43:22 -0700293 char *firmware_name;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800294};
295
296static struct bin_attribute dev_attr_data = {
297 .attr = {
298 .name = "data",
299 .mode = (S_IRUGO | S_IWUGO),
300 },
301 .size = 0,
302 .read = fwu_sysfs_show_image,
303 .write = fwu_sysfs_store_image,
304};
305
306static struct device_attribute attrs[] = {
Amy Maloche3afd75a62013-06-11 11:01:28 -0700307 __ATTR(force_update_fw, S_IWUGO,
Amy Maloche5e0360e2013-05-01 13:31:57 -0700308 synaptics_rmi4_show_error,
309 fwu_sysfs_force_reflash_store),
Amy Maloche3afd75a62013-06-11 11:01:28 -0700310 __ATTR(update_fw, S_IWUGO,
Alexandra Chin669d27c2012-12-24 15:42:30 +0800311 synaptics_rmi4_show_error,
312 fwu_sysfs_do_reflash_store),
313 __ATTR(writeconfig, S_IWUGO,
314 synaptics_rmi4_show_error,
315 fwu_sysfs_write_config_store),
316 __ATTR(readconfig, S_IWUGO,
317 synaptics_rmi4_show_error,
318 fwu_sysfs_read_config_store),
319 __ATTR(configarea, S_IWUGO,
320 synaptics_rmi4_show_error,
321 fwu_sysfs_config_area_store),
322 __ATTR(imagesize, S_IWUGO,
323 synaptics_rmi4_show_error,
324 fwu_sysfs_image_size_store),
325 __ATTR(blocksize, S_IRUGO,
326 fwu_sysfs_block_size_show,
327 synaptics_rmi4_store_error),
328 __ATTR(fwblockcount, S_IRUGO,
329 fwu_sysfs_firmware_block_count_show,
330 synaptics_rmi4_store_error),
331 __ATTR(configblockcount, S_IRUGO,
332 fwu_sysfs_configuration_block_count_show,
333 synaptics_rmi4_store_error),
334 __ATTR(permconfigblockcount, S_IRUGO,
335 fwu_sysfs_perm_config_block_count_show,
336 synaptics_rmi4_store_error),
337 __ATTR(blconfigblockcount, S_IRUGO,
338 fwu_sysfs_bl_config_block_count_show,
339 synaptics_rmi4_store_error),
340 __ATTR(dispconfigblockcount, S_IRUGO,
341 fwu_sysfs_disp_config_block_count_show,
342 synaptics_rmi4_store_error),
Amy Maloched25bd8c2013-01-25 12:34:31 -0800343 __ATTR(config_id, S_IRUGO,
344 fwu_sysfs_config_id_show,
345 synaptics_rmi4_store_error),
Alexandra Chin669d27c2012-12-24 15:42:30 +0800346};
347
348static struct synaptics_rmi4_fwu_handle *fwu;
349
350static struct completion remove_complete;
351
352static unsigned int extract_uint(const unsigned char *ptr)
353{
354 return (unsigned int)ptr[0] +
355 (unsigned int)ptr[1] * 0x100 +
356 (unsigned int)ptr[2] * 0x10000 +
357 (unsigned int)ptr[3] * 0x1000000;
358}
359
Amy Malocheafcecb22013-04-16 18:43:22 -0700360static unsigned int extract_uint_be(const unsigned char *ptr)
361{
362 return (unsigned int)ptr[3] +
363 (unsigned int)ptr[2] * 0x100 +
364 (unsigned int)ptr[1] * 0x10000 +
365 (unsigned int)ptr[0] * 0x1000000;
366}
367
Alexandra Chin669d27c2012-12-24 15:42:30 +0800368static void parse_header(struct image_header *header,
369 const unsigned char *fw_image)
370{
Amy Malocheafcecb22013-04-16 18:43:22 -0700371 struct image_header_data *data = (struct image_header_data *)fw_image;
372 header->checksum = extract_uint(data->file_checksum);
373 header->bootloader_version = data->bootloader_version;
374 header->image_size = extract_uint(data->firmware_size);
375 header->config_size = extract_uint(data->config_size);
376 memcpy(header->product_id, data->product_id,
377 sizeof(data->product_id));
378 header->product_id[sizeof(data->product_info)] = 0;
379 memcpy(header->product_info, data->product_info,
380 sizeof(data->product_info));
381
382 header->is_contain_build_info =
383 (data->options_firmware_id == (1 << OPTION_BUILD_INFO));
384 if (header->is_contain_build_info) {
385 header->firmware_id = extract_uint(data->firmware_id);
386 dev_info(&fwu->rmi4_data->i2c_client->dev,
387 "%s Firwmare build id %d\n", __func__,
388 header->firmware_id);
389 }
Alexandra Chin669d27c2012-12-24 15:42:30 +0800390
391#ifdef DEBUG_FW_UPDATE
392 dev_info(&fwu->rmi4_data->i2c_client->dev,
393 "Firwmare size %d, config size %d\n",
394 header->image_size,
395 header->config_size);
396#endif
397 return;
398}
399
Alexandra Chin669d27c2012-12-24 15:42:30 +0800400static int fwu_read_f01_device_status(struct f01_device_status *status)
401{
402 int retval;
403
404 retval = fwu->fn_ptr->read(fwu->rmi4_data,
405 fwu->f01_fd.data_base_addr,
406 status->data,
407 sizeof(status->data));
408 if (retval < 0) {
409 dev_err(&fwu->rmi4_data->i2c_client->dev,
410 "%s: Failed to read F01 device status\n",
411 __func__);
412 return retval;
413 }
414
415 return 0;
416}
417
418static int fwu_read_f34_queries(void)
419{
420 int retval;
421 unsigned char count = 4;
422 unsigned char buf[10];
423 struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client;
424
425 retval = fwu->fn_ptr->read(fwu->rmi4_data,
426 fwu->f34_fd.query_base_addr + BOOTLOADER_ID_OFFSET,
427 fwu->bootloader_id,
428 sizeof(fwu->bootloader_id));
429 if (retval < 0) {
430 dev_err(&i2c_client->dev,
431 "%s: Failed to read bootloader ID\n",
432 __func__);
433 return retval;
434 }
435
436 retval = fwu->fn_ptr->read(fwu->rmi4_data,
437 fwu->f34_fd.query_base_addr + FLASH_PROPERTIES_OFFSET,
438 fwu->flash_properties.data,
439 sizeof(fwu->flash_properties.data));
440 if (retval < 0) {
441 dev_err(&i2c_client->dev,
442 "%s: Failed to read flash properties\n",
443 __func__);
444 return retval;
445 }
446
Alexandra Chind5591a62013-02-07 12:59:15 -0800447 dev_info(&i2c_client->dev, "%s perm:%d, bl:%d, display:%d\n",
Alexandra Chin669d27c2012-12-24 15:42:30 +0800448 __func__,
449 fwu->flash_properties.has_perm_config,
450 fwu->flash_properties.has_bl_config,
451 fwu->flash_properties.has_display_config);
452
453 if (fwu->flash_properties.has_perm_config)
454 count += 2;
455
456 if (fwu->flash_properties.has_bl_config)
457 count += 2;
458
459 if (fwu->flash_properties.has_display_config)
460 count += 2;
461
462 retval = fwu->fn_ptr->read(fwu->rmi4_data,
463 fwu->f34_fd.query_base_addr + BLOCK_SIZE_OFFSET,
464 buf,
465 2);
466 if (retval < 0) {
467 dev_err(&i2c_client->dev,
468 "%s: Failed to read block size info\n",
469 __func__);
470 return retval;
471 }
472
473 batohs(&fwu->block_size, &(buf[0]));
474
475 retval = fwu->fn_ptr->read(fwu->rmi4_data,
476 fwu->f34_fd.query_base_addr + FW_BLOCK_COUNT_OFFSET,
477 buf,
478 count);
479 if (retval < 0) {
480 dev_err(&i2c_client->dev,
481 "%s: Failed to read block count info\n",
482 __func__);
483 return retval;
484 }
485
486 batohs(&fwu->fw_block_count, &(buf[0]));
487 batohs(&fwu->config_block_count, &(buf[2]));
488
489 count = 4;
490
491 if (fwu->flash_properties.has_perm_config) {
492 batohs(&fwu->perm_config_block_count, &(buf[count]));
493 count += 2;
494 }
495
496 if (fwu->flash_properties.has_bl_config) {
497 batohs(&fwu->bl_config_block_count, &(buf[count]));
498 count += 2;
499 }
500
501 if (fwu->flash_properties.has_display_config)
502 batohs(&fwu->disp_config_block_count, &(buf[count]));
503
504 fwu->addr_f34_flash_control = fwu->f34_fd.data_base_addr +
505 BLOCK_DATA_OFFSET +
506 fwu->block_size;
507 return 0;
508}
509
510static int fwu_read_interrupt_status(void)
511{
512 int retval;
513 unsigned char interrupt_status;
514 retval = fwu->fn_ptr->read(fwu->rmi4_data,
515 fwu->addr_f01_interrupt_register,
516 &interrupt_status,
517 sizeof(interrupt_status));
518 if (retval < 0) {
519 dev_err(&fwu->rmi4_data->i2c_client->dev,
520 "%s: Failed to read flash status\n",
521 __func__);
522 return retval;
523 }
524 return interrupt_status;
525}
526
527static int fwu_read_f34_flash_status(void)
528{
529 int retval;
530 retval = fwu->fn_ptr->read(fwu->rmi4_data,
531 fwu->addr_f34_flash_control,
532 fwu->flash_control.data,
533 sizeof(fwu->flash_control.data));
534 if (retval < 0) {
535 dev_err(&fwu->rmi4_data->i2c_client->dev,
536 "%s: Failed to read flash status\n",
537 __func__);
538 return retval;
539 }
540 return 0;
541}
542
543static int fwu_reset_device(void)
544{
545 int retval;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800546
547#ifdef DEBUG_FW_UPDATE
Alexandra Chind5591a62013-02-07 12:59:15 -0800548 dev_info(&fwu->rmi4_data->i2c_client->dev,
549 "%s: Reset device\n",
550 __func__);
Alexandra Chin669d27c2012-12-24 15:42:30 +0800551#endif
552
Alexandra Chin669d27c2012-12-24 15:42:30 +0800553 retval = fwu->rmi4_data->reset_device(fwu->rmi4_data);
554 if (retval < 0) {
555 dev_err(&fwu->rmi4_data->i2c_client->dev,
556 "%s: Failed to reset core driver after reflash\n",
557 __func__);
558 return retval;
559 }
560 return 0;
561}
562
563static int fwu_write_f34_command(unsigned char cmd)
564{
565 int retval;
566
Alexandra Chind5591a62013-02-07 12:59:15 -0800567 fwu->flash_control.data[0] = cmd;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800568 retval = fwu->fn_ptr->write(fwu->rmi4_data,
569 fwu->addr_f34_flash_control,
Alexandra Chind5591a62013-02-07 12:59:15 -0800570 fwu->flash_control.data,
571 sizeof(fwu->flash_control.data));
Alexandra Chin669d27c2012-12-24 15:42:30 +0800572 if (retval < 0) {
573 dev_err(&fwu->rmi4_data->i2c_client->dev,
574 "%s: Failed to write command 0x%02x\n",
Alexandra Chind5591a62013-02-07 12:59:15 -0800575 __func__, fwu->flash_control.data[0]);
Alexandra Chin669d27c2012-12-24 15:42:30 +0800576 return retval;
577 }
578 return 0;
579}
580
Alexandra Chin669d27c2012-12-24 15:42:30 +0800581static int fwu_wait_for_idle(int timeout_ms)
582{
583 int count = 0;
Alexandra Chind5591a62013-02-07 12:59:15 -0800584 int timeout_count = ((timeout_ms * 1000) / SLEEP_TIME_US) + 1;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800585 do {
Amy Malocheafcecb22013-04-16 18:43:22 -0700586 #if POLLING_MODE
587 fwu_read_f34_flash_status();
588 #endif
Alexandra Chind5591a62013-02-07 12:59:15 -0800589 if (fwu->flash_control.command == 0x00)
Alexandra Chin669d27c2012-12-24 15:42:30 +0800590 return 0;
591
Alexandra Chind5591a62013-02-07 12:59:15 -0800592 usleep_range(SLEEP_TIME_US, SLEEP_TIME_US + 100);
593 } while (count++ < timeout_count);
594
595 fwu_read_f34_flash_status();
596 if (fwu->flash_control.command == 0x00)
597 return 0;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800598
599 dev_err(&fwu->rmi4_data->i2c_client->dev,
600 "%s: Timed out waiting for idle status\n",
601 __func__);
602
603 return -ETIMEDOUT;
604}
605
Amy Malocheafcecb22013-04-16 18:43:22 -0700606static enum flash_area fwu_go_nogo(struct image_header *header)
Alexandra Chind5591a62013-02-07 12:59:15 -0800607{
608 int retval = 0;
609 int index = 0;
610 int deviceFirmwareID;
611 int imageConfigID;
612 int deviceConfigID;
613 unsigned long imageFirmwareID;
614 unsigned char firmware_id[4];
615 unsigned char config_id[4];
616 char *strptr;
617 char *imagePR = kzalloc(sizeof(MAX_FIRMWARE_ID_LEN), GFP_KERNEL);
618 enum flash_area flash_area = NONE;
619 struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client;
620 struct f01_device_status f01_device_status;
621
622 if (fwu->force_update) {
623 flash_area = UI_FIRMWARE;
624 goto exit;
625 }
626
627 retval = fwu_read_f01_device_status(&f01_device_status);
628 if (retval < 0) {
629 flash_area = NONE;
630 goto exit;
631 }
632
Alexandra Chind5591a62013-02-07 12:59:15 -0800633 /* Force update firmware when device is in bootloader mode */
634 if (f01_device_status.flash_prog) {
635 dev_info(&i2c_client->dev,
636 "%s: In flash prog mode\n",
637 __func__);
638 flash_area = UI_FIRMWARE;
639 goto exit;
640 }
641
Alexandra Chind5591a62013-02-07 12:59:15 -0800642 /* device firmware id */
643 retval = fwu->fn_ptr->read(fwu->rmi4_data,
644 fwu->f01_fd.query_base_addr + 18,
645 firmware_id,
646 sizeof(firmware_id));
647 if (retval < 0) {
648 dev_err(&i2c_client->dev,
Amy Malocheafcecb22013-04-16 18:43:22 -0700649 "%s: Failed to read firmware ID (code %d).\n",
650 __func__, retval);
Alexandra Chind5591a62013-02-07 12:59:15 -0800651 goto exit;
652 }
653 firmware_id[3] = 0;
654 deviceFirmwareID = extract_uint(firmware_id);
655
656 /* .img firmware id */
Amy Malocheafcecb22013-04-16 18:43:22 -0700657 if (header->is_contain_build_info) {
Alexandra Chind5591a62013-02-07 12:59:15 -0800658 dev_err(&i2c_client->dev,
Amy Malocheafcecb22013-04-16 18:43:22 -0700659 "%s: Image option contains build info.\n",
660 __func__);
661 imageFirmwareID = header->firmware_id;
662 } else {
663 strptr = strnstr(fwu->firmware_name, "PR",
664 sizeof(fwu->firmware_name));
665 if (!strptr) {
666 dev_err(&i2c_client->dev,
667 "No valid PR number (PRxxxxxxx)" \
668 "found in image file name...\n");
669 goto exit;
670 }
671
672 strptr += 2;
673 while (strptr[index] >= '0' && strptr[index] <= '9') {
674 imagePR[index] = strptr[index];
675 index++;
676 }
677 imagePR[index] = 0;
678
679 retval = kstrtoul(imagePR, 10, &imageFirmwareID);
680 if (retval == -EINVAL) {
681 dev_err(&i2c_client->dev,
682 "invalid image firmware id...\n");
683 goto exit;
684 }
Alexandra Chind5591a62013-02-07 12:59:15 -0800685 }
686
Amy Malocheafcecb22013-04-16 18:43:22 -0700687 dev_dbg(&i2c_client->dev,
Alexandra Chind5591a62013-02-07 12:59:15 -0800688 "Device firmware id %d, .img firmware id %d\n",
689 deviceFirmwareID,
690 (unsigned int)imageFirmwareID);
691 if (imageFirmwareID > deviceFirmwareID) {
692 flash_area = UI_FIRMWARE;
693 goto exit;
Alexandra Chinc556cf02013-03-19 17:46:05 -0700694 } else if (imageFirmwareID < deviceFirmwareID) {
695 flash_area = NONE;
696 dev_info(&i2c_client->dev,
Amy Malocheafcecb22013-04-16 18:43:22 -0700697 "%s: Img fw is older than device fw. Skip fw update.\n",
698 __func__);
Alexandra Chinc556cf02013-03-19 17:46:05 -0700699 goto exit;
Alexandra Chind5591a62013-02-07 12:59:15 -0800700 }
701
702 /* device config id */
703 retval = fwu->fn_ptr->read(fwu->rmi4_data,
704 fwu->f34_fd.ctrl_base_addr,
705 config_id,
706 sizeof(config_id));
707 if (retval < 0) {
708 dev_err(&i2c_client->dev,
Amy Malocheafcecb22013-04-16 18:43:22 -0700709 "%s: Failed to read config ID (code %d).\n",
710 __func__, retval);
Alexandra Chind5591a62013-02-07 12:59:15 -0800711 flash_area = NONE;
712 goto exit;
713 }
Amy Malocheafcecb22013-04-16 18:43:22 -0700714 deviceConfigID = extract_uint_be(config_id);
Alexandra Chind5591a62013-02-07 12:59:15 -0800715
Amy Malocheafcecb22013-04-16 18:43:22 -0700716 dev_dbg(&i2c_client->dev,
Alexandra Chind5591a62013-02-07 12:59:15 -0800717 "Device config ID 0x%02X, 0x%02X, 0x%02X, 0x%02X\n",
718 config_id[0], config_id[1], config_id[2], config_id[3]);
719
720 /* .img config id */
Amy Malocheafcecb22013-04-16 18:43:22 -0700721 dev_dbg(&i2c_client->dev,
Alexandra Chind5591a62013-02-07 12:59:15 -0800722 ".img config ID 0x%02X, 0x%02X, 0x%02X, 0x%02X\n",
723 fwu->config_data[0],
724 fwu->config_data[1],
725 fwu->config_data[2],
726 fwu->config_data[3]);
Amy Malocheafcecb22013-04-16 18:43:22 -0700727 imageConfigID = extract_uint_be(fwu->config_data);
728
729 dev_dbg(&i2c_client->dev,
730 "%s: Device config ID %d, .img config ID %d\n",
731 __func__, deviceConfigID, imageConfigID);
Alexandra Chind5591a62013-02-07 12:59:15 -0800732
733 if (imageConfigID > deviceConfigID) {
734 flash_area = CONFIG_AREA;
735 goto exit;
736 }
737
738exit:
739 kfree(imagePR);
740 if (flash_area == NONE)
741 dev_info(&i2c_client->dev,
Amy Malocheafcecb22013-04-16 18:43:22 -0700742 "%s: Nothing needs to be updated\n", __func__);
Alexandra Chind5591a62013-02-07 12:59:15 -0800743 else
744 dev_info(&i2c_client->dev,
Amy Malocheafcecb22013-04-16 18:43:22 -0700745 "%s: Update %s block\n", __func__,
Alexandra Chind5591a62013-02-07 12:59:15 -0800746 flash_area == UI_FIRMWARE ? "UI FW" : "CONFIG");
747 return flash_area;
748}
749
Alexandra Chin669d27c2012-12-24 15:42:30 +0800750static int fwu_scan_pdt(void)
751{
752 int retval;
753 unsigned char ii;
754 unsigned char intr_count = 0;
755 unsigned char intr_off;
756 unsigned char intr_src;
757 unsigned short addr;
758 bool f01found = false;
759 bool f34found = false;
760 struct synaptics_rmi4_fn_desc rmi_fd;
761
762#ifdef DEBUG_FW_UPDATE
763 dev_info(&fwu->rmi4_data->i2c_client->dev, "Scan PDT\n");
764#endif
765
766 for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
767 retval = fwu->fn_ptr->read(fwu->rmi4_data,
768 addr,
769 (unsigned char *)&rmi_fd,
770 sizeof(rmi_fd));
771 if (retval < 0)
772 return retval;
773
774 if (rmi_fd.fn_number) {
775 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
776 "%s: Found F%02x\n",
777 __func__, rmi_fd.fn_number);
778 switch (rmi_fd.fn_number) {
779 case SYNAPTICS_RMI4_F01:
780 f01found = true;
781 fwu->f01_fd = rmi_fd;
782 fwu->addr_f01_interrupt_register =
783 fwu->f01_fd.data_base_addr + 1;
784 break;
785 case SYNAPTICS_RMI4_F34:
786 f34found = true;
787 fwu->f34_fd = rmi_fd;
788 fwu->intr_mask = 0;
789 intr_src = rmi_fd.intr_src_count;
790 intr_off = intr_count % 8;
791 for (ii = intr_off;
792 ii < ((intr_src & MASK_3BIT) +
793 intr_off);
794 ii++)
795 fwu->intr_mask |= 1 << ii;
796 break;
797 }
798 } else
799 break;
800
801 intr_count += (rmi_fd.intr_src_count & MASK_3BIT);
802 }
803
804 if (!f01found || !f34found) {
805 dev_err(&fwu->rmi4_data->i2c_client->dev,
806 "%s: Failed to find both F01 and F34\n",
807 __func__);
808 return -EINVAL;
809 }
810
811 fwu_read_interrupt_status();
812 return 0;
813}
814
815static int fwu_write_blocks(unsigned char *block_ptr, unsigned short block_cnt,
816 unsigned char command)
817{
818 int retval;
819 unsigned char block_offset[] = {0, 0};
820 unsigned short block_num;
Alexandra Chind5591a62013-02-07 12:59:15 -0800821 struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800822#ifdef SHOW_PROGRESS
823 unsigned int progress = (command == CMD_WRITE_CONFIG_BLOCK) ?
824 10 : 100;
825#endif
Alexandra Chind5591a62013-02-07 12:59:15 -0800826
827#ifdef DEBUG_FW_UPDATE
828 dev_info(&i2c_client->dev,
829 "%s: Start to update %s blocks\n",
830 __func__,
831 command == CMD_WRITE_CONFIG_BLOCK ?
832 "config" : "firmware");
833#endif
Alexandra Chin669d27c2012-12-24 15:42:30 +0800834 retval = fwu->fn_ptr->write(fwu->rmi4_data,
835 fwu->f34_fd.data_base_addr + BLOCK_NUMBER_OFFSET,
836 block_offset,
837 sizeof(block_offset));
838 if (retval < 0) {
Alexandra Chind5591a62013-02-07 12:59:15 -0800839 dev_err(&i2c_client->dev,
Alexandra Chin669d27c2012-12-24 15:42:30 +0800840 "%s: Failed to write to block number registers\n",
841 __func__);
842 return retval;
843 }
844
845 for (block_num = 0; block_num < block_cnt; block_num++) {
846#ifdef SHOW_PROGRESS
847 if (block_num % progress == 0)
Alexandra Chind5591a62013-02-07 12:59:15 -0800848 dev_info(&i2c_client->dev,
849 "%s: update %s %3d / %3d\n",
850 __func__,
851 command == CMD_WRITE_CONFIG_BLOCK ?
852 "config" : "firmware",
853 block_num, block_cnt);
Alexandra Chin669d27c2012-12-24 15:42:30 +0800854#endif
855 retval = fwu->fn_ptr->write(fwu->rmi4_data,
856 fwu->f34_fd.data_base_addr + BLOCK_DATA_OFFSET,
857 block_ptr,
858 fwu->block_size);
859 if (retval < 0) {
Alexandra Chind5591a62013-02-07 12:59:15 -0800860 dev_err(&i2c_client->dev,
Alexandra Chin669d27c2012-12-24 15:42:30 +0800861 "%s: Failed to write block data (block %d)\n",
862 __func__, block_num);
863 return retval;
864 }
865
866 retval = fwu_write_f34_command(command);
867 if (retval < 0) {
Alexandra Chind5591a62013-02-07 12:59:15 -0800868 dev_err(&i2c_client->dev,
Alexandra Chin669d27c2012-12-24 15:42:30 +0800869 "%s: Failed to write command for block %d\n",
870 __func__, block_num);
871 return retval;
872 }
873
874 retval = fwu_wait_for_idle(WRITE_WAIT_MS);
875 if (retval < 0) {
Alexandra Chind5591a62013-02-07 12:59:15 -0800876 dev_err(&i2c_client->dev,
877 "%s: Failed to wait for idle status (block %d)\n",
878 __func__, block_num);
Alexandra Chin669d27c2012-12-24 15:42:30 +0800879 return retval;
880 }
881
Alexandra Chind5591a62013-02-07 12:59:15 -0800882 if (fwu->flash_control.status != 0x00) {
883 dev_err(&i2c_client->dev,
884 "%s: Flash block %d failed, status 0x%02X\n",
Alexandra Chin669d27c2012-12-24 15:42:30 +0800885 __func__, block_num, retval);
Shantanu Jain41f0d472013-01-04 12:14:37 +0530886 return retval;
Alexandra Chin669d27c2012-12-24 15:42:30 +0800887 }
Alexandra Chind5591a62013-02-07 12:59:15 -0800888
Alexandra Chin669d27c2012-12-24 15:42:30 +0800889 block_ptr += fwu->block_size;
890 }
891#ifdef SHOW_PROGRESS
Alexandra Chind5591a62013-02-07 12:59:15 -0800892 dev_info(&i2c_client->dev,
893 "%s: update %s %3d / %3d\n",
894 __func__,
895 command == CMD_WRITE_CONFIG_BLOCK ?
896 "config" : "firmware",
897 block_cnt, block_cnt);
Alexandra Chin669d27c2012-12-24 15:42:30 +0800898#endif
899 return 0;
900}
901
902static int fwu_write_firmware(void)
903{
904 return fwu_write_blocks((unsigned char *)fwu->firmware_data,
905 fwu->fw_block_count, CMD_WRITE_FW_BLOCK);
906}
907
908static int fwu_write_configuration(void)
909{
910 return fwu_write_blocks((unsigned char *)fwu->config_data,
911 fwu->config_block_count, CMD_WRITE_CONFIG_BLOCK);
912}
913
914static int fwu_write_bootloader_id(void)
915{
916 int retval;
917
918#ifdef DEBUG_FW_UPDATE
Alexandra Chind5591a62013-02-07 12:59:15 -0800919 dev_info(&fwu->rmi4_data->i2c_client->dev,
920 "Write bootloader ID 0x%02X 0x%02X\n",
921 fwu->bootloader_id[0],
922 fwu->bootloader_id[1]);
Alexandra Chin669d27c2012-12-24 15:42:30 +0800923#endif
924 retval = fwu->fn_ptr->write(fwu->rmi4_data,
925 fwu->f34_fd.data_base_addr + BLOCK_DATA_OFFSET,
926 fwu->bootloader_id,
927 sizeof(fwu->bootloader_id));
928 if (retval < 0) {
929 dev_err(&fwu->rmi4_data->i2c_client->dev,
930 "%s: Failed to write bootloader ID\n",
931 __func__);
932 return retval;
933 }
934
935 return 0;
936}
937
938static int fwu_enter_flash_prog(void)
939{
940 int retval;
941 struct f01_device_status f01_device_status;
942 struct f01_device_control f01_device_control;
943
944#ifdef DEBUG_FW_UPDATE
945 dev_info(&fwu->rmi4_data->i2c_client->dev, "Enter bootloader mode\n");
946#endif
947 retval = fwu_read_f01_device_status(&f01_device_status);
948 if (retval < 0)
949 return retval;
950
951 if (f01_device_status.flash_prog) {
952 dev_info(&fwu->rmi4_data->i2c_client->dev,
953 "%s: Already in flash prog mode\n",
954 __func__);
955 return 0;
956 }
957
958 retval = fwu_write_bootloader_id();
959 if (retval < 0)
960 return retval;
961
962 retval = fwu_write_f34_command(CMD_ENABLE_FLASH_PROG);
963 if (retval < 0)
964 return retval;
965
966 retval = fwu_wait_for_idle(ENABLE_WAIT_MS);
967 if (retval < 0)
968 return retval;
969
Alexandra Chin669d27c2012-12-24 15:42:30 +0800970 retval = fwu_scan_pdt();
971 if (retval < 0)
972 return retval;
973
974 retval = fwu_read_f01_device_status(&f01_device_status);
975 if (retval < 0)
976 return retval;
977
978 if (!f01_device_status.flash_prog) {
979 dev_err(&fwu->rmi4_data->i2c_client->dev,
980 "%s: Not in flash prog mode\n",
981 __func__);
982 return -EINVAL;
983 }
984
985 retval = fwu_read_f34_queries();
986 if (retval < 0)
987 return retval;
988
989 retval = fwu->fn_ptr->read(fwu->rmi4_data,
990 fwu->f01_fd.ctrl_base_addr,
991 f01_device_control.data,
992 sizeof(f01_device_control.data));
993 if (retval < 0) {
994 dev_err(&fwu->rmi4_data->i2c_client->dev,
995 "%s: Failed to read F01 device control\n",
996 __func__);
997 return retval;
998 }
999
1000 f01_device_control.nosleep = true;
1001 f01_device_control.sleep_mode = SLEEP_MODE_NORMAL;
1002
1003 retval = fwu->fn_ptr->write(fwu->rmi4_data,
1004 fwu->f01_fd.ctrl_base_addr,
1005 f01_device_control.data,
1006 sizeof(f01_device_control.data));
1007 if (retval < 0) {
1008 dev_err(&fwu->rmi4_data->i2c_client->dev,
1009 "%s: Failed to write F01 device control\n",
1010 __func__);
1011 return retval;
1012 }
1013
1014 return retval;
1015}
1016
1017static int fwu_do_reflash(void)
1018{
1019 int retval;
1020
1021 retval = fwu_enter_flash_prog();
1022 if (retval < 0)
1023 return retval;
1024
1025 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
1026 "%s: Entered flash prog mode\n",
1027 __func__);
1028
1029 retval = fwu_write_bootloader_id();
1030 if (retval < 0)
1031 return retval;
1032
1033 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
1034 "%s: Bootloader ID written\n",
1035 __func__);
1036
1037 retval = fwu_write_f34_command(CMD_ERASE_ALL);
1038 if (retval < 0)
1039 return retval;
1040
1041 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
1042 "%s: Erase all command written\n",
1043 __func__);
1044
1045 retval = fwu_wait_for_idle(ERASE_WAIT_MS);
1046 if (retval < 0)
1047 return retval;
1048
Alexandra Chind5591a62013-02-07 12:59:15 -08001049 if (fwu->flash_control.status != 0x00) {
1050 dev_err(&fwu->rmi4_data->i2c_client->dev,
1051 "%s: Erase all command failed, status 0x%02X\n",
1052 __func__, retval);
1053 return -1;
1054 }
Alexandra Chin669d27c2012-12-24 15:42:30 +08001055
1056 if (fwu->firmware_data) {
1057 retval = fwu_write_firmware();
1058 if (retval < 0)
1059 return retval;
1060 pr_notice("%s: Firmware programmed\n", __func__);
1061 }
1062
1063 if (fwu->config_data) {
1064 retval = fwu_write_configuration();
1065 if (retval < 0)
1066 return retval;
1067 pr_notice("%s: Configuration programmed\n", __func__);
1068 }
1069
1070 return retval;
1071}
1072
Alexandra Chin669d27c2012-12-24 15:42:30 +08001073static int fwu_do_write_config(void)
1074{
1075 int retval;
1076
1077 retval = fwu_enter_flash_prog();
1078 if (retval < 0)
1079 return retval;
1080
1081 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
1082 "%s: Entered flash prog mode\n",
1083 __func__);
1084
1085 if (fwu->config_area == PERM_CONFIG_AREA) {
1086 fwu->config_block_count = fwu->perm_config_block_count;
1087 goto write_config;
1088 }
1089
1090 retval = fwu_write_bootloader_id();
1091 if (retval < 0)
1092 return retval;
1093
1094 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
1095 "%s: Bootloader ID written\n",
1096 __func__);
1097
1098 switch (fwu->config_area) {
1099 case UI_CONFIG_AREA:
1100 retval = fwu_write_f34_command(CMD_ERASE_CONFIG);
1101 break;
1102 case BL_CONFIG_AREA:
1103 retval = fwu_write_f34_command(CMD_ERASE_BL_CONFIG);
1104 fwu->config_block_count = fwu->bl_config_block_count;
1105 break;
1106 case DISP_CONFIG_AREA:
1107 retval = fwu_write_f34_command(CMD_ERASE_DISP_CONFIG);
1108 fwu->config_block_count = fwu->disp_config_block_count;
1109 break;
1110 }
1111 if (retval < 0)
1112 return retval;
1113
1114 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
1115 "%s: Erase command written\n",
1116 __func__);
1117
1118 retval = fwu_wait_for_idle(ERASE_WAIT_MS);
1119 if (retval < 0)
1120 return retval;
1121
1122 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
1123 "%s: Idle status detected\n",
1124 __func__);
1125
1126write_config:
1127 retval = fwu_write_configuration();
1128 if (retval < 0)
1129 return retval;
1130
1131 pr_notice("%s: Config written\n", __func__);
1132
1133 return retval;
1134}
1135
1136static int fwu_start_write_config(void)
1137{
1138 int retval;
1139 struct image_header header;
1140
1141 switch (fwu->config_area) {
1142 case UI_CONFIG_AREA:
1143 break;
1144 case PERM_CONFIG_AREA:
1145 if (!fwu->flash_properties.has_perm_config)
1146 return -EINVAL;
1147 break;
1148 case BL_CONFIG_AREA:
1149 if (!fwu->flash_properties.has_bl_config)
1150 return -EINVAL;
1151 break;
1152 case DISP_CONFIG_AREA:
1153 if (!fwu->flash_properties.has_display_config)
1154 return -EINVAL;
1155 break;
1156 default:
1157 return -EINVAL;
1158 }
1159
1160 if (fwu->ext_data_source)
1161 fwu->config_data = fwu->ext_data_source;
1162 else
1163 return -EINVAL;
1164
1165 if (fwu->config_area == UI_CONFIG_AREA) {
1166 parse_header(&header, fwu->ext_data_source);
1167
1168 if (header.config_size) {
1169 fwu->config_data = fwu->ext_data_source +
1170 FW_IMAGE_OFFSET +
1171 header.image_size;
1172 } else {
1173 return -EINVAL;
1174 }
1175 }
1176
1177 pr_notice("%s: Start of write config process\n", __func__);
1178
1179 retval = fwu_do_write_config();
1180 if (retval < 0) {
1181 dev_err(&fwu->rmi4_data->i2c_client->dev,
1182 "%s: Failed to write config\n",
1183 __func__);
1184 }
1185
1186 fwu->rmi4_data->reset_device(fwu->rmi4_data);
1187
1188 pr_notice("%s: End of write config process\n", __func__);
1189
1190 return retval;
1191}
1192
1193static int fwu_do_read_config(void)
1194{
1195 int retval;
1196 unsigned char block_offset[] = {0, 0};
1197 unsigned short block_num;
1198 unsigned short block_count;
1199 unsigned short index = 0;
1200
1201 retval = fwu_enter_flash_prog();
1202 if (retval < 0)
1203 goto exit;
1204
1205 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
1206 "%s: Entered flash prog mode\n",
1207 __func__);
1208
1209 switch (fwu->config_area) {
1210 case UI_CONFIG_AREA:
1211 block_count = fwu->config_block_count;
1212 break;
1213 case PERM_CONFIG_AREA:
1214 if (!fwu->flash_properties.has_perm_config) {
1215 retval = -EINVAL;
1216 goto exit;
1217 }
1218 block_count = fwu->perm_config_block_count;
1219 break;
1220 case BL_CONFIG_AREA:
1221 if (!fwu->flash_properties.has_bl_config) {
1222 retval = -EINVAL;
1223 goto exit;
1224 }
1225 block_count = fwu->bl_config_block_count;
1226 break;
1227 case DISP_CONFIG_AREA:
1228 if (!fwu->flash_properties.has_display_config) {
1229 retval = -EINVAL;
1230 goto exit;
1231 }
1232 block_count = fwu->disp_config_block_count;
1233 break;
1234 default:
1235 retval = -EINVAL;
1236 goto exit;
1237 }
1238
1239 fwu->config_size = fwu->block_size * block_count;
1240
1241 kfree(fwu->read_config_buf);
1242 fwu->read_config_buf = kzalloc(fwu->config_size, GFP_KERNEL);
1243
1244 block_offset[1] |= (fwu->config_area << 5);
1245
1246 retval = fwu->fn_ptr->write(fwu->rmi4_data,
1247 fwu->f34_fd.data_base_addr + BLOCK_NUMBER_OFFSET,
1248 block_offset,
1249 sizeof(block_offset));
1250 if (retval < 0) {
1251 dev_err(&fwu->rmi4_data->i2c_client->dev,
1252 "%s: Failed to write to block number registers\n",
1253 __func__);
1254 goto exit;
1255 }
1256
1257 for (block_num = 0; block_num < block_count; block_num++) {
1258 retval = fwu_write_f34_command(CMD_READ_CONFIG_BLOCK);
1259 if (retval < 0) {
1260 dev_err(&fwu->rmi4_data->i2c_client->dev,
1261 "%s: Failed to write read config command\n",
1262 __func__);
1263 goto exit;
1264 }
1265
1266 retval = fwu_wait_for_idle(WRITE_WAIT_MS);
1267 if (retval < 0) {
1268 dev_err(&fwu->rmi4_data->i2c_client->dev,
1269 "%s: Failed to wait for idle status\n",
1270 __func__);
1271 goto exit;
1272 }
1273
1274 retval = fwu->fn_ptr->read(fwu->rmi4_data,
1275 fwu->f34_fd.data_base_addr + BLOCK_DATA_OFFSET,
1276 &fwu->read_config_buf[index],
1277 fwu->block_size);
1278 if (retval < 0) {
1279 dev_err(&fwu->rmi4_data->i2c_client->dev,
1280 "%s: Failed to read block data (block %d)\n",
1281 __func__, block_num);
1282 goto exit;
1283 }
1284
1285 index += fwu->block_size;
1286 }
1287
1288exit:
1289 fwu->rmi4_data->reset_device(fwu->rmi4_data);
1290
1291 return retval;
1292}
1293
Alexandra Chind5591a62013-02-07 12:59:15 -08001294static int fwu_start_reflash(void)
1295{
Amy Malocheafcecb22013-04-16 18:43:22 -07001296 int retval = 0;
Alexandra Chind5591a62013-02-07 12:59:15 -08001297 struct image_header header;
1298 const unsigned char *fw_image;
1299 const struct firmware *fw_entry = NULL;
1300 struct f01_device_status f01_device_status;
1301 enum flash_area flash_area;
1302
1303 pr_notice("%s: Start of reflash process\n", __func__);
1304
Amy Malochecb835832013-03-26 18:06:05 -07001305 if (!fwu->rmi4_data->fw_image_name) {
1306 retval = 0;
1307 dev_err(&fwu->rmi4_data->i2c_client->dev,
1308 "Firmware image name not given, skipping update\n");
1309 goto exit;
1310 }
1311
Alexandra Chind5591a62013-02-07 12:59:15 -08001312 if (fwu->ext_data_source)
1313 fw_image = fwu->ext_data_source;
1314 else {
Amy Malocheafcecb22013-04-16 18:43:22 -07001315 fwu->firmware_name = kcalloc(NAME_BUFFER_SIZE,
1316 sizeof(char), GFP_KERNEL);
1317 if (!fwu->firmware_name) {
1318 dev_err(&fwu->rmi4_data->i2c_client->dev,
1319 "%s Failed to allocate firmware name (%d).\n",
1320 __func__, NAME_BUFFER_SIZE);
1321 retval = -ENOMEM;
1322 goto memory_exit;
1323 }
1324
1325 snprintf(fwu->firmware_name, NAME_BUFFER_SIZE, "%s",
1326 fwu->rmi4_data->fw_image_name);
1327 dev_info(&fwu->rmi4_data->i2c_client->dev,
1328 "%s: Requesting firmware image %s\n",
1329 __func__, fwu->firmware_name);
Alexandra Chind5591a62013-02-07 12:59:15 -08001330
Amy Malochecb835832013-03-26 18:06:05 -07001331 retval = request_firmware(&fw_entry,
Amy Malocheafcecb22013-04-16 18:43:22 -07001332 fwu->firmware_name,
Alexandra Chind5591a62013-02-07 12:59:15 -08001333 &fwu->rmi4_data->i2c_client->dev);
1334 if (retval != 0) {
1335 dev_err(&fwu->rmi4_data->i2c_client->dev,
1336 "%s: Firmware image %s not available\n",
Amy Malochecb835832013-03-26 18:06:05 -07001337 __func__,
Amy Malocheafcecb22013-04-16 18:43:22 -07001338 fwu->firmware_name);
Alexandra Chind5591a62013-02-07 12:59:15 -08001339 retval = -EINVAL;
1340 goto exit;
1341 }
1342
1343 dev_dbg(&fwu->rmi4_data->i2c_client->dev,
1344 "%s: Firmware image size = %d\n",
1345 __func__, fw_entry->size);
1346
1347 fw_image = fw_entry->data;
1348 }
1349
1350 parse_header(&header, fw_image);
1351
1352 if (header.image_size)
1353 fwu->firmware_data = fw_image + FW_IMAGE_OFFSET;
1354 if (header.config_size) {
1355 fwu->config_data = fw_image + FW_IMAGE_OFFSET +
1356 header.image_size;
1357 }
1358
1359 if (fwu->ext_data_source)
1360 flash_area = UI_FIRMWARE;
1361 else
Amy Malocheafcecb22013-04-16 18:43:22 -07001362 flash_area = fwu_go_nogo(&header);
Alexandra Chind5591a62013-02-07 12:59:15 -08001363
1364 switch (flash_area) {
1365 case NONE:
1366 dev_info(&fwu->rmi4_data->i2c_client->dev,
1367 "%s: No need to do reflash.\n",
1368 __func__);
1369 goto exit;
1370 case UI_FIRMWARE:
1371 retval = fwu_do_reflash();
1372 break;
1373 case CONFIG_AREA:
1374 retval = fwu_do_write_config();
1375 break;
1376 default:
1377 dev_err(&fwu->rmi4_data->i2c_client->dev,
1378 "%s: Unknown flash area\n",
1379 __func__);
1380 goto exit;
1381 }
1382
1383 if (retval < 0) {
1384 dev_err(&fwu->rmi4_data->i2c_client->dev,
1385 "%s: Failed to do reflash\n",
1386 __func__);
1387 }
1388
1389 /* reset device */
1390 fwu_reset_device();
1391
1392 /* check device status */
1393 retval = fwu_read_f01_device_status(&f01_device_status);
1394 if (retval < 0)
1395 goto exit;
1396
1397 dev_info(&fwu->rmi4_data->i2c_client->dev, "Device is in %s mode\n",
1398 f01_device_status.flash_prog == 1 ? "bootloader" : "UI");
1399 if (f01_device_status.flash_prog)
1400 dev_info(&fwu->rmi4_data->i2c_client->dev, "Flash status %d\n",
1401 f01_device_status.status_code);
1402
1403 if (f01_device_status.flash_prog) {
1404 dev_info(&fwu->rmi4_data->i2c_client->dev,
1405 "%s: Device is in flash prog mode 0x%02X\n",
1406 __func__, f01_device_status.status_code);
1407 retval = 0;
1408 goto exit;
1409 }
1410
1411 if (fw_entry)
1412 release_firmware(fw_entry);
1413
1414 pr_notice("%s: End of reflash process\n", __func__);
1415exit:
Amy Malocheafcecb22013-04-16 18:43:22 -07001416 kfree(fwu->firmware_name);
1417memory_exit:
Alexandra Chind5591a62013-02-07 12:59:15 -08001418 return retval;
1419}
1420
Alexandra Chin669d27c2012-12-24 15:42:30 +08001421int synaptics_fw_updater(unsigned char *fw_data)
1422{
1423 int retval;
1424
1425 if (!fwu)
1426 return -ENODEV;
1427
1428 if (!fwu->initialized)
1429 return -ENODEV;
1430
1431 fwu->ext_data_source = fw_data;
1432 fwu->config_area = UI_CONFIG_AREA;
1433
1434 retval = fwu_start_reflash();
1435
1436 return retval;
1437}
1438EXPORT_SYMBOL(synaptics_fw_updater);
1439
1440static ssize_t fwu_sysfs_show_image(struct file *data_file,
1441 struct kobject *kobj, struct bin_attribute *attributes,
1442 char *buf, loff_t pos, size_t count)
1443{
1444 struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
1445
1446 if (count < fwu->config_size) {
1447 dev_err(&rmi4_data->i2c_client->dev,
1448 "%s: Not enough space (%d bytes) in buffer\n",
1449 __func__, count);
1450 return -EINVAL;
1451 }
1452
1453 memcpy(buf, fwu->read_config_buf, fwu->config_size);
1454
1455 return fwu->config_size;
1456}
1457
1458static ssize_t fwu_sysfs_store_image(struct file *data_file,
1459 struct kobject *kobj, struct bin_attribute *attributes,
1460 char *buf, loff_t pos, size_t count)
1461{
1462 memcpy((void *)(&fwu->ext_data_source[fwu->data_pos]),
1463 (const void *)buf,
1464 count);
1465
1466 fwu->data_pos += count;
1467
1468 return count;
1469}
1470
Amy Maloche5e0360e2013-05-01 13:31:57 -07001471static ssize_t fwu_sysfs_force_reflash_store(struct device *dev,
1472 struct device_attribute *attr, const char *buf, size_t count)
1473{
1474 int retval;
1475 unsigned int input;
1476 struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
1477
1478 if (sscanf(buf, "%u", &input) != 1) {
1479 retval = -EINVAL;
1480 goto exit;
1481 }
1482
1483 if (input != 1) {
1484 retval = -EINVAL;
1485 goto exit;
1486 }
1487
1488 fwu->force_update = true;
1489 retval = synaptics_fw_updater(fwu->ext_data_source);
1490 if (retval < 0) {
1491 dev_err(&rmi4_data->i2c_client->dev,
1492 "%s: Failed to do reflash\n",
1493 __func__);
1494 goto exit;
1495 }
1496
1497 retval = count;
1498
1499exit:
1500 kfree(fwu->ext_data_source);
1501 fwu->ext_data_source = NULL;
1502 return retval;
1503}
1504
Alexandra Chin669d27c2012-12-24 15:42:30 +08001505static ssize_t fwu_sysfs_do_reflash_store(struct device *dev,
1506 struct device_attribute *attr, const char *buf, size_t count)
1507{
1508 int retval;
1509 unsigned int input;
1510 struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
1511
1512 if (sscanf(buf, "%u", &input) != 1) {
1513 retval = -EINVAL;
1514 goto exit;
1515 }
1516
1517 if (input != 1) {
1518 retval = -EINVAL;
1519 goto exit;
1520 }
1521
1522 retval = synaptics_fw_updater(fwu->ext_data_source);
1523 if (retval < 0) {
1524 dev_err(&rmi4_data->i2c_client->dev,
1525 "%s: Failed to do reflash\n",
1526 __func__);
1527 goto exit;
1528 }
1529
1530 retval = count;
1531
1532exit:
1533 kfree(fwu->ext_data_source);
1534 fwu->ext_data_source = NULL;
1535 return retval;
1536}
1537
1538static ssize_t fwu_sysfs_write_config_store(struct device *dev,
1539 struct device_attribute *attr, const char *buf, size_t count)
1540{
1541 int retval;
1542 unsigned int input;
1543 struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
1544
1545 if (sscanf(buf, "%u", &input) != 1) {
1546 retval = -EINVAL;
1547 goto exit;
1548 }
1549
1550 if (input != 1) {
1551 retval = -EINVAL;
1552 goto exit;
1553 }
1554
1555 retval = fwu_start_write_config();
1556 if (retval < 0) {
1557 dev_err(&rmi4_data->i2c_client->dev,
1558 "%s: Failed to write config\n",
1559 __func__);
1560 goto exit;
1561 }
1562
1563 retval = count;
1564
1565exit:
1566 kfree(fwu->ext_data_source);
1567 fwu->ext_data_source = NULL;
1568 return retval;
1569}
1570
1571static ssize_t fwu_sysfs_read_config_store(struct device *dev,
1572 struct device_attribute *attr, const char *buf, size_t count)
1573{
1574 int retval;
1575 unsigned int input;
1576 struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
1577
1578 if (sscanf(buf, "%u", &input) != 1)
1579 return -EINVAL;
1580
1581 if (input != 1)
1582 return -EINVAL;
1583
1584 retval = fwu_do_read_config();
1585 if (retval < 0) {
1586 dev_err(&rmi4_data->i2c_client->dev,
1587 "%s: Failed to read config\n",
1588 __func__);
1589 return retval;
1590 }
1591
1592 return count;
1593}
1594
1595static ssize_t fwu_sysfs_config_area_store(struct device *dev,
1596 struct device_attribute *attr, const char *buf, size_t count)
1597{
1598 int retval;
1599 unsigned long config_area;
1600
Shantanu Jain41f0d472013-01-04 12:14:37 +05301601 retval = kstrtoul(buf, 10, &config_area);
Alexandra Chin669d27c2012-12-24 15:42:30 +08001602 if (retval)
1603 return retval;
1604
1605 fwu->config_area = config_area;
1606
1607 return count;
1608}
1609
1610static ssize_t fwu_sysfs_image_size_store(struct device *dev,
1611 struct device_attribute *attr, const char *buf, size_t count)
1612{
1613 int retval;
1614 unsigned long size;
1615 struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
1616
Shantanu Jain41f0d472013-01-04 12:14:37 +05301617 retval = kstrtoul(buf, 10, &size);
Alexandra Chin669d27c2012-12-24 15:42:30 +08001618 if (retval)
1619 return retval;
1620
1621 fwu->image_size = size;
1622 fwu->data_pos = 0;
1623
1624 kfree(fwu->ext_data_source);
1625 fwu->ext_data_source = kzalloc(fwu->image_size, GFP_KERNEL);
1626 if (!fwu->ext_data_source) {
1627 dev_err(&rmi4_data->i2c_client->dev,
1628 "%s: Failed to alloc mem for image data\n",
1629 __func__);
1630 return -ENOMEM;
1631 }
1632
1633 return count;
1634}
1635
1636static ssize_t fwu_sysfs_block_size_show(struct device *dev,
1637 struct device_attribute *attr, char *buf)
1638{
1639 return snprintf(buf, PAGE_SIZE, "%u\n", fwu->block_size);
1640}
1641
1642static ssize_t fwu_sysfs_firmware_block_count_show(struct device *dev,
1643 struct device_attribute *attr, char *buf)
1644{
1645 return snprintf(buf, PAGE_SIZE, "%u\n", fwu->fw_block_count);
1646}
1647
1648static ssize_t fwu_sysfs_configuration_block_count_show(struct device *dev,
1649 struct device_attribute *attr, char *buf)
1650{
1651 return snprintf(buf, PAGE_SIZE, "%u\n", fwu->config_block_count);
1652}
1653
1654static ssize_t fwu_sysfs_perm_config_block_count_show(struct device *dev,
1655 struct device_attribute *attr, char *buf)
1656{
1657 return snprintf(buf, PAGE_SIZE, "%u\n", fwu->perm_config_block_count);
1658}
1659
1660static ssize_t fwu_sysfs_bl_config_block_count_show(struct device *dev,
1661 struct device_attribute *attr, char *buf)
1662{
1663 return snprintf(buf, PAGE_SIZE, "%u\n", fwu->bl_config_block_count);
1664}
1665
1666static ssize_t fwu_sysfs_disp_config_block_count_show(struct device *dev,
1667 struct device_attribute *attr, char *buf)
1668{
1669 return snprintf(buf, PAGE_SIZE, "%u\n", fwu->disp_config_block_count);
1670}
1671
Amy Maloched25bd8c2013-01-25 12:34:31 -08001672static ssize_t fwu_sysfs_config_id_show(struct device *dev,
1673 struct device_attribute *attr, char *buf)
1674{
Amy Maloche581f7402013-02-19 16:29:37 -08001675 unsigned char config_id[4];
Amy Maloched25bd8c2013-01-25 12:34:31 -08001676 /* device config id */
1677 fwu->fn_ptr->read(fwu->rmi4_data,
1678 fwu->f34_fd.ctrl_base_addr,
1679 config_id,
1680 sizeof(config_id));
1681
1682 return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n",
1683 config_id[0], config_id[1], config_id[2], config_id[3]);
1684}
1685
Alexandra Chin669d27c2012-12-24 15:42:30 +08001686static void synaptics_rmi4_fwu_attn(struct synaptics_rmi4_data *rmi4_data,
1687 unsigned char intr_mask)
1688{
1689 if (fwu->intr_mask & intr_mask)
1690 fwu_read_f34_flash_status();
1691
1692 return;
1693}
1694
Alexandra Chind5591a62013-02-07 12:59:15 -08001695static void synaptics_rmi4_fwu_work(struct work_struct *work)
1696{
1697 fwu_start_reflash();
1698}
1699
Alexandra Chin669d27c2012-12-24 15:42:30 +08001700static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data)
1701{
1702 int retval;
1703 unsigned char attr_count;
1704 struct pdt_properties pdt_props;
1705
1706 fwu = kzalloc(sizeof(*fwu), GFP_KERNEL);
1707 if (!fwu) {
1708 dev_err(&rmi4_data->i2c_client->dev,
1709 "%s: Failed to alloc mem for fwu\n",
1710 __func__);
1711 goto exit;
1712 }
1713
1714 fwu->fn_ptr = kzalloc(sizeof(*(fwu->fn_ptr)), GFP_KERNEL);
1715 if (!fwu->fn_ptr) {
1716 dev_err(&rmi4_data->i2c_client->dev,
1717 "%s: Failed to alloc mem for fn_ptr\n",
1718 __func__);
1719 retval = -ENOMEM;
1720 goto exit_free_fwu;
1721 }
1722
1723 fwu->rmi4_data = rmi4_data;
1724 fwu->fn_ptr->read = rmi4_data->i2c_read;
1725 fwu->fn_ptr->write = rmi4_data->i2c_write;
1726 fwu->fn_ptr->enable = rmi4_data->irq_enable;
1727
1728 retval = fwu->fn_ptr->read(rmi4_data,
1729 PDT_PROPS,
1730 pdt_props.data,
1731 sizeof(pdt_props.data));
1732 if (retval < 0) {
1733 dev_dbg(&rmi4_data->i2c_client->dev,
1734 "%s: Failed to read PDT properties, assuming 0x00\n",
1735 __func__);
1736 } else if (pdt_props.has_bsr) {
1737 dev_err(&rmi4_data->i2c_client->dev,
1738 "%s: Reflash for LTS not currently supported\n",
1739 __func__);
1740 goto exit_free_mem;
1741 }
1742
1743 retval = fwu_scan_pdt();
1744 if (retval < 0)
1745 goto exit_free_mem;
1746
1747 fwu->productinfo1 = rmi4_data->rmi4_mod_info.product_info[0];
1748 fwu->productinfo2 = rmi4_data->rmi4_mod_info.product_info[1];
1749
1750 memcpy(fwu->product_id, rmi4_data->rmi4_mod_info.product_id_string,
1751 SYNAPTICS_RMI4_PRODUCT_ID_SIZE);
1752 fwu->product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE] = 0;
1753
1754 dev_dbg(&rmi4_data->i2c_client->dev,
1755 "%s: F01 product info: 0x%04x 0x%04x\n",
1756 __func__, fwu->productinfo1, fwu->productinfo2);
1757 dev_dbg(&rmi4_data->i2c_client->dev,
1758 "%s: F01 product ID: %s\n",
1759 __func__, fwu->product_id);
1760
1761 retval = fwu_read_f34_queries();
1762 if (retval < 0)
1763 goto exit_free_mem;
1764
1765 fwu->initialized = true;
Alexandra Chind5591a62013-02-07 12:59:15 -08001766 fwu->force_update = FORCE_UPDATE;
Alexandra Chin669d27c2012-12-24 15:42:30 +08001767
1768 retval = sysfs_create_bin_file(&rmi4_data->input_dev->dev.kobj,
1769 &dev_attr_data);
1770 if (retval < 0) {
1771 dev_err(&rmi4_data->i2c_client->dev,
1772 "%s: Failed to create sysfs bin file\n",
1773 __func__);
1774 goto exit_free_mem;
1775 }
1776
1777 for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
1778 retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj,
1779 &attrs[attr_count].attr);
1780 if (retval < 0) {
1781 dev_err(&rmi4_data->i2c_client->dev,
1782 "%s: Failed to create sysfs attributes\n",
1783 __func__);
1784 retval = -ENODEV;
1785 goto exit_remove_attrs;
1786 }
1787 }
1788
Alexandra Chind5591a62013-02-07 12:59:15 -08001789#ifdef INSIDE_FIRMWARE_UPDATE
1790 fwu->fwu_workqueue = create_singlethread_workqueue("fwu_workqueue");
1791 INIT_DELAYED_WORK(&fwu->fwu_work, synaptics_rmi4_fwu_work);
1792 queue_delayed_work(fwu->fwu_workqueue,
1793 &fwu->fwu_work,
1794 msecs_to_jiffies(1000));
1795#endif
Alexandra Chinc556cf02013-03-19 17:46:05 -07001796
1797 init_completion(&remove_complete);
1798
Alexandra Chin669d27c2012-12-24 15:42:30 +08001799 return 0;
1800
1801exit_remove_attrs:
1802for (attr_count--; attr_count >= 0; attr_count--) {
1803 sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
1804 &attrs[attr_count].attr);
1805}
1806
1807sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
1808
1809exit_free_mem:
1810 kfree(fwu->fn_ptr);
1811
1812exit_free_fwu:
1813 kfree(fwu);
1814
1815exit:
1816 return 0;
1817}
1818
1819static void synaptics_rmi4_fwu_remove(struct synaptics_rmi4_data *rmi4_data)
1820{
1821 unsigned char attr_count;
1822
1823 sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
1824
1825 for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
1826 sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
1827 &attrs[attr_count].attr);
1828 }
1829
1830 kfree(fwu->fn_ptr);
1831 kfree(fwu);
1832
1833 complete(&remove_complete);
1834
1835 return;
1836}
1837
1838static int __init rmi4_fw_update_module_init(void)
1839{
1840 synaptics_rmi4_new_function(RMI_FW_UPDATER, true,
1841 synaptics_rmi4_fwu_init,
1842 synaptics_rmi4_fwu_remove,
1843 synaptics_rmi4_fwu_attn);
1844 return 0;
1845}
1846
1847static void __exit rmi4_fw_update_module_exit(void)
1848{
Alexandra Chin669d27c2012-12-24 15:42:30 +08001849 synaptics_rmi4_new_function(RMI_FW_UPDATER, false,
1850 synaptics_rmi4_fwu_init,
1851 synaptics_rmi4_fwu_remove,
1852 synaptics_rmi4_fwu_attn);
1853 wait_for_completion(&remove_complete);
1854 return;
1855}
1856
1857module_init(rmi4_fw_update_module_init);
1858module_exit(rmi4_fw_update_module_exit);
1859
1860MODULE_AUTHOR("Synaptics, Inc.");
1861MODULE_DESCRIPTION("RMI4 FW Update Module");
Alexandra Chinbd1dac22013-02-22 12:33:19 -08001862MODULE_LICENSE("GPL v2");