1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Azoteq IQS620A/621/622/624/625 Multi-Function Sensors |
4 | * |
5 | * Copyright (C) 2019 Jeff LaBundy <jeff@labundy.com> |
6 | * |
7 | * These devices rely on application-specific register settings and calibration |
8 | * data developed in and exported from a suite of GUIs offered by the vendor. A |
9 | * separate tool converts the GUIs' ASCII-based output into a standard firmware |
10 | * file parsed by the driver. |
11 | * |
12 | * Link to datasheets and GUIs: https://www.azoteq.com/ |
13 | * |
14 | * Link to conversion tool: https://github.com/jlabundy/iqs62x-h2bin.git |
15 | */ |
16 | |
17 | #include <linux/completion.h> |
18 | #include <linux/delay.h> |
19 | #include <linux/device.h> |
20 | #include <linux/err.h> |
21 | #include <linux/firmware.h> |
22 | #include <linux/i2c.h> |
23 | #include <linux/interrupt.h> |
24 | #include <linux/kernel.h> |
25 | #include <linux/list.h> |
26 | #include <linux/mfd/core.h> |
27 | #include <linux/mfd/iqs62x.h> |
28 | #include <linux/module.h> |
29 | #include <linux/notifier.h> |
30 | #include <linux/of.h> |
31 | #include <linux/property.h> |
32 | #include <linux/regmap.h> |
33 | #include <linux/slab.h> |
34 | #include <asm/unaligned.h> |
35 | |
36 | #define IQS62X_PROD_NUM 0x00 |
37 | |
38 | #define IQS62X_SYS_FLAGS 0x10 |
39 | |
40 | #define IQS620_HALL_FLAGS 0x16 |
41 | #define IQS621_HALL_FLAGS 0x19 |
42 | #define IQS622_HALL_FLAGS IQS621_HALL_FLAGS |
43 | |
44 | #define IQS624_INTERVAL_NUM 0x18 |
45 | #define IQS625_INTERVAL_NUM 0x12 |
46 | |
47 | #define IQS622_PROX_SETTINGS_4 0x48 |
48 | #define IQS620_PROX_SETTINGS_4 0x50 |
49 | #define IQS620_PROX_SETTINGS_4_SAR_EN BIT(7) |
50 | |
51 | #define IQS621_ALS_CAL_DIV_LUX 0x82 |
52 | #define IQS621_ALS_CAL_DIV_IR 0x83 |
53 | |
54 | #define IQS620_TEMP_CAL_MULT 0xC2 |
55 | #define IQS620_TEMP_CAL_DIV 0xC3 |
56 | #define IQS620_TEMP_CAL_OFFS 0xC4 |
57 | |
58 | #define IQS62X_SYS_SETTINGS 0xD0 |
59 | #define IQS62X_SYS_SETTINGS_ACK_RESET BIT(6) |
60 | #define IQS62X_SYS_SETTINGS_EVENT_MODE BIT(5) |
61 | #define IQS62X_SYS_SETTINGS_CLK_DIV BIT(4) |
62 | #define IQS62X_SYS_SETTINGS_COMM_ATI BIT(3) |
63 | #define IQS62X_SYS_SETTINGS_REDO_ATI BIT(1) |
64 | |
65 | #define IQS62X_PWR_SETTINGS 0xD2 |
66 | #define IQS62X_PWR_SETTINGS_DIS_AUTO BIT(5) |
67 | #define IQS62X_PWR_SETTINGS_PWR_MODE_MASK (BIT(4) | BIT(3)) |
68 | #define IQS62X_PWR_SETTINGS_PWR_MODE_HALT (BIT(4) | BIT(3)) |
69 | #define IQS62X_PWR_SETTINGS_PWR_MODE_NORM 0 |
70 | |
71 | #define IQS62X_OTP_CMD 0xF0 |
72 | #define IQS62X_OTP_CMD_FG3 0x13 |
73 | #define IQS62X_OTP_DATA 0xF1 |
74 | #define IQS62X_MAX_REG 0xFF |
75 | |
76 | #define IQS62X_HALL_CAL_MASK GENMASK(3, 0) |
77 | |
78 | #define IQS62X_FW_REC_TYPE_INFO 0 |
79 | #define IQS62X_FW_REC_TYPE_PROD 1 |
80 | #define IQS62X_FW_REC_TYPE_HALL 2 |
81 | #define IQS62X_FW_REC_TYPE_MASK 3 |
82 | #define IQS62X_FW_REC_TYPE_DATA 4 |
83 | |
84 | #define IQS62X_ATI_STARTUP_MS 350 |
85 | #define IQS62X_FILT_SETTLE_MS 250 |
86 | |
87 | struct iqs62x_fw_rec { |
88 | u8 type; |
89 | u8 addr; |
90 | u8 len; |
91 | u8 data; |
92 | } __packed; |
93 | |
94 | struct iqs62x_fw_blk { |
95 | struct list_head list; |
96 | u8 addr; |
97 | u8 mask; |
98 | u8 len; |
99 | u8 data[] __counted_by(len); |
100 | }; |
101 | |
102 | struct iqs62x_info { |
103 | u8 prod_num; |
104 | u8 sw_num; |
105 | u8 hw_num; |
106 | } __packed; |
107 | |
108 | static int iqs62x_dev_init(struct iqs62x_core *iqs62x) |
109 | { |
110 | struct iqs62x_fw_blk *fw_blk; |
111 | unsigned int val; |
112 | int ret; |
113 | |
114 | list_for_each_entry(fw_blk, &iqs62x->fw_blk_head, list) { |
115 | /* |
116 | * In case ATI is in progress, wait for it to complete before |
117 | * lowering the core clock frequency. |
118 | */ |
119 | if (fw_blk->addr == IQS62X_SYS_SETTINGS && |
120 | *fw_blk->data & IQS62X_SYS_SETTINGS_CLK_DIV) |
121 | msleep(IQS62X_ATI_STARTUP_MS); |
122 | |
123 | if (fw_blk->mask) |
124 | ret = regmap_update_bits(map: iqs62x->regmap, reg: fw_blk->addr, |
125 | mask: fw_blk->mask, val: *fw_blk->data); |
126 | else |
127 | ret = regmap_raw_write(map: iqs62x->regmap, reg: fw_blk->addr, |
128 | val: fw_blk->data, val_len: fw_blk->len); |
129 | if (ret) |
130 | return ret; |
131 | } |
132 | |
133 | switch (iqs62x->dev_desc->prod_num) { |
134 | case IQS620_PROD_NUM: |
135 | case IQS622_PROD_NUM: |
136 | ret = regmap_read(map: iqs62x->regmap, |
137 | reg: iqs62x->dev_desc->prox_settings, val: &val); |
138 | if (ret) |
139 | return ret; |
140 | |
141 | if (val & IQS620_PROX_SETTINGS_4_SAR_EN) |
142 | iqs62x->ui_sel = IQS62X_UI_SAR1; |
143 | fallthrough; |
144 | |
145 | case IQS621_PROD_NUM: |
146 | ret = regmap_write(map: iqs62x->regmap, IQS620_GLBL_EVENT_MASK, |
147 | IQS620_GLBL_EVENT_MASK_PMU | |
148 | iqs62x->dev_desc->prox_mask | |
149 | iqs62x->dev_desc->sar_mask | |
150 | iqs62x->dev_desc->hall_mask | |
151 | iqs62x->dev_desc->hyst_mask | |
152 | iqs62x->dev_desc->temp_mask | |
153 | iqs62x->dev_desc->als_mask | |
154 | iqs62x->dev_desc->ir_mask); |
155 | if (ret) |
156 | return ret; |
157 | break; |
158 | |
159 | default: |
160 | ret = regmap_write(map: iqs62x->regmap, IQS624_HALL_UI, |
161 | IQS624_HALL_UI_WHL_EVENT | |
162 | IQS624_HALL_UI_INT_EVENT | |
163 | IQS624_HALL_UI_AUTO_CAL); |
164 | if (ret) |
165 | return ret; |
166 | |
167 | /* |
168 | * The IQS625 default interval divider is below the minimum |
169 | * permissible value, and the datasheet mandates that it is |
170 | * corrected during initialization (unless an updated value |
171 | * has already been provided by firmware). |
172 | * |
173 | * To protect against an unacceptably low user-entered value |
174 | * stored in the firmware, the same check is extended to the |
175 | * IQS624 as well. |
176 | */ |
177 | ret = regmap_read(map: iqs62x->regmap, IQS624_INTERVAL_DIV, val: &val); |
178 | if (ret) |
179 | return ret; |
180 | |
181 | if (val >= iqs62x->dev_desc->interval_div) |
182 | break; |
183 | |
184 | ret = regmap_write(map: iqs62x->regmap, IQS624_INTERVAL_DIV, |
185 | val: iqs62x->dev_desc->interval_div); |
186 | if (ret) |
187 | return ret; |
188 | } |
189 | |
190 | /* |
191 | * Place the device in streaming mode at first so as not to miss the |
192 | * limited number of interrupts that would otherwise occur after ATI |
193 | * completes. The device is subsequently placed in event mode by the |
194 | * interrupt handler. |
195 | * |
196 | * In the meantime, mask interrupts during ATI to prevent the device |
197 | * from soliciting I2C traffic until the noise-sensitive ATI process |
198 | * is complete. |
199 | */ |
200 | ret = regmap_update_bits(map: iqs62x->regmap, IQS62X_SYS_SETTINGS, |
201 | IQS62X_SYS_SETTINGS_ACK_RESET | |
202 | IQS62X_SYS_SETTINGS_EVENT_MODE | |
203 | IQS62X_SYS_SETTINGS_COMM_ATI | |
204 | IQS62X_SYS_SETTINGS_REDO_ATI, |
205 | IQS62X_SYS_SETTINGS_ACK_RESET | |
206 | IQS62X_SYS_SETTINGS_REDO_ATI); |
207 | if (ret) |
208 | return ret; |
209 | |
210 | /* |
211 | * The following delay gives the device time to deassert its RDY output |
212 | * in case a communication window was open while the REDO_ATI field was |
213 | * written. This prevents an interrupt from being serviced prematurely. |
214 | */ |
215 | usleep_range(min: 5000, max: 5100); |
216 | |
217 | return 0; |
218 | } |
219 | |
220 | static int iqs62x_firmware_parse(struct iqs62x_core *iqs62x, |
221 | const struct firmware *fw) |
222 | { |
223 | struct i2c_client *client = iqs62x->client; |
224 | struct iqs62x_fw_rec *fw_rec; |
225 | struct iqs62x_fw_blk *fw_blk; |
226 | unsigned int val; |
227 | size_t pos = 0; |
228 | int ret = 0; |
229 | u8 mask, len, *data; |
230 | u8 hall_cal_index = 0; |
231 | |
232 | while (pos < fw->size) { |
233 | if (pos + sizeof(*fw_rec) > fw->size) { |
234 | ret = -EINVAL; |
235 | break; |
236 | } |
237 | fw_rec = (struct iqs62x_fw_rec *)(fw->data + pos); |
238 | pos += sizeof(*fw_rec); |
239 | |
240 | if (pos + fw_rec->len - 1 > fw->size) { |
241 | ret = -EINVAL; |
242 | break; |
243 | } |
244 | pos += fw_rec->len - 1; |
245 | |
246 | switch (fw_rec->type) { |
247 | case IQS62X_FW_REC_TYPE_INFO: |
248 | continue; |
249 | |
250 | case IQS62X_FW_REC_TYPE_PROD: |
251 | if (fw_rec->data == iqs62x->dev_desc->prod_num) |
252 | continue; |
253 | |
254 | dev_err(&client->dev, |
255 | "Incompatible product number: 0x%02X\n" , |
256 | fw_rec->data); |
257 | ret = -EINVAL; |
258 | break; |
259 | |
260 | case IQS62X_FW_REC_TYPE_HALL: |
261 | if (!hall_cal_index) { |
262 | ret = regmap_write(map: iqs62x->regmap, |
263 | IQS62X_OTP_CMD, |
264 | IQS62X_OTP_CMD_FG3); |
265 | if (ret) |
266 | break; |
267 | |
268 | ret = regmap_read(map: iqs62x->regmap, |
269 | IQS62X_OTP_DATA, val: &val); |
270 | if (ret) |
271 | break; |
272 | |
273 | hall_cal_index = val & IQS62X_HALL_CAL_MASK; |
274 | if (!hall_cal_index) { |
275 | dev_err(&client->dev, |
276 | "Uncalibrated device\n" ); |
277 | ret = -ENODATA; |
278 | break; |
279 | } |
280 | } |
281 | |
282 | if (hall_cal_index > fw_rec->len) { |
283 | ret = -EINVAL; |
284 | break; |
285 | } |
286 | |
287 | mask = 0; |
288 | data = &fw_rec->data + hall_cal_index - 1; |
289 | len = sizeof(*data); |
290 | break; |
291 | |
292 | case IQS62X_FW_REC_TYPE_MASK: |
293 | if (fw_rec->len < (sizeof(mask) + sizeof(*data))) { |
294 | ret = -EINVAL; |
295 | break; |
296 | } |
297 | |
298 | mask = fw_rec->data; |
299 | data = &fw_rec->data + sizeof(mask); |
300 | len = sizeof(*data); |
301 | break; |
302 | |
303 | case IQS62X_FW_REC_TYPE_DATA: |
304 | mask = 0; |
305 | data = &fw_rec->data; |
306 | len = fw_rec->len; |
307 | break; |
308 | |
309 | default: |
310 | dev_err(&client->dev, |
311 | "Unrecognized record type: 0x%02X\n" , |
312 | fw_rec->type); |
313 | ret = -EINVAL; |
314 | } |
315 | |
316 | if (ret) |
317 | break; |
318 | |
319 | fw_blk = devm_kzalloc(dev: &client->dev, |
320 | struct_size(fw_blk, data, len), |
321 | GFP_KERNEL); |
322 | if (!fw_blk) { |
323 | ret = -ENOMEM; |
324 | break; |
325 | } |
326 | |
327 | fw_blk->addr = fw_rec->addr; |
328 | fw_blk->mask = mask; |
329 | fw_blk->len = len; |
330 | memcpy(fw_blk->data, data, len); |
331 | |
332 | list_add(new: &fw_blk->list, head: &iqs62x->fw_blk_head); |
333 | } |
334 | |
335 | release_firmware(fw); |
336 | |
337 | return ret; |
338 | } |
339 | |
340 | const struct iqs62x_event_desc iqs62x_events[IQS62X_NUM_EVENTS] = { |
341 | [IQS62X_EVENT_PROX_CH0_T] = { |
342 | .reg = IQS62X_EVENT_PROX, |
343 | .mask = BIT(4), |
344 | .val = BIT(4), |
345 | }, |
346 | [IQS62X_EVENT_PROX_CH0_P] = { |
347 | .reg = IQS62X_EVENT_PROX, |
348 | .mask = BIT(0), |
349 | .val = BIT(0), |
350 | }, |
351 | [IQS62X_EVENT_PROX_CH1_T] = { |
352 | .reg = IQS62X_EVENT_PROX, |
353 | .mask = BIT(5), |
354 | .val = BIT(5), |
355 | }, |
356 | [IQS62X_EVENT_PROX_CH1_P] = { |
357 | .reg = IQS62X_EVENT_PROX, |
358 | .mask = BIT(1), |
359 | .val = BIT(1), |
360 | }, |
361 | [IQS62X_EVENT_PROX_CH2_T] = { |
362 | .reg = IQS62X_EVENT_PROX, |
363 | .mask = BIT(6), |
364 | .val = BIT(6), |
365 | }, |
366 | [IQS62X_EVENT_PROX_CH2_P] = { |
367 | .reg = IQS62X_EVENT_PROX, |
368 | .mask = BIT(2), |
369 | .val = BIT(2), |
370 | }, |
371 | [IQS62X_EVENT_HYST_POS_T] = { |
372 | .reg = IQS62X_EVENT_HYST, |
373 | .mask = BIT(6) | BIT(7), |
374 | .val = BIT(6), |
375 | }, |
376 | [IQS62X_EVENT_HYST_POS_P] = { |
377 | .reg = IQS62X_EVENT_HYST, |
378 | .mask = BIT(5) | BIT(7), |
379 | .val = BIT(5), |
380 | }, |
381 | [IQS62X_EVENT_HYST_NEG_T] = { |
382 | .reg = IQS62X_EVENT_HYST, |
383 | .mask = BIT(6) | BIT(7), |
384 | .val = BIT(6) | BIT(7), |
385 | }, |
386 | [IQS62X_EVENT_HYST_NEG_P] = { |
387 | .reg = IQS62X_EVENT_HYST, |
388 | .mask = BIT(5) | BIT(7), |
389 | .val = BIT(5) | BIT(7), |
390 | }, |
391 | [IQS62X_EVENT_SAR1_ACT] = { |
392 | .reg = IQS62X_EVENT_HYST, |
393 | .mask = BIT(4), |
394 | .val = BIT(4), |
395 | }, |
396 | [IQS62X_EVENT_SAR1_QRD] = { |
397 | .reg = IQS62X_EVENT_HYST, |
398 | .mask = BIT(2), |
399 | .val = BIT(2), |
400 | }, |
401 | [IQS62X_EVENT_SAR1_MOVE] = { |
402 | .reg = IQS62X_EVENT_HYST, |
403 | .mask = BIT(1), |
404 | .val = BIT(1), |
405 | }, |
406 | [IQS62X_EVENT_SAR1_HALT] = { |
407 | .reg = IQS62X_EVENT_HYST, |
408 | .mask = BIT(0), |
409 | .val = BIT(0), |
410 | }, |
411 | [IQS62X_EVENT_WHEEL_UP] = { |
412 | .reg = IQS62X_EVENT_WHEEL, |
413 | .mask = BIT(7) | BIT(6), |
414 | .val = BIT(7), |
415 | }, |
416 | [IQS62X_EVENT_WHEEL_DN] = { |
417 | .reg = IQS62X_EVENT_WHEEL, |
418 | .mask = BIT(7) | BIT(6), |
419 | .val = BIT(7) | BIT(6), |
420 | }, |
421 | [IQS62X_EVENT_HALL_N_T] = { |
422 | .reg = IQS62X_EVENT_HALL, |
423 | .mask = BIT(2) | BIT(0), |
424 | .val = BIT(2), |
425 | }, |
426 | [IQS62X_EVENT_HALL_N_P] = { |
427 | .reg = IQS62X_EVENT_HALL, |
428 | .mask = BIT(1) | BIT(0), |
429 | .val = BIT(1), |
430 | }, |
431 | [IQS62X_EVENT_HALL_S_T] = { |
432 | .reg = IQS62X_EVENT_HALL, |
433 | .mask = BIT(2) | BIT(0), |
434 | .val = BIT(2) | BIT(0), |
435 | }, |
436 | [IQS62X_EVENT_HALL_S_P] = { |
437 | .reg = IQS62X_EVENT_HALL, |
438 | .mask = BIT(1) | BIT(0), |
439 | .val = BIT(1) | BIT(0), |
440 | }, |
441 | [IQS62X_EVENT_SYS_RESET] = { |
442 | .reg = IQS62X_EVENT_SYS, |
443 | .mask = BIT(7), |
444 | .val = BIT(7), |
445 | }, |
446 | [IQS62X_EVENT_SYS_ATI] = { |
447 | .reg = IQS62X_EVENT_SYS, |
448 | .mask = BIT(2), |
449 | .val = BIT(2), |
450 | }, |
451 | }; |
452 | EXPORT_SYMBOL_GPL(iqs62x_events); |
453 | |
454 | static irqreturn_t iqs62x_irq(int irq, void *context) |
455 | { |
456 | struct iqs62x_core *iqs62x = context; |
457 | struct i2c_client *client = iqs62x->client; |
458 | struct iqs62x_event_data event_data; |
459 | struct iqs62x_event_desc event_desc; |
460 | enum iqs62x_event_reg event_reg; |
461 | unsigned long event_flags = 0; |
462 | int ret, i, j; |
463 | u8 event_map[IQS62X_EVENT_SIZE]; |
464 | |
465 | /* |
466 | * The device asserts the RDY output to signal the beginning of a |
467 | * communication window, which is closed by an I2C stop condition. |
468 | * As such, all interrupt status is captured in a single read and |
469 | * broadcast to any interested sub-device drivers. |
470 | */ |
471 | ret = regmap_raw_read(map: iqs62x->regmap, IQS62X_SYS_FLAGS, val: event_map, |
472 | val_len: sizeof(event_map)); |
473 | if (ret) { |
474 | dev_err(&client->dev, "Failed to read device status: %d\n" , |
475 | ret); |
476 | return IRQ_NONE; |
477 | } |
478 | |
479 | for (i = 0; i < sizeof(event_map); i++) { |
480 | event_reg = iqs62x->dev_desc->event_regs[iqs62x->ui_sel][i]; |
481 | |
482 | switch (event_reg) { |
483 | case IQS62X_EVENT_UI_LO: |
484 | event_data.ui_data = get_unaligned_le16(p: &event_map[i]); |
485 | fallthrough; |
486 | |
487 | case IQS62X_EVENT_UI_HI: |
488 | case IQS62X_EVENT_NONE: |
489 | continue; |
490 | |
491 | case IQS62X_EVENT_ALS: |
492 | event_data.als_flags = event_map[i]; |
493 | continue; |
494 | |
495 | case IQS62X_EVENT_IR: |
496 | event_data.ir_flags = event_map[i]; |
497 | continue; |
498 | |
499 | case IQS62X_EVENT_INTER: |
500 | event_data.interval = event_map[i]; |
501 | continue; |
502 | |
503 | case IQS62X_EVENT_HYST: |
504 | event_map[i] <<= iqs62x->dev_desc->hyst_shift; |
505 | fallthrough; |
506 | |
507 | case IQS62X_EVENT_WHEEL: |
508 | case IQS62X_EVENT_HALL: |
509 | case IQS62X_EVENT_PROX: |
510 | case IQS62X_EVENT_SYS: |
511 | break; |
512 | } |
513 | |
514 | for (j = 0; j < IQS62X_NUM_EVENTS; j++) { |
515 | event_desc = iqs62x_events[j]; |
516 | |
517 | if (event_desc.reg != event_reg) |
518 | continue; |
519 | |
520 | if ((event_map[i] & event_desc.mask) == event_desc.val) |
521 | event_flags |= BIT(j); |
522 | } |
523 | } |
524 | |
525 | /* |
526 | * The device resets itself in response to the I2C master stalling |
527 | * communication past a fixed timeout. In this case, all registers |
528 | * are restored and any interested sub-device drivers are notified. |
529 | */ |
530 | if (event_flags & BIT(IQS62X_EVENT_SYS_RESET)) { |
531 | dev_err(&client->dev, "Unexpected device reset\n" ); |
532 | |
533 | ret = iqs62x_dev_init(iqs62x); |
534 | if (ret) { |
535 | dev_err(&client->dev, |
536 | "Failed to re-initialize device: %d\n" , ret); |
537 | return IRQ_NONE; |
538 | } |
539 | |
540 | iqs62x->event_cache |= BIT(IQS62X_EVENT_SYS_RESET); |
541 | reinit_completion(x: &iqs62x->ati_done); |
542 | } else if (event_flags & BIT(IQS62X_EVENT_SYS_ATI)) { |
543 | iqs62x->event_cache |= BIT(IQS62X_EVENT_SYS_ATI); |
544 | reinit_completion(x: &iqs62x->ati_done); |
545 | } else if (!completion_done(x: &iqs62x->ati_done)) { |
546 | ret = regmap_update_bits(map: iqs62x->regmap, IQS62X_SYS_SETTINGS, |
547 | IQS62X_SYS_SETTINGS_EVENT_MODE, val: 0xFF); |
548 | if (ret) { |
549 | dev_err(&client->dev, |
550 | "Failed to enable event mode: %d\n" , ret); |
551 | return IRQ_NONE; |
552 | } |
553 | |
554 | msleep(IQS62X_FILT_SETTLE_MS); |
555 | complete_all(&iqs62x->ati_done); |
556 | } |
557 | |
558 | /* |
559 | * Reset and ATI events are not broadcast to the sub-device drivers |
560 | * until ATI has completed. Any other events that may have occurred |
561 | * during ATI are ignored. |
562 | */ |
563 | if (completion_done(x: &iqs62x->ati_done)) { |
564 | event_flags |= iqs62x->event_cache; |
565 | ret = blocking_notifier_call_chain(nh: &iqs62x->nh, val: event_flags, |
566 | v: &event_data); |
567 | if (ret & NOTIFY_STOP_MASK) |
568 | return IRQ_NONE; |
569 | |
570 | iqs62x->event_cache = 0; |
571 | } |
572 | |
573 | /* |
574 | * Once the communication window is closed, a small delay is added to |
575 | * ensure the device's RDY output has been deasserted by the time the |
576 | * interrupt handler returns. |
577 | */ |
578 | usleep_range(min: 150, max: 200); |
579 | |
580 | return IRQ_HANDLED; |
581 | } |
582 | |
583 | static void iqs62x_firmware_load(const struct firmware *fw, void *context) |
584 | { |
585 | struct iqs62x_core *iqs62x = context; |
586 | struct i2c_client *client = iqs62x->client; |
587 | int ret; |
588 | |
589 | if (fw) { |
590 | ret = iqs62x_firmware_parse(iqs62x, fw); |
591 | if (ret) { |
592 | dev_err(&client->dev, "Failed to parse firmware: %d\n" , |
593 | ret); |
594 | goto err_out; |
595 | } |
596 | } |
597 | |
598 | ret = iqs62x_dev_init(iqs62x); |
599 | if (ret) { |
600 | dev_err(&client->dev, "Failed to initialize device: %d\n" , ret); |
601 | goto err_out; |
602 | } |
603 | |
604 | ret = devm_request_threaded_irq(dev: &client->dev, irq: client->irq, |
605 | NULL, thread_fn: iqs62x_irq, IRQF_ONESHOT, |
606 | devname: client->name, dev_id: iqs62x); |
607 | if (ret) { |
608 | dev_err(&client->dev, "Failed to request IRQ: %d\n" , ret); |
609 | goto err_out; |
610 | } |
611 | |
612 | if (!wait_for_completion_timeout(x: &iqs62x->ati_done, |
613 | timeout: msecs_to_jiffies(m: 2000))) { |
614 | dev_err(&client->dev, "Failed to complete ATI\n" ); |
615 | goto err_out; |
616 | } |
617 | |
618 | ret = devm_mfd_add_devices(dev: &client->dev, PLATFORM_DEVID_NONE, |
619 | cells: iqs62x->dev_desc->sub_devs, |
620 | n_devs: iqs62x->dev_desc->num_sub_devs, |
621 | NULL, irq_base: 0, NULL); |
622 | if (ret) |
623 | dev_err(&client->dev, "Failed to add sub-devices: %d\n" , ret); |
624 | |
625 | err_out: |
626 | complete_all(&iqs62x->fw_done); |
627 | } |
628 | |
629 | static const struct mfd_cell iqs620at_sub_devs[] = { |
630 | { |
631 | .name = "iqs62x-keys" , |
632 | .of_compatible = "azoteq,iqs620a-keys" , |
633 | }, |
634 | { |
635 | .name = "iqs620a-pwm" , |
636 | .of_compatible = "azoteq,iqs620a-pwm" , |
637 | }, |
638 | { .name = "iqs620at-temp" , }, |
639 | }; |
640 | |
641 | static const struct mfd_cell iqs620a_sub_devs[] = { |
642 | { |
643 | .name = "iqs62x-keys" , |
644 | .of_compatible = "azoteq,iqs620a-keys" , |
645 | }, |
646 | { |
647 | .name = "iqs620a-pwm" , |
648 | .of_compatible = "azoteq,iqs620a-pwm" , |
649 | }, |
650 | }; |
651 | |
652 | static const struct mfd_cell iqs621_sub_devs[] = { |
653 | { |
654 | .name = "iqs62x-keys" , |
655 | .of_compatible = "azoteq,iqs621-keys" , |
656 | }, |
657 | { .name = "iqs621-als" , }, |
658 | }; |
659 | |
660 | static const struct mfd_cell iqs622_sub_devs[] = { |
661 | { |
662 | .name = "iqs62x-keys" , |
663 | .of_compatible = "azoteq,iqs622-keys" , |
664 | }, |
665 | { .name = "iqs621-als" , }, |
666 | }; |
667 | |
668 | static const struct mfd_cell iqs624_sub_devs[] = { |
669 | { |
670 | .name = "iqs62x-keys" , |
671 | .of_compatible = "azoteq,iqs624-keys" , |
672 | }, |
673 | { .name = "iqs624-pos" , }, |
674 | }; |
675 | |
676 | static const struct mfd_cell iqs625_sub_devs[] = { |
677 | { |
678 | .name = "iqs62x-keys" , |
679 | .of_compatible = "azoteq,iqs625-keys" , |
680 | }, |
681 | { .name = "iqs624-pos" , }, |
682 | }; |
683 | |
684 | static const u8 iqs620at_cal_regs[] = { |
685 | IQS620_TEMP_CAL_MULT, |
686 | IQS620_TEMP_CAL_DIV, |
687 | IQS620_TEMP_CAL_OFFS, |
688 | }; |
689 | |
690 | static const u8 iqs621_cal_regs[] = { |
691 | IQS621_ALS_CAL_DIV_LUX, |
692 | IQS621_ALS_CAL_DIV_IR, |
693 | }; |
694 | |
695 | static const enum iqs62x_event_reg iqs620a_event_regs[][IQS62X_EVENT_SIZE] = { |
696 | [IQS62X_UI_PROX] = { |
697 | IQS62X_EVENT_SYS, /* 0x10 */ |
698 | IQS62X_EVENT_NONE, |
699 | IQS62X_EVENT_PROX, /* 0x12 */ |
700 | IQS62X_EVENT_HYST, /* 0x13 */ |
701 | IQS62X_EVENT_NONE, |
702 | IQS62X_EVENT_NONE, |
703 | IQS62X_EVENT_HALL, /* 0x16 */ |
704 | IQS62X_EVENT_NONE, |
705 | IQS62X_EVENT_NONE, |
706 | IQS62X_EVENT_NONE, |
707 | }, |
708 | [IQS62X_UI_SAR1] = { |
709 | IQS62X_EVENT_SYS, /* 0x10 */ |
710 | IQS62X_EVENT_NONE, |
711 | IQS62X_EVENT_NONE, |
712 | IQS62X_EVENT_HYST, /* 0x13 */ |
713 | IQS62X_EVENT_NONE, |
714 | IQS62X_EVENT_NONE, |
715 | IQS62X_EVENT_HALL, /* 0x16 */ |
716 | IQS62X_EVENT_NONE, |
717 | IQS62X_EVENT_NONE, |
718 | IQS62X_EVENT_NONE, |
719 | }, |
720 | }; |
721 | |
722 | static const enum iqs62x_event_reg iqs621_event_regs[][IQS62X_EVENT_SIZE] = { |
723 | [IQS62X_UI_PROX] = { |
724 | IQS62X_EVENT_SYS, /* 0x10 */ |
725 | IQS62X_EVENT_NONE, |
726 | IQS62X_EVENT_PROX, /* 0x12 */ |
727 | IQS62X_EVENT_HYST, /* 0x13 */ |
728 | IQS62X_EVENT_NONE, |
729 | IQS62X_EVENT_NONE, |
730 | IQS62X_EVENT_ALS, /* 0x16 */ |
731 | IQS62X_EVENT_UI_LO, /* 0x17 */ |
732 | IQS62X_EVENT_UI_HI, /* 0x18 */ |
733 | IQS62X_EVENT_HALL, /* 0x19 */ |
734 | }, |
735 | }; |
736 | |
737 | static const enum iqs62x_event_reg iqs622_event_regs[][IQS62X_EVENT_SIZE] = { |
738 | [IQS62X_UI_PROX] = { |
739 | IQS62X_EVENT_SYS, /* 0x10 */ |
740 | IQS62X_EVENT_NONE, |
741 | IQS62X_EVENT_PROX, /* 0x12 */ |
742 | IQS62X_EVENT_NONE, |
743 | IQS62X_EVENT_ALS, /* 0x14 */ |
744 | IQS62X_EVENT_NONE, |
745 | IQS62X_EVENT_IR, /* 0x16 */ |
746 | IQS62X_EVENT_UI_LO, /* 0x17 */ |
747 | IQS62X_EVENT_UI_HI, /* 0x18 */ |
748 | IQS62X_EVENT_HALL, /* 0x19 */ |
749 | }, |
750 | [IQS62X_UI_SAR1] = { |
751 | IQS62X_EVENT_SYS, /* 0x10 */ |
752 | IQS62X_EVENT_NONE, |
753 | IQS62X_EVENT_NONE, |
754 | IQS62X_EVENT_HYST, /* 0x13 */ |
755 | IQS62X_EVENT_ALS, /* 0x14 */ |
756 | IQS62X_EVENT_NONE, |
757 | IQS62X_EVENT_IR, /* 0x16 */ |
758 | IQS62X_EVENT_UI_LO, /* 0x17 */ |
759 | IQS62X_EVENT_UI_HI, /* 0x18 */ |
760 | IQS62X_EVENT_HALL, /* 0x19 */ |
761 | }, |
762 | }; |
763 | |
764 | static const enum iqs62x_event_reg iqs624_event_regs[][IQS62X_EVENT_SIZE] = { |
765 | [IQS62X_UI_PROX] = { |
766 | IQS62X_EVENT_SYS, /* 0x10 */ |
767 | IQS62X_EVENT_NONE, |
768 | IQS62X_EVENT_PROX, /* 0x12 */ |
769 | IQS62X_EVENT_NONE, |
770 | IQS62X_EVENT_WHEEL, /* 0x14 */ |
771 | IQS62X_EVENT_NONE, |
772 | IQS62X_EVENT_UI_LO, /* 0x16 */ |
773 | IQS62X_EVENT_UI_HI, /* 0x17 */ |
774 | IQS62X_EVENT_INTER, /* 0x18 */ |
775 | IQS62X_EVENT_NONE, |
776 | }, |
777 | }; |
778 | |
779 | static const enum iqs62x_event_reg iqs625_event_regs[][IQS62X_EVENT_SIZE] = { |
780 | [IQS62X_UI_PROX] = { |
781 | IQS62X_EVENT_SYS, /* 0x10 */ |
782 | IQS62X_EVENT_PROX, /* 0x11 */ |
783 | IQS62X_EVENT_INTER, /* 0x12 */ |
784 | IQS62X_EVENT_NONE, |
785 | IQS62X_EVENT_NONE, |
786 | IQS62X_EVENT_NONE, |
787 | IQS62X_EVENT_NONE, |
788 | IQS62X_EVENT_NONE, |
789 | IQS62X_EVENT_NONE, |
790 | IQS62X_EVENT_NONE, |
791 | }, |
792 | }; |
793 | |
794 | static const struct iqs62x_dev_desc iqs62x_devs[] = { |
795 | { |
796 | .dev_name = "iqs620at" , |
797 | .sub_devs = iqs620at_sub_devs, |
798 | .num_sub_devs = ARRAY_SIZE(iqs620at_sub_devs), |
799 | .prod_num = IQS620_PROD_NUM, |
800 | .sw_num = 0x08, |
801 | .cal_regs = iqs620at_cal_regs, |
802 | .num_cal_regs = ARRAY_SIZE(iqs620at_cal_regs), |
803 | .prox_mask = BIT(0), |
804 | .sar_mask = BIT(1) | BIT(7), |
805 | .hall_mask = BIT(2), |
806 | .hyst_mask = BIT(3), |
807 | .temp_mask = BIT(4), |
808 | .prox_settings = IQS620_PROX_SETTINGS_4, |
809 | .hall_flags = IQS620_HALL_FLAGS, |
810 | .fw_name = "iqs620a.bin" , |
811 | .event_regs = &iqs620a_event_regs[IQS62X_UI_PROX], |
812 | }, |
813 | { |
814 | .dev_name = "iqs620a" , |
815 | .sub_devs = iqs620a_sub_devs, |
816 | .num_sub_devs = ARRAY_SIZE(iqs620a_sub_devs), |
817 | .prod_num = IQS620_PROD_NUM, |
818 | .sw_num = 0x08, |
819 | .prox_mask = BIT(0), |
820 | .sar_mask = BIT(1) | BIT(7), |
821 | .hall_mask = BIT(2), |
822 | .hyst_mask = BIT(3), |
823 | .temp_mask = BIT(4), |
824 | .prox_settings = IQS620_PROX_SETTINGS_4, |
825 | .hall_flags = IQS620_HALL_FLAGS, |
826 | .fw_name = "iqs620a.bin" , |
827 | .event_regs = &iqs620a_event_regs[IQS62X_UI_PROX], |
828 | }, |
829 | { |
830 | .dev_name = "iqs621" , |
831 | .sub_devs = iqs621_sub_devs, |
832 | .num_sub_devs = ARRAY_SIZE(iqs621_sub_devs), |
833 | .prod_num = IQS621_PROD_NUM, |
834 | .sw_num = 0x09, |
835 | .cal_regs = iqs621_cal_regs, |
836 | .num_cal_regs = ARRAY_SIZE(iqs621_cal_regs), |
837 | .prox_mask = BIT(0), |
838 | .hall_mask = BIT(1), |
839 | .als_mask = BIT(2), |
840 | .hyst_mask = BIT(3), |
841 | .temp_mask = BIT(4), |
842 | .als_flags = IQS621_ALS_FLAGS, |
843 | .hall_flags = IQS621_HALL_FLAGS, |
844 | .hyst_shift = 5, |
845 | .fw_name = "iqs621.bin" , |
846 | .event_regs = &iqs621_event_regs[IQS62X_UI_PROX], |
847 | }, |
848 | { |
849 | .dev_name = "iqs622" , |
850 | .sub_devs = iqs622_sub_devs, |
851 | .num_sub_devs = ARRAY_SIZE(iqs622_sub_devs), |
852 | .prod_num = IQS622_PROD_NUM, |
853 | .sw_num = 0x06, |
854 | .prox_mask = BIT(0), |
855 | .sar_mask = BIT(1), |
856 | .hall_mask = BIT(2), |
857 | .als_mask = BIT(3), |
858 | .ir_mask = BIT(4), |
859 | .prox_settings = IQS622_PROX_SETTINGS_4, |
860 | .als_flags = IQS622_ALS_FLAGS, |
861 | .hall_flags = IQS622_HALL_FLAGS, |
862 | .fw_name = "iqs622.bin" , |
863 | .event_regs = &iqs622_event_regs[IQS62X_UI_PROX], |
864 | }, |
865 | { |
866 | .dev_name = "iqs624" , |
867 | .sub_devs = iqs624_sub_devs, |
868 | .num_sub_devs = ARRAY_SIZE(iqs624_sub_devs), |
869 | .prod_num = IQS624_PROD_NUM, |
870 | .sw_num = 0x0B, |
871 | .interval = IQS624_INTERVAL_NUM, |
872 | .interval_div = 3, |
873 | .fw_name = "iqs624.bin" , |
874 | .event_regs = &iqs624_event_regs[IQS62X_UI_PROX], |
875 | }, |
876 | { |
877 | .dev_name = "iqs625" , |
878 | .sub_devs = iqs625_sub_devs, |
879 | .num_sub_devs = ARRAY_SIZE(iqs625_sub_devs), |
880 | .prod_num = IQS625_PROD_NUM, |
881 | .sw_num = 0x0B, |
882 | .interval = IQS625_INTERVAL_NUM, |
883 | .interval_div = 10, |
884 | .fw_name = "iqs625.bin" , |
885 | .event_regs = &iqs625_event_regs[IQS62X_UI_PROX], |
886 | }, |
887 | }; |
888 | |
889 | static const struct regmap_config iqs62x_regmap_config = { |
890 | .reg_bits = 8, |
891 | .val_bits = 8, |
892 | .max_register = IQS62X_MAX_REG, |
893 | }; |
894 | |
895 | static int iqs62x_probe(struct i2c_client *client) |
896 | { |
897 | struct iqs62x_core *iqs62x; |
898 | struct iqs62x_info info; |
899 | unsigned int val; |
900 | int ret, i, j; |
901 | const char *fw_name = NULL; |
902 | |
903 | iqs62x = devm_kzalloc(dev: &client->dev, size: sizeof(*iqs62x), GFP_KERNEL); |
904 | if (!iqs62x) |
905 | return -ENOMEM; |
906 | |
907 | i2c_set_clientdata(client, data: iqs62x); |
908 | iqs62x->client = client; |
909 | |
910 | BLOCKING_INIT_NOTIFIER_HEAD(&iqs62x->nh); |
911 | INIT_LIST_HEAD(list: &iqs62x->fw_blk_head); |
912 | |
913 | init_completion(x: &iqs62x->ati_done); |
914 | init_completion(x: &iqs62x->fw_done); |
915 | |
916 | iqs62x->regmap = devm_regmap_init_i2c(client, &iqs62x_regmap_config); |
917 | if (IS_ERR(ptr: iqs62x->regmap)) { |
918 | ret = PTR_ERR(ptr: iqs62x->regmap); |
919 | dev_err(&client->dev, "Failed to initialize register map: %d\n" , |
920 | ret); |
921 | return ret; |
922 | } |
923 | |
924 | ret = regmap_raw_read(map: iqs62x->regmap, IQS62X_PROD_NUM, val: &info, |
925 | val_len: sizeof(info)); |
926 | if (ret) |
927 | return ret; |
928 | |
929 | /* |
930 | * The following sequence validates the device's product and software |
931 | * numbers. It then determines if the device is factory-calibrated by |
932 | * checking for nonzero values in the device's designated calibration |
933 | * registers (if applicable). Depending on the device, the absence of |
934 | * calibration data indicates a reduced feature set or invalid device. |
935 | * |
936 | * For devices given in both calibrated and uncalibrated versions, the |
937 | * calibrated version (e.g. IQS620AT) appears first in the iqs62x_devs |
938 | * array. The uncalibrated version (e.g. IQS620A) appears next and has |
939 | * the same product and software numbers, but no calibration registers |
940 | * are specified. |
941 | */ |
942 | for (i = 0; i < ARRAY_SIZE(iqs62x_devs); i++) { |
943 | if (info.prod_num != iqs62x_devs[i].prod_num) |
944 | continue; |
945 | |
946 | iqs62x->dev_desc = &iqs62x_devs[i]; |
947 | |
948 | if (info.sw_num < iqs62x->dev_desc->sw_num) |
949 | continue; |
950 | |
951 | iqs62x->sw_num = info.sw_num; |
952 | iqs62x->hw_num = info.hw_num; |
953 | |
954 | /* |
955 | * Read each of the device's designated calibration registers, |
956 | * if any, and exit from the inner loop early if any are equal |
957 | * to zero (indicating the device is uncalibrated). This could |
958 | * be acceptable depending on the device (e.g. IQS620A instead |
959 | * of IQS620AT). |
960 | */ |
961 | for (j = 0; j < iqs62x->dev_desc->num_cal_regs; j++) { |
962 | ret = regmap_read(map: iqs62x->regmap, |
963 | reg: iqs62x->dev_desc->cal_regs[j], val: &val); |
964 | if (ret) |
965 | return ret; |
966 | |
967 | if (!val) |
968 | break; |
969 | } |
970 | |
971 | /* |
972 | * If the number of nonzero values read from the device equals |
973 | * the number of designated calibration registers (which could |
974 | * be zero), exit from the outer loop early to signal that the |
975 | * device's product and software numbers match a known device, |
976 | * and the device is calibrated (if applicable). |
977 | */ |
978 | if (j == iqs62x->dev_desc->num_cal_regs) |
979 | break; |
980 | } |
981 | |
982 | if (!iqs62x->dev_desc) { |
983 | dev_err(&client->dev, "Unrecognized product number: 0x%02X\n" , |
984 | info.prod_num); |
985 | return -EINVAL; |
986 | } |
987 | |
988 | if (!iqs62x->sw_num) { |
989 | dev_err(&client->dev, "Unrecognized software number: 0x%02X\n" , |
990 | info.sw_num); |
991 | return -EINVAL; |
992 | } |
993 | |
994 | if (i == ARRAY_SIZE(iqs62x_devs)) { |
995 | dev_err(&client->dev, "Uncalibrated device\n" ); |
996 | return -ENODATA; |
997 | } |
998 | |
999 | device_property_read_string(dev: &client->dev, propname: "firmware-name" , val: &fw_name); |
1000 | |
1001 | ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, |
1002 | name: fw_name ? : iqs62x->dev_desc->fw_name, |
1003 | device: &client->dev, GFP_KERNEL, context: iqs62x, |
1004 | cont: iqs62x_firmware_load); |
1005 | if (ret) |
1006 | dev_err(&client->dev, "Failed to request firmware: %d\n" , ret); |
1007 | |
1008 | return ret; |
1009 | } |
1010 | |
1011 | static void iqs62x_remove(struct i2c_client *client) |
1012 | { |
1013 | struct iqs62x_core *iqs62x = i2c_get_clientdata(client); |
1014 | |
1015 | wait_for_completion(&iqs62x->fw_done); |
1016 | } |
1017 | |
1018 | static int __maybe_unused iqs62x_suspend(struct device *dev) |
1019 | { |
1020 | struct iqs62x_core *iqs62x = dev_get_drvdata(dev); |
1021 | int ret; |
1022 | |
1023 | wait_for_completion(&iqs62x->fw_done); |
1024 | |
1025 | /* |
1026 | * As per the datasheet, automatic mode switching must be disabled |
1027 | * before the device is placed in or taken out of halt mode. |
1028 | */ |
1029 | ret = regmap_update_bits(map: iqs62x->regmap, IQS62X_PWR_SETTINGS, |
1030 | IQS62X_PWR_SETTINGS_DIS_AUTO, val: 0xFF); |
1031 | if (ret) |
1032 | return ret; |
1033 | |
1034 | return regmap_update_bits(map: iqs62x->regmap, IQS62X_PWR_SETTINGS, |
1035 | IQS62X_PWR_SETTINGS_PWR_MODE_MASK, |
1036 | IQS62X_PWR_SETTINGS_PWR_MODE_HALT); |
1037 | } |
1038 | |
1039 | static int __maybe_unused iqs62x_resume(struct device *dev) |
1040 | { |
1041 | struct iqs62x_core *iqs62x = dev_get_drvdata(dev); |
1042 | int ret; |
1043 | |
1044 | ret = regmap_update_bits(map: iqs62x->regmap, IQS62X_PWR_SETTINGS, |
1045 | IQS62X_PWR_SETTINGS_PWR_MODE_MASK, |
1046 | IQS62X_PWR_SETTINGS_PWR_MODE_NORM); |
1047 | if (ret) |
1048 | return ret; |
1049 | |
1050 | return regmap_update_bits(map: iqs62x->regmap, IQS62X_PWR_SETTINGS, |
1051 | IQS62X_PWR_SETTINGS_DIS_AUTO, val: 0); |
1052 | } |
1053 | |
1054 | static SIMPLE_DEV_PM_OPS(iqs62x_pm, iqs62x_suspend, iqs62x_resume); |
1055 | |
1056 | static const struct of_device_id iqs62x_of_match[] = { |
1057 | { .compatible = "azoteq,iqs620a" }, |
1058 | { .compatible = "azoteq,iqs621" }, |
1059 | { .compatible = "azoteq,iqs622" }, |
1060 | { .compatible = "azoteq,iqs624" }, |
1061 | { .compatible = "azoteq,iqs625" }, |
1062 | { } |
1063 | }; |
1064 | MODULE_DEVICE_TABLE(of, iqs62x_of_match); |
1065 | |
1066 | static struct i2c_driver iqs62x_i2c_driver = { |
1067 | .driver = { |
1068 | .name = "iqs62x" , |
1069 | .of_match_table = iqs62x_of_match, |
1070 | .pm = &iqs62x_pm, |
1071 | }, |
1072 | .probe = iqs62x_probe, |
1073 | .remove = iqs62x_remove, |
1074 | }; |
1075 | module_i2c_driver(iqs62x_i2c_driver); |
1076 | |
1077 | MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>" ); |
1078 | MODULE_DESCRIPTION("Azoteq IQS620A/621/622/624/625 Multi-Function Sensors" ); |
1079 | MODULE_LICENSE("GPL" ); |
1080 | |