]>
Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
29fd0ec2 ND |
2 | /* |
3 | * Copyright (c) 2007-2016, Synaptics Incorporated | |
4 | * Copyright (C) 2016 Zodiac Inflight Innovations | |
29fd0ec2 ND |
5 | */ |
6 | ||
7 | #include <linux/kernel.h> | |
8 | #include <linux/rmi.h> | |
9 | #include <linux/firmware.h> | |
10 | #include <asm/unaligned.h> | |
5191d88a | 11 | #include <linux/bitops.h> |
29fd0ec2 ND |
12 | |
13 | #include "rmi_driver.h" | |
14 | #include "rmi_f34.h" | |
15 | ||
16 | static int rmi_f34_write_bootloader_id(struct f34_data *f34) | |
17 | { | |
18 | struct rmi_function *fn = f34->fn; | |
19 | struct rmi_device *rmi_dev = fn->rmi_dev; | |
20 | u8 bootloader_id[F34_BOOTLOADER_ID_LEN]; | |
21 | int ret; | |
22 | ||
23 | ret = rmi_read_block(rmi_dev, fn->fd.query_base_addr, | |
24 | bootloader_id, sizeof(bootloader_id)); | |
25 | if (ret) { | |
26 | dev_err(&fn->dev, "%s: Reading bootloader ID failed: %d\n", | |
27 | __func__, ret); | |
28 | return ret; | |
29 | } | |
30 | ||
31 | rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: writing bootloader id '%c%c'\n", | |
32 | __func__, bootloader_id[0], bootloader_id[1]); | |
33 | ||
34 | ret = rmi_write_block(rmi_dev, | |
35 | fn->fd.data_base_addr + F34_BLOCK_DATA_OFFSET, | |
36 | bootloader_id, sizeof(bootloader_id)); | |
37 | if (ret) { | |
38 | dev_err(&fn->dev, "Failed to write bootloader ID: %d\n", ret); | |
39 | return ret; | |
40 | } | |
41 | ||
42 | return 0; | |
43 | } | |
44 | ||
45 | static int rmi_f34_command(struct f34_data *f34, u8 command, | |
46 | unsigned int timeout, bool write_bl_id) | |
47 | { | |
48 | struct rmi_function *fn = f34->fn; | |
49 | struct rmi_device *rmi_dev = fn->rmi_dev; | |
50 | int ret; | |
51 | ||
52 | if (write_bl_id) { | |
53 | ret = rmi_f34_write_bootloader_id(f34); | |
54 | if (ret) | |
55 | return ret; | |
56 | } | |
57 | ||
58 | init_completion(&f34->v5.cmd_done); | |
59 | ||
60 | ret = rmi_read(rmi_dev, f34->v5.ctrl_address, &f34->v5.status); | |
61 | if (ret) { | |
62 | dev_err(&f34->fn->dev, | |
63 | "%s: Failed to read cmd register: %d (command %#02x)\n", | |
64 | __func__, ret, command); | |
65 | return ret; | |
66 | } | |
67 | ||
68 | f34->v5.status |= command & 0x0f; | |
69 | ||
70 | ret = rmi_write(rmi_dev, f34->v5.ctrl_address, f34->v5.status); | |
71 | if (ret < 0) { | |
72 | dev_err(&f34->fn->dev, | |
73 | "Failed to write F34 command %#02x: %d\n", | |
74 | command, ret); | |
75 | return ret; | |
76 | } | |
77 | ||
78 | if (!wait_for_completion_timeout(&f34->v5.cmd_done, | |
79 | msecs_to_jiffies(timeout))) { | |
80 | ||
81 | ret = rmi_read(rmi_dev, f34->v5.ctrl_address, &f34->v5.status); | |
82 | if (ret) { | |
83 | dev_err(&f34->fn->dev, | |
84 | "%s: cmd %#02x timed out: %d\n", | |
85 | __func__, command, ret); | |
86 | return ret; | |
87 | } | |
88 | ||
89 | if (f34->v5.status & 0x7f) { | |
90 | dev_err(&f34->fn->dev, | |
91 | "%s: cmd %#02x timed out, status: %#02x\n", | |
92 | __func__, command, f34->v5.status); | |
93 | return -ETIMEDOUT; | |
94 | } | |
95 | } | |
96 | ||
97 | return 0; | |
98 | } | |
99 | ||
24d28e4f | 100 | static irqreturn_t rmi_f34_attention(int irq, void *ctx) |
29fd0ec2 | 101 | { |
24d28e4f | 102 | struct rmi_function *fn = ctx; |
29fd0ec2 ND |
103 | struct f34_data *f34 = dev_get_drvdata(&fn->dev); |
104 | int ret; | |
a6869e3a ND |
105 | u8 status; |
106 | ||
107 | if (f34->bl_version == 5) { | |
108 | ret = rmi_read(f34->fn->rmi_dev, f34->v5.ctrl_address, | |
109 | &status); | |
110 | rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: status: %#02x, ret: %d\n", | |
111 | __func__, status, ret); | |
112 | ||
113 | if (!ret && !(status & 0x7f)) | |
114 | complete(&f34->v5.cmd_done); | |
115 | } else { | |
116 | ret = rmi_read_block(f34->fn->rmi_dev, | |
117 | f34->fn->fd.data_base_addr + | |
118 | f34->v7.off.flash_status, | |
119 | &status, sizeof(status)); | |
120 | rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: status: %#02x, ret: %d\n", | |
121 | __func__, status, ret); | |
122 | ||
123 | if (!ret && !(status & 0x1f)) | |
124 | complete(&f34->v7.cmd_done); | |
125 | } | |
29fd0ec2 | 126 | |
24d28e4f | 127 | return IRQ_HANDLED; |
29fd0ec2 ND |
128 | } |
129 | ||
130 | static int rmi_f34_write_blocks(struct f34_data *f34, const void *data, | |
131 | int block_count, u8 command) | |
132 | { | |
133 | struct rmi_function *fn = f34->fn; | |
134 | struct rmi_device *rmi_dev = fn->rmi_dev; | |
135 | u16 address = fn->fd.data_base_addr + F34_BLOCK_DATA_OFFSET; | |
136 | u8 start_address[] = { 0, 0 }; | |
137 | int i; | |
138 | int ret; | |
139 | ||
140 | ret = rmi_write_block(rmi_dev, fn->fd.data_base_addr, | |
141 | start_address, sizeof(start_address)); | |
142 | if (ret) { | |
143 | dev_err(&fn->dev, "Failed to write initial zeros: %d\n", ret); | |
144 | return ret; | |
145 | } | |
146 | ||
147 | for (i = 0; i < block_count; i++) { | |
148 | ret = rmi_write_block(rmi_dev, address, | |
149 | data, f34->v5.block_size); | |
150 | if (ret) { | |
151 | dev_err(&fn->dev, | |
152 | "failed to write block #%d: %d\n", i, ret); | |
153 | return ret; | |
154 | } | |
155 | ||
156 | ret = rmi_f34_command(f34, command, F34_IDLE_WAIT_MS, false); | |
157 | if (ret) { | |
158 | dev_err(&fn->dev, | |
159 | "Failed to write command for block #%d: %d\n", | |
160 | i, ret); | |
161 | return ret; | |
162 | } | |
163 | ||
164 | rmi_dbg(RMI_DEBUG_FN, &fn->dev, "wrote block %d of %d\n", | |
165 | i + 1, block_count); | |
166 | ||
167 | data += f34->v5.block_size; | |
5a89916d ND |
168 | f34->update_progress += f34->v5.block_size; |
169 | f34->update_status = (f34->update_progress * 100) / | |
170 | f34->update_size; | |
29fd0ec2 ND |
171 | } |
172 | ||
173 | return 0; | |
174 | } | |
175 | ||
176 | static int rmi_f34_write_firmware(struct f34_data *f34, const void *data) | |
177 | { | |
178 | return rmi_f34_write_blocks(f34, data, f34->v5.fw_blocks, | |
179 | F34_WRITE_FW_BLOCK); | |
180 | } | |
181 | ||
182 | static int rmi_f34_write_config(struct f34_data *f34, const void *data) | |
183 | { | |
184 | return rmi_f34_write_blocks(f34, data, f34->v5.config_blocks, | |
185 | F34_WRITE_CONFIG_BLOCK); | |
186 | } | |
187 | ||
5a89916d | 188 | static int rmi_f34_enable_flash(struct f34_data *f34) |
29fd0ec2 ND |
189 | { |
190 | return rmi_f34_command(f34, F34_ENABLE_FLASH_PROG, | |
191 | F34_ENABLE_WAIT_MS, true); | |
192 | } | |
193 | ||
194 | static int rmi_f34_flash_firmware(struct f34_data *f34, | |
195 | const struct rmi_f34_firmware *syn_fw) | |
196 | { | |
197 | struct rmi_function *fn = f34->fn; | |
5a89916d ND |
198 | u32 image_size = le32_to_cpu(syn_fw->image_size); |
199 | u32 config_size = le32_to_cpu(syn_fw->config_size); | |
29fd0ec2 ND |
200 | int ret; |
201 | ||
5a89916d ND |
202 | f34->update_progress = 0; |
203 | f34->update_size = image_size + config_size; | |
204 | ||
205 | if (image_size) { | |
29fd0ec2 ND |
206 | dev_info(&fn->dev, "Erasing firmware...\n"); |
207 | ret = rmi_f34_command(f34, F34_ERASE_ALL, | |
208 | F34_ERASE_WAIT_MS, true); | |
209 | if (ret) | |
210 | return ret; | |
211 | ||
212 | dev_info(&fn->dev, "Writing firmware (%d bytes)...\n", | |
5a89916d | 213 | image_size); |
29fd0ec2 ND |
214 | ret = rmi_f34_write_firmware(f34, syn_fw->data); |
215 | if (ret) | |
216 | return ret; | |
217 | } | |
218 | ||
5a89916d | 219 | if (config_size) { |
29fd0ec2 ND |
220 | /* |
221 | * We only need to erase config if we haven't updated | |
222 | * firmware. | |
223 | */ | |
5a89916d | 224 | if (!image_size) { |
29fd0ec2 ND |
225 | dev_info(&fn->dev, "Erasing config...\n"); |
226 | ret = rmi_f34_command(f34, F34_ERASE_CONFIG, | |
227 | F34_ERASE_WAIT_MS, true); | |
228 | if (ret) | |
229 | return ret; | |
230 | } | |
231 | ||
232 | dev_info(&fn->dev, "Writing config (%d bytes)...\n", | |
5a89916d ND |
233 | config_size); |
234 | ret = rmi_f34_write_config(f34, &syn_fw->data[image_size]); | |
29fd0ec2 ND |
235 | if (ret) |
236 | return ret; | |
237 | } | |
238 | ||
239 | return 0; | |
240 | } | |
241 | ||
5a89916d ND |
242 | static int rmi_f34_update_firmware(struct f34_data *f34, |
243 | const struct firmware *fw) | |
29fd0ec2 | 244 | { |
5a89916d ND |
245 | const struct rmi_f34_firmware *syn_fw = |
246 | (const struct rmi_f34_firmware *)fw->data; | |
247 | u32 image_size = le32_to_cpu(syn_fw->image_size); | |
248 | u32 config_size = le32_to_cpu(syn_fw->config_size); | |
29fd0ec2 ND |
249 | int ret; |
250 | ||
29fd0ec2 ND |
251 | BUILD_BUG_ON(offsetof(struct rmi_f34_firmware, data) != |
252 | F34_FW_IMAGE_OFFSET); | |
253 | ||
254 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, | |
5a89916d ND |
255 | "FW size:%zd, checksum:%08x, image_size:%d, config_size:%d\n", |
256 | fw->size, | |
29fd0ec2 | 257 | le32_to_cpu(syn_fw->checksum), |
5a89916d | 258 | image_size, config_size); |
29fd0ec2 ND |
259 | |
260 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, | |
261 | "FW bootloader_id:%02x, product_id:%.*s, info: %02x%02x\n", | |
262 | syn_fw->bootloader_version, | |
263 | (int)sizeof(syn_fw->product_id), syn_fw->product_id, | |
264 | syn_fw->product_info[0], syn_fw->product_info[1]); | |
265 | ||
5a89916d | 266 | if (image_size && image_size != f34->v5.fw_blocks * f34->v5.block_size) { |
29fd0ec2 ND |
267 | dev_err(&f34->fn->dev, |
268 | "Bad firmware image: fw size %d, expected %d\n", | |
5a89916d | 269 | image_size, f34->v5.fw_blocks * f34->v5.block_size); |
29fd0ec2 ND |
270 | ret = -EILSEQ; |
271 | goto out; | |
272 | } | |
273 | ||
5a89916d ND |
274 | if (config_size && |
275 | config_size != f34->v5.config_blocks * f34->v5.block_size) { | |
29fd0ec2 ND |
276 | dev_err(&f34->fn->dev, |
277 | "Bad firmware image: config size %d, expected %d\n", | |
5a89916d | 278 | config_size, |
29fd0ec2 ND |
279 | f34->v5.config_blocks * f34->v5.block_size); |
280 | ret = -EILSEQ; | |
281 | goto out; | |
282 | } | |
283 | ||
5a89916d | 284 | if (image_size && !config_size) { |
29fd0ec2 ND |
285 | dev_err(&f34->fn->dev, "Bad firmware image: no config data\n"); |
286 | ret = -EILSEQ; | |
287 | goto out; | |
288 | } | |
289 | ||
290 | dev_info(&f34->fn->dev, "Firmware image OK\n"); | |
291 | mutex_lock(&f34->v5.flash_mutex); | |
292 | ||
293 | ret = rmi_f34_flash_firmware(f34, syn_fw); | |
294 | ||
295 | mutex_unlock(&f34->v5.flash_mutex); | |
296 | ||
297 | out: | |
298 | return ret; | |
299 | } | |
300 | ||
5a89916d ND |
301 | static int rmi_f34_status(struct rmi_function *fn) |
302 | { | |
303 | struct f34_data *f34 = dev_get_drvdata(&fn->dev); | |
304 | ||
305 | /* | |
306 | * The status is the percentage complete, or once complete, | |
307 | * zero for success or a negative return code. | |
308 | */ | |
309 | return f34->update_status; | |
310 | } | |
311 | ||
ce363f0d ND |
312 | static ssize_t rmi_driver_bootloader_id_show(struct device *dev, |
313 | struct device_attribute *dattr, | |
314 | char *buf) | |
315 | { | |
316 | struct rmi_driver_data *data = dev_get_drvdata(dev); | |
317 | struct rmi_function *fn = data->f34_container; | |
318 | struct f34_data *f34; | |
319 | ||
320 | if (fn) { | |
321 | f34 = dev_get_drvdata(&fn->dev); | |
322 | ||
323 | if (f34->bl_version == 5) | |
324 | return scnprintf(buf, PAGE_SIZE, "%c%c\n", | |
325 | f34->bootloader_id[0], | |
326 | f34->bootloader_id[1]); | |
327 | else | |
328 | return scnprintf(buf, PAGE_SIZE, "V%d.%d\n", | |
329 | f34->bootloader_id[1], | |
330 | f34->bootloader_id[0]); | |
331 | } | |
332 | ||
333 | return 0; | |
334 | } | |
335 | ||
336 | static DEVICE_ATTR(bootloader_id, 0444, rmi_driver_bootloader_id_show, NULL); | |
337 | ||
338 | static ssize_t rmi_driver_configuration_id_show(struct device *dev, | |
339 | struct device_attribute *dattr, | |
340 | char *buf) | |
341 | { | |
342 | struct rmi_driver_data *data = dev_get_drvdata(dev); | |
343 | struct rmi_function *fn = data->f34_container; | |
344 | struct f34_data *f34; | |
345 | ||
346 | if (fn) { | |
347 | f34 = dev_get_drvdata(&fn->dev); | |
348 | ||
349 | return scnprintf(buf, PAGE_SIZE, "%s\n", f34->configuration_id); | |
350 | } | |
351 | ||
352 | return 0; | |
353 | } | |
354 | ||
355 | static DEVICE_ATTR(configuration_id, 0444, | |
356 | rmi_driver_configuration_id_show, NULL); | |
357 | ||
29fd0ec2 ND |
358 | static int rmi_firmware_update(struct rmi_driver_data *data, |
359 | const struct firmware *fw) | |
360 | { | |
e155d4ee BT |
361 | struct rmi_device *rmi_dev = data->rmi_dev; |
362 | struct device *dev = &rmi_dev->dev; | |
29fd0ec2 ND |
363 | struct f34_data *f34; |
364 | int ret; | |
365 | ||
366 | if (!data->f34_container) { | |
367 | dev_warn(dev, "%s: No F34 present!\n", __func__); | |
368 | return -EINVAL; | |
369 | } | |
370 | ||
5191d88a ND |
371 | f34 = dev_get_drvdata(&data->f34_container->dev); |
372 | ||
373 | if (f34->bl_version == 7) { | |
374 | if (data->pdt_props & HAS_BSR) { | |
375 | dev_err(dev, "%s: LTS not supported\n", __func__); | |
376 | return -ENODEV; | |
377 | } | |
378 | } else if (f34->bl_version != 5) { | |
29fd0ec2 ND |
379 | dev_warn(dev, "F34 V%d not supported!\n", |
380 | data->f34_container->fd.function_version); | |
381 | return -ENODEV; | |
382 | } | |
383 | ||
29fd0ec2 | 384 | /* Enter flash mode */ |
5191d88a ND |
385 | if (f34->bl_version == 7) |
386 | ret = rmi_f34v7_start_reflash(f34, fw); | |
387 | else | |
388 | ret = rmi_f34_enable_flash(f34); | |
29fd0ec2 ND |
389 | if (ret) |
390 | return ret; | |
391 | ||
e155d4ee BT |
392 | rmi_disable_irq(rmi_dev, false); |
393 | ||
29fd0ec2 | 394 | /* Tear down functions and re-probe */ |
e155d4ee | 395 | rmi_free_function_list(rmi_dev); |
29fd0ec2 ND |
396 | |
397 | ret = rmi_probe_interrupts(data); | |
398 | if (ret) | |
399 | return ret; | |
400 | ||
401 | ret = rmi_init_functions(data); | |
402 | if (ret) | |
403 | return ret; | |
404 | ||
5191d88a | 405 | if (!data->bootloader_mode || !data->f34_container) { |
29fd0ec2 ND |
406 | dev_warn(dev, "%s: No F34 present or not in bootloader!\n", |
407 | __func__); | |
408 | return -EINVAL; | |
409 | } | |
410 | ||
e155d4ee BT |
411 | rmi_enable_irq(rmi_dev, false); |
412 | ||
29fd0ec2 ND |
413 | f34 = dev_get_drvdata(&data->f34_container->dev); |
414 | ||
415 | /* Perform firmware update */ | |
5191d88a ND |
416 | if (f34->bl_version == 7) |
417 | ret = rmi_f34v7_do_reflash(f34, fw); | |
418 | else | |
419 | ret = rmi_f34_update_firmware(f34, fw); | |
29fd0ec2 | 420 | |
5a89916d ND |
421 | if (ret) { |
422 | f34->update_status = ret; | |
423 | dev_err(&f34->fn->dev, | |
424 | "Firmware update failed, status: %d\n", ret); | |
425 | } else { | |
426 | dev_info(&f34->fn->dev, "Firmware update complete\n"); | |
427 | } | |
29fd0ec2 | 428 | |
e155d4ee BT |
429 | rmi_disable_irq(rmi_dev, false); |
430 | ||
29fd0ec2 ND |
431 | /* Re-probe */ |
432 | rmi_dbg(RMI_DEBUG_FN, dev, "Re-probing device\n"); | |
e155d4ee | 433 | rmi_free_function_list(rmi_dev); |
29fd0ec2 | 434 | |
e155d4ee | 435 | ret = rmi_scan_pdt(rmi_dev, NULL, rmi_initial_reset); |
29fd0ec2 ND |
436 | if (ret < 0) |
437 | dev_warn(dev, "RMI reset failed!\n"); | |
438 | ||
439 | ret = rmi_probe_interrupts(data); | |
440 | if (ret) | |
441 | return ret; | |
442 | ||
443 | ret = rmi_init_functions(data); | |
444 | if (ret) | |
445 | return ret; | |
446 | ||
e155d4ee BT |
447 | rmi_enable_irq(rmi_dev, false); |
448 | ||
29fd0ec2 ND |
449 | if (data->f01_container->dev.driver) |
450 | /* Driver already bound, so enable ATTN now. */ | |
e155d4ee | 451 | return rmi_enable_sensor(rmi_dev); |
29fd0ec2 ND |
452 | |
453 | rmi_dbg(RMI_DEBUG_FN, dev, "%s complete\n", __func__); | |
454 | ||
455 | return ret; | |
456 | } | |
457 | ||
458 | static ssize_t rmi_driver_update_fw_store(struct device *dev, | |
459 | struct device_attribute *dattr, | |
460 | const char *buf, size_t count) | |
461 | { | |
462 | struct rmi_driver_data *data = dev_get_drvdata(dev); | |
463 | char fw_name[NAME_MAX]; | |
464 | const struct firmware *fw; | |
465 | size_t copy_count = count; | |
466 | int ret; | |
467 | ||
468 | if (count == 0 || count >= NAME_MAX) | |
469 | return -EINVAL; | |
470 | ||
471 | if (buf[count - 1] == '\0' || buf[count - 1] == '\n') | |
472 | copy_count -= 1; | |
473 | ||
474 | strncpy(fw_name, buf, copy_count); | |
475 | fw_name[copy_count] = '\0'; | |
476 | ||
477 | ret = request_firmware(&fw, fw_name, dev); | |
478 | if (ret) | |
479 | return ret; | |
480 | ||
481 | dev_info(dev, "Flashing %s\n", fw_name); | |
482 | ||
483 | ret = rmi_firmware_update(data, fw); | |
484 | ||
485 | release_firmware(fw); | |
486 | ||
487 | return ret ?: count; | |
488 | } | |
489 | ||
490 | static DEVICE_ATTR(update_fw, 0200, NULL, rmi_driver_update_fw_store); | |
491 | ||
5a89916d ND |
492 | static ssize_t rmi_driver_update_fw_status_show(struct device *dev, |
493 | struct device_attribute *dattr, | |
494 | char *buf) | |
495 | { | |
496 | struct rmi_driver_data *data = dev_get_drvdata(dev); | |
497 | int update_status = 0; | |
498 | ||
499 | if (data->f34_container) | |
500 | update_status = rmi_f34_status(data->f34_container); | |
501 | ||
502 | return scnprintf(buf, PAGE_SIZE, "%d\n", update_status); | |
503 | } | |
504 | ||
505 | static DEVICE_ATTR(update_fw_status, 0444, | |
506 | rmi_driver_update_fw_status_show, NULL); | |
507 | ||
29fd0ec2 | 508 | static struct attribute *rmi_firmware_attrs[] = { |
ce363f0d ND |
509 | &dev_attr_bootloader_id.attr, |
510 | &dev_attr_configuration_id.attr, | |
29fd0ec2 | 511 | &dev_attr_update_fw.attr, |
5a89916d | 512 | &dev_attr_update_fw_status.attr, |
29fd0ec2 ND |
513 | NULL |
514 | }; | |
515 | ||
fab2f5e0 | 516 | static const struct attribute_group rmi_firmware_attr_group = { |
29fd0ec2 ND |
517 | .attrs = rmi_firmware_attrs, |
518 | }; | |
519 | ||
520 | static int rmi_f34_probe(struct rmi_function *fn) | |
521 | { | |
522 | struct f34_data *f34; | |
523 | unsigned char f34_queries[9]; | |
524 | bool has_config_id; | |
5191d88a | 525 | u8 version = fn->fd.function_version; |
29fd0ec2 ND |
526 | int ret; |
527 | ||
528 | f34 = devm_kzalloc(&fn->dev, sizeof(struct f34_data), GFP_KERNEL); | |
529 | if (!f34) | |
530 | return -ENOMEM; | |
531 | ||
532 | f34->fn = fn; | |
533 | dev_set_drvdata(&fn->dev, f34); | |
534 | ||
5191d88a ND |
535 | /* v5 code only supported version 0, try V7 probe */ |
536 | if (version > 0) | |
537 | return rmi_f34v7_probe(f34); | |
5191d88a ND |
538 | |
539 | f34->bl_version = 5; | |
540 | ||
29fd0ec2 ND |
541 | ret = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr, |
542 | f34_queries, sizeof(f34_queries)); | |
543 | if (ret) { | |
544 | dev_err(&fn->dev, "%s: Failed to query properties\n", | |
545 | __func__); | |
546 | return ret; | |
547 | } | |
548 | ||
549 | snprintf(f34->bootloader_id, sizeof(f34->bootloader_id), | |
550 | "%c%c", f34_queries[0], f34_queries[1]); | |
551 | ||
552 | mutex_init(&f34->v5.flash_mutex); | |
553 | init_completion(&f34->v5.cmd_done); | |
554 | ||
555 | f34->v5.block_size = get_unaligned_le16(&f34_queries[3]); | |
556 | f34->v5.fw_blocks = get_unaligned_le16(&f34_queries[5]); | |
557 | f34->v5.config_blocks = get_unaligned_le16(&f34_queries[7]); | |
558 | f34->v5.ctrl_address = fn->fd.data_base_addr + F34_BLOCK_DATA_OFFSET + | |
559 | f34->v5.block_size; | |
560 | has_config_id = f34_queries[2] & (1 << 2); | |
561 | ||
562 | rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Bootloader ID: %s\n", | |
563 | f34->bootloader_id); | |
564 | rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Block size: %d\n", | |
565 | f34->v5.block_size); | |
566 | rmi_dbg(RMI_DEBUG_FN, &fn->dev, "FW blocks: %d\n", | |
567 | f34->v5.fw_blocks); | |
568 | rmi_dbg(RMI_DEBUG_FN, &fn->dev, "CFG blocks: %d\n", | |
569 | f34->v5.config_blocks); | |
570 | ||
571 | if (has_config_id) { | |
572 | ret = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr, | |
573 | f34_queries, sizeof(f34_queries)); | |
574 | if (ret) { | |
575 | dev_err(&fn->dev, "Failed to read F34 config ID\n"); | |
576 | return ret; | |
577 | } | |
578 | ||
579 | snprintf(f34->configuration_id, sizeof(f34->configuration_id), | |
580 | "%02x%02x%02x%02x", | |
581 | f34_queries[0], f34_queries[1], | |
582 | f34_queries[2], f34_queries[3]); | |
583 | ||
584 | rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Configuration ID: %s\n", | |
585 | f34->configuration_id); | |
586 | } | |
587 | ||
588 | return 0; | |
589 | } | |
590 | ||
591 | int rmi_f34_create_sysfs(struct rmi_device *rmi_dev) | |
592 | { | |
593 | return sysfs_create_group(&rmi_dev->dev.kobj, &rmi_firmware_attr_group); | |
594 | } | |
595 | ||
596 | void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev) | |
597 | { | |
598 | sysfs_remove_group(&rmi_dev->dev.kobj, &rmi_firmware_attr_group); | |
599 | } | |
600 | ||
601 | struct rmi_function_handler rmi_f34_handler = { | |
602 | .driver = { | |
603 | .name = "rmi4_f34", | |
604 | }, | |
605 | .func = 0x34, | |
606 | .probe = rmi_f34_probe, | |
607 | .attention = rmi_f34_attention, | |
608 | }; |