1e505edaeSJeff LaBundy // SPDX-License-Identifier: GPL-2.0-or-later
2e505edaeSJeff LaBundy /*
3dd24e202SJeff LaBundy * Azoteq IQS7222A/B/C/D Capacitive Touch Controller
4e505edaeSJeff LaBundy *
5e505edaeSJeff LaBundy * Copyright (C) 2022 Jeff LaBundy <jeff@labundy.com>
6e505edaeSJeff LaBundy */
7e505edaeSJeff LaBundy
8e505edaeSJeff LaBundy #include <linux/bits.h>
9e505edaeSJeff LaBundy #include <linux/delay.h>
10e505edaeSJeff LaBundy #include <linux/device.h>
11e505edaeSJeff LaBundy #include <linux/err.h>
12e505edaeSJeff LaBundy #include <linux/gpio/consumer.h>
13e505edaeSJeff LaBundy #include <linux/i2c.h>
14e505edaeSJeff LaBundy #include <linux/input.h>
15dd24e202SJeff LaBundy #include <linux/input/touchscreen.h>
16e505edaeSJeff LaBundy #include <linux/interrupt.h>
17e505edaeSJeff LaBundy #include <linux/kernel.h>
18e505edaeSJeff LaBundy #include <linux/ktime.h>
19dbce1a7dSRob Herring #include <linux/mod_devicetable.h>
20e505edaeSJeff LaBundy #include <linux/module.h>
21e505edaeSJeff LaBundy #include <linux/property.h>
22e505edaeSJeff LaBundy #include <linux/slab.h>
23e505edaeSJeff LaBundy #include <asm/unaligned.h>
24e505edaeSJeff LaBundy
25e505edaeSJeff LaBundy #define IQS7222_PROD_NUM 0x00
26e505edaeSJeff LaBundy #define IQS7222_PROD_NUM_A 840
27e505edaeSJeff LaBundy #define IQS7222_PROD_NUM_B 698
28e505edaeSJeff LaBundy #define IQS7222_PROD_NUM_C 863
29dd24e202SJeff LaBundy #define IQS7222_PROD_NUM_D 1046
30e505edaeSJeff LaBundy
31e505edaeSJeff LaBundy #define IQS7222_SYS_STATUS 0x10
32e505edaeSJeff LaBundy #define IQS7222_SYS_STATUS_RESET BIT(3)
33e505edaeSJeff LaBundy #define IQS7222_SYS_STATUS_ATI_ERROR BIT(1)
34e505edaeSJeff LaBundy #define IQS7222_SYS_STATUS_ATI_ACTIVE BIT(0)
35e505edaeSJeff LaBundy
36e505edaeSJeff LaBundy #define IQS7222_CHAN_SETUP_0_REF_MODE_MASK GENMASK(15, 14)
37e505edaeSJeff LaBundy #define IQS7222_CHAN_SETUP_0_REF_MODE_FOLLOW BIT(15)
38e505edaeSJeff LaBundy #define IQS7222_CHAN_SETUP_0_REF_MODE_REF BIT(14)
39e505edaeSJeff LaBundy #define IQS7222_CHAN_SETUP_0_CHAN_EN BIT(8)
40e505edaeSJeff LaBundy
41e505edaeSJeff LaBundy #define IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK GENMASK(2, 0)
42e505edaeSJeff LaBundy #define IQS7222_SLDR_SETUP_2_RES_MASK GENMASK(15, 8)
43e505edaeSJeff LaBundy #define IQS7222_SLDR_SETUP_2_RES_SHIFT 8
44e505edaeSJeff LaBundy #define IQS7222_SLDR_SETUP_2_TOP_SPEED_MASK GENMASK(7, 0)
45e505edaeSJeff LaBundy
46e505edaeSJeff LaBundy #define IQS7222_GPIO_SETUP_0_GPIO_EN BIT(0)
47e505edaeSJeff LaBundy
48e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP 0xD0
49e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP_INTF_MODE_MASK GENMASK(7, 6)
50e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP_INTF_MODE_TOUCH BIT(7)
51e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP_INTF_MODE_EVENT BIT(6)
52e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP_PWR_MODE_MASK GENMASK(5, 4)
53e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP_PWR_MODE_AUTO IQS7222_SYS_SETUP_PWR_MODE_MASK
54e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP_REDO_ATI BIT(2)
55e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP_ACK_RESET BIT(0)
56e505edaeSJeff LaBundy
57e505edaeSJeff LaBundy #define IQS7222_EVENT_MASK_ATI BIT(12)
5895215d3dSJeff LaBundy #define IQS7222_EVENT_MASK_SLDR BIT(10)
59dd24e202SJeff LaBundy #define IQS7222_EVENT_MASK_TPAD IQS7222_EVENT_MASK_SLDR
6095215d3dSJeff LaBundy #define IQS7222_EVENT_MASK_TOUCH BIT(1)
6195215d3dSJeff LaBundy #define IQS7222_EVENT_MASK_PROX BIT(0)
62e505edaeSJeff LaBundy
63e505edaeSJeff LaBundy #define IQS7222_COMMS_HOLD BIT(0)
64e505edaeSJeff LaBundy #define IQS7222_COMMS_ERROR 0xEEEE
65e505edaeSJeff LaBundy #define IQS7222_COMMS_RETRY_MS 50
66e505edaeSJeff LaBundy #define IQS7222_COMMS_TIMEOUT_MS 100
67e505edaeSJeff LaBundy #define IQS7222_RESET_TIMEOUT_MS 250
68e505edaeSJeff LaBundy #define IQS7222_ATI_TIMEOUT_MS 2000
69e505edaeSJeff LaBundy
70e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_STAT 8
71e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_CYCLE 3
72e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_GLBL 3
73e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_BTN 3
74e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_CHAN 6
75e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_FILT 2
76e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_SLDR 11
77dd24e202SJeff LaBundy #define IQS7222_MAX_COLS_TPAD 24
78e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_GPIO 3
79e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_SYS 13
80e505edaeSJeff LaBundy
81e505edaeSJeff LaBundy #define IQS7222_MAX_CHAN 20
82e505edaeSJeff LaBundy #define IQS7222_MAX_SLDR 2
83e505edaeSJeff LaBundy
84e505edaeSJeff LaBundy #define IQS7222_NUM_RETRIES 5
85e505edaeSJeff LaBundy #define IQS7222_REG_OFFSET 0x100
86e505edaeSJeff LaBundy
87e505edaeSJeff LaBundy enum iqs7222_reg_key_id {
88e505edaeSJeff LaBundy IQS7222_REG_KEY_NONE,
89e505edaeSJeff LaBundy IQS7222_REG_KEY_PROX,
90e505edaeSJeff LaBundy IQS7222_REG_KEY_TOUCH,
91e505edaeSJeff LaBundy IQS7222_REG_KEY_DEBOUNCE,
92e505edaeSJeff LaBundy IQS7222_REG_KEY_TAP,
938d4c313cSJeff LaBundy IQS7222_REG_KEY_TAP_LEGACY,
94e505edaeSJeff LaBundy IQS7222_REG_KEY_AXIAL,
958d4c313cSJeff LaBundy IQS7222_REG_KEY_AXIAL_LEGACY,
96e505edaeSJeff LaBundy IQS7222_REG_KEY_WHEEL,
97e505edaeSJeff LaBundy IQS7222_REG_KEY_NO_WHEEL,
98e505edaeSJeff LaBundy IQS7222_REG_KEY_RESERVED
99e505edaeSJeff LaBundy };
100e505edaeSJeff LaBundy
101e505edaeSJeff LaBundy enum iqs7222_reg_grp_id {
102e505edaeSJeff LaBundy IQS7222_REG_GRP_STAT,
1032e70ef52SJeff LaBundy IQS7222_REG_GRP_FILT,
104e505edaeSJeff LaBundy IQS7222_REG_GRP_CYCLE,
105e505edaeSJeff LaBundy IQS7222_REG_GRP_GLBL,
106e505edaeSJeff LaBundy IQS7222_REG_GRP_BTN,
107e505edaeSJeff LaBundy IQS7222_REG_GRP_CHAN,
108e505edaeSJeff LaBundy IQS7222_REG_GRP_SLDR,
109dd24e202SJeff LaBundy IQS7222_REG_GRP_TPAD,
110e505edaeSJeff LaBundy IQS7222_REG_GRP_GPIO,
111e505edaeSJeff LaBundy IQS7222_REG_GRP_SYS,
112e505edaeSJeff LaBundy IQS7222_NUM_REG_GRPS
113e505edaeSJeff LaBundy };
114e505edaeSJeff LaBundy
115bbd16b0dSJeff LaBundy static const char * const iqs7222_reg_grp_names[IQS7222_NUM_REG_GRPS] = {
116dd24e202SJeff LaBundy [IQS7222_REG_GRP_CYCLE] = "cycle-%d",
117dd24e202SJeff LaBundy [IQS7222_REG_GRP_CHAN] = "channel-%d",
118dd24e202SJeff LaBundy [IQS7222_REG_GRP_SLDR] = "slider-%d",
119dd24e202SJeff LaBundy [IQS7222_REG_GRP_TPAD] = "trackpad",
120dd24e202SJeff LaBundy [IQS7222_REG_GRP_GPIO] = "gpio-%d",
121e505edaeSJeff LaBundy };
122e505edaeSJeff LaBundy
123bbd16b0dSJeff LaBundy static const unsigned int iqs7222_max_cols[IQS7222_NUM_REG_GRPS] = {
124e505edaeSJeff LaBundy [IQS7222_REG_GRP_STAT] = IQS7222_MAX_COLS_STAT,
125e505edaeSJeff LaBundy [IQS7222_REG_GRP_CYCLE] = IQS7222_MAX_COLS_CYCLE,
126e505edaeSJeff LaBundy [IQS7222_REG_GRP_GLBL] = IQS7222_MAX_COLS_GLBL,
127e505edaeSJeff LaBundy [IQS7222_REG_GRP_BTN] = IQS7222_MAX_COLS_BTN,
128e505edaeSJeff LaBundy [IQS7222_REG_GRP_CHAN] = IQS7222_MAX_COLS_CHAN,
129e505edaeSJeff LaBundy [IQS7222_REG_GRP_FILT] = IQS7222_MAX_COLS_FILT,
130e505edaeSJeff LaBundy [IQS7222_REG_GRP_SLDR] = IQS7222_MAX_COLS_SLDR,
131dd24e202SJeff LaBundy [IQS7222_REG_GRP_TPAD] = IQS7222_MAX_COLS_TPAD,
132e505edaeSJeff LaBundy [IQS7222_REG_GRP_GPIO] = IQS7222_MAX_COLS_GPIO,
133e505edaeSJeff LaBundy [IQS7222_REG_GRP_SYS] = IQS7222_MAX_COLS_SYS,
134e505edaeSJeff LaBundy };
135e505edaeSJeff LaBundy
136e505edaeSJeff LaBundy static const unsigned int iqs7222_gpio_links[] = { 2, 5, 6, };
137e505edaeSJeff LaBundy
138e505edaeSJeff LaBundy struct iqs7222_event_desc {
139e505edaeSJeff LaBundy const char *name;
140dd24e202SJeff LaBundy u16 link;
141e505edaeSJeff LaBundy u16 mask;
142e505edaeSJeff LaBundy u16 val;
143dd24e202SJeff LaBundy u16 strict;
144e505edaeSJeff LaBundy u16 enable;
145e505edaeSJeff LaBundy enum iqs7222_reg_key_id reg_key;
146e505edaeSJeff LaBundy };
147e505edaeSJeff LaBundy
148e505edaeSJeff LaBundy static const struct iqs7222_event_desc iqs7222_kp_events[] = {
149e505edaeSJeff LaBundy {
150e505edaeSJeff LaBundy .name = "event-prox",
15195215d3dSJeff LaBundy .enable = IQS7222_EVENT_MASK_PROX,
152e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_PROX,
153e505edaeSJeff LaBundy },
154e505edaeSJeff LaBundy {
155e505edaeSJeff LaBundy .name = "event-touch",
15695215d3dSJeff LaBundy .enable = IQS7222_EVENT_MASK_TOUCH,
157e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_TOUCH,
158e505edaeSJeff LaBundy },
159e505edaeSJeff LaBundy };
160e505edaeSJeff LaBundy
161e505edaeSJeff LaBundy static const struct iqs7222_event_desc iqs7222_sl_events[] = {
162e505edaeSJeff LaBundy { .name = "event-press", },
163e505edaeSJeff LaBundy {
164e505edaeSJeff LaBundy .name = "event-tap",
165e505edaeSJeff LaBundy .mask = BIT(0),
166e505edaeSJeff LaBundy .val = BIT(0),
167e505edaeSJeff LaBundy .enable = BIT(0),
168e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_TAP,
169e505edaeSJeff LaBundy },
170e505edaeSJeff LaBundy {
171e505edaeSJeff LaBundy .name = "event-swipe-pos",
172e505edaeSJeff LaBundy .mask = BIT(5) | BIT(1),
173e505edaeSJeff LaBundy .val = BIT(1),
174e505edaeSJeff LaBundy .enable = BIT(1),
175e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL,
176e505edaeSJeff LaBundy },
177e505edaeSJeff LaBundy {
178e505edaeSJeff LaBundy .name = "event-swipe-neg",
179e505edaeSJeff LaBundy .mask = BIT(5) | BIT(1),
180e505edaeSJeff LaBundy .val = BIT(5) | BIT(1),
181e505edaeSJeff LaBundy .enable = BIT(1),
182e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL,
183e505edaeSJeff LaBundy },
184e505edaeSJeff LaBundy {
185e505edaeSJeff LaBundy .name = "event-flick-pos",
186e505edaeSJeff LaBundy .mask = BIT(5) | BIT(2),
187e505edaeSJeff LaBundy .val = BIT(2),
188e505edaeSJeff LaBundy .enable = BIT(2),
189e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL,
190e505edaeSJeff LaBundy },
191e505edaeSJeff LaBundy {
192e505edaeSJeff LaBundy .name = "event-flick-neg",
193e505edaeSJeff LaBundy .mask = BIT(5) | BIT(2),
194e505edaeSJeff LaBundy .val = BIT(5) | BIT(2),
195e505edaeSJeff LaBundy .enable = BIT(2),
196e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL,
197e505edaeSJeff LaBundy },
198e505edaeSJeff LaBundy };
199e505edaeSJeff LaBundy
200dd24e202SJeff LaBundy static const struct iqs7222_event_desc iqs7222_tp_events[] = {
201dd24e202SJeff LaBundy {
202dd24e202SJeff LaBundy .name = "event-press",
203dd24e202SJeff LaBundy .link = BIT(7),
204dd24e202SJeff LaBundy },
205dd24e202SJeff LaBundy {
206dd24e202SJeff LaBundy .name = "event-tap",
207dd24e202SJeff LaBundy .link = BIT(0),
208dd24e202SJeff LaBundy .mask = BIT(0),
209dd24e202SJeff LaBundy .val = BIT(0),
210dd24e202SJeff LaBundy .enable = BIT(0),
211dd24e202SJeff LaBundy .reg_key = IQS7222_REG_KEY_TAP,
212dd24e202SJeff LaBundy },
213dd24e202SJeff LaBundy {
214dd24e202SJeff LaBundy .name = "event-swipe-x-pos",
215dd24e202SJeff LaBundy .link = BIT(2),
216dd24e202SJeff LaBundy .mask = BIT(2) | BIT(1),
217dd24e202SJeff LaBundy .val = BIT(2),
218dd24e202SJeff LaBundy .strict = BIT(4),
219dd24e202SJeff LaBundy .enable = BIT(1),
220dd24e202SJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL,
221dd24e202SJeff LaBundy },
222dd24e202SJeff LaBundy {
223dd24e202SJeff LaBundy .name = "event-swipe-y-pos",
224dd24e202SJeff LaBundy .link = BIT(3),
225dd24e202SJeff LaBundy .mask = BIT(3) | BIT(1),
226dd24e202SJeff LaBundy .val = BIT(3),
227dd24e202SJeff LaBundy .strict = BIT(3),
228dd24e202SJeff LaBundy .enable = BIT(1),
229dd24e202SJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL,
230dd24e202SJeff LaBundy },
231dd24e202SJeff LaBundy {
232dd24e202SJeff LaBundy .name = "event-swipe-x-neg",
233dd24e202SJeff LaBundy .link = BIT(4),
234dd24e202SJeff LaBundy .mask = BIT(4) | BIT(1),
235dd24e202SJeff LaBundy .val = BIT(4),
236dd24e202SJeff LaBundy .strict = BIT(4),
237dd24e202SJeff LaBundy .enable = BIT(1),
238dd24e202SJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL,
239dd24e202SJeff LaBundy },
240dd24e202SJeff LaBundy {
241dd24e202SJeff LaBundy .name = "event-swipe-y-neg",
242dd24e202SJeff LaBundy .link = BIT(5),
243dd24e202SJeff LaBundy .mask = BIT(5) | BIT(1),
244dd24e202SJeff LaBundy .val = BIT(5),
245dd24e202SJeff LaBundy .strict = BIT(3),
246dd24e202SJeff LaBundy .enable = BIT(1),
247dd24e202SJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL,
248dd24e202SJeff LaBundy },
249dd24e202SJeff LaBundy {
250dd24e202SJeff LaBundy .name = "event-flick-x-pos",
251dd24e202SJeff LaBundy .link = BIT(2),
252dd24e202SJeff LaBundy .mask = BIT(2) | BIT(1),
253dd24e202SJeff LaBundy .val = BIT(2) | BIT(1),
254dd24e202SJeff LaBundy .strict = BIT(4),
255dd24e202SJeff LaBundy .enable = BIT(2),
256dd24e202SJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL,
257dd24e202SJeff LaBundy },
258dd24e202SJeff LaBundy {
259dd24e202SJeff LaBundy .name = "event-flick-y-pos",
260dd24e202SJeff LaBundy .link = BIT(3),
261dd24e202SJeff LaBundy .mask = BIT(3) | BIT(1),
262dd24e202SJeff LaBundy .val = BIT(3) | BIT(1),
263dd24e202SJeff LaBundy .strict = BIT(3),
264dd24e202SJeff LaBundy .enable = BIT(2),
265dd24e202SJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL,
266dd24e202SJeff LaBundy },
267dd24e202SJeff LaBundy {
268dd24e202SJeff LaBundy .name = "event-flick-x-neg",
269dd24e202SJeff LaBundy .link = BIT(4),
270dd24e202SJeff LaBundy .mask = BIT(4) | BIT(1),
271dd24e202SJeff LaBundy .val = BIT(4) | BIT(1),
272dd24e202SJeff LaBundy .strict = BIT(4),
273dd24e202SJeff LaBundy .enable = BIT(2),
274dd24e202SJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL,
275dd24e202SJeff LaBundy },
276dd24e202SJeff LaBundy {
277dd24e202SJeff LaBundy .name = "event-flick-y-neg",
278dd24e202SJeff LaBundy .link = BIT(5),
279dd24e202SJeff LaBundy .mask = BIT(5) | BIT(1),
280dd24e202SJeff LaBundy .val = BIT(5) | BIT(1),
281dd24e202SJeff LaBundy .strict = BIT(3),
282dd24e202SJeff LaBundy .enable = BIT(2),
283dd24e202SJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL,
284dd24e202SJeff LaBundy },
285dd24e202SJeff LaBundy };
286dd24e202SJeff LaBundy
287e505edaeSJeff LaBundy struct iqs7222_reg_grp_desc {
288e505edaeSJeff LaBundy u16 base;
289e505edaeSJeff LaBundy int num_row;
290e505edaeSJeff LaBundy int num_col;
291e505edaeSJeff LaBundy };
292e505edaeSJeff LaBundy
293e505edaeSJeff LaBundy struct iqs7222_dev_desc {
294e505edaeSJeff LaBundy u16 prod_num;
295e505edaeSJeff LaBundy u16 fw_major;
296e505edaeSJeff LaBundy u16 fw_minor;
297e505edaeSJeff LaBundy u16 sldr_res;
298e505edaeSJeff LaBundy u16 touch_link;
299e505edaeSJeff LaBundy u16 wheel_enable;
300e505edaeSJeff LaBundy int allow_offset;
301e505edaeSJeff LaBundy int event_offset;
302e505edaeSJeff LaBundy int comms_offset;
3038d4c313cSJeff LaBundy bool legacy_gesture;
304e505edaeSJeff LaBundy struct iqs7222_reg_grp_desc reg_grps[IQS7222_NUM_REG_GRPS];
305e505edaeSJeff LaBundy };
306e505edaeSJeff LaBundy
307e505edaeSJeff LaBundy static const struct iqs7222_dev_desc iqs7222_devs[] = {
308e505edaeSJeff LaBundy {
309e505edaeSJeff LaBundy .prod_num = IQS7222_PROD_NUM_A,
310e505edaeSJeff LaBundy .fw_major = 1,
3118d4c313cSJeff LaBundy .fw_minor = 13,
3128d4c313cSJeff LaBundy .sldr_res = U8_MAX * 16,
3138d4c313cSJeff LaBundy .touch_link = 1768,
3148d4c313cSJeff LaBundy .allow_offset = 9,
3158d4c313cSJeff LaBundy .event_offset = 10,
3168d4c313cSJeff LaBundy .comms_offset = 12,
3178d4c313cSJeff LaBundy .reg_grps = {
3188d4c313cSJeff LaBundy [IQS7222_REG_GRP_STAT] = {
3198d4c313cSJeff LaBundy .base = IQS7222_SYS_STATUS,
3208d4c313cSJeff LaBundy .num_row = 1,
3218d4c313cSJeff LaBundy .num_col = 8,
3228d4c313cSJeff LaBundy },
3238d4c313cSJeff LaBundy [IQS7222_REG_GRP_CYCLE] = {
3248d4c313cSJeff LaBundy .base = 0x8000,
3258d4c313cSJeff LaBundy .num_row = 7,
3268d4c313cSJeff LaBundy .num_col = 3,
3278d4c313cSJeff LaBundy },
3288d4c313cSJeff LaBundy [IQS7222_REG_GRP_GLBL] = {
3298d4c313cSJeff LaBundy .base = 0x8700,
3308d4c313cSJeff LaBundy .num_row = 1,
3318d4c313cSJeff LaBundy .num_col = 3,
3328d4c313cSJeff LaBundy },
3338d4c313cSJeff LaBundy [IQS7222_REG_GRP_BTN] = {
3348d4c313cSJeff LaBundy .base = 0x9000,
3358d4c313cSJeff LaBundy .num_row = 12,
3368d4c313cSJeff LaBundy .num_col = 3,
3378d4c313cSJeff LaBundy },
3388d4c313cSJeff LaBundy [IQS7222_REG_GRP_CHAN] = {
3398d4c313cSJeff LaBundy .base = 0xA000,
3408d4c313cSJeff LaBundy .num_row = 12,
3418d4c313cSJeff LaBundy .num_col = 6,
3428d4c313cSJeff LaBundy },
3438d4c313cSJeff LaBundy [IQS7222_REG_GRP_FILT] = {
3448d4c313cSJeff LaBundy .base = 0xAC00,
3458d4c313cSJeff LaBundy .num_row = 1,
3468d4c313cSJeff LaBundy .num_col = 2,
3478d4c313cSJeff LaBundy },
3488d4c313cSJeff LaBundy [IQS7222_REG_GRP_SLDR] = {
3498d4c313cSJeff LaBundy .base = 0xB000,
3508d4c313cSJeff LaBundy .num_row = 2,
3518d4c313cSJeff LaBundy .num_col = 11,
3528d4c313cSJeff LaBundy },
3538d4c313cSJeff LaBundy [IQS7222_REG_GRP_GPIO] = {
3548d4c313cSJeff LaBundy .base = 0xC000,
3558d4c313cSJeff LaBundy .num_row = 1,
3568d4c313cSJeff LaBundy .num_col = 3,
3578d4c313cSJeff LaBundy },
3588d4c313cSJeff LaBundy [IQS7222_REG_GRP_SYS] = {
3598d4c313cSJeff LaBundy .base = IQS7222_SYS_SETUP,
3608d4c313cSJeff LaBundy .num_row = 1,
3618d4c313cSJeff LaBundy .num_col = 13,
3628d4c313cSJeff LaBundy },
3638d4c313cSJeff LaBundy },
3648d4c313cSJeff LaBundy },
3658d4c313cSJeff LaBundy {
3668d4c313cSJeff LaBundy .prod_num = IQS7222_PROD_NUM_A,
3678d4c313cSJeff LaBundy .fw_major = 1,
368e505edaeSJeff LaBundy .fw_minor = 12,
369e505edaeSJeff LaBundy .sldr_res = U8_MAX * 16,
370e505edaeSJeff LaBundy .touch_link = 1768,
371e505edaeSJeff LaBundy .allow_offset = 9,
372e505edaeSJeff LaBundy .event_offset = 10,
373e505edaeSJeff LaBundy .comms_offset = 12,
3748d4c313cSJeff LaBundy .legacy_gesture = true,
375e505edaeSJeff LaBundy .reg_grps = {
376e505edaeSJeff LaBundy [IQS7222_REG_GRP_STAT] = {
377e505edaeSJeff LaBundy .base = IQS7222_SYS_STATUS,
378e505edaeSJeff LaBundy .num_row = 1,
379e505edaeSJeff LaBundy .num_col = 8,
380e505edaeSJeff LaBundy },
381e505edaeSJeff LaBundy [IQS7222_REG_GRP_CYCLE] = {
382e505edaeSJeff LaBundy .base = 0x8000,
383e505edaeSJeff LaBundy .num_row = 7,
384e505edaeSJeff LaBundy .num_col = 3,
385e505edaeSJeff LaBundy },
386e505edaeSJeff LaBundy [IQS7222_REG_GRP_GLBL] = {
387e505edaeSJeff LaBundy .base = 0x8700,
388e505edaeSJeff LaBundy .num_row = 1,
389e505edaeSJeff LaBundy .num_col = 3,
390e505edaeSJeff LaBundy },
391e505edaeSJeff LaBundy [IQS7222_REG_GRP_BTN] = {
392e505edaeSJeff LaBundy .base = 0x9000,
393e505edaeSJeff LaBundy .num_row = 12,
394e505edaeSJeff LaBundy .num_col = 3,
395e505edaeSJeff LaBundy },
396e505edaeSJeff LaBundy [IQS7222_REG_GRP_CHAN] = {
397e505edaeSJeff LaBundy .base = 0xA000,
398e505edaeSJeff LaBundy .num_row = 12,
399e505edaeSJeff LaBundy .num_col = 6,
400e505edaeSJeff LaBundy },
401e505edaeSJeff LaBundy [IQS7222_REG_GRP_FILT] = {
402e505edaeSJeff LaBundy .base = 0xAC00,
403e505edaeSJeff LaBundy .num_row = 1,
404e505edaeSJeff LaBundy .num_col = 2,
405e505edaeSJeff LaBundy },
406e505edaeSJeff LaBundy [IQS7222_REG_GRP_SLDR] = {
407e505edaeSJeff LaBundy .base = 0xB000,
408e505edaeSJeff LaBundy .num_row = 2,
409e505edaeSJeff LaBundy .num_col = 11,
410e505edaeSJeff LaBundy },
411e505edaeSJeff LaBundy [IQS7222_REG_GRP_GPIO] = {
412e505edaeSJeff LaBundy .base = 0xC000,
413e505edaeSJeff LaBundy .num_row = 1,
414e505edaeSJeff LaBundy .num_col = 3,
415e505edaeSJeff LaBundy },
416e505edaeSJeff LaBundy [IQS7222_REG_GRP_SYS] = {
417e505edaeSJeff LaBundy .base = IQS7222_SYS_SETUP,
418e505edaeSJeff LaBundy .num_row = 1,
419e505edaeSJeff LaBundy .num_col = 13,
420e505edaeSJeff LaBundy },
421e505edaeSJeff LaBundy },
422e505edaeSJeff LaBundy },
423e505edaeSJeff LaBundy {
424e505edaeSJeff LaBundy .prod_num = IQS7222_PROD_NUM_B,
425e505edaeSJeff LaBundy .fw_major = 1,
426e505edaeSJeff LaBundy .fw_minor = 43,
427e505edaeSJeff LaBundy .event_offset = 10,
428e505edaeSJeff LaBundy .comms_offset = 11,
429e505edaeSJeff LaBundy .reg_grps = {
430e505edaeSJeff LaBundy [IQS7222_REG_GRP_STAT] = {
431e505edaeSJeff LaBundy .base = IQS7222_SYS_STATUS,
432e505edaeSJeff LaBundy .num_row = 1,
433e505edaeSJeff LaBundy .num_col = 6,
434e505edaeSJeff LaBundy },
435e505edaeSJeff LaBundy [IQS7222_REG_GRP_CYCLE] = {
436e505edaeSJeff LaBundy .base = 0x8000,
437e505edaeSJeff LaBundy .num_row = 10,
438e505edaeSJeff LaBundy .num_col = 2,
439e505edaeSJeff LaBundy },
440e505edaeSJeff LaBundy [IQS7222_REG_GRP_GLBL] = {
441e505edaeSJeff LaBundy .base = 0x8A00,
442e505edaeSJeff LaBundy .num_row = 1,
443e505edaeSJeff LaBundy .num_col = 3,
444e505edaeSJeff LaBundy },
445e505edaeSJeff LaBundy [IQS7222_REG_GRP_BTN] = {
446e505edaeSJeff LaBundy .base = 0x9000,
447e505edaeSJeff LaBundy .num_row = 20,
448e505edaeSJeff LaBundy .num_col = 2,
449e505edaeSJeff LaBundy },
450e505edaeSJeff LaBundy [IQS7222_REG_GRP_CHAN] = {
451e505edaeSJeff LaBundy .base = 0xB000,
452e505edaeSJeff LaBundy .num_row = 20,
453e505edaeSJeff LaBundy .num_col = 4,
454e505edaeSJeff LaBundy },
455e505edaeSJeff LaBundy [IQS7222_REG_GRP_FILT] = {
456e505edaeSJeff LaBundy .base = 0xC400,
457e505edaeSJeff LaBundy .num_row = 1,
458e505edaeSJeff LaBundy .num_col = 2,
459e505edaeSJeff LaBundy },
460e505edaeSJeff LaBundy [IQS7222_REG_GRP_SYS] = {
461e505edaeSJeff LaBundy .base = IQS7222_SYS_SETUP,
462e505edaeSJeff LaBundy .num_row = 1,
463e505edaeSJeff LaBundy .num_col = 13,
464e505edaeSJeff LaBundy },
465e505edaeSJeff LaBundy },
466e505edaeSJeff LaBundy },
467e505edaeSJeff LaBundy {
468e505edaeSJeff LaBundy .prod_num = IQS7222_PROD_NUM_B,
469e505edaeSJeff LaBundy .fw_major = 1,
470e505edaeSJeff LaBundy .fw_minor = 27,
471e505edaeSJeff LaBundy .reg_grps = {
472e505edaeSJeff LaBundy [IQS7222_REG_GRP_STAT] = {
473e505edaeSJeff LaBundy .base = IQS7222_SYS_STATUS,
474e505edaeSJeff LaBundy .num_row = 1,
475e505edaeSJeff LaBundy .num_col = 6,
476e505edaeSJeff LaBundy },
477e505edaeSJeff LaBundy [IQS7222_REG_GRP_CYCLE] = {
478e505edaeSJeff LaBundy .base = 0x8000,
479e505edaeSJeff LaBundy .num_row = 10,
480e505edaeSJeff LaBundy .num_col = 2,
481e505edaeSJeff LaBundy },
482e505edaeSJeff LaBundy [IQS7222_REG_GRP_GLBL] = {
483e505edaeSJeff LaBundy .base = 0x8A00,
484e505edaeSJeff LaBundy .num_row = 1,
485e505edaeSJeff LaBundy .num_col = 3,
486e505edaeSJeff LaBundy },
487e505edaeSJeff LaBundy [IQS7222_REG_GRP_BTN] = {
488e505edaeSJeff LaBundy .base = 0x9000,
489e505edaeSJeff LaBundy .num_row = 20,
490e505edaeSJeff LaBundy .num_col = 2,
491e505edaeSJeff LaBundy },
492e505edaeSJeff LaBundy [IQS7222_REG_GRP_CHAN] = {
493e505edaeSJeff LaBundy .base = 0xB000,
494e505edaeSJeff LaBundy .num_row = 20,
495e505edaeSJeff LaBundy .num_col = 4,
496e505edaeSJeff LaBundy },
497e505edaeSJeff LaBundy [IQS7222_REG_GRP_FILT] = {
498e505edaeSJeff LaBundy .base = 0xC400,
499e505edaeSJeff LaBundy .num_row = 1,
500e505edaeSJeff LaBundy .num_col = 2,
501e505edaeSJeff LaBundy },
502e505edaeSJeff LaBundy [IQS7222_REG_GRP_SYS] = {
503e505edaeSJeff LaBundy .base = IQS7222_SYS_SETUP,
504e505edaeSJeff LaBundy .num_row = 1,
505e505edaeSJeff LaBundy .num_col = 10,
506e505edaeSJeff LaBundy },
507e505edaeSJeff LaBundy },
508e505edaeSJeff LaBundy },
509e505edaeSJeff LaBundy {
510e505edaeSJeff LaBundy .prod_num = IQS7222_PROD_NUM_C,
511e505edaeSJeff LaBundy .fw_major = 2,
512e505edaeSJeff LaBundy .fw_minor = 6,
513e505edaeSJeff LaBundy .sldr_res = U16_MAX,
514e505edaeSJeff LaBundy .touch_link = 1686,
515e505edaeSJeff LaBundy .wheel_enable = BIT(3),
516e505edaeSJeff LaBundy .event_offset = 9,
517e505edaeSJeff LaBundy .comms_offset = 10,
518e505edaeSJeff LaBundy .reg_grps = {
519e505edaeSJeff LaBundy [IQS7222_REG_GRP_STAT] = {
520e505edaeSJeff LaBundy .base = IQS7222_SYS_STATUS,
521e505edaeSJeff LaBundy .num_row = 1,
522e505edaeSJeff LaBundy .num_col = 6,
523e505edaeSJeff LaBundy },
524e505edaeSJeff LaBundy [IQS7222_REG_GRP_CYCLE] = {
525e505edaeSJeff LaBundy .base = 0x8000,
526e505edaeSJeff LaBundy .num_row = 5,
527e505edaeSJeff LaBundy .num_col = 3,
528e505edaeSJeff LaBundy },
529e505edaeSJeff LaBundy [IQS7222_REG_GRP_GLBL] = {
530e505edaeSJeff LaBundy .base = 0x8500,
531e505edaeSJeff LaBundy .num_row = 1,
532e505edaeSJeff LaBundy .num_col = 3,
533e505edaeSJeff LaBundy },
534e505edaeSJeff LaBundy [IQS7222_REG_GRP_BTN] = {
535e505edaeSJeff LaBundy .base = 0x9000,
536e505edaeSJeff LaBundy .num_row = 10,
537e505edaeSJeff LaBundy .num_col = 3,
538e505edaeSJeff LaBundy },
539e505edaeSJeff LaBundy [IQS7222_REG_GRP_CHAN] = {
540e505edaeSJeff LaBundy .base = 0xA000,
541e505edaeSJeff LaBundy .num_row = 10,
542e505edaeSJeff LaBundy .num_col = 6,
543e505edaeSJeff LaBundy },
544e505edaeSJeff LaBundy [IQS7222_REG_GRP_FILT] = {
545e505edaeSJeff LaBundy .base = 0xAA00,
546e505edaeSJeff LaBundy .num_row = 1,
547e505edaeSJeff LaBundy .num_col = 2,
548e505edaeSJeff LaBundy },
549e505edaeSJeff LaBundy [IQS7222_REG_GRP_SLDR] = {
550e505edaeSJeff LaBundy .base = 0xB000,
551e505edaeSJeff LaBundy .num_row = 2,
552e505edaeSJeff LaBundy .num_col = 10,
553e505edaeSJeff LaBundy },
554e505edaeSJeff LaBundy [IQS7222_REG_GRP_GPIO] = {
555e505edaeSJeff LaBundy .base = 0xC000,
556e505edaeSJeff LaBundy .num_row = 3,
557e505edaeSJeff LaBundy .num_col = 3,
558e505edaeSJeff LaBundy },
559e505edaeSJeff LaBundy [IQS7222_REG_GRP_SYS] = {
560e505edaeSJeff LaBundy .base = IQS7222_SYS_SETUP,
561e505edaeSJeff LaBundy .num_row = 1,
562e505edaeSJeff LaBundy .num_col = 12,
563e505edaeSJeff LaBundy },
564e505edaeSJeff LaBundy },
565e505edaeSJeff LaBundy },
566e505edaeSJeff LaBundy {
567e505edaeSJeff LaBundy .prod_num = IQS7222_PROD_NUM_C,
568e505edaeSJeff LaBundy .fw_major = 1,
569e505edaeSJeff LaBundy .fw_minor = 13,
570e505edaeSJeff LaBundy .sldr_res = U16_MAX,
571e505edaeSJeff LaBundy .touch_link = 1674,
572e505edaeSJeff LaBundy .wheel_enable = BIT(3),
573e505edaeSJeff LaBundy .event_offset = 9,
574e505edaeSJeff LaBundy .comms_offset = 10,
575e505edaeSJeff LaBundy .reg_grps = {
576e505edaeSJeff LaBundy [IQS7222_REG_GRP_STAT] = {
577e505edaeSJeff LaBundy .base = IQS7222_SYS_STATUS,
578e505edaeSJeff LaBundy .num_row = 1,
579e505edaeSJeff LaBundy .num_col = 6,
580e505edaeSJeff LaBundy },
581e505edaeSJeff LaBundy [IQS7222_REG_GRP_CYCLE] = {
582e505edaeSJeff LaBundy .base = 0x8000,
583e505edaeSJeff LaBundy .num_row = 5,
584e505edaeSJeff LaBundy .num_col = 3,
585e505edaeSJeff LaBundy },
586e505edaeSJeff LaBundy [IQS7222_REG_GRP_GLBL] = {
587e505edaeSJeff LaBundy .base = 0x8500,
588e505edaeSJeff LaBundy .num_row = 1,
589e505edaeSJeff LaBundy .num_col = 3,
590e505edaeSJeff LaBundy },
591e505edaeSJeff LaBundy [IQS7222_REG_GRP_BTN] = {
592e505edaeSJeff LaBundy .base = 0x9000,
593e505edaeSJeff LaBundy .num_row = 10,
594e505edaeSJeff LaBundy .num_col = 3,
595e505edaeSJeff LaBundy },
596e505edaeSJeff LaBundy [IQS7222_REG_GRP_CHAN] = {
597e505edaeSJeff LaBundy .base = 0xA000,
598e505edaeSJeff LaBundy .num_row = 10,
599e505edaeSJeff LaBundy .num_col = 6,
600e505edaeSJeff LaBundy },
601e505edaeSJeff LaBundy [IQS7222_REG_GRP_FILT] = {
602e505edaeSJeff LaBundy .base = 0xAA00,
603e505edaeSJeff LaBundy .num_row = 1,
604e505edaeSJeff LaBundy .num_col = 2,
605e505edaeSJeff LaBundy },
606e505edaeSJeff LaBundy [IQS7222_REG_GRP_SLDR] = {
607e505edaeSJeff LaBundy .base = 0xB000,
608e505edaeSJeff LaBundy .num_row = 2,
609e505edaeSJeff LaBundy .num_col = 10,
610e505edaeSJeff LaBundy },
611e505edaeSJeff LaBundy [IQS7222_REG_GRP_GPIO] = {
612e505edaeSJeff LaBundy .base = 0xC000,
613e505edaeSJeff LaBundy .num_row = 1,
614e505edaeSJeff LaBundy .num_col = 3,
615e505edaeSJeff LaBundy },
616e505edaeSJeff LaBundy [IQS7222_REG_GRP_SYS] = {
617e505edaeSJeff LaBundy .base = IQS7222_SYS_SETUP,
618e505edaeSJeff LaBundy .num_row = 1,
619e505edaeSJeff LaBundy .num_col = 11,
620e505edaeSJeff LaBundy },
621e505edaeSJeff LaBundy },
622e505edaeSJeff LaBundy },
623dd24e202SJeff LaBundy {
624dd24e202SJeff LaBundy .prod_num = IQS7222_PROD_NUM_D,
625*992cf656SJeff LaBundy .fw_major = 1,
626*992cf656SJeff LaBundy .fw_minor = 2,
627*992cf656SJeff LaBundy .touch_link = 1770,
628*992cf656SJeff LaBundy .allow_offset = 9,
629*992cf656SJeff LaBundy .event_offset = 10,
630*992cf656SJeff LaBundy .comms_offset = 11,
631*992cf656SJeff LaBundy .reg_grps = {
632*992cf656SJeff LaBundy [IQS7222_REG_GRP_STAT] = {
633*992cf656SJeff LaBundy .base = IQS7222_SYS_STATUS,
634*992cf656SJeff LaBundy .num_row = 1,
635*992cf656SJeff LaBundy .num_col = 7,
636*992cf656SJeff LaBundy },
637*992cf656SJeff LaBundy [IQS7222_REG_GRP_CYCLE] = {
638*992cf656SJeff LaBundy .base = 0x8000,
639*992cf656SJeff LaBundy .num_row = 7,
640*992cf656SJeff LaBundy .num_col = 2,
641*992cf656SJeff LaBundy },
642*992cf656SJeff LaBundy [IQS7222_REG_GRP_GLBL] = {
643*992cf656SJeff LaBundy .base = 0x8700,
644*992cf656SJeff LaBundy .num_row = 1,
645*992cf656SJeff LaBundy .num_col = 3,
646*992cf656SJeff LaBundy },
647*992cf656SJeff LaBundy [IQS7222_REG_GRP_BTN] = {
648*992cf656SJeff LaBundy .base = 0x9000,
649*992cf656SJeff LaBundy .num_row = 14,
650*992cf656SJeff LaBundy .num_col = 3,
651*992cf656SJeff LaBundy },
652*992cf656SJeff LaBundy [IQS7222_REG_GRP_CHAN] = {
653*992cf656SJeff LaBundy .base = 0xA000,
654*992cf656SJeff LaBundy .num_row = 14,
655*992cf656SJeff LaBundy .num_col = 4,
656*992cf656SJeff LaBundy },
657*992cf656SJeff LaBundy [IQS7222_REG_GRP_FILT] = {
658*992cf656SJeff LaBundy .base = 0xAE00,
659*992cf656SJeff LaBundy .num_row = 1,
660*992cf656SJeff LaBundy .num_col = 2,
661*992cf656SJeff LaBundy },
662*992cf656SJeff LaBundy [IQS7222_REG_GRP_TPAD] = {
663*992cf656SJeff LaBundy .base = 0xB000,
664*992cf656SJeff LaBundy .num_row = 1,
665*992cf656SJeff LaBundy .num_col = 24,
666*992cf656SJeff LaBundy },
667*992cf656SJeff LaBundy [IQS7222_REG_GRP_GPIO] = {
668*992cf656SJeff LaBundy .base = 0xC000,
669*992cf656SJeff LaBundy .num_row = 3,
670*992cf656SJeff LaBundy .num_col = 3,
671*992cf656SJeff LaBundy },
672*992cf656SJeff LaBundy [IQS7222_REG_GRP_SYS] = {
673*992cf656SJeff LaBundy .base = IQS7222_SYS_SETUP,
674*992cf656SJeff LaBundy .num_row = 1,
675*992cf656SJeff LaBundy .num_col = 12,
676*992cf656SJeff LaBundy },
677*992cf656SJeff LaBundy },
678*992cf656SJeff LaBundy },
679*992cf656SJeff LaBundy {
680*992cf656SJeff LaBundy .prod_num = IQS7222_PROD_NUM_D,
681*992cf656SJeff LaBundy .fw_major = 1,
682*992cf656SJeff LaBundy .fw_minor = 1,
683*992cf656SJeff LaBundy .touch_link = 1774,
684*992cf656SJeff LaBundy .allow_offset = 9,
685*992cf656SJeff LaBundy .event_offset = 10,
686*992cf656SJeff LaBundy .comms_offset = 11,
687*992cf656SJeff LaBundy .reg_grps = {
688*992cf656SJeff LaBundy [IQS7222_REG_GRP_STAT] = {
689*992cf656SJeff LaBundy .base = IQS7222_SYS_STATUS,
690*992cf656SJeff LaBundy .num_row = 1,
691*992cf656SJeff LaBundy .num_col = 7,
692*992cf656SJeff LaBundy },
693*992cf656SJeff LaBundy [IQS7222_REG_GRP_CYCLE] = {
694*992cf656SJeff LaBundy .base = 0x8000,
695*992cf656SJeff LaBundy .num_row = 7,
696*992cf656SJeff LaBundy .num_col = 2,
697*992cf656SJeff LaBundy },
698*992cf656SJeff LaBundy [IQS7222_REG_GRP_GLBL] = {
699*992cf656SJeff LaBundy .base = 0x8700,
700*992cf656SJeff LaBundy .num_row = 1,
701*992cf656SJeff LaBundy .num_col = 3,
702*992cf656SJeff LaBundy },
703*992cf656SJeff LaBundy [IQS7222_REG_GRP_BTN] = {
704*992cf656SJeff LaBundy .base = 0x9000,
705*992cf656SJeff LaBundy .num_row = 14,
706*992cf656SJeff LaBundy .num_col = 3,
707*992cf656SJeff LaBundy },
708*992cf656SJeff LaBundy [IQS7222_REG_GRP_CHAN] = {
709*992cf656SJeff LaBundy .base = 0xA000,
710*992cf656SJeff LaBundy .num_row = 14,
711*992cf656SJeff LaBundy .num_col = 4,
712*992cf656SJeff LaBundy },
713*992cf656SJeff LaBundy [IQS7222_REG_GRP_FILT] = {
714*992cf656SJeff LaBundy .base = 0xAE00,
715*992cf656SJeff LaBundy .num_row = 1,
716*992cf656SJeff LaBundy .num_col = 2,
717*992cf656SJeff LaBundy },
718*992cf656SJeff LaBundy [IQS7222_REG_GRP_TPAD] = {
719*992cf656SJeff LaBundy .base = 0xB000,
720*992cf656SJeff LaBundy .num_row = 1,
721*992cf656SJeff LaBundy .num_col = 24,
722*992cf656SJeff LaBundy },
723*992cf656SJeff LaBundy [IQS7222_REG_GRP_GPIO] = {
724*992cf656SJeff LaBundy .base = 0xC000,
725*992cf656SJeff LaBundy .num_row = 3,
726*992cf656SJeff LaBundy .num_col = 3,
727*992cf656SJeff LaBundy },
728*992cf656SJeff LaBundy [IQS7222_REG_GRP_SYS] = {
729*992cf656SJeff LaBundy .base = IQS7222_SYS_SETUP,
730*992cf656SJeff LaBundy .num_row = 1,
731*992cf656SJeff LaBundy .num_col = 12,
732*992cf656SJeff LaBundy },
733*992cf656SJeff LaBundy },
734*992cf656SJeff LaBundy },
735*992cf656SJeff LaBundy {
736*992cf656SJeff LaBundy .prod_num = IQS7222_PROD_NUM_D,
737dd24e202SJeff LaBundy .fw_major = 0,
738dd24e202SJeff LaBundy .fw_minor = 37,
739dd24e202SJeff LaBundy .touch_link = 1770,
740dd24e202SJeff LaBundy .allow_offset = 9,
741dd24e202SJeff LaBundy .event_offset = 10,
742dd24e202SJeff LaBundy .comms_offset = 11,
743dd24e202SJeff LaBundy .reg_grps = {
744dd24e202SJeff LaBundy [IQS7222_REG_GRP_STAT] = {
745dd24e202SJeff LaBundy .base = IQS7222_SYS_STATUS,
746dd24e202SJeff LaBundy .num_row = 1,
747dd24e202SJeff LaBundy .num_col = 7,
748dd24e202SJeff LaBundy },
749dd24e202SJeff LaBundy [IQS7222_REG_GRP_CYCLE] = {
750dd24e202SJeff LaBundy .base = 0x8000,
751dd24e202SJeff LaBundy .num_row = 7,
752dd24e202SJeff LaBundy .num_col = 2,
753dd24e202SJeff LaBundy },
754dd24e202SJeff LaBundy [IQS7222_REG_GRP_GLBL] = {
755dd24e202SJeff LaBundy .base = 0x8700,
756dd24e202SJeff LaBundy .num_row = 1,
757dd24e202SJeff LaBundy .num_col = 3,
758dd24e202SJeff LaBundy },
759dd24e202SJeff LaBundy [IQS7222_REG_GRP_BTN] = {
760dd24e202SJeff LaBundy .base = 0x9000,
761dd24e202SJeff LaBundy .num_row = 14,
762dd24e202SJeff LaBundy .num_col = 3,
763dd24e202SJeff LaBundy },
764dd24e202SJeff LaBundy [IQS7222_REG_GRP_CHAN] = {
765dd24e202SJeff LaBundy .base = 0xA000,
766dd24e202SJeff LaBundy .num_row = 14,
767dd24e202SJeff LaBundy .num_col = 4,
768dd24e202SJeff LaBundy },
769dd24e202SJeff LaBundy [IQS7222_REG_GRP_FILT] = {
770dd24e202SJeff LaBundy .base = 0xAE00,
771dd24e202SJeff LaBundy .num_row = 1,
772dd24e202SJeff LaBundy .num_col = 2,
773dd24e202SJeff LaBundy },
774dd24e202SJeff LaBundy [IQS7222_REG_GRP_TPAD] = {
775dd24e202SJeff LaBundy .base = 0xB000,
776dd24e202SJeff LaBundy .num_row = 1,
777dd24e202SJeff LaBundy .num_col = 24,
778dd24e202SJeff LaBundy },
779dd24e202SJeff LaBundy [IQS7222_REG_GRP_GPIO] = {
780dd24e202SJeff LaBundy .base = 0xC000,
781dd24e202SJeff LaBundy .num_row = 3,
782dd24e202SJeff LaBundy .num_col = 3,
783dd24e202SJeff LaBundy },
784dd24e202SJeff LaBundy [IQS7222_REG_GRP_SYS] = {
785dd24e202SJeff LaBundy .base = IQS7222_SYS_SETUP,
786dd24e202SJeff LaBundy .num_row = 1,
787dd24e202SJeff LaBundy .num_col = 12,
788dd24e202SJeff LaBundy },
789dd24e202SJeff LaBundy },
790dd24e202SJeff LaBundy },
791e505edaeSJeff LaBundy };
792e505edaeSJeff LaBundy
793e505edaeSJeff LaBundy struct iqs7222_prop_desc {
794e505edaeSJeff LaBundy const char *name;
795e505edaeSJeff LaBundy enum iqs7222_reg_grp_id reg_grp;
796e505edaeSJeff LaBundy enum iqs7222_reg_key_id reg_key;
797e505edaeSJeff LaBundy int reg_offset;
798e505edaeSJeff LaBundy int reg_shift;
799e505edaeSJeff LaBundy int reg_width;
800e505edaeSJeff LaBundy int val_pitch;
801e505edaeSJeff LaBundy int val_min;
802e505edaeSJeff LaBundy int val_max;
803e505edaeSJeff LaBundy bool invert;
804e505edaeSJeff LaBundy const char *label;
805e505edaeSJeff LaBundy };
806e505edaeSJeff LaBundy
807e505edaeSJeff LaBundy static const struct iqs7222_prop_desc iqs7222_props[] = {
808e505edaeSJeff LaBundy {
809e505edaeSJeff LaBundy .name = "azoteq,conv-period",
810e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CYCLE,
811e505edaeSJeff LaBundy .reg_offset = 0,
812e505edaeSJeff LaBundy .reg_shift = 8,
813e505edaeSJeff LaBundy .reg_width = 8,
814e505edaeSJeff LaBundy .label = "conversion period",
815e505edaeSJeff LaBundy },
816e505edaeSJeff LaBundy {
817e505edaeSJeff LaBundy .name = "azoteq,conv-frac",
818e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CYCLE,
819e505edaeSJeff LaBundy .reg_offset = 0,
820e505edaeSJeff LaBundy .reg_shift = 0,
821e505edaeSJeff LaBundy .reg_width = 8,
822e505edaeSJeff LaBundy .label = "conversion frequency fractional divider",
823e505edaeSJeff LaBundy },
824e505edaeSJeff LaBundy {
825e505edaeSJeff LaBundy .name = "azoteq,rx-float-inactive",
826e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CYCLE,
827e505edaeSJeff LaBundy .reg_offset = 1,
828e505edaeSJeff LaBundy .reg_shift = 6,
829e505edaeSJeff LaBundy .reg_width = 1,
830e505edaeSJeff LaBundy .invert = true,
831e505edaeSJeff LaBundy },
832e505edaeSJeff LaBundy {
833e505edaeSJeff LaBundy .name = "azoteq,dead-time-enable",
834e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CYCLE,
835e505edaeSJeff LaBundy .reg_offset = 1,
836e505edaeSJeff LaBundy .reg_shift = 5,
837e505edaeSJeff LaBundy .reg_width = 1,
838e505edaeSJeff LaBundy },
839e505edaeSJeff LaBundy {
840e505edaeSJeff LaBundy .name = "azoteq,tx-freq-fosc",
841e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CYCLE,
842e505edaeSJeff LaBundy .reg_offset = 1,
843e505edaeSJeff LaBundy .reg_shift = 4,
844e505edaeSJeff LaBundy .reg_width = 1,
845e505edaeSJeff LaBundy },
846e505edaeSJeff LaBundy {
847e505edaeSJeff LaBundy .name = "azoteq,vbias-enable",
848e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CYCLE,
849e505edaeSJeff LaBundy .reg_offset = 1,
850e505edaeSJeff LaBundy .reg_shift = 3,
851e505edaeSJeff LaBundy .reg_width = 1,
852e505edaeSJeff LaBundy },
853e505edaeSJeff LaBundy {
854e505edaeSJeff LaBundy .name = "azoteq,sense-mode",
855e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CYCLE,
856e505edaeSJeff LaBundy .reg_offset = 1,
857e505edaeSJeff LaBundy .reg_shift = 0,
858e505edaeSJeff LaBundy .reg_width = 3,
859e505edaeSJeff LaBundy .val_max = 3,
860e505edaeSJeff LaBundy .label = "sensing mode",
861e505edaeSJeff LaBundy },
862e505edaeSJeff LaBundy {
863e505edaeSJeff LaBundy .name = "azoteq,iref-enable",
864e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CYCLE,
865e505edaeSJeff LaBundy .reg_offset = 2,
866e505edaeSJeff LaBundy .reg_shift = 10,
867e505edaeSJeff LaBundy .reg_width = 1,
868e505edaeSJeff LaBundy },
869e505edaeSJeff LaBundy {
870e505edaeSJeff LaBundy .name = "azoteq,iref-level",
871e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CYCLE,
872e505edaeSJeff LaBundy .reg_offset = 2,
873e505edaeSJeff LaBundy .reg_shift = 4,
874e505edaeSJeff LaBundy .reg_width = 4,
875e505edaeSJeff LaBundy .label = "current reference level",
876e505edaeSJeff LaBundy },
877e505edaeSJeff LaBundy {
878e505edaeSJeff LaBundy .name = "azoteq,iref-trim",
879e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CYCLE,
880e505edaeSJeff LaBundy .reg_offset = 2,
881e505edaeSJeff LaBundy .reg_shift = 0,
882e505edaeSJeff LaBundy .reg_width = 4,
883e505edaeSJeff LaBundy .label = "current reference trim",
884e505edaeSJeff LaBundy },
885e505edaeSJeff LaBundy {
886e505edaeSJeff LaBundy .name = "azoteq,max-counts",
887e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_GLBL,
888e505edaeSJeff LaBundy .reg_offset = 0,
889e505edaeSJeff LaBundy .reg_shift = 13,
890e505edaeSJeff LaBundy .reg_width = 2,
891e505edaeSJeff LaBundy .label = "maximum counts",
892e505edaeSJeff LaBundy },
893e505edaeSJeff LaBundy {
894e505edaeSJeff LaBundy .name = "azoteq,auto-mode",
895e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_GLBL,
896e505edaeSJeff LaBundy .reg_offset = 0,
897e505edaeSJeff LaBundy .reg_shift = 2,
898e505edaeSJeff LaBundy .reg_width = 2,
899e505edaeSJeff LaBundy .label = "number of conversions",
900e505edaeSJeff LaBundy },
901e505edaeSJeff LaBundy {
902e505edaeSJeff LaBundy .name = "azoteq,ati-frac-div-fine",
903e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_GLBL,
904e505edaeSJeff LaBundy .reg_offset = 1,
905e505edaeSJeff LaBundy .reg_shift = 9,
906e505edaeSJeff LaBundy .reg_width = 5,
907e505edaeSJeff LaBundy .label = "ATI fine fractional divider",
908e505edaeSJeff LaBundy },
909e505edaeSJeff LaBundy {
910e505edaeSJeff LaBundy .name = "azoteq,ati-frac-div-coarse",
911e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_GLBL,
912e505edaeSJeff LaBundy .reg_offset = 1,
913e505edaeSJeff LaBundy .reg_shift = 0,
914e505edaeSJeff LaBundy .reg_width = 5,
915e505edaeSJeff LaBundy .label = "ATI coarse fractional divider",
916e505edaeSJeff LaBundy },
917e505edaeSJeff LaBundy {
918e505edaeSJeff LaBundy .name = "azoteq,ati-comp-select",
919e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_GLBL,
920e505edaeSJeff LaBundy .reg_offset = 2,
921e505edaeSJeff LaBundy .reg_shift = 0,
922e505edaeSJeff LaBundy .reg_width = 10,
923e505edaeSJeff LaBundy .label = "ATI compensation selection",
924e505edaeSJeff LaBundy },
925e505edaeSJeff LaBundy {
926e505edaeSJeff LaBundy .name = "azoteq,ati-band",
927e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN,
928e505edaeSJeff LaBundy .reg_offset = 0,
929e505edaeSJeff LaBundy .reg_shift = 12,
930e505edaeSJeff LaBundy .reg_width = 2,
931e505edaeSJeff LaBundy .label = "ATI band",
932e505edaeSJeff LaBundy },
933e505edaeSJeff LaBundy {
934e505edaeSJeff LaBundy .name = "azoteq,global-halt",
935e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN,
936e505edaeSJeff LaBundy .reg_offset = 0,
937e505edaeSJeff LaBundy .reg_shift = 11,
938e505edaeSJeff LaBundy .reg_width = 1,
939e505edaeSJeff LaBundy },
940e505edaeSJeff LaBundy {
941e505edaeSJeff LaBundy .name = "azoteq,invert-enable",
942e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN,
943e505edaeSJeff LaBundy .reg_offset = 0,
944e505edaeSJeff LaBundy .reg_shift = 10,
945e505edaeSJeff LaBundy .reg_width = 1,
946e505edaeSJeff LaBundy },
947e505edaeSJeff LaBundy {
948e505edaeSJeff LaBundy .name = "azoteq,dual-direction",
949e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN,
950e505edaeSJeff LaBundy .reg_offset = 0,
951e505edaeSJeff LaBundy .reg_shift = 9,
952e505edaeSJeff LaBundy .reg_width = 1,
953e505edaeSJeff LaBundy },
954e505edaeSJeff LaBundy {
955e505edaeSJeff LaBundy .name = "azoteq,samp-cap-double",
956e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN,
957e505edaeSJeff LaBundy .reg_offset = 0,
958e505edaeSJeff LaBundy .reg_shift = 3,
959e505edaeSJeff LaBundy .reg_width = 1,
960e505edaeSJeff LaBundy },
961e505edaeSJeff LaBundy {
962e505edaeSJeff LaBundy .name = "azoteq,vref-half",
963e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN,
964e505edaeSJeff LaBundy .reg_offset = 0,
965e505edaeSJeff LaBundy .reg_shift = 2,
966e505edaeSJeff LaBundy .reg_width = 1,
967e505edaeSJeff LaBundy },
968e505edaeSJeff LaBundy {
969e505edaeSJeff LaBundy .name = "azoteq,proj-bias",
970e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN,
971e505edaeSJeff LaBundy .reg_offset = 0,
972e505edaeSJeff LaBundy .reg_shift = 0,
973e505edaeSJeff LaBundy .reg_width = 2,
974e505edaeSJeff LaBundy .label = "projected bias current",
975e505edaeSJeff LaBundy },
976e505edaeSJeff LaBundy {
977e505edaeSJeff LaBundy .name = "azoteq,ati-target",
978e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN,
979e505edaeSJeff LaBundy .reg_offset = 1,
980e505edaeSJeff LaBundy .reg_shift = 8,
981e505edaeSJeff LaBundy .reg_width = 8,
982e505edaeSJeff LaBundy .val_pitch = 8,
983e505edaeSJeff LaBundy .label = "ATI target",
984e505edaeSJeff LaBundy },
985e505edaeSJeff LaBundy {
986e505edaeSJeff LaBundy .name = "azoteq,ati-base",
987e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN,
988e505edaeSJeff LaBundy .reg_offset = 1,
989e505edaeSJeff LaBundy .reg_shift = 3,
990e505edaeSJeff LaBundy .reg_width = 5,
991e505edaeSJeff LaBundy .val_pitch = 16,
992e505edaeSJeff LaBundy .label = "ATI base",
993e505edaeSJeff LaBundy },
994e505edaeSJeff LaBundy {
995e505edaeSJeff LaBundy .name = "azoteq,ati-mode",
996e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN,
997e505edaeSJeff LaBundy .reg_offset = 1,
998e505edaeSJeff LaBundy .reg_shift = 0,
999e505edaeSJeff LaBundy .reg_width = 3,
1000e505edaeSJeff LaBundy .val_max = 5,
1001e505edaeSJeff LaBundy .label = "ATI mode",
1002e505edaeSJeff LaBundy },
1003e505edaeSJeff LaBundy {
1004e505edaeSJeff LaBundy .name = "azoteq,ati-frac-div-fine",
1005e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN,
1006e505edaeSJeff LaBundy .reg_offset = 2,
1007e505edaeSJeff LaBundy .reg_shift = 9,
1008e505edaeSJeff LaBundy .reg_width = 5,
1009e505edaeSJeff LaBundy .label = "ATI fine fractional divider",
1010e505edaeSJeff LaBundy },
1011e505edaeSJeff LaBundy {
1012e505edaeSJeff LaBundy .name = "azoteq,ati-frac-mult-coarse",
1013e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN,
1014e505edaeSJeff LaBundy .reg_offset = 2,
1015e505edaeSJeff LaBundy .reg_shift = 5,
1016e505edaeSJeff LaBundy .reg_width = 4,
1017e505edaeSJeff LaBundy .label = "ATI coarse fractional multiplier",
1018e505edaeSJeff LaBundy },
1019e505edaeSJeff LaBundy {
1020e505edaeSJeff LaBundy .name = "azoteq,ati-frac-div-coarse",
1021e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN,
1022e505edaeSJeff LaBundy .reg_offset = 2,
1023e505edaeSJeff LaBundy .reg_shift = 0,
1024e505edaeSJeff LaBundy .reg_width = 5,
1025e505edaeSJeff LaBundy .label = "ATI coarse fractional divider",
1026e505edaeSJeff LaBundy },
1027e505edaeSJeff LaBundy {
1028e505edaeSJeff LaBundy .name = "azoteq,ati-comp-div",
1029e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN,
1030e505edaeSJeff LaBundy .reg_offset = 3,
1031e505edaeSJeff LaBundy .reg_shift = 11,
1032e505edaeSJeff LaBundy .reg_width = 5,
1033e505edaeSJeff LaBundy .label = "ATI compensation divider",
1034e505edaeSJeff LaBundy },
1035e505edaeSJeff LaBundy {
1036e505edaeSJeff LaBundy .name = "azoteq,ati-comp-select",
1037e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN,
1038e505edaeSJeff LaBundy .reg_offset = 3,
1039e505edaeSJeff LaBundy .reg_shift = 0,
1040e505edaeSJeff LaBundy .reg_width = 10,
1041e505edaeSJeff LaBundy .label = "ATI compensation selection",
1042e505edaeSJeff LaBundy },
1043e505edaeSJeff LaBundy {
1044e505edaeSJeff LaBundy .name = "azoteq,debounce-exit",
1045e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_BTN,
1046e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_DEBOUNCE,
1047e505edaeSJeff LaBundy .reg_offset = 0,
1048e505edaeSJeff LaBundy .reg_shift = 12,
1049e505edaeSJeff LaBundy .reg_width = 4,
1050e505edaeSJeff LaBundy .label = "debounce exit factor",
1051e505edaeSJeff LaBundy },
1052e505edaeSJeff LaBundy {
1053e505edaeSJeff LaBundy .name = "azoteq,debounce-enter",
1054e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_BTN,
1055e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_DEBOUNCE,
1056e505edaeSJeff LaBundy .reg_offset = 0,
1057e505edaeSJeff LaBundy .reg_shift = 8,
1058e505edaeSJeff LaBundy .reg_width = 4,
1059e505edaeSJeff LaBundy .label = "debounce entrance factor",
1060e505edaeSJeff LaBundy },
1061e505edaeSJeff LaBundy {
1062e505edaeSJeff LaBundy .name = "azoteq,thresh",
1063e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_BTN,
1064e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_PROX,
1065e505edaeSJeff LaBundy .reg_offset = 0,
1066e505edaeSJeff LaBundy .reg_shift = 0,
1067e505edaeSJeff LaBundy .reg_width = 8,
1068e505edaeSJeff LaBundy .val_max = 127,
1069e505edaeSJeff LaBundy .label = "threshold",
1070e505edaeSJeff LaBundy },
1071e505edaeSJeff LaBundy {
1072e505edaeSJeff LaBundy .name = "azoteq,thresh",
1073e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_BTN,
1074e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_TOUCH,
1075e505edaeSJeff LaBundy .reg_offset = 1,
1076e505edaeSJeff LaBundy .reg_shift = 0,
1077e505edaeSJeff LaBundy .reg_width = 8,
1078e505edaeSJeff LaBundy .label = "threshold",
1079e505edaeSJeff LaBundy },
1080e505edaeSJeff LaBundy {
1081e505edaeSJeff LaBundy .name = "azoteq,hyst",
1082e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_BTN,
1083e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_TOUCH,
1084e505edaeSJeff LaBundy .reg_offset = 1,
1085e505edaeSJeff LaBundy .reg_shift = 8,
1086e505edaeSJeff LaBundy .reg_width = 8,
1087e505edaeSJeff LaBundy .label = "hysteresis",
1088e505edaeSJeff LaBundy },
1089e505edaeSJeff LaBundy {
1090e505edaeSJeff LaBundy .name = "azoteq,lta-beta-lp",
1091e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_FILT,
1092e505edaeSJeff LaBundy .reg_offset = 0,
1093e505edaeSJeff LaBundy .reg_shift = 12,
1094e505edaeSJeff LaBundy .reg_width = 4,
1095e505edaeSJeff LaBundy .label = "low-power mode long-term average beta",
1096e505edaeSJeff LaBundy },
1097e505edaeSJeff LaBundy {
1098e505edaeSJeff LaBundy .name = "azoteq,lta-beta-np",
1099e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_FILT,
1100e505edaeSJeff LaBundy .reg_offset = 0,
1101e505edaeSJeff LaBundy .reg_shift = 8,
1102e505edaeSJeff LaBundy .reg_width = 4,
1103e505edaeSJeff LaBundy .label = "normal-power mode long-term average beta",
1104e505edaeSJeff LaBundy },
1105e505edaeSJeff LaBundy {
1106e505edaeSJeff LaBundy .name = "azoteq,counts-beta-lp",
1107e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_FILT,
1108e505edaeSJeff LaBundy .reg_offset = 0,
1109e505edaeSJeff LaBundy .reg_shift = 4,
1110e505edaeSJeff LaBundy .reg_width = 4,
1111e505edaeSJeff LaBundy .label = "low-power mode counts beta",
1112e505edaeSJeff LaBundy },
1113e505edaeSJeff LaBundy {
1114e505edaeSJeff LaBundy .name = "azoteq,counts-beta-np",
1115e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_FILT,
1116e505edaeSJeff LaBundy .reg_offset = 0,
1117e505edaeSJeff LaBundy .reg_shift = 0,
1118e505edaeSJeff LaBundy .reg_width = 4,
1119e505edaeSJeff LaBundy .label = "normal-power mode counts beta",
1120e505edaeSJeff LaBundy },
1121e505edaeSJeff LaBundy {
1122e505edaeSJeff LaBundy .name = "azoteq,lta-fast-beta-lp",
1123e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_FILT,
1124e505edaeSJeff LaBundy .reg_offset = 1,
1125e505edaeSJeff LaBundy .reg_shift = 4,
1126e505edaeSJeff LaBundy .reg_width = 4,
1127e505edaeSJeff LaBundy .label = "low-power mode long-term average fast beta",
1128e505edaeSJeff LaBundy },
1129e505edaeSJeff LaBundy {
1130e505edaeSJeff LaBundy .name = "azoteq,lta-fast-beta-np",
1131e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_FILT,
1132e505edaeSJeff LaBundy .reg_offset = 1,
1133e505edaeSJeff LaBundy .reg_shift = 0,
1134e505edaeSJeff LaBundy .reg_width = 4,
1135e505edaeSJeff LaBundy .label = "normal-power mode long-term average fast beta",
1136e505edaeSJeff LaBundy },
1137e505edaeSJeff LaBundy {
1138e505edaeSJeff LaBundy .name = "azoteq,lower-cal",
1139e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR,
1140e505edaeSJeff LaBundy .reg_offset = 0,
1141e505edaeSJeff LaBundy .reg_shift = 8,
1142e505edaeSJeff LaBundy .reg_width = 8,
1143e505edaeSJeff LaBundy .label = "lower calibration",
1144e505edaeSJeff LaBundy },
1145e505edaeSJeff LaBundy {
1146e505edaeSJeff LaBundy .name = "azoteq,static-beta",
1147e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR,
1148e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_NO_WHEEL,
1149e505edaeSJeff LaBundy .reg_offset = 0,
1150e505edaeSJeff LaBundy .reg_shift = 6,
1151e505edaeSJeff LaBundy .reg_width = 1,
1152e505edaeSJeff LaBundy },
1153e505edaeSJeff LaBundy {
1154e505edaeSJeff LaBundy .name = "azoteq,bottom-beta",
1155e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR,
1156e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_NO_WHEEL,
1157e505edaeSJeff LaBundy .reg_offset = 0,
1158e505edaeSJeff LaBundy .reg_shift = 3,
1159e505edaeSJeff LaBundy .reg_width = 3,
1160e505edaeSJeff LaBundy .label = "bottom beta",
1161e505edaeSJeff LaBundy },
1162e505edaeSJeff LaBundy {
1163e505edaeSJeff LaBundy .name = "azoteq,static-beta",
1164e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR,
1165e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_WHEEL,
1166e505edaeSJeff LaBundy .reg_offset = 0,
1167e505edaeSJeff LaBundy .reg_shift = 7,
1168e505edaeSJeff LaBundy .reg_width = 1,
1169e505edaeSJeff LaBundy },
1170e505edaeSJeff LaBundy {
1171e505edaeSJeff LaBundy .name = "azoteq,bottom-beta",
1172e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR,
1173e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_WHEEL,
1174e505edaeSJeff LaBundy .reg_offset = 0,
1175e505edaeSJeff LaBundy .reg_shift = 4,
1176e505edaeSJeff LaBundy .reg_width = 3,
1177e505edaeSJeff LaBundy .label = "bottom beta",
1178e505edaeSJeff LaBundy },
1179e505edaeSJeff LaBundy {
1180e505edaeSJeff LaBundy .name = "azoteq,bottom-speed",
1181e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR,
1182e505edaeSJeff LaBundy .reg_offset = 1,
1183e505edaeSJeff LaBundy .reg_shift = 8,
1184e505edaeSJeff LaBundy .reg_width = 8,
1185e505edaeSJeff LaBundy .label = "bottom speed",
1186e505edaeSJeff LaBundy },
1187e505edaeSJeff LaBundy {
1188e505edaeSJeff LaBundy .name = "azoteq,upper-cal",
1189e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR,
1190e505edaeSJeff LaBundy .reg_offset = 1,
1191e505edaeSJeff LaBundy .reg_shift = 0,
1192e505edaeSJeff LaBundy .reg_width = 8,
1193e505edaeSJeff LaBundy .label = "upper calibration",
1194e505edaeSJeff LaBundy },
1195e505edaeSJeff LaBundy {
1196e505edaeSJeff LaBundy .name = "azoteq,gesture-max-ms",
1197e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR,
1198e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_TAP,
1199e505edaeSJeff LaBundy .reg_offset = 9,
1200e505edaeSJeff LaBundy .reg_shift = 8,
1201e505edaeSJeff LaBundy .reg_width = 8,
12028d4c313cSJeff LaBundy .val_pitch = 16,
12038d4c313cSJeff LaBundy .label = "maximum gesture time",
12048d4c313cSJeff LaBundy },
12058d4c313cSJeff LaBundy {
12068d4c313cSJeff LaBundy .name = "azoteq,gesture-max-ms",
12078d4c313cSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR,
12088d4c313cSJeff LaBundy .reg_key = IQS7222_REG_KEY_TAP_LEGACY,
12098d4c313cSJeff LaBundy .reg_offset = 9,
12108d4c313cSJeff LaBundy .reg_shift = 8,
12118d4c313cSJeff LaBundy .reg_width = 8,
1212e505edaeSJeff LaBundy .val_pitch = 4,
1213e505edaeSJeff LaBundy .label = "maximum gesture time",
1214e505edaeSJeff LaBundy },
1215e505edaeSJeff LaBundy {
1216e505edaeSJeff LaBundy .name = "azoteq,gesture-min-ms",
1217e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR,
1218e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_TAP,
1219e505edaeSJeff LaBundy .reg_offset = 9,
1220e505edaeSJeff LaBundy .reg_shift = 3,
1221e505edaeSJeff LaBundy .reg_width = 5,
12228d4c313cSJeff LaBundy .val_pitch = 16,
12238d4c313cSJeff LaBundy .label = "minimum gesture time",
12248d4c313cSJeff LaBundy },
12258d4c313cSJeff LaBundy {
12268d4c313cSJeff LaBundy .name = "azoteq,gesture-min-ms",
12278d4c313cSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR,
12288d4c313cSJeff LaBundy .reg_key = IQS7222_REG_KEY_TAP_LEGACY,
12298d4c313cSJeff LaBundy .reg_offset = 9,
12308d4c313cSJeff LaBundy .reg_shift = 3,
12318d4c313cSJeff LaBundy .reg_width = 5,
1232e505edaeSJeff LaBundy .val_pitch = 4,
1233e505edaeSJeff LaBundy .label = "minimum gesture time",
1234e505edaeSJeff LaBundy },
1235e505edaeSJeff LaBundy {
1236e505edaeSJeff LaBundy .name = "azoteq,gesture-dist",
1237e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR,
1238e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL,
1239e505edaeSJeff LaBundy .reg_offset = 10,
1240e505edaeSJeff LaBundy .reg_shift = 8,
1241e505edaeSJeff LaBundy .reg_width = 8,
1242e505edaeSJeff LaBundy .val_pitch = 16,
1243e505edaeSJeff LaBundy .label = "gesture distance",
1244e505edaeSJeff LaBundy },
1245e505edaeSJeff LaBundy {
12468d4c313cSJeff LaBundy .name = "azoteq,gesture-dist",
12478d4c313cSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR,
12488d4c313cSJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL_LEGACY,
12498d4c313cSJeff LaBundy .reg_offset = 10,
12508d4c313cSJeff LaBundy .reg_shift = 8,
12518d4c313cSJeff LaBundy .reg_width = 8,
12528d4c313cSJeff LaBundy .val_pitch = 16,
12538d4c313cSJeff LaBundy .label = "gesture distance",
12548d4c313cSJeff LaBundy },
12558d4c313cSJeff LaBundy {
1256e505edaeSJeff LaBundy .name = "azoteq,gesture-max-ms",
1257e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR,
1258e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL,
1259e505edaeSJeff LaBundy .reg_offset = 10,
1260e505edaeSJeff LaBundy .reg_shift = 0,
1261e505edaeSJeff LaBundy .reg_width = 8,
12628d4c313cSJeff LaBundy .val_pitch = 16,
12638d4c313cSJeff LaBundy .label = "maximum gesture time",
12648d4c313cSJeff LaBundy },
12658d4c313cSJeff LaBundy {
12668d4c313cSJeff LaBundy .name = "azoteq,gesture-max-ms",
12678d4c313cSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR,
12688d4c313cSJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL_LEGACY,
12698d4c313cSJeff LaBundy .reg_offset = 10,
12708d4c313cSJeff LaBundy .reg_shift = 0,
12718d4c313cSJeff LaBundy .reg_width = 8,
1272e505edaeSJeff LaBundy .val_pitch = 4,
1273e505edaeSJeff LaBundy .label = "maximum gesture time",
1274e505edaeSJeff LaBundy },
1275e505edaeSJeff LaBundy {
1276dd24e202SJeff LaBundy .name = "azoteq,num-rows",
1277dd24e202SJeff LaBundy .reg_grp = IQS7222_REG_GRP_TPAD,
1278dd24e202SJeff LaBundy .reg_offset = 0,
1279dd24e202SJeff LaBundy .reg_shift = 4,
1280dd24e202SJeff LaBundy .reg_width = 4,
1281dd24e202SJeff LaBundy .val_min = 1,
1282dd24e202SJeff LaBundy .val_max = 12,
1283dd24e202SJeff LaBundy .label = "number of rows",
1284dd24e202SJeff LaBundy },
1285dd24e202SJeff LaBundy {
1286dd24e202SJeff LaBundy .name = "azoteq,num-cols",
1287dd24e202SJeff LaBundy .reg_grp = IQS7222_REG_GRP_TPAD,
1288dd24e202SJeff LaBundy .reg_offset = 0,
1289dd24e202SJeff LaBundy .reg_shift = 0,
1290dd24e202SJeff LaBundy .reg_width = 4,
1291dd24e202SJeff LaBundy .val_min = 1,
1292dd24e202SJeff LaBundy .val_max = 12,
1293dd24e202SJeff LaBundy .label = "number of columns",
1294dd24e202SJeff LaBundy },
1295dd24e202SJeff LaBundy {
1296dd24e202SJeff LaBundy .name = "azoteq,lower-cal-y",
1297dd24e202SJeff LaBundy .reg_grp = IQS7222_REG_GRP_TPAD,
1298dd24e202SJeff LaBundy .reg_offset = 1,
1299dd24e202SJeff LaBundy .reg_shift = 8,
1300dd24e202SJeff LaBundy .reg_width = 8,
1301dd24e202SJeff LaBundy .label = "lower vertical calibration",
1302dd24e202SJeff LaBundy },
1303dd24e202SJeff LaBundy {
1304dd24e202SJeff LaBundy .name = "azoteq,lower-cal-x",
1305dd24e202SJeff LaBundy .reg_grp = IQS7222_REG_GRP_TPAD,
1306dd24e202SJeff LaBundy .reg_offset = 1,
1307dd24e202SJeff LaBundy .reg_shift = 0,
1308dd24e202SJeff LaBundy .reg_width = 8,
1309dd24e202SJeff LaBundy .label = "lower horizontal calibration",
1310dd24e202SJeff LaBundy },
1311dd24e202SJeff LaBundy {
1312dd24e202SJeff LaBundy .name = "azoteq,upper-cal-y",
1313dd24e202SJeff LaBundy .reg_grp = IQS7222_REG_GRP_TPAD,
1314dd24e202SJeff LaBundy .reg_offset = 2,
1315dd24e202SJeff LaBundy .reg_shift = 8,
1316dd24e202SJeff LaBundy .reg_width = 8,
1317dd24e202SJeff LaBundy .label = "upper vertical calibration",
1318dd24e202SJeff LaBundy },
1319dd24e202SJeff LaBundy {
1320dd24e202SJeff LaBundy .name = "azoteq,upper-cal-x",
1321dd24e202SJeff LaBundy .reg_grp = IQS7222_REG_GRP_TPAD,
1322dd24e202SJeff LaBundy .reg_offset = 2,
1323dd24e202SJeff LaBundy .reg_shift = 0,
1324dd24e202SJeff LaBundy .reg_width = 8,
1325dd24e202SJeff LaBundy .label = "upper horizontal calibration",
1326dd24e202SJeff LaBundy },
1327dd24e202SJeff LaBundy {
1328dd24e202SJeff LaBundy .name = "azoteq,top-speed",
1329dd24e202SJeff LaBundy .reg_grp = IQS7222_REG_GRP_TPAD,
1330dd24e202SJeff LaBundy .reg_offset = 3,
1331dd24e202SJeff LaBundy .reg_shift = 8,
1332dd24e202SJeff LaBundy .reg_width = 8,
1333dd24e202SJeff LaBundy .val_pitch = 4,
1334dd24e202SJeff LaBundy .label = "top speed",
1335dd24e202SJeff LaBundy },
1336dd24e202SJeff LaBundy {
1337dd24e202SJeff LaBundy .name = "azoteq,bottom-speed",
1338dd24e202SJeff LaBundy .reg_grp = IQS7222_REG_GRP_TPAD,
1339dd24e202SJeff LaBundy .reg_offset = 3,
1340dd24e202SJeff LaBundy .reg_shift = 0,
1341dd24e202SJeff LaBundy .reg_width = 8,
1342dd24e202SJeff LaBundy .label = "bottom speed",
1343dd24e202SJeff LaBundy },
1344dd24e202SJeff LaBundy {
1345dd24e202SJeff LaBundy .name = "azoteq,gesture-min-ms",
1346dd24e202SJeff LaBundy .reg_grp = IQS7222_REG_GRP_TPAD,
1347dd24e202SJeff LaBundy .reg_key = IQS7222_REG_KEY_TAP,
1348dd24e202SJeff LaBundy .reg_offset = 20,
1349dd24e202SJeff LaBundy .reg_shift = 8,
1350dd24e202SJeff LaBundy .reg_width = 8,
1351dd24e202SJeff LaBundy .val_pitch = 16,
1352dd24e202SJeff LaBundy .label = "minimum gesture time",
1353dd24e202SJeff LaBundy },
1354dd24e202SJeff LaBundy {
1355dd24e202SJeff LaBundy .name = "azoteq,gesture-max-ms",
1356dd24e202SJeff LaBundy .reg_grp = IQS7222_REG_GRP_TPAD,
1357dd24e202SJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL,
1358dd24e202SJeff LaBundy .reg_offset = 21,
1359dd24e202SJeff LaBundy .reg_shift = 8,
1360dd24e202SJeff LaBundy .reg_width = 8,
1361dd24e202SJeff LaBundy .val_pitch = 16,
1362dd24e202SJeff LaBundy .label = "maximum gesture time",
1363dd24e202SJeff LaBundy },
1364dd24e202SJeff LaBundy {
1365dd24e202SJeff LaBundy .name = "azoteq,gesture-max-ms",
1366dd24e202SJeff LaBundy .reg_grp = IQS7222_REG_GRP_TPAD,
1367dd24e202SJeff LaBundy .reg_key = IQS7222_REG_KEY_TAP,
1368dd24e202SJeff LaBundy .reg_offset = 21,
1369dd24e202SJeff LaBundy .reg_shift = 0,
1370dd24e202SJeff LaBundy .reg_width = 8,
1371dd24e202SJeff LaBundy .val_pitch = 16,
1372dd24e202SJeff LaBundy .label = "maximum gesture time",
1373dd24e202SJeff LaBundy },
1374dd24e202SJeff LaBundy {
1375dd24e202SJeff LaBundy .name = "azoteq,gesture-dist",
1376dd24e202SJeff LaBundy .reg_grp = IQS7222_REG_GRP_TPAD,
1377dd24e202SJeff LaBundy .reg_key = IQS7222_REG_KEY_TAP,
1378dd24e202SJeff LaBundy .reg_offset = 22,
1379dd24e202SJeff LaBundy .reg_shift = 0,
1380dd24e202SJeff LaBundy .reg_width = 16,
1381dd24e202SJeff LaBundy .label = "gesture distance",
1382dd24e202SJeff LaBundy },
1383dd24e202SJeff LaBundy {
1384dd24e202SJeff LaBundy .name = "azoteq,gesture-dist",
1385dd24e202SJeff LaBundy .reg_grp = IQS7222_REG_GRP_TPAD,
1386dd24e202SJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL,
1387dd24e202SJeff LaBundy .reg_offset = 23,
1388dd24e202SJeff LaBundy .reg_shift = 0,
1389dd24e202SJeff LaBundy .reg_width = 16,
1390dd24e202SJeff LaBundy .label = "gesture distance",
1391dd24e202SJeff LaBundy },
1392dd24e202SJeff LaBundy {
1393e505edaeSJeff LaBundy .name = "drive-open-drain",
1394e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_GPIO,
1395e505edaeSJeff LaBundy .reg_offset = 0,
1396e505edaeSJeff LaBundy .reg_shift = 1,
1397e505edaeSJeff LaBundy .reg_width = 1,
1398e505edaeSJeff LaBundy },
1399e505edaeSJeff LaBundy {
1400e505edaeSJeff LaBundy .name = "azoteq,timeout-ati-ms",
1401e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SYS,
1402e505edaeSJeff LaBundy .reg_offset = 1,
1403e505edaeSJeff LaBundy .reg_shift = 0,
1404e505edaeSJeff LaBundy .reg_width = 16,
1405e505edaeSJeff LaBundy .val_pitch = 500,
1406e505edaeSJeff LaBundy .label = "ATI error timeout",
1407e505edaeSJeff LaBundy },
1408e505edaeSJeff LaBundy {
1409e505edaeSJeff LaBundy .name = "azoteq,rate-ati-ms",
1410e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SYS,
1411e505edaeSJeff LaBundy .reg_offset = 2,
1412e505edaeSJeff LaBundy .reg_shift = 0,
1413e505edaeSJeff LaBundy .reg_width = 16,
1414e505edaeSJeff LaBundy .label = "ATI report rate",
1415e505edaeSJeff LaBundy },
1416e505edaeSJeff LaBundy {
1417e505edaeSJeff LaBundy .name = "azoteq,timeout-np-ms",
1418e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SYS,
1419e505edaeSJeff LaBundy .reg_offset = 3,
1420e505edaeSJeff LaBundy .reg_shift = 0,
1421e505edaeSJeff LaBundy .reg_width = 16,
1422e505edaeSJeff LaBundy .label = "normal-power mode timeout",
1423e505edaeSJeff LaBundy },
1424e505edaeSJeff LaBundy {
1425e505edaeSJeff LaBundy .name = "azoteq,rate-np-ms",
1426e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SYS,
1427e505edaeSJeff LaBundy .reg_offset = 4,
1428e505edaeSJeff LaBundy .reg_shift = 0,
1429e505edaeSJeff LaBundy .reg_width = 16,
1430e505edaeSJeff LaBundy .val_max = 3000,
1431e505edaeSJeff LaBundy .label = "normal-power mode report rate",
1432e505edaeSJeff LaBundy },
1433e505edaeSJeff LaBundy {
1434e505edaeSJeff LaBundy .name = "azoteq,timeout-lp-ms",
1435e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SYS,
1436e505edaeSJeff LaBundy .reg_offset = 5,
1437e505edaeSJeff LaBundy .reg_shift = 0,
1438e505edaeSJeff LaBundy .reg_width = 16,
1439e505edaeSJeff LaBundy .label = "low-power mode timeout",
1440e505edaeSJeff LaBundy },
1441e505edaeSJeff LaBundy {
1442e505edaeSJeff LaBundy .name = "azoteq,rate-lp-ms",
1443e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SYS,
1444e505edaeSJeff LaBundy .reg_offset = 6,
1445e505edaeSJeff LaBundy .reg_shift = 0,
1446e505edaeSJeff LaBundy .reg_width = 16,
1447e505edaeSJeff LaBundy .val_max = 3000,
1448e505edaeSJeff LaBundy .label = "low-power mode report rate",
1449e505edaeSJeff LaBundy },
1450e505edaeSJeff LaBundy {
1451e505edaeSJeff LaBundy .name = "azoteq,timeout-ulp-ms",
1452e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SYS,
1453e505edaeSJeff LaBundy .reg_offset = 7,
1454e505edaeSJeff LaBundy .reg_shift = 0,
1455e505edaeSJeff LaBundy .reg_width = 16,
1456e505edaeSJeff LaBundy .label = "ultra-low-power mode timeout",
1457e505edaeSJeff LaBundy },
1458e505edaeSJeff LaBundy {
1459e505edaeSJeff LaBundy .name = "azoteq,rate-ulp-ms",
1460e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SYS,
1461e505edaeSJeff LaBundy .reg_offset = 8,
1462e505edaeSJeff LaBundy .reg_shift = 0,
1463e505edaeSJeff LaBundy .reg_width = 16,
1464e505edaeSJeff LaBundy .val_max = 3000,
1465e505edaeSJeff LaBundy .label = "ultra-low-power mode report rate",
1466e505edaeSJeff LaBundy },
1467e505edaeSJeff LaBundy };
1468e505edaeSJeff LaBundy
1469e505edaeSJeff LaBundy struct iqs7222_private {
1470e505edaeSJeff LaBundy const struct iqs7222_dev_desc *dev_desc;
1471e505edaeSJeff LaBundy struct gpio_desc *reset_gpio;
1472e505edaeSJeff LaBundy struct gpio_desc *irq_gpio;
1473e505edaeSJeff LaBundy struct i2c_client *client;
1474e505edaeSJeff LaBundy struct input_dev *keypad;
1475dd24e202SJeff LaBundy struct touchscreen_properties prop;
1476e505edaeSJeff LaBundy unsigned int kp_type[IQS7222_MAX_CHAN][ARRAY_SIZE(iqs7222_kp_events)];
1477e505edaeSJeff LaBundy unsigned int kp_code[IQS7222_MAX_CHAN][ARRAY_SIZE(iqs7222_kp_events)];
1478e505edaeSJeff LaBundy unsigned int sl_code[IQS7222_MAX_SLDR][ARRAY_SIZE(iqs7222_sl_events)];
1479e505edaeSJeff LaBundy unsigned int sl_axis[IQS7222_MAX_SLDR];
1480dd24e202SJeff LaBundy unsigned int tp_code[ARRAY_SIZE(iqs7222_tp_events)];
1481e505edaeSJeff LaBundy u16 cycle_setup[IQS7222_MAX_CHAN / 2][IQS7222_MAX_COLS_CYCLE];
1482e505edaeSJeff LaBundy u16 glbl_setup[IQS7222_MAX_COLS_GLBL];
1483e505edaeSJeff LaBundy u16 btn_setup[IQS7222_MAX_CHAN][IQS7222_MAX_COLS_BTN];
1484e505edaeSJeff LaBundy u16 chan_setup[IQS7222_MAX_CHAN][IQS7222_MAX_COLS_CHAN];
1485e505edaeSJeff LaBundy u16 filt_setup[IQS7222_MAX_COLS_FILT];
1486e505edaeSJeff LaBundy u16 sldr_setup[IQS7222_MAX_SLDR][IQS7222_MAX_COLS_SLDR];
1487dd24e202SJeff LaBundy u16 tpad_setup[IQS7222_MAX_COLS_TPAD];
1488e505edaeSJeff LaBundy u16 gpio_setup[ARRAY_SIZE(iqs7222_gpio_links)][IQS7222_MAX_COLS_GPIO];
1489e505edaeSJeff LaBundy u16 sys_setup[IQS7222_MAX_COLS_SYS];
1490e505edaeSJeff LaBundy };
1491e505edaeSJeff LaBundy
iqs7222_setup(struct iqs7222_private * iqs7222,enum iqs7222_reg_grp_id reg_grp,int row)1492e505edaeSJeff LaBundy static u16 *iqs7222_setup(struct iqs7222_private *iqs7222,
1493e505edaeSJeff LaBundy enum iqs7222_reg_grp_id reg_grp, int row)
1494e505edaeSJeff LaBundy {
1495e505edaeSJeff LaBundy switch (reg_grp) {
1496e505edaeSJeff LaBundy case IQS7222_REG_GRP_CYCLE:
1497e505edaeSJeff LaBundy return iqs7222->cycle_setup[row];
1498e505edaeSJeff LaBundy
1499e505edaeSJeff LaBundy case IQS7222_REG_GRP_GLBL:
1500e505edaeSJeff LaBundy return iqs7222->glbl_setup;
1501e505edaeSJeff LaBundy
1502e505edaeSJeff LaBundy case IQS7222_REG_GRP_BTN:
1503e505edaeSJeff LaBundy return iqs7222->btn_setup[row];
1504e505edaeSJeff LaBundy
1505e505edaeSJeff LaBundy case IQS7222_REG_GRP_CHAN:
1506e505edaeSJeff LaBundy return iqs7222->chan_setup[row];
1507e505edaeSJeff LaBundy
1508e505edaeSJeff LaBundy case IQS7222_REG_GRP_FILT:
1509e505edaeSJeff LaBundy return iqs7222->filt_setup;
1510e505edaeSJeff LaBundy
1511e505edaeSJeff LaBundy case IQS7222_REG_GRP_SLDR:
1512e505edaeSJeff LaBundy return iqs7222->sldr_setup[row];
1513e505edaeSJeff LaBundy
1514dd24e202SJeff LaBundy case IQS7222_REG_GRP_TPAD:
1515dd24e202SJeff LaBundy return iqs7222->tpad_setup;
1516dd24e202SJeff LaBundy
1517e505edaeSJeff LaBundy case IQS7222_REG_GRP_GPIO:
1518e505edaeSJeff LaBundy return iqs7222->gpio_setup[row];
1519e505edaeSJeff LaBundy
1520e505edaeSJeff LaBundy case IQS7222_REG_GRP_SYS:
1521e505edaeSJeff LaBundy return iqs7222->sys_setup;
1522e505edaeSJeff LaBundy
1523e505edaeSJeff LaBundy default:
1524e505edaeSJeff LaBundy return NULL;
1525e505edaeSJeff LaBundy }
1526e505edaeSJeff LaBundy }
1527e505edaeSJeff LaBundy
iqs7222_irq_poll(struct iqs7222_private * iqs7222,u16 timeout_ms)1528e505edaeSJeff LaBundy static int iqs7222_irq_poll(struct iqs7222_private *iqs7222, u16 timeout_ms)
1529e505edaeSJeff LaBundy {
1530e505edaeSJeff LaBundy ktime_t irq_timeout = ktime_add_ms(ktime_get(), timeout_ms);
1531e505edaeSJeff LaBundy int ret;
1532e505edaeSJeff LaBundy
1533e505edaeSJeff LaBundy do {
1534e505edaeSJeff LaBundy usleep_range(1000, 1100);
1535e505edaeSJeff LaBundy
1536e505edaeSJeff LaBundy ret = gpiod_get_value_cansleep(iqs7222->irq_gpio);
1537e505edaeSJeff LaBundy if (ret < 0)
1538e505edaeSJeff LaBundy return ret;
1539e505edaeSJeff LaBundy else if (ret > 0)
1540e505edaeSJeff LaBundy return 0;
1541e505edaeSJeff LaBundy } while (ktime_compare(ktime_get(), irq_timeout) < 0);
1542e505edaeSJeff LaBundy
1543e505edaeSJeff LaBundy return -EBUSY;
1544e505edaeSJeff LaBundy }
1545e505edaeSJeff LaBundy
iqs7222_hard_reset(struct iqs7222_private * iqs7222)1546e505edaeSJeff LaBundy static int iqs7222_hard_reset(struct iqs7222_private *iqs7222)
1547e505edaeSJeff LaBundy {
1548e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client;
1549e505edaeSJeff LaBundy int error;
1550e505edaeSJeff LaBundy
1551e505edaeSJeff LaBundy if (!iqs7222->reset_gpio)
1552e505edaeSJeff LaBundy return 0;
1553e505edaeSJeff LaBundy
1554e505edaeSJeff LaBundy gpiod_set_value_cansleep(iqs7222->reset_gpio, 1);
1555e505edaeSJeff LaBundy usleep_range(1000, 1100);
1556e505edaeSJeff LaBundy
1557e505edaeSJeff LaBundy gpiod_set_value_cansleep(iqs7222->reset_gpio, 0);
1558e505edaeSJeff LaBundy
1559e505edaeSJeff LaBundy error = iqs7222_irq_poll(iqs7222, IQS7222_RESET_TIMEOUT_MS);
1560e505edaeSJeff LaBundy if (error)
1561e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to reset device: %d\n", error);
1562e505edaeSJeff LaBundy
1563e505edaeSJeff LaBundy return error;
1564e505edaeSJeff LaBundy }
1565e505edaeSJeff LaBundy
iqs7222_force_comms(struct iqs7222_private * iqs7222)1566e505edaeSJeff LaBundy static int iqs7222_force_comms(struct iqs7222_private *iqs7222)
1567e505edaeSJeff LaBundy {
156810e629d3SJeff LaBundy u8 msg_buf[] = { 0xFF, };
1569e505edaeSJeff LaBundy int ret;
1570e505edaeSJeff LaBundy
1571e505edaeSJeff LaBundy /*
1572e505edaeSJeff LaBundy * The device cannot communicate until it asserts its interrupt (RDY)
1573e505edaeSJeff LaBundy * pin. Attempts to do so while RDY is deasserted return an ACK; how-
1574e505edaeSJeff LaBundy * ever all write data is ignored, and all read data returns 0xEE.
1575e505edaeSJeff LaBundy *
1576e505edaeSJeff LaBundy * Unsolicited communication must be preceded by a special force com-
1577e505edaeSJeff LaBundy * munication command, after which the device eventually asserts its
1578e505edaeSJeff LaBundy * RDY pin and agrees to communicate.
1579e505edaeSJeff LaBundy *
1580e505edaeSJeff LaBundy * Regardless of whether communication is forced or the result of an
1581e505edaeSJeff LaBundy * interrupt, the device automatically deasserts its RDY pin once it
1582e505edaeSJeff LaBundy * detects an I2C stop condition, or a timeout expires.
1583e505edaeSJeff LaBundy */
1584e505edaeSJeff LaBundy ret = gpiod_get_value_cansleep(iqs7222->irq_gpio);
1585e505edaeSJeff LaBundy if (ret < 0)
1586e505edaeSJeff LaBundy return ret;
1587e505edaeSJeff LaBundy else if (ret > 0)
1588e505edaeSJeff LaBundy return 0;
1589e505edaeSJeff LaBundy
1590e505edaeSJeff LaBundy ret = i2c_master_send(iqs7222->client, msg_buf, sizeof(msg_buf));
1591e505edaeSJeff LaBundy if (ret < (int)sizeof(msg_buf)) {
1592e505edaeSJeff LaBundy if (ret >= 0)
1593e505edaeSJeff LaBundy ret = -EIO;
1594e505edaeSJeff LaBundy
1595e505edaeSJeff LaBundy /*
1596e505edaeSJeff LaBundy * The datasheet states that the host must wait to retry any
1597e505edaeSJeff LaBundy * failed attempt to communicate over I2C.
1598e505edaeSJeff LaBundy */
1599e505edaeSJeff LaBundy msleep(IQS7222_COMMS_RETRY_MS);
1600e505edaeSJeff LaBundy return ret;
1601e505edaeSJeff LaBundy }
1602e505edaeSJeff LaBundy
1603e505edaeSJeff LaBundy return iqs7222_irq_poll(iqs7222, IQS7222_COMMS_TIMEOUT_MS);
1604e505edaeSJeff LaBundy }
1605e505edaeSJeff LaBundy
iqs7222_read_burst(struct iqs7222_private * iqs7222,u16 reg,void * val,u16 num_val)1606e505edaeSJeff LaBundy static int iqs7222_read_burst(struct iqs7222_private *iqs7222,
1607e505edaeSJeff LaBundy u16 reg, void *val, u16 num_val)
1608e505edaeSJeff LaBundy {
1609e505edaeSJeff LaBundy u8 reg_buf[sizeof(__be16)];
1610e505edaeSJeff LaBundy int ret, i;
1611e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client;
1612e505edaeSJeff LaBundy struct i2c_msg msg[] = {
1613e505edaeSJeff LaBundy {
1614e505edaeSJeff LaBundy .addr = client->addr,
1615e505edaeSJeff LaBundy .flags = 0,
1616e505edaeSJeff LaBundy .len = reg > U8_MAX ? sizeof(reg) : sizeof(u8),
1617e505edaeSJeff LaBundy .buf = reg_buf,
1618e505edaeSJeff LaBundy },
1619e505edaeSJeff LaBundy {
1620e505edaeSJeff LaBundy .addr = client->addr,
1621e505edaeSJeff LaBundy .flags = I2C_M_RD,
1622e505edaeSJeff LaBundy .len = num_val * sizeof(__le16),
1623e505edaeSJeff LaBundy .buf = (u8 *)val,
1624e505edaeSJeff LaBundy },
1625e505edaeSJeff LaBundy };
1626e505edaeSJeff LaBundy
1627e505edaeSJeff LaBundy if (reg > U8_MAX)
1628e505edaeSJeff LaBundy put_unaligned_be16(reg, reg_buf);
1629e505edaeSJeff LaBundy else
1630e505edaeSJeff LaBundy *reg_buf = (u8)reg;
1631e505edaeSJeff LaBundy
1632e505edaeSJeff LaBundy /*
1633e505edaeSJeff LaBundy * The following loop protects against an edge case in which the RDY
1634e505edaeSJeff LaBundy * pin is automatically deasserted just as the read is initiated. In
1635e505edaeSJeff LaBundy * that case, the read must be retried using forced communication.
1636e505edaeSJeff LaBundy */
1637e505edaeSJeff LaBundy for (i = 0; i < IQS7222_NUM_RETRIES; i++) {
1638e505edaeSJeff LaBundy ret = iqs7222_force_comms(iqs7222);
1639e505edaeSJeff LaBundy if (ret < 0)
1640e505edaeSJeff LaBundy continue;
1641e505edaeSJeff LaBundy
1642e505edaeSJeff LaBundy ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
1643e505edaeSJeff LaBundy if (ret < (int)ARRAY_SIZE(msg)) {
1644e505edaeSJeff LaBundy if (ret >= 0)
1645e505edaeSJeff LaBundy ret = -EIO;
1646e505edaeSJeff LaBundy
1647e505edaeSJeff LaBundy msleep(IQS7222_COMMS_RETRY_MS);
1648e505edaeSJeff LaBundy continue;
1649e505edaeSJeff LaBundy }
1650e505edaeSJeff LaBundy
1651e505edaeSJeff LaBundy if (get_unaligned_le16(msg[1].buf) == IQS7222_COMMS_ERROR) {
1652e505edaeSJeff LaBundy ret = -ENODATA;
1653e505edaeSJeff LaBundy continue;
1654e505edaeSJeff LaBundy }
1655e505edaeSJeff LaBundy
1656e505edaeSJeff LaBundy ret = 0;
1657e505edaeSJeff LaBundy break;
1658e505edaeSJeff LaBundy }
1659e505edaeSJeff LaBundy
1660e505edaeSJeff LaBundy /*
1661e505edaeSJeff LaBundy * The following delay ensures the device has deasserted the RDY pin
1662e505edaeSJeff LaBundy * following the I2C stop condition.
1663e505edaeSJeff LaBundy */
1664e505edaeSJeff LaBundy usleep_range(50, 100);
1665e505edaeSJeff LaBundy
1666e505edaeSJeff LaBundy if (ret < 0)
1667e505edaeSJeff LaBundy dev_err(&client->dev,
1668e505edaeSJeff LaBundy "Failed to read from address 0x%04X: %d\n", reg, ret);
1669e505edaeSJeff LaBundy
1670e505edaeSJeff LaBundy return ret;
1671e505edaeSJeff LaBundy }
1672e505edaeSJeff LaBundy
iqs7222_read_word(struct iqs7222_private * iqs7222,u16 reg,u16 * val)1673e505edaeSJeff LaBundy static int iqs7222_read_word(struct iqs7222_private *iqs7222, u16 reg, u16 *val)
1674e505edaeSJeff LaBundy {
1675e505edaeSJeff LaBundy __le16 val_buf;
1676e505edaeSJeff LaBundy int error;
1677e505edaeSJeff LaBundy
1678e505edaeSJeff LaBundy error = iqs7222_read_burst(iqs7222, reg, &val_buf, 1);
1679e505edaeSJeff LaBundy if (error)
1680e505edaeSJeff LaBundy return error;
1681e505edaeSJeff LaBundy
1682e505edaeSJeff LaBundy *val = le16_to_cpu(val_buf);
1683e505edaeSJeff LaBundy
1684e505edaeSJeff LaBundy return 0;
1685e505edaeSJeff LaBundy }
1686e505edaeSJeff LaBundy
iqs7222_write_burst(struct iqs7222_private * iqs7222,u16 reg,const void * val,u16 num_val)1687e505edaeSJeff LaBundy static int iqs7222_write_burst(struct iqs7222_private *iqs7222,
1688e505edaeSJeff LaBundy u16 reg, const void *val, u16 num_val)
1689e505edaeSJeff LaBundy {
1690e505edaeSJeff LaBundy int reg_len = reg > U8_MAX ? sizeof(reg) : sizeof(u8);
1691e505edaeSJeff LaBundy int val_len = num_val * sizeof(__le16);
1692e505edaeSJeff LaBundy int msg_len = reg_len + val_len;
1693e505edaeSJeff LaBundy int ret, i;
1694e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client;
1695e505edaeSJeff LaBundy u8 *msg_buf;
1696e505edaeSJeff LaBundy
1697e505edaeSJeff LaBundy msg_buf = kzalloc(msg_len, GFP_KERNEL);
1698e505edaeSJeff LaBundy if (!msg_buf)
1699e505edaeSJeff LaBundy return -ENOMEM;
1700e505edaeSJeff LaBundy
1701e505edaeSJeff LaBundy if (reg > U8_MAX)
1702e505edaeSJeff LaBundy put_unaligned_be16(reg, msg_buf);
1703e505edaeSJeff LaBundy else
1704e505edaeSJeff LaBundy *msg_buf = (u8)reg;
1705e505edaeSJeff LaBundy
1706e505edaeSJeff LaBundy memcpy(msg_buf + reg_len, val, val_len);
1707e505edaeSJeff LaBundy
1708e505edaeSJeff LaBundy /*
1709e505edaeSJeff LaBundy * The following loop protects against an edge case in which the RDY
1710e505edaeSJeff LaBundy * pin is automatically asserted just before the force communication
1711e505edaeSJeff LaBundy * command is sent.
1712e505edaeSJeff LaBundy *
1713e505edaeSJeff LaBundy * In that case, the subsequent I2C stop condition tricks the device
1714e505edaeSJeff LaBundy * into preemptively deasserting the RDY pin and the command must be
1715e505edaeSJeff LaBundy * sent again.
1716e505edaeSJeff LaBundy */
1717e505edaeSJeff LaBundy for (i = 0; i < IQS7222_NUM_RETRIES; i++) {
1718e505edaeSJeff LaBundy ret = iqs7222_force_comms(iqs7222);
1719e505edaeSJeff LaBundy if (ret < 0)
1720e505edaeSJeff LaBundy continue;
1721e505edaeSJeff LaBundy
1722e505edaeSJeff LaBundy ret = i2c_master_send(client, msg_buf, msg_len);
1723e505edaeSJeff LaBundy if (ret < msg_len) {
1724e505edaeSJeff LaBundy if (ret >= 0)
1725e505edaeSJeff LaBundy ret = -EIO;
1726e505edaeSJeff LaBundy
1727e505edaeSJeff LaBundy msleep(IQS7222_COMMS_RETRY_MS);
1728e505edaeSJeff LaBundy continue;
1729e505edaeSJeff LaBundy }
1730e505edaeSJeff LaBundy
1731e505edaeSJeff LaBundy ret = 0;
1732e505edaeSJeff LaBundy break;
1733e505edaeSJeff LaBundy }
1734e505edaeSJeff LaBundy
1735e505edaeSJeff LaBundy kfree(msg_buf);
1736e505edaeSJeff LaBundy
1737e505edaeSJeff LaBundy usleep_range(50, 100);
1738e505edaeSJeff LaBundy
1739e505edaeSJeff LaBundy if (ret < 0)
1740e505edaeSJeff LaBundy dev_err(&client->dev,
1741e505edaeSJeff LaBundy "Failed to write to address 0x%04X: %d\n", reg, ret);
1742e505edaeSJeff LaBundy
1743e505edaeSJeff LaBundy return ret;
1744e505edaeSJeff LaBundy }
1745e505edaeSJeff LaBundy
iqs7222_write_word(struct iqs7222_private * iqs7222,u16 reg,u16 val)1746e505edaeSJeff LaBundy static int iqs7222_write_word(struct iqs7222_private *iqs7222, u16 reg, u16 val)
1747e505edaeSJeff LaBundy {
1748e505edaeSJeff LaBundy __le16 val_buf = cpu_to_le16(val);
1749e505edaeSJeff LaBundy
1750e505edaeSJeff LaBundy return iqs7222_write_burst(iqs7222, reg, &val_buf, 1);
1751e505edaeSJeff LaBundy }
1752e505edaeSJeff LaBundy
iqs7222_ati_trigger(struct iqs7222_private * iqs7222)1753e505edaeSJeff LaBundy static int iqs7222_ati_trigger(struct iqs7222_private *iqs7222)
1754e505edaeSJeff LaBundy {
1755e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client;
1756e505edaeSJeff LaBundy ktime_t ati_timeout;
1757e505edaeSJeff LaBundy u16 sys_status = 0;
17581e4189d8SJeff LaBundy u16 sys_setup;
1759e505edaeSJeff LaBundy int error, i;
1760e505edaeSJeff LaBundy
17611e4189d8SJeff LaBundy /*
17621e4189d8SJeff LaBundy * The reserved fields of the system setup register may have changed
17631e4189d8SJeff LaBundy * as a result of other registers having been written. As such, read
17641e4189d8SJeff LaBundy * the register's latest value to avoid unexpected behavior when the
17651e4189d8SJeff LaBundy * register is written in the loop that follows.
17661e4189d8SJeff LaBundy */
17671e4189d8SJeff LaBundy error = iqs7222_read_word(iqs7222, IQS7222_SYS_SETUP, &sys_setup);
17681e4189d8SJeff LaBundy if (error)
17691e4189d8SJeff LaBundy return error;
17701e4189d8SJeff LaBundy
1771e505edaeSJeff LaBundy for (i = 0; i < IQS7222_NUM_RETRIES; i++) {
1772e505edaeSJeff LaBundy /*
1773e505edaeSJeff LaBundy * Trigger ATI from streaming and normal-power modes so that
1774e505edaeSJeff LaBundy * the RDY pin continues to be asserted during ATI.
1775e505edaeSJeff LaBundy */
1776e505edaeSJeff LaBundy error = iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP,
1777e505edaeSJeff LaBundy sys_setup |
1778e505edaeSJeff LaBundy IQS7222_SYS_SETUP_REDO_ATI);
1779e505edaeSJeff LaBundy if (error)
1780e505edaeSJeff LaBundy return error;
1781e505edaeSJeff LaBundy
1782e505edaeSJeff LaBundy ati_timeout = ktime_add_ms(ktime_get(), IQS7222_ATI_TIMEOUT_MS);
1783e505edaeSJeff LaBundy
1784e505edaeSJeff LaBundy do {
1785e505edaeSJeff LaBundy error = iqs7222_irq_poll(iqs7222,
1786e505edaeSJeff LaBundy IQS7222_COMMS_TIMEOUT_MS);
1787e505edaeSJeff LaBundy if (error)
1788e505edaeSJeff LaBundy continue;
1789e505edaeSJeff LaBundy
1790e505edaeSJeff LaBundy error = iqs7222_read_word(iqs7222, IQS7222_SYS_STATUS,
1791e505edaeSJeff LaBundy &sys_status);
1792e505edaeSJeff LaBundy if (error)
1793e505edaeSJeff LaBundy return error;
1794e505edaeSJeff LaBundy
17958635c688SJeff LaBundy if (sys_status & IQS7222_SYS_STATUS_RESET)
17968635c688SJeff LaBundy return 0;
1797e505edaeSJeff LaBundy
1798e505edaeSJeff LaBundy if (sys_status & IQS7222_SYS_STATUS_ATI_ERROR)
1799e505edaeSJeff LaBundy break;
1800e505edaeSJeff LaBundy
18018635c688SJeff LaBundy if (sys_status & IQS7222_SYS_STATUS_ATI_ACTIVE)
18028635c688SJeff LaBundy continue;
18038635c688SJeff LaBundy
1804e505edaeSJeff LaBundy /*
1805e505edaeSJeff LaBundy * Use stream-in-touch mode if either slider reports
1806e505edaeSJeff LaBundy * absolute position.
1807e505edaeSJeff LaBundy */
1808e505edaeSJeff LaBundy sys_setup |= test_bit(EV_ABS, iqs7222->keypad->evbit)
1809e505edaeSJeff LaBundy ? IQS7222_SYS_SETUP_INTF_MODE_TOUCH
1810e505edaeSJeff LaBundy : IQS7222_SYS_SETUP_INTF_MODE_EVENT;
1811e505edaeSJeff LaBundy sys_setup |= IQS7222_SYS_SETUP_PWR_MODE_AUTO;
1812e505edaeSJeff LaBundy
1813e505edaeSJeff LaBundy return iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP,
1814e505edaeSJeff LaBundy sys_setup);
1815e505edaeSJeff LaBundy } while (ktime_compare(ktime_get(), ati_timeout) < 0);
1816e505edaeSJeff LaBundy
1817e505edaeSJeff LaBundy dev_err(&client->dev,
1818e505edaeSJeff LaBundy "ATI attempt %d of %d failed with status 0x%02X, %s\n",
1819e505edaeSJeff LaBundy i + 1, IQS7222_NUM_RETRIES, (u8)sys_status,
18208635c688SJeff LaBundy i + 1 < IQS7222_NUM_RETRIES ? "retrying" : "stopping");
1821e505edaeSJeff LaBundy }
1822e505edaeSJeff LaBundy
1823e505edaeSJeff LaBundy return -ETIMEDOUT;
1824e505edaeSJeff LaBundy }
1825e505edaeSJeff LaBundy
iqs7222_dev_init(struct iqs7222_private * iqs7222,int dir)1826e505edaeSJeff LaBundy static int iqs7222_dev_init(struct iqs7222_private *iqs7222, int dir)
1827e505edaeSJeff LaBundy {
1828e505edaeSJeff LaBundy const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
1829e505edaeSJeff LaBundy int comms_offset = dev_desc->comms_offset;
1830e505edaeSJeff LaBundy int error, i, j, k;
1831e505edaeSJeff LaBundy
1832e505edaeSJeff LaBundy /*
18332e70ef52SJeff LaBundy * Acknowledge reset before writing any registers in case the device
18342e70ef52SJeff LaBundy * suffers a spurious reset during initialization. Because this step
18352e70ef52SJeff LaBundy * may change the reserved fields of the second filter beta register,
18362e70ef52SJeff LaBundy * its cache must be updated.
18372e70ef52SJeff LaBundy *
18382e70ef52SJeff LaBundy * Writing the second filter beta register, in turn, may clobber the
18392e70ef52SJeff LaBundy * system status register. As such, the filter beta register pair is
18402e70ef52SJeff LaBundy * written first to protect against this hazard.
18412e70ef52SJeff LaBundy */
18422e70ef52SJeff LaBundy if (dir == WRITE) {
18432e70ef52SJeff LaBundy u16 reg = dev_desc->reg_grps[IQS7222_REG_GRP_FILT].base + 1;
18442e70ef52SJeff LaBundy u16 filt_setup;
18452e70ef52SJeff LaBundy
18462e70ef52SJeff LaBundy error = iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP,
18472e70ef52SJeff LaBundy iqs7222->sys_setup[0] |
18482e70ef52SJeff LaBundy IQS7222_SYS_SETUP_ACK_RESET);
18492e70ef52SJeff LaBundy if (error)
18502e70ef52SJeff LaBundy return error;
18512e70ef52SJeff LaBundy
18522e70ef52SJeff LaBundy error = iqs7222_read_word(iqs7222, reg, &filt_setup);
18532e70ef52SJeff LaBundy if (error)
18542e70ef52SJeff LaBundy return error;
18552e70ef52SJeff LaBundy
18562e70ef52SJeff LaBundy iqs7222->filt_setup[1] &= GENMASK(7, 0);
18572e70ef52SJeff LaBundy iqs7222->filt_setup[1] |= (filt_setup & ~GENMASK(7, 0));
18582e70ef52SJeff LaBundy }
18592e70ef52SJeff LaBundy
18602e70ef52SJeff LaBundy /*
1861e505edaeSJeff LaBundy * Take advantage of the stop-bit disable function, if available, to
1862e505edaeSJeff LaBundy * save the trouble of having to reopen a communication window after
1863e505edaeSJeff LaBundy * each burst read or write.
1864e505edaeSJeff LaBundy */
1865e505edaeSJeff LaBundy if (comms_offset) {
1866e505edaeSJeff LaBundy u16 comms_setup;
1867e505edaeSJeff LaBundy
1868e505edaeSJeff LaBundy error = iqs7222_read_word(iqs7222,
1869e505edaeSJeff LaBundy IQS7222_SYS_SETUP + comms_offset,
1870e505edaeSJeff LaBundy &comms_setup);
1871e505edaeSJeff LaBundy if (error)
1872e505edaeSJeff LaBundy return error;
1873e505edaeSJeff LaBundy
1874e505edaeSJeff LaBundy error = iqs7222_write_word(iqs7222,
1875e505edaeSJeff LaBundy IQS7222_SYS_SETUP + comms_offset,
1876e505edaeSJeff LaBundy comms_setup | IQS7222_COMMS_HOLD);
1877e505edaeSJeff LaBundy if (error)
1878e505edaeSJeff LaBundy return error;
1879e505edaeSJeff LaBundy }
1880e505edaeSJeff LaBundy
1881e505edaeSJeff LaBundy for (i = 0; i < IQS7222_NUM_REG_GRPS; i++) {
1882e505edaeSJeff LaBundy int num_row = dev_desc->reg_grps[i].num_row;
1883e505edaeSJeff LaBundy int num_col = dev_desc->reg_grps[i].num_col;
1884e505edaeSJeff LaBundy u16 reg = dev_desc->reg_grps[i].base;
1885e505edaeSJeff LaBundy __le16 *val_buf;
1886e505edaeSJeff LaBundy u16 *val;
1887e505edaeSJeff LaBundy
1888e505edaeSJeff LaBundy if (!num_col)
1889e505edaeSJeff LaBundy continue;
1890e505edaeSJeff LaBundy
1891e505edaeSJeff LaBundy val = iqs7222_setup(iqs7222, i, 0);
1892e505edaeSJeff LaBundy if (!val)
1893e505edaeSJeff LaBundy continue;
1894e505edaeSJeff LaBundy
1895e505edaeSJeff LaBundy val_buf = kcalloc(num_col, sizeof(__le16), GFP_KERNEL);
1896e505edaeSJeff LaBundy if (!val_buf)
1897e505edaeSJeff LaBundy return -ENOMEM;
1898e505edaeSJeff LaBundy
1899e505edaeSJeff LaBundy for (j = 0; j < num_row; j++) {
1900e505edaeSJeff LaBundy switch (dir) {
1901e505edaeSJeff LaBundy case READ:
1902e505edaeSJeff LaBundy error = iqs7222_read_burst(iqs7222, reg,
1903e505edaeSJeff LaBundy val_buf, num_col);
1904e505edaeSJeff LaBundy for (k = 0; k < num_col; k++)
1905e505edaeSJeff LaBundy val[k] = le16_to_cpu(val_buf[k]);
1906e505edaeSJeff LaBundy break;
1907e505edaeSJeff LaBundy
1908e505edaeSJeff LaBundy case WRITE:
1909e505edaeSJeff LaBundy for (k = 0; k < num_col; k++)
1910e505edaeSJeff LaBundy val_buf[k] = cpu_to_le16(val[k]);
1911e505edaeSJeff LaBundy error = iqs7222_write_burst(iqs7222, reg,
1912e505edaeSJeff LaBundy val_buf, num_col);
1913e505edaeSJeff LaBundy break;
1914e505edaeSJeff LaBundy
1915e505edaeSJeff LaBundy default:
1916e505edaeSJeff LaBundy error = -EINVAL;
1917e505edaeSJeff LaBundy }
1918e505edaeSJeff LaBundy
1919e505edaeSJeff LaBundy if (error)
1920e505edaeSJeff LaBundy break;
1921e505edaeSJeff LaBundy
1922e505edaeSJeff LaBundy reg += IQS7222_REG_OFFSET;
1923e505edaeSJeff LaBundy val += iqs7222_max_cols[i];
1924e505edaeSJeff LaBundy }
1925e505edaeSJeff LaBundy
1926e505edaeSJeff LaBundy kfree(val_buf);
1927e505edaeSJeff LaBundy
1928e505edaeSJeff LaBundy if (error)
1929e505edaeSJeff LaBundy return error;
1930e505edaeSJeff LaBundy }
1931e505edaeSJeff LaBundy
1932e505edaeSJeff LaBundy if (comms_offset) {
1933e505edaeSJeff LaBundy u16 comms_setup;
1934e505edaeSJeff LaBundy
1935e505edaeSJeff LaBundy error = iqs7222_read_word(iqs7222,
1936e505edaeSJeff LaBundy IQS7222_SYS_SETUP + comms_offset,
1937e505edaeSJeff LaBundy &comms_setup);
1938e505edaeSJeff LaBundy if (error)
1939e505edaeSJeff LaBundy return error;
1940e505edaeSJeff LaBundy
1941e505edaeSJeff LaBundy error = iqs7222_write_word(iqs7222,
1942e505edaeSJeff LaBundy IQS7222_SYS_SETUP + comms_offset,
1943e505edaeSJeff LaBundy comms_setup & ~IQS7222_COMMS_HOLD);
1944e505edaeSJeff LaBundy if (error)
1945e505edaeSJeff LaBundy return error;
1946e505edaeSJeff LaBundy }
1947e505edaeSJeff LaBundy
19482e00b8bfSJeff LaBundy if (dir == READ) {
19492e00b8bfSJeff LaBundy iqs7222->sys_setup[0] &= ~IQS7222_SYS_SETUP_INTF_MODE_MASK;
19502e00b8bfSJeff LaBundy iqs7222->sys_setup[0] &= ~IQS7222_SYS_SETUP_PWR_MODE_MASK;
1951e505edaeSJeff LaBundy return 0;
19522e00b8bfSJeff LaBundy }
1953e505edaeSJeff LaBundy
1954e505edaeSJeff LaBundy return iqs7222_ati_trigger(iqs7222);
1955e505edaeSJeff LaBundy }
1956e505edaeSJeff LaBundy
iqs7222_dev_info(struct iqs7222_private * iqs7222)1957e505edaeSJeff LaBundy static int iqs7222_dev_info(struct iqs7222_private *iqs7222)
1958e505edaeSJeff LaBundy {
1959e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client;
1960e505edaeSJeff LaBundy bool prod_num_valid = false;
1961e505edaeSJeff LaBundy __le16 dev_id[3];
1962e505edaeSJeff LaBundy int error, i;
1963e505edaeSJeff LaBundy
1964e505edaeSJeff LaBundy error = iqs7222_read_burst(iqs7222, IQS7222_PROD_NUM, dev_id,
1965e505edaeSJeff LaBundy ARRAY_SIZE(dev_id));
1966e505edaeSJeff LaBundy if (error)
1967e505edaeSJeff LaBundy return error;
1968e505edaeSJeff LaBundy
1969e505edaeSJeff LaBundy for (i = 0; i < ARRAY_SIZE(iqs7222_devs); i++) {
1970e505edaeSJeff LaBundy if (le16_to_cpu(dev_id[0]) != iqs7222_devs[i].prod_num)
1971e505edaeSJeff LaBundy continue;
1972e505edaeSJeff LaBundy
1973e505edaeSJeff LaBundy prod_num_valid = true;
1974e505edaeSJeff LaBundy
1975e505edaeSJeff LaBundy if (le16_to_cpu(dev_id[1]) < iqs7222_devs[i].fw_major)
1976e505edaeSJeff LaBundy continue;
1977e505edaeSJeff LaBundy
1978e505edaeSJeff LaBundy if (le16_to_cpu(dev_id[2]) < iqs7222_devs[i].fw_minor)
1979e505edaeSJeff LaBundy continue;
1980e505edaeSJeff LaBundy
1981e505edaeSJeff LaBundy iqs7222->dev_desc = &iqs7222_devs[i];
1982e505edaeSJeff LaBundy return 0;
1983e505edaeSJeff LaBundy }
1984e505edaeSJeff LaBundy
1985e505edaeSJeff LaBundy if (prod_num_valid)
1986e505edaeSJeff LaBundy dev_err(&client->dev, "Unsupported firmware revision: %u.%u\n",
1987e505edaeSJeff LaBundy le16_to_cpu(dev_id[1]), le16_to_cpu(dev_id[2]));
1988e505edaeSJeff LaBundy else
1989e505edaeSJeff LaBundy dev_err(&client->dev, "Unrecognized product number: %u\n",
1990e505edaeSJeff LaBundy le16_to_cpu(dev_id[0]));
1991e505edaeSJeff LaBundy
1992e505edaeSJeff LaBundy return -EINVAL;
1993e505edaeSJeff LaBundy }
1994e505edaeSJeff LaBundy
iqs7222_gpio_select(struct iqs7222_private * iqs7222,struct fwnode_handle * child_node,int child_enable,u16 child_link)1995e505edaeSJeff LaBundy static int iqs7222_gpio_select(struct iqs7222_private *iqs7222,
1996e505edaeSJeff LaBundy struct fwnode_handle *child_node,
1997e505edaeSJeff LaBundy int child_enable, u16 child_link)
1998e505edaeSJeff LaBundy {
1999e505edaeSJeff LaBundy const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
2000e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client;
2001e505edaeSJeff LaBundy int num_gpio = dev_desc->reg_grps[IQS7222_REG_GRP_GPIO].num_row;
2002e505edaeSJeff LaBundy int error, count, i;
2003e505edaeSJeff LaBundy unsigned int gpio_sel[ARRAY_SIZE(iqs7222_gpio_links)];
2004e505edaeSJeff LaBundy
2005e505edaeSJeff LaBundy if (!num_gpio)
2006e505edaeSJeff LaBundy return 0;
2007e505edaeSJeff LaBundy
2008e505edaeSJeff LaBundy if (!fwnode_property_present(child_node, "azoteq,gpio-select"))
2009e505edaeSJeff LaBundy return 0;
2010e505edaeSJeff LaBundy
2011e505edaeSJeff LaBundy count = fwnode_property_count_u32(child_node, "azoteq,gpio-select");
2012e505edaeSJeff LaBundy if (count > num_gpio) {
2013e505edaeSJeff LaBundy dev_err(&client->dev, "Invalid number of %s GPIOs\n",
2014e505edaeSJeff LaBundy fwnode_get_name(child_node));
2015e505edaeSJeff LaBundy return -EINVAL;
2016e505edaeSJeff LaBundy } else if (count < 0) {
2017e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to count %s GPIOs: %d\n",
2018e505edaeSJeff LaBundy fwnode_get_name(child_node), count);
2019e505edaeSJeff LaBundy return count;
2020e505edaeSJeff LaBundy }
2021e505edaeSJeff LaBundy
2022e505edaeSJeff LaBundy error = fwnode_property_read_u32_array(child_node,
2023e505edaeSJeff LaBundy "azoteq,gpio-select",
2024e505edaeSJeff LaBundy gpio_sel, count);
2025e505edaeSJeff LaBundy if (error) {
2026e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to read %s GPIOs: %d\n",
2027e505edaeSJeff LaBundy fwnode_get_name(child_node), error);
2028e505edaeSJeff LaBundy return error;
2029e505edaeSJeff LaBundy }
2030e505edaeSJeff LaBundy
2031e505edaeSJeff LaBundy for (i = 0; i < count; i++) {
2032e505edaeSJeff LaBundy u16 *gpio_setup;
2033e505edaeSJeff LaBundy
2034e505edaeSJeff LaBundy if (gpio_sel[i] >= num_gpio) {
2035e505edaeSJeff LaBundy dev_err(&client->dev, "Invalid %s GPIO: %u\n",
2036e505edaeSJeff LaBundy fwnode_get_name(child_node), gpio_sel[i]);
2037e505edaeSJeff LaBundy return -EINVAL;
2038e505edaeSJeff LaBundy }
2039e505edaeSJeff LaBundy
2040e505edaeSJeff LaBundy gpio_setup = iqs7222->gpio_setup[gpio_sel[i]];
2041e505edaeSJeff LaBundy
2042e505edaeSJeff LaBundy if (gpio_setup[2] && child_link != gpio_setup[2]) {
2043e505edaeSJeff LaBundy dev_err(&client->dev,
2044e505edaeSJeff LaBundy "Conflicting GPIO %u event types\n",
2045e505edaeSJeff LaBundy gpio_sel[i]);
2046e505edaeSJeff LaBundy return -EINVAL;
2047e505edaeSJeff LaBundy }
2048e505edaeSJeff LaBundy
2049e505edaeSJeff LaBundy gpio_setup[0] |= IQS7222_GPIO_SETUP_0_GPIO_EN;
2050e505edaeSJeff LaBundy gpio_setup[1] |= child_enable;
2051e505edaeSJeff LaBundy gpio_setup[2] = child_link;
2052e505edaeSJeff LaBundy }
2053e505edaeSJeff LaBundy
2054e505edaeSJeff LaBundy return 0;
2055e505edaeSJeff LaBundy }
2056e505edaeSJeff LaBundy
iqs7222_parse_props(struct iqs7222_private * iqs7222,struct fwnode_handle * reg_grp_node,int reg_grp_index,enum iqs7222_reg_grp_id reg_grp,enum iqs7222_reg_key_id reg_key)2057e505edaeSJeff LaBundy static int iqs7222_parse_props(struct iqs7222_private *iqs7222,
2058bbd16b0dSJeff LaBundy struct fwnode_handle *reg_grp_node,
2059bbd16b0dSJeff LaBundy int reg_grp_index,
2060e505edaeSJeff LaBundy enum iqs7222_reg_grp_id reg_grp,
2061e505edaeSJeff LaBundy enum iqs7222_reg_key_id reg_key)
2062e505edaeSJeff LaBundy {
2063bbd16b0dSJeff LaBundy u16 *setup = iqs7222_setup(iqs7222, reg_grp, reg_grp_index);
2064e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client;
2065e505edaeSJeff LaBundy int i;
2066e505edaeSJeff LaBundy
2067bbd16b0dSJeff LaBundy if (!setup)
2068e505edaeSJeff LaBundy return 0;
2069e505edaeSJeff LaBundy
2070e505edaeSJeff LaBundy for (i = 0; i < ARRAY_SIZE(iqs7222_props); i++) {
2071e505edaeSJeff LaBundy const char *name = iqs7222_props[i].name;
2072e505edaeSJeff LaBundy int reg_offset = iqs7222_props[i].reg_offset;
2073e505edaeSJeff LaBundy int reg_shift = iqs7222_props[i].reg_shift;
2074e505edaeSJeff LaBundy int reg_width = iqs7222_props[i].reg_width;
2075e505edaeSJeff LaBundy int val_pitch = iqs7222_props[i].val_pitch ? : 1;
2076e505edaeSJeff LaBundy int val_min = iqs7222_props[i].val_min;
2077e505edaeSJeff LaBundy int val_max = iqs7222_props[i].val_max;
2078e505edaeSJeff LaBundy bool invert = iqs7222_props[i].invert;
2079e505edaeSJeff LaBundy const char *label = iqs7222_props[i].label ? : name;
2080e505edaeSJeff LaBundy unsigned int val;
2081e505edaeSJeff LaBundy int error;
2082e505edaeSJeff LaBundy
2083e505edaeSJeff LaBundy if (iqs7222_props[i].reg_grp != reg_grp ||
2084e505edaeSJeff LaBundy iqs7222_props[i].reg_key != reg_key)
2085e505edaeSJeff LaBundy continue;
2086e505edaeSJeff LaBundy
2087e505edaeSJeff LaBundy /*
2088e505edaeSJeff LaBundy * Boolean register fields are one bit wide; they are forcibly
2089e505edaeSJeff LaBundy * reset to provide a means to undo changes by a bootloader if
2090e505edaeSJeff LaBundy * necessary.
2091e505edaeSJeff LaBundy *
2092e505edaeSJeff LaBundy * Scalar fields, on the other hand, are left untouched unless
2093e505edaeSJeff LaBundy * their corresponding properties are present.
2094e505edaeSJeff LaBundy */
2095e505edaeSJeff LaBundy if (reg_width == 1) {
2096e505edaeSJeff LaBundy if (invert)
2097e505edaeSJeff LaBundy setup[reg_offset] |= BIT(reg_shift);
2098e505edaeSJeff LaBundy else
2099e505edaeSJeff LaBundy setup[reg_offset] &= ~BIT(reg_shift);
2100e505edaeSJeff LaBundy }
2101e505edaeSJeff LaBundy
2102e505edaeSJeff LaBundy if (!fwnode_property_present(reg_grp_node, name))
2103e505edaeSJeff LaBundy continue;
2104e505edaeSJeff LaBundy
2105e505edaeSJeff LaBundy if (reg_width == 1) {
2106e505edaeSJeff LaBundy if (invert)
2107e505edaeSJeff LaBundy setup[reg_offset] &= ~BIT(reg_shift);
2108e505edaeSJeff LaBundy else
2109e505edaeSJeff LaBundy setup[reg_offset] |= BIT(reg_shift);
2110e505edaeSJeff LaBundy
2111e505edaeSJeff LaBundy continue;
2112e505edaeSJeff LaBundy }
2113e505edaeSJeff LaBundy
2114e505edaeSJeff LaBundy error = fwnode_property_read_u32(reg_grp_node, name, &val);
2115e505edaeSJeff LaBundy if (error) {
2116e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to read %s %s: %d\n",
2117e505edaeSJeff LaBundy fwnode_get_name(reg_grp_node), label, error);
2118e505edaeSJeff LaBundy return error;
2119e505edaeSJeff LaBundy }
2120e505edaeSJeff LaBundy
2121e505edaeSJeff LaBundy if (!val_max)
2122e505edaeSJeff LaBundy val_max = GENMASK(reg_width - 1, 0) * val_pitch;
2123e505edaeSJeff LaBundy
2124e505edaeSJeff LaBundy if (val < val_min || val > val_max) {
2125e505edaeSJeff LaBundy dev_err(&client->dev, "Invalid %s %s: %u\n",
2126e505edaeSJeff LaBundy fwnode_get_name(reg_grp_node), label, val);
2127e505edaeSJeff LaBundy return -EINVAL;
2128e505edaeSJeff LaBundy }
2129e505edaeSJeff LaBundy
2130e505edaeSJeff LaBundy setup[reg_offset] &= ~GENMASK(reg_shift + reg_width - 1,
2131e505edaeSJeff LaBundy reg_shift);
2132e505edaeSJeff LaBundy setup[reg_offset] |= (val / val_pitch << reg_shift);
2133e505edaeSJeff LaBundy }
2134e505edaeSJeff LaBundy
2135e505edaeSJeff LaBundy return 0;
2136e505edaeSJeff LaBundy }
2137e505edaeSJeff LaBundy
iqs7222_parse_event(struct iqs7222_private * iqs7222,struct fwnode_handle * event_node,int reg_grp_index,enum iqs7222_reg_grp_id reg_grp,enum iqs7222_reg_key_id reg_key,u16 event_enable,u16 event_link,unsigned int * event_type,unsigned int * event_code)2138bbd16b0dSJeff LaBundy static int iqs7222_parse_event(struct iqs7222_private *iqs7222,
2139bbd16b0dSJeff LaBundy struct fwnode_handle *event_node,
2140bbd16b0dSJeff LaBundy int reg_grp_index,
2141bbd16b0dSJeff LaBundy enum iqs7222_reg_grp_id reg_grp,
2142bbd16b0dSJeff LaBundy enum iqs7222_reg_key_id reg_key,
2143bbd16b0dSJeff LaBundy u16 event_enable, u16 event_link,
2144bbd16b0dSJeff LaBundy unsigned int *event_type,
2145bbd16b0dSJeff LaBundy unsigned int *event_code)
2146bbd16b0dSJeff LaBundy {
2147bbd16b0dSJeff LaBundy struct i2c_client *client = iqs7222->client;
2148bbd16b0dSJeff LaBundy int error;
2149bbd16b0dSJeff LaBundy
2150bbd16b0dSJeff LaBundy error = iqs7222_parse_props(iqs7222, event_node, reg_grp_index,
2151bbd16b0dSJeff LaBundy reg_grp, reg_key);
2152bbd16b0dSJeff LaBundy if (error)
2153bbd16b0dSJeff LaBundy return error;
2154bbd16b0dSJeff LaBundy
2155bbd16b0dSJeff LaBundy error = iqs7222_gpio_select(iqs7222, event_node, event_enable,
2156bbd16b0dSJeff LaBundy event_link);
2157bbd16b0dSJeff LaBundy if (error)
2158bbd16b0dSJeff LaBundy return error;
2159bbd16b0dSJeff LaBundy
2160bbd16b0dSJeff LaBundy error = fwnode_property_read_u32(event_node, "linux,code", event_code);
2161bbd16b0dSJeff LaBundy if (error == -EINVAL) {
2162bbd16b0dSJeff LaBundy return 0;
2163bbd16b0dSJeff LaBundy } else if (error) {
2164bbd16b0dSJeff LaBundy dev_err(&client->dev, "Failed to read %s code: %d\n",
2165bbd16b0dSJeff LaBundy fwnode_get_name(event_node), error);
2166bbd16b0dSJeff LaBundy return error;
2167bbd16b0dSJeff LaBundy }
2168bbd16b0dSJeff LaBundy
2169bbd16b0dSJeff LaBundy if (!event_type) {
2170bbd16b0dSJeff LaBundy input_set_capability(iqs7222->keypad, EV_KEY, *event_code);
2171bbd16b0dSJeff LaBundy return 0;
2172bbd16b0dSJeff LaBundy }
2173bbd16b0dSJeff LaBundy
2174bbd16b0dSJeff LaBundy error = fwnode_property_read_u32(event_node, "linux,input-type",
2175bbd16b0dSJeff LaBundy event_type);
2176bbd16b0dSJeff LaBundy if (error == -EINVAL) {
2177bbd16b0dSJeff LaBundy *event_type = EV_KEY;
2178bbd16b0dSJeff LaBundy } else if (error) {
2179bbd16b0dSJeff LaBundy dev_err(&client->dev, "Failed to read %s input type: %d\n",
2180bbd16b0dSJeff LaBundy fwnode_get_name(event_node), error);
2181bbd16b0dSJeff LaBundy return error;
2182bbd16b0dSJeff LaBundy } else if (*event_type != EV_KEY && *event_type != EV_SW) {
2183bbd16b0dSJeff LaBundy dev_err(&client->dev, "Invalid %s input type: %d\n",
2184bbd16b0dSJeff LaBundy fwnode_get_name(event_node), *event_type);
2185bbd16b0dSJeff LaBundy return -EINVAL;
2186bbd16b0dSJeff LaBundy }
2187bbd16b0dSJeff LaBundy
2188bbd16b0dSJeff LaBundy input_set_capability(iqs7222->keypad, *event_type, *event_code);
2189bbd16b0dSJeff LaBundy
2190bbd16b0dSJeff LaBundy return 0;
2191bbd16b0dSJeff LaBundy }
2192bbd16b0dSJeff LaBundy
iqs7222_parse_cycle(struct iqs7222_private * iqs7222,struct fwnode_handle * cycle_node,int cycle_index)2193bbd16b0dSJeff LaBundy static int iqs7222_parse_cycle(struct iqs7222_private *iqs7222,
2194bbd16b0dSJeff LaBundy struct fwnode_handle *cycle_node, int cycle_index)
2195e505edaeSJeff LaBundy {
2196e505edaeSJeff LaBundy u16 *cycle_setup = iqs7222->cycle_setup[cycle_index];
2197e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client;
2198e505edaeSJeff LaBundy unsigned int pins[9];
2199e505edaeSJeff LaBundy int error, count, i;
2200e505edaeSJeff LaBundy
2201e505edaeSJeff LaBundy /*
2202e505edaeSJeff LaBundy * Each channel shares a cycle with one other channel; the mapping of
2203e505edaeSJeff LaBundy * channels to cycles is fixed. Properties defined for a cycle impact
2204e505edaeSJeff LaBundy * both channels tied to the cycle.
2205bbd16b0dSJeff LaBundy *
2206e505edaeSJeff LaBundy * Unlike channels which are restricted to a select range of CRx pins
2207e505edaeSJeff LaBundy * based on channel number, any cycle can claim any of the device's 9
2208e505edaeSJeff LaBundy * CTx pins (CTx0-8).
2209e505edaeSJeff LaBundy */
2210e505edaeSJeff LaBundy if (!fwnode_property_present(cycle_node, "azoteq,tx-enable"))
2211e505edaeSJeff LaBundy return 0;
2212e505edaeSJeff LaBundy
2213e505edaeSJeff LaBundy count = fwnode_property_count_u32(cycle_node, "azoteq,tx-enable");
2214eba697b3SDan Carpenter if (count < 0) {
2215e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to count %s CTx pins: %d\n",
2216e505edaeSJeff LaBundy fwnode_get_name(cycle_node), count);
2217e505edaeSJeff LaBundy return count;
2218eba697b3SDan Carpenter } else if (count > ARRAY_SIZE(pins)) {
2219eba697b3SDan Carpenter dev_err(&client->dev, "Invalid number of %s CTx pins\n",
2220eba697b3SDan Carpenter fwnode_get_name(cycle_node));
2221eba697b3SDan Carpenter return -EINVAL;
2222e505edaeSJeff LaBundy }
2223e505edaeSJeff LaBundy
2224e505edaeSJeff LaBundy error = fwnode_property_read_u32_array(cycle_node, "azoteq,tx-enable",
2225e505edaeSJeff LaBundy pins, count);
2226e505edaeSJeff LaBundy if (error) {
2227e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to read %s CTx pins: %d\n",
2228e505edaeSJeff LaBundy fwnode_get_name(cycle_node), error);
2229e505edaeSJeff LaBundy return error;
2230e505edaeSJeff LaBundy }
2231e505edaeSJeff LaBundy
2232e505edaeSJeff LaBundy cycle_setup[1] &= ~GENMASK(7 + ARRAY_SIZE(pins) - 1, 7);
2233e505edaeSJeff LaBundy
2234e505edaeSJeff LaBundy for (i = 0; i < count; i++) {
2235e505edaeSJeff LaBundy if (pins[i] > 8) {
2236e505edaeSJeff LaBundy dev_err(&client->dev, "Invalid %s CTx pin: %u\n",
2237e505edaeSJeff LaBundy fwnode_get_name(cycle_node), pins[i]);
2238e505edaeSJeff LaBundy return -EINVAL;
2239e505edaeSJeff LaBundy }
2240e505edaeSJeff LaBundy
2241e505edaeSJeff LaBundy cycle_setup[1] |= BIT(pins[i] + 7);
2242e505edaeSJeff LaBundy }
2243e505edaeSJeff LaBundy
2244e505edaeSJeff LaBundy return 0;
2245e505edaeSJeff LaBundy }
2246e505edaeSJeff LaBundy
iqs7222_parse_chan(struct iqs7222_private * iqs7222,struct fwnode_handle * chan_node,int chan_index)2247bbd16b0dSJeff LaBundy static int iqs7222_parse_chan(struct iqs7222_private *iqs7222,
2248bbd16b0dSJeff LaBundy struct fwnode_handle *chan_node, int chan_index)
2249e505edaeSJeff LaBundy {
2250e505edaeSJeff LaBundy const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
2251e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client;
2252e505edaeSJeff LaBundy int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
2253e505edaeSJeff LaBundy int ext_chan = rounddown(num_chan, 10);
2254e505edaeSJeff LaBundy int error, i;
2255e505edaeSJeff LaBundy u16 *chan_setup = iqs7222->chan_setup[chan_index];
2256e505edaeSJeff LaBundy u16 *sys_setup = iqs7222->sys_setup;
2257e505edaeSJeff LaBundy unsigned int val;
2258e505edaeSJeff LaBundy
2259d56111edSJeff LaBundy if (dev_desc->allow_offset &&
2260d56111edSJeff LaBundy fwnode_property_present(chan_node, "azoteq,ulp-allow"))
2261e505edaeSJeff LaBundy sys_setup[dev_desc->allow_offset] &= ~BIT(chan_index);
2262e505edaeSJeff LaBundy
2263e505edaeSJeff LaBundy chan_setup[0] |= IQS7222_CHAN_SETUP_0_CHAN_EN;
2264e505edaeSJeff LaBundy
2265e505edaeSJeff LaBundy /*
2266e505edaeSJeff LaBundy * The reference channel function allows for differential measurements
2267e505edaeSJeff LaBundy * and is only available in the case of IQS7222A or IQS7222C.
2268e505edaeSJeff LaBundy */
2269e505edaeSJeff LaBundy if (dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_col > 4 &&
2270e505edaeSJeff LaBundy fwnode_property_present(chan_node, "azoteq,ref-select")) {
2271e505edaeSJeff LaBundy u16 *ref_setup;
2272e505edaeSJeff LaBundy
2273e505edaeSJeff LaBundy error = fwnode_property_read_u32(chan_node, "azoteq,ref-select",
2274e505edaeSJeff LaBundy &val);
2275e505edaeSJeff LaBundy if (error) {
2276e505edaeSJeff LaBundy dev_err(&client->dev,
2277e505edaeSJeff LaBundy "Failed to read %s reference channel: %d\n",
2278e505edaeSJeff LaBundy fwnode_get_name(chan_node), error);
2279e505edaeSJeff LaBundy return error;
2280e505edaeSJeff LaBundy }
2281e505edaeSJeff LaBundy
2282e505edaeSJeff LaBundy if (val >= ext_chan) {
2283e505edaeSJeff LaBundy dev_err(&client->dev,
2284e505edaeSJeff LaBundy "Invalid %s reference channel: %u\n",
2285e505edaeSJeff LaBundy fwnode_get_name(chan_node), val);
2286e505edaeSJeff LaBundy return -EINVAL;
2287e505edaeSJeff LaBundy }
2288e505edaeSJeff LaBundy
2289e505edaeSJeff LaBundy ref_setup = iqs7222->chan_setup[val];
2290e505edaeSJeff LaBundy
2291e505edaeSJeff LaBundy /*
2292e505edaeSJeff LaBundy * Configure the current channel as a follower of the selected
2293e505edaeSJeff LaBundy * reference channel.
2294e505edaeSJeff LaBundy */
2295e505edaeSJeff LaBundy chan_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_FOLLOW;
2296e505edaeSJeff LaBundy chan_setup[4] = val * 42 + 1048;
2297e505edaeSJeff LaBundy
2298404f3b48SJeff LaBundy error = fwnode_property_read_u32(chan_node, "azoteq,ref-weight",
2299404f3b48SJeff LaBundy &val);
2300404f3b48SJeff LaBundy if (!error) {
2301e505edaeSJeff LaBundy if (val > U16_MAX) {
2302e505edaeSJeff LaBundy dev_err(&client->dev,
2303e505edaeSJeff LaBundy "Invalid %s reference weight: %u\n",
2304e505edaeSJeff LaBundy fwnode_get_name(chan_node), val);
2305e505edaeSJeff LaBundy return -EINVAL;
2306e505edaeSJeff LaBundy }
2307e505edaeSJeff LaBundy
2308e505edaeSJeff LaBundy chan_setup[5] = val;
2309404f3b48SJeff LaBundy } else if (error != -EINVAL) {
2310404f3b48SJeff LaBundy dev_err(&client->dev,
2311404f3b48SJeff LaBundy "Failed to read %s reference weight: %d\n",
2312404f3b48SJeff LaBundy fwnode_get_name(chan_node), error);
2313404f3b48SJeff LaBundy return error;
2314e505edaeSJeff LaBundy }
2315e505edaeSJeff LaBundy
2316e505edaeSJeff LaBundy /*
2317e505edaeSJeff LaBundy * Configure the selected channel as a reference channel which
2318e505edaeSJeff LaBundy * serves the current channel.
2319e505edaeSJeff LaBundy */
2320e505edaeSJeff LaBundy ref_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_REF;
2321e505edaeSJeff LaBundy ref_setup[5] |= BIT(chan_index);
2322e505edaeSJeff LaBundy
2323e505edaeSJeff LaBundy ref_setup[4] = dev_desc->touch_link;
2324e505edaeSJeff LaBundy if (fwnode_property_present(chan_node, "azoteq,use-prox"))
2325e505edaeSJeff LaBundy ref_setup[4] -= 2;
2326dd24e202SJeff LaBundy } else if (dev_desc->reg_grps[IQS7222_REG_GRP_TPAD].num_row &&
2327dd24e202SJeff LaBundy fwnode_property_present(chan_node,
2328dd24e202SJeff LaBundy "azoteq,counts-filt-enable")) {
2329dd24e202SJeff LaBundy /*
2330dd24e202SJeff LaBundy * In the case of IQS7222D, however, the reference mode field
2331dd24e202SJeff LaBundy * is partially repurposed as a counts filter enable control.
2332dd24e202SJeff LaBundy */
2333dd24e202SJeff LaBundy chan_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_REF;
2334e505edaeSJeff LaBundy }
2335e505edaeSJeff LaBundy
2336e505edaeSJeff LaBundy if (fwnode_property_present(chan_node, "azoteq,rx-enable")) {
2337e505edaeSJeff LaBundy /*
2338e505edaeSJeff LaBundy * Each channel can claim up to 4 CRx pins. The first half of
2339e505edaeSJeff LaBundy * the channels can use CRx0-3, while the second half can use
2340e505edaeSJeff LaBundy * CRx4-7.
2341e505edaeSJeff LaBundy */
2342e505edaeSJeff LaBundy unsigned int pins[4];
2343e505edaeSJeff LaBundy int count;
2344e505edaeSJeff LaBundy
2345e505edaeSJeff LaBundy count = fwnode_property_count_u32(chan_node,
2346e505edaeSJeff LaBundy "azoteq,rx-enable");
2347eba697b3SDan Carpenter if (count < 0) {
2348e505edaeSJeff LaBundy dev_err(&client->dev,
2349e505edaeSJeff LaBundy "Failed to count %s CRx pins: %d\n",
2350e505edaeSJeff LaBundy fwnode_get_name(chan_node), count);
2351e505edaeSJeff LaBundy return count;
2352eba697b3SDan Carpenter } else if (count > ARRAY_SIZE(pins)) {
2353eba697b3SDan Carpenter dev_err(&client->dev,
2354eba697b3SDan Carpenter "Invalid number of %s CRx pins\n",
2355eba697b3SDan Carpenter fwnode_get_name(chan_node));
2356eba697b3SDan Carpenter return -EINVAL;
2357e505edaeSJeff LaBundy }
2358e505edaeSJeff LaBundy
2359e505edaeSJeff LaBundy error = fwnode_property_read_u32_array(chan_node,
2360e505edaeSJeff LaBundy "azoteq,rx-enable",
2361e505edaeSJeff LaBundy pins, count);
2362e505edaeSJeff LaBundy if (error) {
2363e505edaeSJeff LaBundy dev_err(&client->dev,
2364e505edaeSJeff LaBundy "Failed to read %s CRx pins: %d\n",
2365e505edaeSJeff LaBundy fwnode_get_name(chan_node), error);
2366e505edaeSJeff LaBundy return error;
2367e505edaeSJeff LaBundy }
2368e505edaeSJeff LaBundy
2369e505edaeSJeff LaBundy chan_setup[0] &= ~GENMASK(4 + ARRAY_SIZE(pins) - 1, 4);
2370e505edaeSJeff LaBundy
2371e505edaeSJeff LaBundy for (i = 0; i < count; i++) {
2372e505edaeSJeff LaBundy int min_crx = chan_index < ext_chan / 2 ? 0 : 4;
2373e505edaeSJeff LaBundy
2374e505edaeSJeff LaBundy if (pins[i] < min_crx || pins[i] > min_crx + 3) {
2375e505edaeSJeff LaBundy dev_err(&client->dev,
2376e505edaeSJeff LaBundy "Invalid %s CRx pin: %u\n",
2377e505edaeSJeff LaBundy fwnode_get_name(chan_node), pins[i]);
2378e505edaeSJeff LaBundy return -EINVAL;
2379e505edaeSJeff LaBundy }
2380e505edaeSJeff LaBundy
2381e505edaeSJeff LaBundy chan_setup[0] |= BIT(pins[i] + 4 - min_crx);
2382e505edaeSJeff LaBundy }
2383e505edaeSJeff LaBundy }
2384e505edaeSJeff LaBundy
2385e505edaeSJeff LaBundy for (i = 0; i < ARRAY_SIZE(iqs7222_kp_events); i++) {
2386e505edaeSJeff LaBundy const char *event_name = iqs7222_kp_events[i].name;
2387e505edaeSJeff LaBundy u16 event_enable = iqs7222_kp_events[i].enable;
2388e505edaeSJeff LaBundy struct fwnode_handle *event_node;
2389e505edaeSJeff LaBundy
2390e505edaeSJeff LaBundy event_node = fwnode_get_named_child_node(chan_node, event_name);
2391e505edaeSJeff LaBundy if (!event_node)
2392e505edaeSJeff LaBundy continue;
2393e505edaeSJeff LaBundy
2394404f3b48SJeff LaBundy error = fwnode_property_read_u32(event_node,
2395e505edaeSJeff LaBundy "azoteq,timeout-press-ms",
2396404f3b48SJeff LaBundy &val);
2397404f3b48SJeff LaBundy if (!error) {
2398e505edaeSJeff LaBundy /*
2399e505edaeSJeff LaBundy * The IQS7222B employs a global pair of press timeout
2400e505edaeSJeff LaBundy * registers as opposed to channel-specific registers.
2401e505edaeSJeff LaBundy */
2402e505edaeSJeff LaBundy u16 *setup = dev_desc->reg_grps
2403e505edaeSJeff LaBundy [IQS7222_REG_GRP_BTN].num_col > 2 ?
2404e505edaeSJeff LaBundy &iqs7222->btn_setup[chan_index][2] :
2405e505edaeSJeff LaBundy &sys_setup[9];
2406e505edaeSJeff LaBundy
2407e505edaeSJeff LaBundy if (val > U8_MAX * 500) {
2408e505edaeSJeff LaBundy dev_err(&client->dev,
2409e505edaeSJeff LaBundy "Invalid %s press timeout: %u\n",
2410bbd16b0dSJeff LaBundy fwnode_get_name(event_node), val);
2411bbd16b0dSJeff LaBundy fwnode_handle_put(event_node);
2412e505edaeSJeff LaBundy return -EINVAL;
2413e505edaeSJeff LaBundy }
2414e505edaeSJeff LaBundy
2415e505edaeSJeff LaBundy *setup &= ~(U8_MAX << i * 8);
2416e505edaeSJeff LaBundy *setup |= (val / 500 << i * 8);
2417404f3b48SJeff LaBundy } else if (error != -EINVAL) {
2418404f3b48SJeff LaBundy dev_err(&client->dev,
2419404f3b48SJeff LaBundy "Failed to read %s press timeout: %d\n",
2420404f3b48SJeff LaBundy fwnode_get_name(event_node), error);
2421404f3b48SJeff LaBundy fwnode_handle_put(event_node);
2422404f3b48SJeff LaBundy return error;
2423e505edaeSJeff LaBundy }
2424e505edaeSJeff LaBundy
2425bbd16b0dSJeff LaBundy error = iqs7222_parse_event(iqs7222, event_node, chan_index,
2426bbd16b0dSJeff LaBundy IQS7222_REG_GRP_BTN,
2427bbd16b0dSJeff LaBundy iqs7222_kp_events[i].reg_key,
2428bbd16b0dSJeff LaBundy BIT(chan_index),
2429bbd16b0dSJeff LaBundy dev_desc->touch_link - (i ? 0 : 2),
2430bbd16b0dSJeff LaBundy &iqs7222->kp_type[chan_index][i],
2431bbd16b0dSJeff LaBundy &iqs7222->kp_code[chan_index][i]);
2432bbd16b0dSJeff LaBundy fwnode_handle_put(event_node);
2433bbd16b0dSJeff LaBundy if (error)
2434e505edaeSJeff LaBundy return error;
2435e505edaeSJeff LaBundy
2436e505edaeSJeff LaBundy if (!dev_desc->event_offset)
2437e505edaeSJeff LaBundy continue;
2438e505edaeSJeff LaBundy
2439e505edaeSJeff LaBundy sys_setup[dev_desc->event_offset] |= event_enable;
2440e505edaeSJeff LaBundy }
2441e505edaeSJeff LaBundy
2442e505edaeSJeff LaBundy /*
2443e505edaeSJeff LaBundy * The following call handles a special pair of properties that apply
2444e505edaeSJeff LaBundy * to a channel node, but reside within the button (event) group.
2445e505edaeSJeff LaBundy */
2446bbd16b0dSJeff LaBundy return iqs7222_parse_props(iqs7222, chan_node, chan_index,
2447e505edaeSJeff LaBundy IQS7222_REG_GRP_BTN,
2448e505edaeSJeff LaBundy IQS7222_REG_KEY_DEBOUNCE);
2449e505edaeSJeff LaBundy }
2450e505edaeSJeff LaBundy
iqs7222_parse_sldr(struct iqs7222_private * iqs7222,struct fwnode_handle * sldr_node,int sldr_index)2451bbd16b0dSJeff LaBundy static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222,
2452bbd16b0dSJeff LaBundy struct fwnode_handle *sldr_node, int sldr_index)
2453e505edaeSJeff LaBundy {
2454e505edaeSJeff LaBundy const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
2455e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client;
2456e505edaeSJeff LaBundy int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
2457e505edaeSJeff LaBundy int ext_chan = rounddown(num_chan, 10);
2458e505edaeSJeff LaBundy int count, error, reg_offset, i;
245995215d3dSJeff LaBundy u16 *event_mask = &iqs7222->sys_setup[dev_desc->event_offset];
2460e505edaeSJeff LaBundy u16 *sldr_setup = iqs7222->sldr_setup[sldr_index];
2461e505edaeSJeff LaBundy unsigned int chan_sel[4], val;
2462e505edaeSJeff LaBundy
2463e505edaeSJeff LaBundy /*
2464e505edaeSJeff LaBundy * Each slider can be spread across 3 to 4 channels. It is possible to
2465e505edaeSJeff LaBundy * select only 2 channels, but doing so prevents the slider from using
2466e505edaeSJeff LaBundy * the specified resolution.
2467e505edaeSJeff LaBundy */
2468e505edaeSJeff LaBundy count = fwnode_property_count_u32(sldr_node, "azoteq,channel-select");
2469eba697b3SDan Carpenter if (count < 0) {
2470e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to count %s channels: %d\n",
2471e505edaeSJeff LaBundy fwnode_get_name(sldr_node), count);
2472e505edaeSJeff LaBundy return count;
2473eba697b3SDan Carpenter } else if (count < 3 || count > ARRAY_SIZE(chan_sel)) {
2474eba697b3SDan Carpenter dev_err(&client->dev, "Invalid number of %s channels\n",
2475eba697b3SDan Carpenter fwnode_get_name(sldr_node));
2476eba697b3SDan Carpenter return -EINVAL;
2477e505edaeSJeff LaBundy }
2478e505edaeSJeff LaBundy
2479e505edaeSJeff LaBundy error = fwnode_property_read_u32_array(sldr_node,
2480e505edaeSJeff LaBundy "azoteq,channel-select",
2481e505edaeSJeff LaBundy chan_sel, count);
2482e505edaeSJeff LaBundy if (error) {
2483e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to read %s channels: %d\n",
2484e505edaeSJeff LaBundy fwnode_get_name(sldr_node), error);
2485e505edaeSJeff LaBundy return error;
2486e505edaeSJeff LaBundy }
2487e505edaeSJeff LaBundy
2488e505edaeSJeff LaBundy /*
2489e505edaeSJeff LaBundy * Resolution and top speed, if small enough, are packed into a single
2490e505edaeSJeff LaBundy * register. Otherwise, each occupies its own register and the rest of
2491e505edaeSJeff LaBundy * the slider-related register addresses are offset by one.
2492e505edaeSJeff LaBundy */
2493e505edaeSJeff LaBundy reg_offset = dev_desc->sldr_res < U16_MAX ? 0 : 1;
2494e505edaeSJeff LaBundy
2495e505edaeSJeff LaBundy sldr_setup[0] |= count;
249695215d3dSJeff LaBundy sldr_setup[3 + reg_offset] &= ~GENMASK(ext_chan - 1, 0);
2497e505edaeSJeff LaBundy
2498e505edaeSJeff LaBundy for (i = 0; i < ARRAY_SIZE(chan_sel); i++) {
2499e505edaeSJeff LaBundy sldr_setup[5 + reg_offset + i] = 0;
2500e505edaeSJeff LaBundy if (i >= count)
2501e505edaeSJeff LaBundy continue;
2502e505edaeSJeff LaBundy
2503e505edaeSJeff LaBundy if (chan_sel[i] >= ext_chan) {
2504e505edaeSJeff LaBundy dev_err(&client->dev, "Invalid %s channel: %u\n",
2505e505edaeSJeff LaBundy fwnode_get_name(sldr_node), chan_sel[i]);
2506e505edaeSJeff LaBundy return -EINVAL;
2507e505edaeSJeff LaBundy }
2508e505edaeSJeff LaBundy
2509e505edaeSJeff LaBundy /*
2510e505edaeSJeff LaBundy * The following fields indicate which channels participate in
2511e505edaeSJeff LaBundy * the slider, as well as each channel's relative placement.
2512e505edaeSJeff LaBundy */
2513e505edaeSJeff LaBundy sldr_setup[3 + reg_offset] |= BIT(chan_sel[i]);
2514e505edaeSJeff LaBundy sldr_setup[5 + reg_offset + i] = chan_sel[i] * 42 + 1080;
2515e505edaeSJeff LaBundy }
2516e505edaeSJeff LaBundy
2517e505edaeSJeff LaBundy sldr_setup[4 + reg_offset] = dev_desc->touch_link;
2518e505edaeSJeff LaBundy if (fwnode_property_present(sldr_node, "azoteq,use-prox"))
2519e505edaeSJeff LaBundy sldr_setup[4 + reg_offset] -= 2;
2520e505edaeSJeff LaBundy
2521404f3b48SJeff LaBundy error = fwnode_property_read_u32(sldr_node, "azoteq,slider-size", &val);
2522404f3b48SJeff LaBundy if (!error) {
25232f6fd232SJeff LaBundy if (val > dev_desc->sldr_res) {
2524e505edaeSJeff LaBundy dev_err(&client->dev, "Invalid %s size: %u\n",
2525e505edaeSJeff LaBundy fwnode_get_name(sldr_node), val);
2526e505edaeSJeff LaBundy return -EINVAL;
2527e505edaeSJeff LaBundy }
2528e505edaeSJeff LaBundy
2529e505edaeSJeff LaBundy if (reg_offset) {
2530e505edaeSJeff LaBundy sldr_setup[3] = val;
2531e505edaeSJeff LaBundy } else {
2532e505edaeSJeff LaBundy sldr_setup[2] &= ~IQS7222_SLDR_SETUP_2_RES_MASK;
2533e505edaeSJeff LaBundy sldr_setup[2] |= (val / 16 <<
2534e505edaeSJeff LaBundy IQS7222_SLDR_SETUP_2_RES_SHIFT);
2535e505edaeSJeff LaBundy }
2536404f3b48SJeff LaBundy } else if (error != -EINVAL) {
2537404f3b48SJeff LaBundy dev_err(&client->dev, "Failed to read %s size: %d\n",
2538404f3b48SJeff LaBundy fwnode_get_name(sldr_node), error);
2539404f3b48SJeff LaBundy return error;
2540e505edaeSJeff LaBundy }
2541e505edaeSJeff LaBundy
25422f6fd232SJeff LaBundy if (!(reg_offset ? sldr_setup[3]
25432f6fd232SJeff LaBundy : sldr_setup[2] & IQS7222_SLDR_SETUP_2_RES_MASK)) {
25442f6fd232SJeff LaBundy dev_err(&client->dev, "Undefined %s size\n",
25452f6fd232SJeff LaBundy fwnode_get_name(sldr_node));
25462f6fd232SJeff LaBundy return -EINVAL;
25472f6fd232SJeff LaBundy }
25482f6fd232SJeff LaBundy
2549404f3b48SJeff LaBundy error = fwnode_property_read_u32(sldr_node, "azoteq,top-speed", &val);
2550404f3b48SJeff LaBundy if (!error) {
2551e505edaeSJeff LaBundy if (val > (reg_offset ? U16_MAX : U8_MAX * 4)) {
2552e505edaeSJeff LaBundy dev_err(&client->dev, "Invalid %s top speed: %u\n",
2553e505edaeSJeff LaBundy fwnode_get_name(sldr_node), val);
2554e505edaeSJeff LaBundy return -EINVAL;
2555e505edaeSJeff LaBundy }
2556e505edaeSJeff LaBundy
2557e505edaeSJeff LaBundy if (reg_offset) {
2558e505edaeSJeff LaBundy sldr_setup[2] = val;
2559e505edaeSJeff LaBundy } else {
2560e505edaeSJeff LaBundy sldr_setup[2] &= ~IQS7222_SLDR_SETUP_2_TOP_SPEED_MASK;
2561e505edaeSJeff LaBundy sldr_setup[2] |= (val / 4);
2562e505edaeSJeff LaBundy }
2563404f3b48SJeff LaBundy } else if (error != -EINVAL) {
2564404f3b48SJeff LaBundy dev_err(&client->dev, "Failed to read %s top speed: %d\n",
2565404f3b48SJeff LaBundy fwnode_get_name(sldr_node), error);
2566404f3b48SJeff LaBundy return error;
2567e505edaeSJeff LaBundy }
2568e505edaeSJeff LaBundy
2569404f3b48SJeff LaBundy error = fwnode_property_read_u32(sldr_node, "linux,axis", &val);
2570404f3b48SJeff LaBundy if (!error) {
2571e505edaeSJeff LaBundy u16 sldr_max = sldr_setup[3] - 1;
2572e505edaeSJeff LaBundy
2573e505edaeSJeff LaBundy if (!reg_offset) {
2574e505edaeSJeff LaBundy sldr_max = sldr_setup[2];
2575e505edaeSJeff LaBundy
2576e505edaeSJeff LaBundy sldr_max &= IQS7222_SLDR_SETUP_2_RES_MASK;
2577e505edaeSJeff LaBundy sldr_max >>= IQS7222_SLDR_SETUP_2_RES_SHIFT;
2578e505edaeSJeff LaBundy
2579e505edaeSJeff LaBundy sldr_max = sldr_max * 16 - 1;
2580e505edaeSJeff LaBundy }
2581e505edaeSJeff LaBundy
2582e505edaeSJeff LaBundy input_set_abs_params(iqs7222->keypad, val, 0, sldr_max, 0, 0);
2583e505edaeSJeff LaBundy iqs7222->sl_axis[sldr_index] = val;
2584404f3b48SJeff LaBundy } else if (error != -EINVAL) {
2585404f3b48SJeff LaBundy dev_err(&client->dev, "Failed to read %s axis: %d\n",
2586404f3b48SJeff LaBundy fwnode_get_name(sldr_node), error);
2587404f3b48SJeff LaBundy return error;
2588e505edaeSJeff LaBundy }
2589e505edaeSJeff LaBundy
2590e505edaeSJeff LaBundy if (dev_desc->wheel_enable) {
2591e505edaeSJeff LaBundy sldr_setup[0] &= ~dev_desc->wheel_enable;
2592e505edaeSJeff LaBundy if (iqs7222->sl_axis[sldr_index] == ABS_WHEEL)
2593e505edaeSJeff LaBundy sldr_setup[0] |= dev_desc->wheel_enable;
2594e505edaeSJeff LaBundy }
2595e505edaeSJeff LaBundy
259656a0c54cSJeff LaBundy /*
259756a0c54cSJeff LaBundy * The absence of a register offset makes it safe to assume the device
259856a0c54cSJeff LaBundy * supports gestures, each of which is first disabled until explicitly
259956a0c54cSJeff LaBundy * enabled.
260056a0c54cSJeff LaBundy */
260156a0c54cSJeff LaBundy if (!reg_offset)
260256a0c54cSJeff LaBundy for (i = 0; i < ARRAY_SIZE(iqs7222_sl_events); i++)
260356a0c54cSJeff LaBundy sldr_setup[9] &= ~iqs7222_sl_events[i].enable;
260456a0c54cSJeff LaBundy
2605e505edaeSJeff LaBundy for (i = 0; i < ARRAY_SIZE(iqs7222_sl_events); i++) {
2606e505edaeSJeff LaBundy const char *event_name = iqs7222_sl_events[i].name;
2607e505edaeSJeff LaBundy struct fwnode_handle *event_node;
2608bbd16b0dSJeff LaBundy enum iqs7222_reg_key_id reg_key;
2609e505edaeSJeff LaBundy
2610e505edaeSJeff LaBundy event_node = fwnode_get_named_child_node(sldr_node, event_name);
2611e505edaeSJeff LaBundy if (!event_node)
2612e505edaeSJeff LaBundy continue;
2613e505edaeSJeff LaBundy
26148d4c313cSJeff LaBundy /*
26158d4c313cSJeff LaBundy * Depending on the device, gestures are either offered using
26168d4c313cSJeff LaBundy * one of two timing resolutions, or are not supported at all.
26178d4c313cSJeff LaBundy */
2618bbd16b0dSJeff LaBundy if (reg_offset)
2619bbd16b0dSJeff LaBundy reg_key = IQS7222_REG_KEY_RESERVED;
26208d4c313cSJeff LaBundy else if (dev_desc->legacy_gesture &&
26218d4c313cSJeff LaBundy iqs7222_sl_events[i].reg_key == IQS7222_REG_KEY_TAP)
26228d4c313cSJeff LaBundy reg_key = IQS7222_REG_KEY_TAP_LEGACY;
26238d4c313cSJeff LaBundy else if (dev_desc->legacy_gesture &&
26248d4c313cSJeff LaBundy iqs7222_sl_events[i].reg_key == IQS7222_REG_KEY_AXIAL)
26258d4c313cSJeff LaBundy reg_key = IQS7222_REG_KEY_AXIAL_LEGACY;
2626bbd16b0dSJeff LaBundy else
2627bbd16b0dSJeff LaBundy reg_key = iqs7222_sl_events[i].reg_key;
2628e505edaeSJeff LaBundy
262995215d3dSJeff LaBundy /*
263095215d3dSJeff LaBundy * The press/release event does not expose a direct GPIO link,
263195215d3dSJeff LaBundy * but one can be emulated by tying each of the participating
263295215d3dSJeff LaBundy * channels to the same GPIO.
263395215d3dSJeff LaBundy */
2634bbd16b0dSJeff LaBundy error = iqs7222_parse_event(iqs7222, event_node, sldr_index,
2635bbd16b0dSJeff LaBundy IQS7222_REG_GRP_SLDR, reg_key,
263695215d3dSJeff LaBundy i ? iqs7222_sl_events[i].enable
263795215d3dSJeff LaBundy : sldr_setup[3 + reg_offset],
263895215d3dSJeff LaBundy i ? 1568 + sldr_index * 30
2639bbd16b0dSJeff LaBundy : sldr_setup[4 + reg_offset],
2640bbd16b0dSJeff LaBundy NULL,
2641bbd16b0dSJeff LaBundy &iqs7222->sl_code[sldr_index][i]);
2642bbd16b0dSJeff LaBundy fwnode_handle_put(event_node);
264395215d3dSJeff LaBundy if (error)
264495215d3dSJeff LaBundy return error;
264595215d3dSJeff LaBundy
264695215d3dSJeff LaBundy if (!reg_offset)
264795215d3dSJeff LaBundy sldr_setup[9] |= iqs7222_sl_events[i].enable;
264895215d3dSJeff LaBundy
2649e505edaeSJeff LaBundy if (!dev_desc->event_offset)
2650e505edaeSJeff LaBundy continue;
2651e505edaeSJeff LaBundy
265295215d3dSJeff LaBundy /*
265395215d3dSJeff LaBundy * The press/release event is determined based on whether the
265495215d3dSJeff LaBundy * coordinate field reports 0xFFFF and solely relies on touch
265595215d3dSJeff LaBundy * or proximity interrupts to be unmasked.
265695215d3dSJeff LaBundy */
265795215d3dSJeff LaBundy if (i && !reg_offset)
265895215d3dSJeff LaBundy *event_mask |= (IQS7222_EVENT_MASK_SLDR << sldr_index);
265995215d3dSJeff LaBundy else if (sldr_setup[4 + reg_offset] == dev_desc->touch_link)
266095215d3dSJeff LaBundy *event_mask |= IQS7222_EVENT_MASK_TOUCH;
266195215d3dSJeff LaBundy else
266295215d3dSJeff LaBundy *event_mask |= IQS7222_EVENT_MASK_PROX;
2663e505edaeSJeff LaBundy }
2664e505edaeSJeff LaBundy
2665e505edaeSJeff LaBundy /*
2666e505edaeSJeff LaBundy * The following call handles a special pair of properties that shift
2667e505edaeSJeff LaBundy * to make room for a wheel enable control in the case of IQS7222C.
2668e505edaeSJeff LaBundy */
2669bbd16b0dSJeff LaBundy return iqs7222_parse_props(iqs7222, sldr_node, sldr_index,
2670e505edaeSJeff LaBundy IQS7222_REG_GRP_SLDR,
2671e505edaeSJeff LaBundy dev_desc->wheel_enable ?
2672e505edaeSJeff LaBundy IQS7222_REG_KEY_WHEEL :
2673e505edaeSJeff LaBundy IQS7222_REG_KEY_NO_WHEEL);
2674e505edaeSJeff LaBundy }
2675e505edaeSJeff LaBundy
iqs7222_parse_tpad(struct iqs7222_private * iqs7222,struct fwnode_handle * tpad_node,int tpad_index)2676dd24e202SJeff LaBundy static int iqs7222_parse_tpad(struct iqs7222_private *iqs7222,
2677dd24e202SJeff LaBundy struct fwnode_handle *tpad_node, int tpad_index)
2678dd24e202SJeff LaBundy {
2679dd24e202SJeff LaBundy const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
2680dd24e202SJeff LaBundy struct touchscreen_properties *prop = &iqs7222->prop;
2681dd24e202SJeff LaBundy struct i2c_client *client = iqs7222->client;
2682dd24e202SJeff LaBundy int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
2683dd24e202SJeff LaBundy int count, error, i;
2684dd24e202SJeff LaBundy u16 *event_mask = &iqs7222->sys_setup[dev_desc->event_offset];
2685dd24e202SJeff LaBundy u16 *tpad_setup = iqs7222->tpad_setup;
2686dd24e202SJeff LaBundy unsigned int chan_sel[12];
2687dd24e202SJeff LaBundy
2688dd24e202SJeff LaBundy error = iqs7222_parse_props(iqs7222, tpad_node, tpad_index,
2689dd24e202SJeff LaBundy IQS7222_REG_GRP_TPAD,
2690dd24e202SJeff LaBundy IQS7222_REG_KEY_NONE);
2691dd24e202SJeff LaBundy if (error)
2692dd24e202SJeff LaBundy return error;
2693dd24e202SJeff LaBundy
2694dd24e202SJeff LaBundy count = fwnode_property_count_u32(tpad_node, "azoteq,channel-select");
2695dd24e202SJeff LaBundy if (count < 0) {
2696dd24e202SJeff LaBundy dev_err(&client->dev, "Failed to count %s channels: %d\n",
2697dd24e202SJeff LaBundy fwnode_get_name(tpad_node), count);
2698dd24e202SJeff LaBundy return count;
2699dd24e202SJeff LaBundy } else if (!count || count > ARRAY_SIZE(chan_sel)) {
2700dd24e202SJeff LaBundy dev_err(&client->dev, "Invalid number of %s channels\n",
2701dd24e202SJeff LaBundy fwnode_get_name(tpad_node));
2702dd24e202SJeff LaBundy return -EINVAL;
2703dd24e202SJeff LaBundy }
2704dd24e202SJeff LaBundy
2705dd24e202SJeff LaBundy error = fwnode_property_read_u32_array(tpad_node,
2706dd24e202SJeff LaBundy "azoteq,channel-select",
2707dd24e202SJeff LaBundy chan_sel, count);
2708dd24e202SJeff LaBundy if (error) {
2709dd24e202SJeff LaBundy dev_err(&client->dev, "Failed to read %s channels: %d\n",
2710dd24e202SJeff LaBundy fwnode_get_name(tpad_node), error);
2711dd24e202SJeff LaBundy return error;
2712dd24e202SJeff LaBundy }
2713dd24e202SJeff LaBundy
2714dd24e202SJeff LaBundy tpad_setup[6] &= ~GENMASK(num_chan - 1, 0);
2715dd24e202SJeff LaBundy
2716dd24e202SJeff LaBundy for (i = 0; i < ARRAY_SIZE(chan_sel); i++) {
2717dd24e202SJeff LaBundy tpad_setup[8 + i] = 0;
2718dd24e202SJeff LaBundy if (i >= count || chan_sel[i] == U8_MAX)
2719dd24e202SJeff LaBundy continue;
2720dd24e202SJeff LaBundy
2721dd24e202SJeff LaBundy if (chan_sel[i] >= num_chan) {
2722dd24e202SJeff LaBundy dev_err(&client->dev, "Invalid %s channel: %u\n",
2723dd24e202SJeff LaBundy fwnode_get_name(tpad_node), chan_sel[i]);
2724dd24e202SJeff LaBundy return -EINVAL;
2725dd24e202SJeff LaBundy }
2726dd24e202SJeff LaBundy
2727dd24e202SJeff LaBundy /*
2728dd24e202SJeff LaBundy * The following fields indicate which channels participate in
2729dd24e202SJeff LaBundy * the trackpad, as well as each channel's relative placement.
2730dd24e202SJeff LaBundy */
2731dd24e202SJeff LaBundy tpad_setup[6] |= BIT(chan_sel[i]);
2732dd24e202SJeff LaBundy tpad_setup[8 + i] = chan_sel[i] * 34 + 1072;
2733dd24e202SJeff LaBundy }
2734dd24e202SJeff LaBundy
2735dd24e202SJeff LaBundy tpad_setup[7] = dev_desc->touch_link;
2736dd24e202SJeff LaBundy if (fwnode_property_present(tpad_node, "azoteq,use-prox"))
2737dd24e202SJeff LaBundy tpad_setup[7] -= 2;
2738dd24e202SJeff LaBundy
2739dd24e202SJeff LaBundy for (i = 0; i < ARRAY_SIZE(iqs7222_tp_events); i++)
2740dd24e202SJeff LaBundy tpad_setup[20] &= ~(iqs7222_tp_events[i].strict |
2741dd24e202SJeff LaBundy iqs7222_tp_events[i].enable);
2742dd24e202SJeff LaBundy
2743dd24e202SJeff LaBundy for (i = 0; i < ARRAY_SIZE(iqs7222_tp_events); i++) {
2744dd24e202SJeff LaBundy const char *event_name = iqs7222_tp_events[i].name;
2745dd24e202SJeff LaBundy struct fwnode_handle *event_node;
2746dd24e202SJeff LaBundy
2747dd24e202SJeff LaBundy event_node = fwnode_get_named_child_node(tpad_node, event_name);
2748dd24e202SJeff LaBundy if (!event_node)
2749dd24e202SJeff LaBundy continue;
2750dd24e202SJeff LaBundy
2751dd24e202SJeff LaBundy if (fwnode_property_present(event_node,
2752dd24e202SJeff LaBundy "azoteq,gesture-angle-tighten"))
2753dd24e202SJeff LaBundy tpad_setup[20] |= iqs7222_tp_events[i].strict;
2754dd24e202SJeff LaBundy
2755dd24e202SJeff LaBundy tpad_setup[20] |= iqs7222_tp_events[i].enable;
2756dd24e202SJeff LaBundy
2757dd24e202SJeff LaBundy error = iqs7222_parse_event(iqs7222, event_node, tpad_index,
2758dd24e202SJeff LaBundy IQS7222_REG_GRP_TPAD,
2759dd24e202SJeff LaBundy iqs7222_tp_events[i].reg_key,
2760dd24e202SJeff LaBundy iqs7222_tp_events[i].link, 1566,
2761dd24e202SJeff LaBundy NULL,
2762dd24e202SJeff LaBundy &iqs7222->tp_code[i]);
2763dd24e202SJeff LaBundy fwnode_handle_put(event_node);
2764dd24e202SJeff LaBundy if (error)
2765dd24e202SJeff LaBundy return error;
2766dd24e202SJeff LaBundy
2767dd24e202SJeff LaBundy if (!dev_desc->event_offset)
2768dd24e202SJeff LaBundy continue;
2769dd24e202SJeff LaBundy
2770dd24e202SJeff LaBundy /*
2771dd24e202SJeff LaBundy * The press/release event is determined based on whether the
2772dd24e202SJeff LaBundy * coordinate fields report 0xFFFF and solely relies on touch
2773dd24e202SJeff LaBundy * or proximity interrupts to be unmasked.
2774dd24e202SJeff LaBundy */
2775dd24e202SJeff LaBundy if (i)
2776dd24e202SJeff LaBundy *event_mask |= IQS7222_EVENT_MASK_TPAD;
2777dd24e202SJeff LaBundy else if (tpad_setup[7] == dev_desc->touch_link)
2778dd24e202SJeff LaBundy *event_mask |= IQS7222_EVENT_MASK_TOUCH;
2779dd24e202SJeff LaBundy else
2780dd24e202SJeff LaBundy *event_mask |= IQS7222_EVENT_MASK_PROX;
2781dd24e202SJeff LaBundy }
2782dd24e202SJeff LaBundy
2783dd24e202SJeff LaBundy if (!iqs7222->tp_code[0])
2784dd24e202SJeff LaBundy return 0;
2785dd24e202SJeff LaBundy
2786dd24e202SJeff LaBundy input_set_abs_params(iqs7222->keypad, ABS_X,
2787dd24e202SJeff LaBundy 0, (tpad_setup[4] ? : 1) - 1, 0, 0);
2788dd24e202SJeff LaBundy
2789dd24e202SJeff LaBundy input_set_abs_params(iqs7222->keypad, ABS_Y,
2790dd24e202SJeff LaBundy 0, (tpad_setup[5] ? : 1) - 1, 0, 0);
2791dd24e202SJeff LaBundy
2792dd24e202SJeff LaBundy touchscreen_parse_properties(iqs7222->keypad, false, prop);
2793dd24e202SJeff LaBundy
2794dd24e202SJeff LaBundy if (prop->max_x >= U16_MAX || prop->max_y >= U16_MAX) {
2795dd24e202SJeff LaBundy dev_err(&client->dev, "Invalid trackpad size: %u*%u\n",
2796dd24e202SJeff LaBundy prop->max_x, prop->max_y);
2797dd24e202SJeff LaBundy return -EINVAL;
2798dd24e202SJeff LaBundy }
2799dd24e202SJeff LaBundy
2800dd24e202SJeff LaBundy tpad_setup[4] = prop->max_x + 1;
2801dd24e202SJeff LaBundy tpad_setup[5] = prop->max_y + 1;
2802dd24e202SJeff LaBundy
2803dd24e202SJeff LaBundy return 0;
2804dd24e202SJeff LaBundy }
2805dd24e202SJeff LaBundy
2806bbd16b0dSJeff LaBundy static int (*iqs7222_parse_extra[IQS7222_NUM_REG_GRPS])
2807bbd16b0dSJeff LaBundy (struct iqs7222_private *iqs7222,
2808bbd16b0dSJeff LaBundy struct fwnode_handle *reg_grp_node,
2809bbd16b0dSJeff LaBundy int reg_grp_index) = {
2810bbd16b0dSJeff LaBundy [IQS7222_REG_GRP_CYCLE] = iqs7222_parse_cycle,
2811bbd16b0dSJeff LaBundy [IQS7222_REG_GRP_CHAN] = iqs7222_parse_chan,
2812bbd16b0dSJeff LaBundy [IQS7222_REG_GRP_SLDR] = iqs7222_parse_sldr,
2813dd24e202SJeff LaBundy [IQS7222_REG_GRP_TPAD] = iqs7222_parse_tpad,
2814bbd16b0dSJeff LaBundy };
2815bbd16b0dSJeff LaBundy
iqs7222_parse_reg_grp(struct iqs7222_private * iqs7222,enum iqs7222_reg_grp_id reg_grp,int reg_grp_index)2816bbd16b0dSJeff LaBundy static int iqs7222_parse_reg_grp(struct iqs7222_private *iqs7222,
2817bbd16b0dSJeff LaBundy enum iqs7222_reg_grp_id reg_grp,
2818bbd16b0dSJeff LaBundy int reg_grp_index)
2819bbd16b0dSJeff LaBundy {
2820bbd16b0dSJeff LaBundy struct i2c_client *client = iqs7222->client;
2821bbd16b0dSJeff LaBundy struct fwnode_handle *reg_grp_node;
2822bbd16b0dSJeff LaBundy int error;
2823bbd16b0dSJeff LaBundy
2824bbd16b0dSJeff LaBundy if (iqs7222_reg_grp_names[reg_grp]) {
2825bbd16b0dSJeff LaBundy char reg_grp_name[16];
2826bbd16b0dSJeff LaBundy
2827dd24e202SJeff LaBundy snprintf(reg_grp_name, sizeof(reg_grp_name),
2828bbd16b0dSJeff LaBundy iqs7222_reg_grp_names[reg_grp], reg_grp_index);
2829bbd16b0dSJeff LaBundy
2830bbd16b0dSJeff LaBundy reg_grp_node = device_get_named_child_node(&client->dev,
2831bbd16b0dSJeff LaBundy reg_grp_name);
2832bbd16b0dSJeff LaBundy } else {
2833bbd16b0dSJeff LaBundy reg_grp_node = fwnode_handle_get(dev_fwnode(&client->dev));
2834bbd16b0dSJeff LaBundy }
2835bbd16b0dSJeff LaBundy
2836bbd16b0dSJeff LaBundy if (!reg_grp_node)
2837bbd16b0dSJeff LaBundy return 0;
2838bbd16b0dSJeff LaBundy
2839bbd16b0dSJeff LaBundy error = iqs7222_parse_props(iqs7222, reg_grp_node, reg_grp_index,
2840bbd16b0dSJeff LaBundy reg_grp, IQS7222_REG_KEY_NONE);
2841bbd16b0dSJeff LaBundy
2842bbd16b0dSJeff LaBundy if (!error && iqs7222_parse_extra[reg_grp])
2843bbd16b0dSJeff LaBundy error = iqs7222_parse_extra[reg_grp](iqs7222, reg_grp_node,
2844bbd16b0dSJeff LaBundy reg_grp_index);
2845bbd16b0dSJeff LaBundy
2846bbd16b0dSJeff LaBundy fwnode_handle_put(reg_grp_node);
2847bbd16b0dSJeff LaBundy
2848bbd16b0dSJeff LaBundy return error;
2849bbd16b0dSJeff LaBundy }
2850bbd16b0dSJeff LaBundy
iqs7222_parse_all(struct iqs7222_private * iqs7222)2851e505edaeSJeff LaBundy static int iqs7222_parse_all(struct iqs7222_private *iqs7222)
2852e505edaeSJeff LaBundy {
2853e505edaeSJeff LaBundy const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
2854e505edaeSJeff LaBundy const struct iqs7222_reg_grp_desc *reg_grps = dev_desc->reg_grps;
2855e505edaeSJeff LaBundy u16 *sys_setup = iqs7222->sys_setup;
2856bbd16b0dSJeff LaBundy int error, i, j;
2857e505edaeSJeff LaBundy
2858d56111edSJeff LaBundy if (dev_desc->allow_offset)
2859d56111edSJeff LaBundy sys_setup[dev_desc->allow_offset] = U16_MAX;
2860d56111edSJeff LaBundy
2861e505edaeSJeff LaBundy if (dev_desc->event_offset)
2862e505edaeSJeff LaBundy sys_setup[dev_desc->event_offset] = IQS7222_EVENT_MASK_ATI;
2863e505edaeSJeff LaBundy
2864e505edaeSJeff LaBundy for (i = 0; i < reg_grps[IQS7222_REG_GRP_GPIO].num_row; i++) {
2865e505edaeSJeff LaBundy u16 *gpio_setup = iqs7222->gpio_setup[i];
2866e505edaeSJeff LaBundy
2867e505edaeSJeff LaBundy gpio_setup[0] &= ~IQS7222_GPIO_SETUP_0_GPIO_EN;
2868e505edaeSJeff LaBundy gpio_setup[1] = 0;
2869e505edaeSJeff LaBundy gpio_setup[2] = 0;
2870e505edaeSJeff LaBundy
2871e505edaeSJeff LaBundy if (reg_grps[IQS7222_REG_GRP_GPIO].num_row == 1)
2872e505edaeSJeff LaBundy continue;
2873e505edaeSJeff LaBundy
2874e505edaeSJeff LaBundy /*
2875dd24e202SJeff LaBundy * The IQS7222C and IQS7222D expose multiple GPIO and must be
2876dd24e202SJeff LaBundy * informed as to which GPIO this group represents.
2877e505edaeSJeff LaBundy */
2878e505edaeSJeff LaBundy for (j = 0; j < ARRAY_SIZE(iqs7222_gpio_links); j++)
2879e505edaeSJeff LaBundy gpio_setup[0] &= ~BIT(iqs7222_gpio_links[j]);
2880e505edaeSJeff LaBundy
2881e505edaeSJeff LaBundy gpio_setup[0] |= BIT(iqs7222_gpio_links[i]);
2882e505edaeSJeff LaBundy }
2883e505edaeSJeff LaBundy
2884e505edaeSJeff LaBundy for (i = 0; i < reg_grps[IQS7222_REG_GRP_CHAN].num_row; i++) {
2885e505edaeSJeff LaBundy u16 *chan_setup = iqs7222->chan_setup[i];
2886e505edaeSJeff LaBundy
2887e505edaeSJeff LaBundy chan_setup[0] &= ~IQS7222_CHAN_SETUP_0_REF_MODE_MASK;
2888e505edaeSJeff LaBundy chan_setup[0] &= ~IQS7222_CHAN_SETUP_0_CHAN_EN;
2889e505edaeSJeff LaBundy
2890e505edaeSJeff LaBundy chan_setup[5] = 0;
2891e505edaeSJeff LaBundy }
2892e505edaeSJeff LaBundy
2893e505edaeSJeff LaBundy for (i = 0; i < reg_grps[IQS7222_REG_GRP_SLDR].num_row; i++) {
2894e505edaeSJeff LaBundy u16 *sldr_setup = iqs7222->sldr_setup[i];
2895e505edaeSJeff LaBundy
2896e505edaeSJeff LaBundy sldr_setup[0] &= ~IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK;
2897bbd16b0dSJeff LaBundy }
2898e505edaeSJeff LaBundy
2899bbd16b0dSJeff LaBundy for (i = 0; i < IQS7222_NUM_REG_GRPS; i++) {
2900bbd16b0dSJeff LaBundy for (j = 0; j < reg_grps[i].num_row; j++) {
2901bbd16b0dSJeff LaBundy error = iqs7222_parse_reg_grp(iqs7222, i, j);
2902e505edaeSJeff LaBundy if (error)
2903e505edaeSJeff LaBundy return error;
2904e505edaeSJeff LaBundy }
2905bbd16b0dSJeff LaBundy }
2906e505edaeSJeff LaBundy
2907bbd16b0dSJeff LaBundy return 0;
2908e505edaeSJeff LaBundy }
2909e505edaeSJeff LaBundy
iqs7222_report(struct iqs7222_private * iqs7222)2910e505edaeSJeff LaBundy static int iqs7222_report(struct iqs7222_private *iqs7222)
2911e505edaeSJeff LaBundy {
2912e505edaeSJeff LaBundy const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
2913e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client;
2914e505edaeSJeff LaBundy int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
2915e505edaeSJeff LaBundy int num_stat = dev_desc->reg_grps[IQS7222_REG_GRP_STAT].num_col;
2916e505edaeSJeff LaBundy int error, i, j;
2917e505edaeSJeff LaBundy __le16 status[IQS7222_MAX_COLS_STAT];
2918e505edaeSJeff LaBundy
2919e505edaeSJeff LaBundy error = iqs7222_read_burst(iqs7222, IQS7222_SYS_STATUS, status,
2920e505edaeSJeff LaBundy num_stat);
2921e505edaeSJeff LaBundy if (error)
2922e505edaeSJeff LaBundy return error;
2923e505edaeSJeff LaBundy
2924e505edaeSJeff LaBundy if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_RESET) {
2925e505edaeSJeff LaBundy dev_err(&client->dev, "Unexpected device reset\n");
2926e505edaeSJeff LaBundy return iqs7222_dev_init(iqs7222, WRITE);
2927e505edaeSJeff LaBundy }
2928e505edaeSJeff LaBundy
2929e505edaeSJeff LaBundy if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_ATI_ERROR) {
2930e505edaeSJeff LaBundy dev_err(&client->dev, "Unexpected ATI error\n");
2931e505edaeSJeff LaBundy return iqs7222_ati_trigger(iqs7222);
2932e505edaeSJeff LaBundy }
2933e505edaeSJeff LaBundy
2934e505edaeSJeff LaBundy if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_ATI_ACTIVE)
2935e505edaeSJeff LaBundy return 0;
2936e505edaeSJeff LaBundy
2937e505edaeSJeff LaBundy for (i = 0; i < num_chan; i++) {
2938e505edaeSJeff LaBundy u16 *chan_setup = iqs7222->chan_setup[i];
2939e505edaeSJeff LaBundy
2940e505edaeSJeff LaBundy if (!(chan_setup[0] & IQS7222_CHAN_SETUP_0_CHAN_EN))
2941e505edaeSJeff LaBundy continue;
2942e505edaeSJeff LaBundy
2943e505edaeSJeff LaBundy for (j = 0; j < ARRAY_SIZE(iqs7222_kp_events); j++) {
2944e505edaeSJeff LaBundy /*
2945e505edaeSJeff LaBundy * Proximity state begins at offset 2 and spills into
2946e505edaeSJeff LaBundy * offset 3 for devices with more than 16 channels.
2947e505edaeSJeff LaBundy *
2948e505edaeSJeff LaBundy * Touch state begins at the first offset immediately
2949e505edaeSJeff LaBundy * following proximity state.
2950e505edaeSJeff LaBundy */
2951e505edaeSJeff LaBundy int k = 2 + j * (num_chan > 16 ? 2 : 1);
2952e505edaeSJeff LaBundy u16 state = le16_to_cpu(status[k + i / 16]);
2953e505edaeSJeff LaBundy
2954514c13b1SJeff LaBundy if (!iqs7222->kp_type[i][j])
2955514c13b1SJeff LaBundy continue;
2956514c13b1SJeff LaBundy
2957e505edaeSJeff LaBundy input_event(iqs7222->keypad,
2958e505edaeSJeff LaBundy iqs7222->kp_type[i][j],
2959e505edaeSJeff LaBundy iqs7222->kp_code[i][j],
2960e505edaeSJeff LaBundy !!(state & BIT(i % 16)));
2961e505edaeSJeff LaBundy }
2962e505edaeSJeff LaBundy }
2963e505edaeSJeff LaBundy
2964e505edaeSJeff LaBundy for (i = 0; i < dev_desc->reg_grps[IQS7222_REG_GRP_SLDR].num_row; i++) {
2965e505edaeSJeff LaBundy u16 *sldr_setup = iqs7222->sldr_setup[i];
2966e505edaeSJeff LaBundy u16 sldr_pos = le16_to_cpu(status[4 + i]);
2967e505edaeSJeff LaBundy u16 state = le16_to_cpu(status[6 + i]);
2968e505edaeSJeff LaBundy
2969e505edaeSJeff LaBundy if (!(sldr_setup[0] & IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK))
2970e505edaeSJeff LaBundy continue;
2971e505edaeSJeff LaBundy
2972e505edaeSJeff LaBundy if (sldr_pos < dev_desc->sldr_res)
2973e505edaeSJeff LaBundy input_report_abs(iqs7222->keypad, iqs7222->sl_axis[i],
2974e505edaeSJeff LaBundy sldr_pos);
2975e505edaeSJeff LaBundy
297695215d3dSJeff LaBundy input_report_key(iqs7222->keypad, iqs7222->sl_code[i][0],
2977e505edaeSJeff LaBundy sldr_pos < dev_desc->sldr_res);
2978e505edaeSJeff LaBundy
2979e505edaeSJeff LaBundy /*
298095215d3dSJeff LaBundy * A maximum resolution indicates the device does not support
298195215d3dSJeff LaBundy * gestures, in which case the remaining fields are ignored.
2982e505edaeSJeff LaBundy */
298395215d3dSJeff LaBundy if (dev_desc->sldr_res == U16_MAX)
2984e505edaeSJeff LaBundy continue;
2985e505edaeSJeff LaBundy
298695215d3dSJeff LaBundy if (!(le16_to_cpu(status[1]) & IQS7222_EVENT_MASK_SLDR << i))
298795215d3dSJeff LaBundy continue;
298895215d3dSJeff LaBundy
298995215d3dSJeff LaBundy /*
299095215d3dSJeff LaBundy * Skip the press/release event, as it does not have separate
299195215d3dSJeff LaBundy * status fields and is handled separately.
299295215d3dSJeff LaBundy */
299395215d3dSJeff LaBundy for (j = 1; j < ARRAY_SIZE(iqs7222_sl_events); j++) {
299495215d3dSJeff LaBundy u16 mask = iqs7222_sl_events[j].mask;
299595215d3dSJeff LaBundy u16 val = iqs7222_sl_events[j].val;
299695215d3dSJeff LaBundy
2997e505edaeSJeff LaBundy input_report_key(iqs7222->keypad,
2998e505edaeSJeff LaBundy iqs7222->sl_code[i][j],
2999e505edaeSJeff LaBundy (state & mask) == val);
3000e505edaeSJeff LaBundy }
300195215d3dSJeff LaBundy
300295215d3dSJeff LaBundy input_sync(iqs7222->keypad);
300395215d3dSJeff LaBundy
300495215d3dSJeff LaBundy for (j = 1; j < ARRAY_SIZE(iqs7222_sl_events); j++)
300595215d3dSJeff LaBundy input_report_key(iqs7222->keypad,
300695215d3dSJeff LaBundy iqs7222->sl_code[i][j], 0);
3007e505edaeSJeff LaBundy }
3008e505edaeSJeff LaBundy
3009dd24e202SJeff LaBundy for (i = 0; i < dev_desc->reg_grps[IQS7222_REG_GRP_TPAD].num_row; i++) {
3010dd24e202SJeff LaBundy u16 tpad_pos_x = le16_to_cpu(status[4]);
3011dd24e202SJeff LaBundy u16 tpad_pos_y = le16_to_cpu(status[5]);
3012dd24e202SJeff LaBundy u16 state = le16_to_cpu(status[6]);
3013dd24e202SJeff LaBundy
3014dd24e202SJeff LaBundy input_report_key(iqs7222->keypad, iqs7222->tp_code[0],
3015dd24e202SJeff LaBundy tpad_pos_x < U16_MAX);
3016dd24e202SJeff LaBundy
3017dd24e202SJeff LaBundy if (tpad_pos_x < U16_MAX)
3018dd24e202SJeff LaBundy touchscreen_report_pos(iqs7222->keypad, &iqs7222->prop,
3019dd24e202SJeff LaBundy tpad_pos_x, tpad_pos_y, false);
3020dd24e202SJeff LaBundy
3021dd24e202SJeff LaBundy if (!(le16_to_cpu(status[1]) & IQS7222_EVENT_MASK_TPAD))
3022dd24e202SJeff LaBundy continue;
3023dd24e202SJeff LaBundy
3024dd24e202SJeff LaBundy /*
3025dd24e202SJeff LaBundy * Skip the press/release event, as it does not have separate
3026dd24e202SJeff LaBundy * status fields and is handled separately.
3027dd24e202SJeff LaBundy */
3028dd24e202SJeff LaBundy for (j = 1; j < ARRAY_SIZE(iqs7222_tp_events); j++) {
3029dd24e202SJeff LaBundy u16 mask = iqs7222_tp_events[j].mask;
3030dd24e202SJeff LaBundy u16 val = iqs7222_tp_events[j].val;
3031dd24e202SJeff LaBundy
3032dd24e202SJeff LaBundy input_report_key(iqs7222->keypad,
3033dd24e202SJeff LaBundy iqs7222->tp_code[j],
3034dd24e202SJeff LaBundy (state & mask) == val);
3035dd24e202SJeff LaBundy }
3036dd24e202SJeff LaBundy
3037dd24e202SJeff LaBundy input_sync(iqs7222->keypad);
3038dd24e202SJeff LaBundy
3039dd24e202SJeff LaBundy for (j = 1; j < ARRAY_SIZE(iqs7222_tp_events); j++)
3040dd24e202SJeff LaBundy input_report_key(iqs7222->keypad,
3041dd24e202SJeff LaBundy iqs7222->tp_code[j], 0);
3042dd24e202SJeff LaBundy }
3043dd24e202SJeff LaBundy
3044e505edaeSJeff LaBundy input_sync(iqs7222->keypad);
3045e505edaeSJeff LaBundy
3046e505edaeSJeff LaBundy return 0;
3047e505edaeSJeff LaBundy }
3048e505edaeSJeff LaBundy
iqs7222_irq(int irq,void * context)3049e505edaeSJeff LaBundy static irqreturn_t iqs7222_irq(int irq, void *context)
3050e505edaeSJeff LaBundy {
3051e505edaeSJeff LaBundy struct iqs7222_private *iqs7222 = context;
3052e505edaeSJeff LaBundy
3053e505edaeSJeff LaBundy return iqs7222_report(iqs7222) ? IRQ_NONE : IRQ_HANDLED;
3054e505edaeSJeff LaBundy }
3055e505edaeSJeff LaBundy
iqs7222_probe(struct i2c_client * client)3056e505edaeSJeff LaBundy static int iqs7222_probe(struct i2c_client *client)
3057e505edaeSJeff LaBundy {
3058e505edaeSJeff LaBundy struct iqs7222_private *iqs7222;
3059e505edaeSJeff LaBundy unsigned long irq_flags;
3060e505edaeSJeff LaBundy int error, irq;
3061e505edaeSJeff LaBundy
3062e505edaeSJeff LaBundy iqs7222 = devm_kzalloc(&client->dev, sizeof(*iqs7222), GFP_KERNEL);
3063e505edaeSJeff LaBundy if (!iqs7222)
3064e505edaeSJeff LaBundy return -ENOMEM;
3065e505edaeSJeff LaBundy
3066e505edaeSJeff LaBundy i2c_set_clientdata(client, iqs7222);
3067e505edaeSJeff LaBundy iqs7222->client = client;
3068e505edaeSJeff LaBundy
3069e505edaeSJeff LaBundy iqs7222->keypad = devm_input_allocate_device(&client->dev);
3070e505edaeSJeff LaBundy if (!iqs7222->keypad)
3071e505edaeSJeff LaBundy return -ENOMEM;
3072e505edaeSJeff LaBundy
3073e505edaeSJeff LaBundy iqs7222->keypad->name = client->name;
3074e505edaeSJeff LaBundy iqs7222->keypad->id.bustype = BUS_I2C;
3075e505edaeSJeff LaBundy
3076e505edaeSJeff LaBundy /*
3077e505edaeSJeff LaBundy * The RDY pin behaves as an interrupt, but must also be polled ahead
3078e505edaeSJeff LaBundy * of unsolicited I2C communication. As such, it is first opened as a
3079e505edaeSJeff LaBundy * GPIO and then passed to gpiod_to_irq() to register the interrupt.
3080e505edaeSJeff LaBundy */
3081e505edaeSJeff LaBundy iqs7222->irq_gpio = devm_gpiod_get(&client->dev, "irq", GPIOD_IN);
3082e505edaeSJeff LaBundy if (IS_ERR(iqs7222->irq_gpio)) {
3083e505edaeSJeff LaBundy error = PTR_ERR(iqs7222->irq_gpio);
3084e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to request IRQ GPIO: %d\n",
3085e505edaeSJeff LaBundy error);
3086e505edaeSJeff LaBundy return error;
3087e505edaeSJeff LaBundy }
3088e505edaeSJeff LaBundy
3089e505edaeSJeff LaBundy iqs7222->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
3090e505edaeSJeff LaBundy GPIOD_OUT_HIGH);
3091e505edaeSJeff LaBundy if (IS_ERR(iqs7222->reset_gpio)) {
3092e505edaeSJeff LaBundy error = PTR_ERR(iqs7222->reset_gpio);
3093e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to request reset GPIO: %d\n",
3094e505edaeSJeff LaBundy error);
3095e505edaeSJeff LaBundy return error;
3096e505edaeSJeff LaBundy }
3097e505edaeSJeff LaBundy
3098e505edaeSJeff LaBundy error = iqs7222_hard_reset(iqs7222);
3099e505edaeSJeff LaBundy if (error)
3100e505edaeSJeff LaBundy return error;
3101e505edaeSJeff LaBundy
3102e505edaeSJeff LaBundy error = iqs7222_dev_info(iqs7222);
3103e505edaeSJeff LaBundy if (error)
3104e505edaeSJeff LaBundy return error;
3105e505edaeSJeff LaBundy
3106e505edaeSJeff LaBundy error = iqs7222_dev_init(iqs7222, READ);
3107e505edaeSJeff LaBundy if (error)
3108e505edaeSJeff LaBundy return error;
3109e505edaeSJeff LaBundy
3110e505edaeSJeff LaBundy error = iqs7222_parse_all(iqs7222);
3111e505edaeSJeff LaBundy if (error)
3112e505edaeSJeff LaBundy return error;
3113e505edaeSJeff LaBundy
3114e505edaeSJeff LaBundy error = iqs7222_dev_init(iqs7222, WRITE);
3115e505edaeSJeff LaBundy if (error)
3116e505edaeSJeff LaBundy return error;
3117e505edaeSJeff LaBundy
3118e505edaeSJeff LaBundy error = iqs7222_report(iqs7222);
3119e505edaeSJeff LaBundy if (error)
3120e505edaeSJeff LaBundy return error;
3121e505edaeSJeff LaBundy
3122e505edaeSJeff LaBundy error = input_register_device(iqs7222->keypad);
3123e505edaeSJeff LaBundy if (error) {
3124e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to register device: %d\n", error);
3125e505edaeSJeff LaBundy return error;
3126e505edaeSJeff LaBundy }
3127e505edaeSJeff LaBundy
3128e505edaeSJeff LaBundy irq = gpiod_to_irq(iqs7222->irq_gpio);
3129e505edaeSJeff LaBundy if (irq < 0)
3130e505edaeSJeff LaBundy return irq;
3131e505edaeSJeff LaBundy
3132e505edaeSJeff LaBundy irq_flags = gpiod_is_active_low(iqs7222->irq_gpio) ? IRQF_TRIGGER_LOW
3133e505edaeSJeff LaBundy : IRQF_TRIGGER_HIGH;
3134e505edaeSJeff LaBundy irq_flags |= IRQF_ONESHOT;
3135e505edaeSJeff LaBundy
3136e505edaeSJeff LaBundy error = devm_request_threaded_irq(&client->dev, irq, NULL, iqs7222_irq,
3137e505edaeSJeff LaBundy irq_flags, client->name, iqs7222);
3138e505edaeSJeff LaBundy if (error)
3139e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to request IRQ: %d\n", error);
3140e505edaeSJeff LaBundy
3141e505edaeSJeff LaBundy return error;
3142e505edaeSJeff LaBundy }
3143e505edaeSJeff LaBundy
3144e505edaeSJeff LaBundy static const struct of_device_id iqs7222_of_match[] = {
3145e505edaeSJeff LaBundy { .compatible = "azoteq,iqs7222a" },
3146e505edaeSJeff LaBundy { .compatible = "azoteq,iqs7222b" },
3147e505edaeSJeff LaBundy { .compatible = "azoteq,iqs7222c" },
3148dd24e202SJeff LaBundy { .compatible = "azoteq,iqs7222d" },
3149e505edaeSJeff LaBundy { }
3150e505edaeSJeff LaBundy };
3151e505edaeSJeff LaBundy MODULE_DEVICE_TABLE(of, iqs7222_of_match);
3152e505edaeSJeff LaBundy
3153e505edaeSJeff LaBundy static struct i2c_driver iqs7222_i2c_driver = {
3154e505edaeSJeff LaBundy .driver = {
3155e505edaeSJeff LaBundy .name = "iqs7222",
3156e505edaeSJeff LaBundy .of_match_table = iqs7222_of_match,
3157e505edaeSJeff LaBundy },
3158d8bde56dSUwe Kleine-König .probe = iqs7222_probe,
3159e505edaeSJeff LaBundy };
3160e505edaeSJeff LaBundy module_i2c_driver(iqs7222_i2c_driver);
3161e505edaeSJeff LaBundy
3162e505edaeSJeff LaBundy MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
3163dd24e202SJeff LaBundy MODULE_DESCRIPTION("Azoteq IQS7222A/B/C/D Capacitive Touch Controller");
3164e505edaeSJeff LaBundy MODULE_LICENSE("GPL");
3165