xref: /openbmc/linux/drivers/input/misc/iqs7222.c (revision f83f1bda)
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*f83f1bdaSJeff LaBundy 		.fw_major = 1,
626*f83f1bdaSJeff LaBundy 		.fw_minor = 2,
627*f83f1bdaSJeff LaBundy 		.touch_link = 1770,
628*f83f1bdaSJeff LaBundy 		.allow_offset = 9,
629*f83f1bdaSJeff LaBundy 		.event_offset = 10,
630*f83f1bdaSJeff LaBundy 		.comms_offset = 11,
631*f83f1bdaSJeff LaBundy 		.reg_grps = {
632*f83f1bdaSJeff LaBundy 			[IQS7222_REG_GRP_STAT] = {
633*f83f1bdaSJeff LaBundy 				.base = IQS7222_SYS_STATUS,
634*f83f1bdaSJeff LaBundy 				.num_row = 1,
635*f83f1bdaSJeff LaBundy 				.num_col = 7,
636*f83f1bdaSJeff LaBundy 			},
637*f83f1bdaSJeff LaBundy 			[IQS7222_REG_GRP_CYCLE] = {
638*f83f1bdaSJeff LaBundy 				.base = 0x8000,
639*f83f1bdaSJeff LaBundy 				.num_row = 7,
640*f83f1bdaSJeff LaBundy 				.num_col = 2,
641*f83f1bdaSJeff LaBundy 			},
642*f83f1bdaSJeff LaBundy 			[IQS7222_REG_GRP_GLBL] = {
643*f83f1bdaSJeff LaBundy 				.base = 0x8700,
644*f83f1bdaSJeff LaBundy 				.num_row = 1,
645*f83f1bdaSJeff LaBundy 				.num_col = 3,
646*f83f1bdaSJeff LaBundy 			},
647*f83f1bdaSJeff LaBundy 			[IQS7222_REG_GRP_BTN] = {
648*f83f1bdaSJeff LaBundy 				.base = 0x9000,
649*f83f1bdaSJeff LaBundy 				.num_row = 14,
650*f83f1bdaSJeff LaBundy 				.num_col = 3,
651*f83f1bdaSJeff LaBundy 			},
652*f83f1bdaSJeff LaBundy 			[IQS7222_REG_GRP_CHAN] = {
653*f83f1bdaSJeff LaBundy 				.base = 0xA000,
654*f83f1bdaSJeff LaBundy 				.num_row = 14,
655*f83f1bdaSJeff LaBundy 				.num_col = 4,
656*f83f1bdaSJeff LaBundy 			},
657*f83f1bdaSJeff LaBundy 			[IQS7222_REG_GRP_FILT] = {
658*f83f1bdaSJeff LaBundy 				.base = 0xAE00,
659*f83f1bdaSJeff LaBundy 				.num_row = 1,
660*f83f1bdaSJeff LaBundy 				.num_col = 2,
661*f83f1bdaSJeff LaBundy 			},
662*f83f1bdaSJeff LaBundy 			[IQS7222_REG_GRP_TPAD] = {
663*f83f1bdaSJeff LaBundy 				.base = 0xB000,
664*f83f1bdaSJeff LaBundy 				.num_row = 1,
665*f83f1bdaSJeff LaBundy 				.num_col = 24,
666*f83f1bdaSJeff LaBundy 			},
667*f83f1bdaSJeff LaBundy 			[IQS7222_REG_GRP_GPIO] = {
668*f83f1bdaSJeff LaBundy 				.base = 0xC000,
669*f83f1bdaSJeff LaBundy 				.num_row = 3,
670*f83f1bdaSJeff LaBundy 				.num_col = 3,
671*f83f1bdaSJeff LaBundy 			},
672*f83f1bdaSJeff LaBundy 			[IQS7222_REG_GRP_SYS] = {
673*f83f1bdaSJeff LaBundy 				.base = IQS7222_SYS_SETUP,
674*f83f1bdaSJeff LaBundy 				.num_row = 1,
675*f83f1bdaSJeff LaBundy 				.num_col = 12,
676*f83f1bdaSJeff LaBundy 			},
677*f83f1bdaSJeff LaBundy 		},
678*f83f1bdaSJeff LaBundy 	},
679*f83f1bdaSJeff LaBundy 	{
680*f83f1bdaSJeff LaBundy 		.prod_num = IQS7222_PROD_NUM_D,
681*f83f1bdaSJeff LaBundy 		.fw_major = 1,
682*f83f1bdaSJeff LaBundy 		.fw_minor = 1,
683*f83f1bdaSJeff LaBundy 		.touch_link = 1774,
684*f83f1bdaSJeff LaBundy 		.allow_offset = 9,
685*f83f1bdaSJeff LaBundy 		.event_offset = 10,
686*f83f1bdaSJeff LaBundy 		.comms_offset = 11,
687*f83f1bdaSJeff LaBundy 		.reg_grps = {
688*f83f1bdaSJeff LaBundy 			[IQS7222_REG_GRP_STAT] = {
689*f83f1bdaSJeff LaBundy 				.base = IQS7222_SYS_STATUS,
690*f83f1bdaSJeff LaBundy 				.num_row = 1,
691*f83f1bdaSJeff LaBundy 				.num_col = 7,
692*f83f1bdaSJeff LaBundy 			},
693*f83f1bdaSJeff LaBundy 			[IQS7222_REG_GRP_CYCLE] = {
694*f83f1bdaSJeff LaBundy 				.base = 0x8000,
695*f83f1bdaSJeff LaBundy 				.num_row = 7,
696*f83f1bdaSJeff LaBundy 				.num_col = 2,
697*f83f1bdaSJeff LaBundy 			},
698*f83f1bdaSJeff LaBundy 			[IQS7222_REG_GRP_GLBL] = {
699*f83f1bdaSJeff LaBundy 				.base = 0x8700,
700*f83f1bdaSJeff LaBundy 				.num_row = 1,
701*f83f1bdaSJeff LaBundy 				.num_col = 3,
702*f83f1bdaSJeff LaBundy 			},
703*f83f1bdaSJeff LaBundy 			[IQS7222_REG_GRP_BTN] = {
704*f83f1bdaSJeff LaBundy 				.base = 0x9000,
705*f83f1bdaSJeff LaBundy 				.num_row = 14,
706*f83f1bdaSJeff LaBundy 				.num_col = 3,
707*f83f1bdaSJeff LaBundy 			},
708*f83f1bdaSJeff LaBundy 			[IQS7222_REG_GRP_CHAN] = {
709*f83f1bdaSJeff LaBundy 				.base = 0xA000,
710*f83f1bdaSJeff LaBundy 				.num_row = 14,
711*f83f1bdaSJeff LaBundy 				.num_col = 4,
712*f83f1bdaSJeff LaBundy 			},
713*f83f1bdaSJeff LaBundy 			[IQS7222_REG_GRP_FILT] = {
714*f83f1bdaSJeff LaBundy 				.base = 0xAE00,
715*f83f1bdaSJeff LaBundy 				.num_row = 1,
716*f83f1bdaSJeff LaBundy 				.num_col = 2,
717*f83f1bdaSJeff LaBundy 			},
718*f83f1bdaSJeff LaBundy 			[IQS7222_REG_GRP_TPAD] = {
719*f83f1bdaSJeff LaBundy 				.base = 0xB000,
720*f83f1bdaSJeff LaBundy 				.num_row = 1,
721*f83f1bdaSJeff LaBundy 				.num_col = 24,
722*f83f1bdaSJeff LaBundy 			},
723*f83f1bdaSJeff LaBundy 			[IQS7222_REG_GRP_GPIO] = {
724*f83f1bdaSJeff LaBundy 				.base = 0xC000,
725*f83f1bdaSJeff LaBundy 				.num_row = 3,
726*f83f1bdaSJeff LaBundy 				.num_col = 3,
727*f83f1bdaSJeff LaBundy 			},
728*f83f1bdaSJeff LaBundy 			[IQS7222_REG_GRP_SYS] = {
729*f83f1bdaSJeff LaBundy 				.base = IQS7222_SYS_SETUP,
730*f83f1bdaSJeff LaBundy 				.num_row = 1,
731*f83f1bdaSJeff LaBundy 				.num_col = 12,
732*f83f1bdaSJeff LaBundy 			},
733*f83f1bdaSJeff LaBundy 		},
734*f83f1bdaSJeff LaBundy 	},
735*f83f1bdaSJeff LaBundy 	{
736*f83f1bdaSJeff 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