xref: /linux/drivers/input/misc/iqs7222.c (revision eba697b3)
1e505edaeSJeff LaBundy // SPDX-License-Identifier: GPL-2.0-or-later
2e505edaeSJeff LaBundy /*
3e505edaeSJeff LaBundy  * Azoteq IQS7222A/B/C 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>
15e505edaeSJeff LaBundy #include <linux/interrupt.h>
16e505edaeSJeff LaBundy #include <linux/kernel.h>
17e505edaeSJeff LaBundy #include <linux/ktime.h>
18e505edaeSJeff LaBundy #include <linux/module.h>
19e505edaeSJeff LaBundy #include <linux/of_device.h>
20e505edaeSJeff LaBundy #include <linux/property.h>
21e505edaeSJeff LaBundy #include <linux/slab.h>
22e505edaeSJeff LaBundy #include <asm/unaligned.h>
23e505edaeSJeff LaBundy 
24e505edaeSJeff LaBundy #define IQS7222_PROD_NUM			0x00
25e505edaeSJeff LaBundy #define IQS7222_PROD_NUM_A			840
26e505edaeSJeff LaBundy #define IQS7222_PROD_NUM_B			698
27e505edaeSJeff LaBundy #define IQS7222_PROD_NUM_C			863
28e505edaeSJeff LaBundy 
29e505edaeSJeff LaBundy #define IQS7222_SYS_STATUS			0x10
30e505edaeSJeff LaBundy #define IQS7222_SYS_STATUS_RESET		BIT(3)
31e505edaeSJeff LaBundy #define IQS7222_SYS_STATUS_ATI_ERROR		BIT(1)
32e505edaeSJeff LaBundy #define IQS7222_SYS_STATUS_ATI_ACTIVE		BIT(0)
33e505edaeSJeff LaBundy 
34e505edaeSJeff LaBundy #define IQS7222_CHAN_SETUP_0_REF_MODE_MASK	GENMASK(15, 14)
35e505edaeSJeff LaBundy #define IQS7222_CHAN_SETUP_0_REF_MODE_FOLLOW	BIT(15)
36e505edaeSJeff LaBundy #define IQS7222_CHAN_SETUP_0_REF_MODE_REF	BIT(14)
37e505edaeSJeff LaBundy #define IQS7222_CHAN_SETUP_0_CHAN_EN		BIT(8)
38e505edaeSJeff LaBundy 
39e505edaeSJeff LaBundy #define IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK	GENMASK(2, 0)
40e505edaeSJeff LaBundy #define IQS7222_SLDR_SETUP_2_RES_MASK		GENMASK(15, 8)
41e505edaeSJeff LaBundy #define IQS7222_SLDR_SETUP_2_RES_SHIFT		8
42e505edaeSJeff LaBundy #define IQS7222_SLDR_SETUP_2_TOP_SPEED_MASK	GENMASK(7, 0)
43e505edaeSJeff LaBundy #define IQS7222_SLDR_SETUP_3_CHAN_SEL_MASK	GENMASK(9, 0)
44e505edaeSJeff LaBundy 
45e505edaeSJeff LaBundy #define IQS7222_GPIO_SETUP_0_GPIO_EN		BIT(0)
46e505edaeSJeff LaBundy 
47e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP			0xD0
48e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP_INTF_MODE_MASK	GENMASK(7, 6)
49e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP_INTF_MODE_TOUCH	BIT(7)
50e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP_INTF_MODE_EVENT	BIT(6)
51e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP_PWR_MODE_MASK		GENMASK(5, 4)
52e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP_PWR_MODE_AUTO		IQS7222_SYS_SETUP_PWR_MODE_MASK
53e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP_REDO_ATI		BIT(2)
54e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP_ACK_RESET		BIT(0)
55e505edaeSJeff LaBundy 
56e505edaeSJeff LaBundy #define IQS7222_EVENT_MASK_ATI			BIT(12)
57e505edaeSJeff LaBundy 
58e505edaeSJeff LaBundy #define IQS7222_COMMS_HOLD			BIT(0)
59e505edaeSJeff LaBundy #define IQS7222_COMMS_ERROR			0xEEEE
60e505edaeSJeff LaBundy #define IQS7222_COMMS_RETRY_MS			50
61e505edaeSJeff LaBundy #define IQS7222_COMMS_TIMEOUT_MS		100
62e505edaeSJeff LaBundy #define IQS7222_RESET_TIMEOUT_MS		250
63e505edaeSJeff LaBundy #define IQS7222_ATI_TIMEOUT_MS			2000
64e505edaeSJeff LaBundy 
65e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_STAT			8
66e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_CYCLE			3
67e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_GLBL			3
68e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_BTN			3
69e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_CHAN			6
70e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_FILT			2
71e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_SLDR			11
72e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_GPIO			3
73e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_SYS			13
74e505edaeSJeff LaBundy 
75e505edaeSJeff LaBundy #define IQS7222_MAX_CHAN			20
76e505edaeSJeff LaBundy #define IQS7222_MAX_SLDR			2
77e505edaeSJeff LaBundy 
78e505edaeSJeff LaBundy #define IQS7222_NUM_RETRIES			5
79e505edaeSJeff LaBundy #define IQS7222_REG_OFFSET			0x100
80e505edaeSJeff LaBundy 
81e505edaeSJeff LaBundy enum iqs7222_reg_key_id {
82e505edaeSJeff LaBundy 	IQS7222_REG_KEY_NONE,
83e505edaeSJeff LaBundy 	IQS7222_REG_KEY_PROX,
84e505edaeSJeff LaBundy 	IQS7222_REG_KEY_TOUCH,
85e505edaeSJeff LaBundy 	IQS7222_REG_KEY_DEBOUNCE,
86e505edaeSJeff LaBundy 	IQS7222_REG_KEY_TAP,
87e505edaeSJeff LaBundy 	IQS7222_REG_KEY_AXIAL,
88e505edaeSJeff LaBundy 	IQS7222_REG_KEY_WHEEL,
89e505edaeSJeff LaBundy 	IQS7222_REG_KEY_NO_WHEEL,
90e505edaeSJeff LaBundy 	IQS7222_REG_KEY_RESERVED
91e505edaeSJeff LaBundy };
92e505edaeSJeff LaBundy 
93e505edaeSJeff LaBundy enum iqs7222_reg_grp_id {
94e505edaeSJeff LaBundy 	IQS7222_REG_GRP_STAT,
95e505edaeSJeff LaBundy 	IQS7222_REG_GRP_CYCLE,
96e505edaeSJeff LaBundy 	IQS7222_REG_GRP_GLBL,
97e505edaeSJeff LaBundy 	IQS7222_REG_GRP_BTN,
98e505edaeSJeff LaBundy 	IQS7222_REG_GRP_CHAN,
99e505edaeSJeff LaBundy 	IQS7222_REG_GRP_FILT,
100e505edaeSJeff LaBundy 	IQS7222_REG_GRP_SLDR,
101e505edaeSJeff LaBundy 	IQS7222_REG_GRP_GPIO,
102e505edaeSJeff LaBundy 	IQS7222_REG_GRP_SYS,
103e505edaeSJeff LaBundy 	IQS7222_NUM_REG_GRPS
104e505edaeSJeff LaBundy };
105e505edaeSJeff LaBundy 
106e505edaeSJeff LaBundy static const char * const iqs7222_reg_grp_names[] = {
107e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_CYCLE] = "cycle",
108e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_CHAN] = "channel",
109e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_SLDR] = "slider",
110e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_GPIO] = "gpio",
111e505edaeSJeff LaBundy };
112e505edaeSJeff LaBundy 
113e505edaeSJeff LaBundy static const unsigned int iqs7222_max_cols[] = {
114e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_STAT] = IQS7222_MAX_COLS_STAT,
115e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_CYCLE] = IQS7222_MAX_COLS_CYCLE,
116e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_GLBL] = IQS7222_MAX_COLS_GLBL,
117e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_BTN] = IQS7222_MAX_COLS_BTN,
118e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_CHAN] = IQS7222_MAX_COLS_CHAN,
119e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_FILT] = IQS7222_MAX_COLS_FILT,
120e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_SLDR] = IQS7222_MAX_COLS_SLDR,
121e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_GPIO] = IQS7222_MAX_COLS_GPIO,
122e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_SYS] = IQS7222_MAX_COLS_SYS,
123e505edaeSJeff LaBundy };
124e505edaeSJeff LaBundy 
125e505edaeSJeff LaBundy static const unsigned int iqs7222_gpio_links[] = { 2, 5, 6, };
126e505edaeSJeff LaBundy 
127e505edaeSJeff LaBundy struct iqs7222_event_desc {
128e505edaeSJeff LaBundy 	const char *name;
129e505edaeSJeff LaBundy 	u16 mask;
130e505edaeSJeff LaBundy 	u16 val;
131e505edaeSJeff LaBundy 	u16 enable;
132e505edaeSJeff LaBundy 	enum iqs7222_reg_key_id reg_key;
133e505edaeSJeff LaBundy };
134e505edaeSJeff LaBundy 
135e505edaeSJeff LaBundy static const struct iqs7222_event_desc iqs7222_kp_events[] = {
136e505edaeSJeff LaBundy 	{
137e505edaeSJeff LaBundy 		.name = "event-prox",
138e505edaeSJeff LaBundy 		.enable = BIT(0),
139e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_PROX,
140e505edaeSJeff LaBundy 	},
141e505edaeSJeff LaBundy 	{
142e505edaeSJeff LaBundy 		.name = "event-touch",
143e505edaeSJeff LaBundy 		.enable = BIT(1),
144e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_TOUCH,
145e505edaeSJeff LaBundy 	},
146e505edaeSJeff LaBundy };
147e505edaeSJeff LaBundy 
148e505edaeSJeff LaBundy static const struct iqs7222_event_desc iqs7222_sl_events[] = {
149e505edaeSJeff LaBundy 	{ .name = "event-press", },
150e505edaeSJeff LaBundy 	{
151e505edaeSJeff LaBundy 		.name = "event-tap",
152e505edaeSJeff LaBundy 		.mask = BIT(0),
153e505edaeSJeff LaBundy 		.val = BIT(0),
154e505edaeSJeff LaBundy 		.enable = BIT(0),
155e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_TAP,
156e505edaeSJeff LaBundy 	},
157e505edaeSJeff LaBundy 	{
158e505edaeSJeff LaBundy 		.name = "event-swipe-pos",
159e505edaeSJeff LaBundy 		.mask = BIT(5) | BIT(1),
160e505edaeSJeff LaBundy 		.val = BIT(1),
161e505edaeSJeff LaBundy 		.enable = BIT(1),
162e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_AXIAL,
163e505edaeSJeff LaBundy 	},
164e505edaeSJeff LaBundy 	{
165e505edaeSJeff LaBundy 		.name = "event-swipe-neg",
166e505edaeSJeff LaBundy 		.mask = BIT(5) | BIT(1),
167e505edaeSJeff LaBundy 		.val = BIT(5) | BIT(1),
168e505edaeSJeff LaBundy 		.enable = BIT(1),
169e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_AXIAL,
170e505edaeSJeff LaBundy 	},
171e505edaeSJeff LaBundy 	{
172e505edaeSJeff LaBundy 		.name = "event-flick-pos",
173e505edaeSJeff LaBundy 		.mask = BIT(5) | BIT(2),
174e505edaeSJeff LaBundy 		.val = BIT(2),
175e505edaeSJeff LaBundy 		.enable = BIT(2),
176e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_AXIAL,
177e505edaeSJeff LaBundy 	},
178e505edaeSJeff LaBundy 	{
179e505edaeSJeff LaBundy 		.name = "event-flick-neg",
180e505edaeSJeff LaBundy 		.mask = BIT(5) | BIT(2),
181e505edaeSJeff LaBundy 		.val = BIT(5) | BIT(2),
182e505edaeSJeff LaBundy 		.enable = BIT(2),
183e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_AXIAL,
184e505edaeSJeff LaBundy 	},
185e505edaeSJeff LaBundy };
186e505edaeSJeff LaBundy 
187e505edaeSJeff LaBundy struct iqs7222_reg_grp_desc {
188e505edaeSJeff LaBundy 	u16 base;
189e505edaeSJeff LaBundy 	int num_row;
190e505edaeSJeff LaBundy 	int num_col;
191e505edaeSJeff LaBundy };
192e505edaeSJeff LaBundy 
193e505edaeSJeff LaBundy struct iqs7222_dev_desc {
194e505edaeSJeff LaBundy 	u16 prod_num;
195e505edaeSJeff LaBundy 	u16 fw_major;
196e505edaeSJeff LaBundy 	u16 fw_minor;
197e505edaeSJeff LaBundy 	u16 sldr_res;
198e505edaeSJeff LaBundy 	u16 touch_link;
199e505edaeSJeff LaBundy 	u16 wheel_enable;
200e505edaeSJeff LaBundy 	int allow_offset;
201e505edaeSJeff LaBundy 	int event_offset;
202e505edaeSJeff LaBundy 	int comms_offset;
203e505edaeSJeff LaBundy 	struct iqs7222_reg_grp_desc reg_grps[IQS7222_NUM_REG_GRPS];
204e505edaeSJeff LaBundy };
205e505edaeSJeff LaBundy 
206e505edaeSJeff LaBundy static const struct iqs7222_dev_desc iqs7222_devs[] = {
207e505edaeSJeff LaBundy 	{
208e505edaeSJeff LaBundy 		.prod_num = IQS7222_PROD_NUM_A,
209e505edaeSJeff LaBundy 		.fw_major = 1,
210e505edaeSJeff LaBundy 		.fw_minor = 12,
211e505edaeSJeff LaBundy 		.sldr_res = U8_MAX * 16,
212e505edaeSJeff LaBundy 		.touch_link = 1768,
213e505edaeSJeff LaBundy 		.allow_offset = 9,
214e505edaeSJeff LaBundy 		.event_offset = 10,
215e505edaeSJeff LaBundy 		.comms_offset = 12,
216e505edaeSJeff LaBundy 		.reg_grps = {
217e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_STAT] = {
218e505edaeSJeff LaBundy 				.base = IQS7222_SYS_STATUS,
219e505edaeSJeff LaBundy 				.num_row = 1,
220e505edaeSJeff LaBundy 				.num_col = 8,
221e505edaeSJeff LaBundy 			},
222e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_CYCLE] = {
223e505edaeSJeff LaBundy 				.base = 0x8000,
224e505edaeSJeff LaBundy 				.num_row = 7,
225e505edaeSJeff LaBundy 				.num_col = 3,
226e505edaeSJeff LaBundy 			},
227e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_GLBL] = {
228e505edaeSJeff LaBundy 				.base = 0x8700,
229e505edaeSJeff LaBundy 				.num_row = 1,
230e505edaeSJeff LaBundy 				.num_col = 3,
231e505edaeSJeff LaBundy 			},
232e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_BTN] = {
233e505edaeSJeff LaBundy 				.base = 0x9000,
234e505edaeSJeff LaBundy 				.num_row = 12,
235e505edaeSJeff LaBundy 				.num_col = 3,
236e505edaeSJeff LaBundy 			},
237e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_CHAN] = {
238e505edaeSJeff LaBundy 				.base = 0xA000,
239e505edaeSJeff LaBundy 				.num_row = 12,
240e505edaeSJeff LaBundy 				.num_col = 6,
241e505edaeSJeff LaBundy 			},
242e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_FILT] = {
243e505edaeSJeff LaBundy 				.base = 0xAC00,
244e505edaeSJeff LaBundy 				.num_row = 1,
245e505edaeSJeff LaBundy 				.num_col = 2,
246e505edaeSJeff LaBundy 			},
247e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_SLDR] = {
248e505edaeSJeff LaBundy 				.base = 0xB000,
249e505edaeSJeff LaBundy 				.num_row = 2,
250e505edaeSJeff LaBundy 				.num_col = 11,
251e505edaeSJeff LaBundy 			},
252e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_GPIO] = {
253e505edaeSJeff LaBundy 				.base = 0xC000,
254e505edaeSJeff LaBundy 				.num_row = 1,
255e505edaeSJeff LaBundy 				.num_col = 3,
256e505edaeSJeff LaBundy 			},
257e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_SYS] = {
258e505edaeSJeff LaBundy 				.base = IQS7222_SYS_SETUP,
259e505edaeSJeff LaBundy 				.num_row = 1,
260e505edaeSJeff LaBundy 				.num_col = 13,
261e505edaeSJeff LaBundy 			},
262e505edaeSJeff LaBundy 		},
263e505edaeSJeff LaBundy 	},
264e505edaeSJeff LaBundy 	{
265e505edaeSJeff LaBundy 		.prod_num = IQS7222_PROD_NUM_B,
266e505edaeSJeff LaBundy 		.fw_major = 1,
267e505edaeSJeff LaBundy 		.fw_minor = 43,
268e505edaeSJeff LaBundy 		.event_offset = 10,
269e505edaeSJeff LaBundy 		.comms_offset = 11,
270e505edaeSJeff LaBundy 		.reg_grps = {
271e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_STAT] = {
272e505edaeSJeff LaBundy 				.base = IQS7222_SYS_STATUS,
273e505edaeSJeff LaBundy 				.num_row = 1,
274e505edaeSJeff LaBundy 				.num_col = 6,
275e505edaeSJeff LaBundy 			},
276e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_CYCLE] = {
277e505edaeSJeff LaBundy 				.base = 0x8000,
278e505edaeSJeff LaBundy 				.num_row = 10,
279e505edaeSJeff LaBundy 				.num_col = 2,
280e505edaeSJeff LaBundy 			},
281e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_GLBL] = {
282e505edaeSJeff LaBundy 				.base = 0x8A00,
283e505edaeSJeff LaBundy 				.num_row = 1,
284e505edaeSJeff LaBundy 				.num_col = 3,
285e505edaeSJeff LaBundy 			},
286e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_BTN] = {
287e505edaeSJeff LaBundy 				.base = 0x9000,
288e505edaeSJeff LaBundy 				.num_row = 20,
289e505edaeSJeff LaBundy 				.num_col = 2,
290e505edaeSJeff LaBundy 			},
291e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_CHAN] = {
292e505edaeSJeff LaBundy 				.base = 0xB000,
293e505edaeSJeff LaBundy 				.num_row = 20,
294e505edaeSJeff LaBundy 				.num_col = 4,
295e505edaeSJeff LaBundy 			},
296e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_FILT] = {
297e505edaeSJeff LaBundy 				.base = 0xC400,
298e505edaeSJeff LaBundy 				.num_row = 1,
299e505edaeSJeff LaBundy 				.num_col = 2,
300e505edaeSJeff LaBundy 			},
301e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_SYS] = {
302e505edaeSJeff LaBundy 				.base = IQS7222_SYS_SETUP,
303e505edaeSJeff LaBundy 				.num_row = 1,
304e505edaeSJeff LaBundy 				.num_col = 13,
305e505edaeSJeff LaBundy 			},
306e505edaeSJeff LaBundy 		},
307e505edaeSJeff LaBundy 	},
308e505edaeSJeff LaBundy 	{
309e505edaeSJeff LaBundy 		.prod_num = IQS7222_PROD_NUM_B,
310e505edaeSJeff LaBundy 		.fw_major = 1,
311e505edaeSJeff LaBundy 		.fw_minor = 27,
312e505edaeSJeff LaBundy 		.reg_grps = {
313e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_STAT] = {
314e505edaeSJeff LaBundy 				.base = IQS7222_SYS_STATUS,
315e505edaeSJeff LaBundy 				.num_row = 1,
316e505edaeSJeff LaBundy 				.num_col = 6,
317e505edaeSJeff LaBundy 			},
318e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_CYCLE] = {
319e505edaeSJeff LaBundy 				.base = 0x8000,
320e505edaeSJeff LaBundy 				.num_row = 10,
321e505edaeSJeff LaBundy 				.num_col = 2,
322e505edaeSJeff LaBundy 			},
323e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_GLBL] = {
324e505edaeSJeff LaBundy 				.base = 0x8A00,
325e505edaeSJeff LaBundy 				.num_row = 1,
326e505edaeSJeff LaBundy 				.num_col = 3,
327e505edaeSJeff LaBundy 			},
328e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_BTN] = {
329e505edaeSJeff LaBundy 				.base = 0x9000,
330e505edaeSJeff LaBundy 				.num_row = 20,
331e505edaeSJeff LaBundy 				.num_col = 2,
332e505edaeSJeff LaBundy 			},
333e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_CHAN] = {
334e505edaeSJeff LaBundy 				.base = 0xB000,
335e505edaeSJeff LaBundy 				.num_row = 20,
336e505edaeSJeff LaBundy 				.num_col = 4,
337e505edaeSJeff LaBundy 			},
338e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_FILT] = {
339e505edaeSJeff LaBundy 				.base = 0xC400,
340e505edaeSJeff LaBundy 				.num_row = 1,
341e505edaeSJeff LaBundy 				.num_col = 2,
342e505edaeSJeff LaBundy 			},
343e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_SYS] = {
344e505edaeSJeff LaBundy 				.base = IQS7222_SYS_SETUP,
345e505edaeSJeff LaBundy 				.num_row = 1,
346e505edaeSJeff LaBundy 				.num_col = 10,
347e505edaeSJeff LaBundy 			},
348e505edaeSJeff LaBundy 		},
349e505edaeSJeff LaBundy 	},
350e505edaeSJeff LaBundy 	{
351e505edaeSJeff LaBundy 		.prod_num = IQS7222_PROD_NUM_C,
352e505edaeSJeff LaBundy 		.fw_major = 2,
353e505edaeSJeff LaBundy 		.fw_minor = 6,
354e505edaeSJeff LaBundy 		.sldr_res = U16_MAX,
355e505edaeSJeff LaBundy 		.touch_link = 1686,
356e505edaeSJeff LaBundy 		.wheel_enable = BIT(3),
357e505edaeSJeff LaBundy 		.event_offset = 9,
358e505edaeSJeff LaBundy 		.comms_offset = 10,
359e505edaeSJeff LaBundy 		.reg_grps = {
360e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_STAT] = {
361e505edaeSJeff LaBundy 				.base = IQS7222_SYS_STATUS,
362e505edaeSJeff LaBundy 				.num_row = 1,
363e505edaeSJeff LaBundy 				.num_col = 6,
364e505edaeSJeff LaBundy 			},
365e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_CYCLE] = {
366e505edaeSJeff LaBundy 				.base = 0x8000,
367e505edaeSJeff LaBundy 				.num_row = 5,
368e505edaeSJeff LaBundy 				.num_col = 3,
369e505edaeSJeff LaBundy 			},
370e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_GLBL] = {
371e505edaeSJeff LaBundy 				.base = 0x8500,
372e505edaeSJeff LaBundy 				.num_row = 1,
373e505edaeSJeff LaBundy 				.num_col = 3,
374e505edaeSJeff LaBundy 			},
375e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_BTN] = {
376e505edaeSJeff LaBundy 				.base = 0x9000,
377e505edaeSJeff LaBundy 				.num_row = 10,
378e505edaeSJeff LaBundy 				.num_col = 3,
379e505edaeSJeff LaBundy 			},
380e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_CHAN] = {
381e505edaeSJeff LaBundy 				.base = 0xA000,
382e505edaeSJeff LaBundy 				.num_row = 10,
383e505edaeSJeff LaBundy 				.num_col = 6,
384e505edaeSJeff LaBundy 			},
385e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_FILT] = {
386e505edaeSJeff LaBundy 				.base = 0xAA00,
387e505edaeSJeff LaBundy 				.num_row = 1,
388e505edaeSJeff LaBundy 				.num_col = 2,
389e505edaeSJeff LaBundy 			},
390e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_SLDR] = {
391e505edaeSJeff LaBundy 				.base = 0xB000,
392e505edaeSJeff LaBundy 				.num_row = 2,
393e505edaeSJeff LaBundy 				.num_col = 10,
394e505edaeSJeff LaBundy 			},
395e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_GPIO] = {
396e505edaeSJeff LaBundy 				.base = 0xC000,
397e505edaeSJeff LaBundy 				.num_row = 3,
398e505edaeSJeff LaBundy 				.num_col = 3,
399e505edaeSJeff LaBundy 			},
400e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_SYS] = {
401e505edaeSJeff LaBundy 				.base = IQS7222_SYS_SETUP,
402e505edaeSJeff LaBundy 				.num_row = 1,
403e505edaeSJeff LaBundy 				.num_col = 12,
404e505edaeSJeff LaBundy 			},
405e505edaeSJeff LaBundy 		},
406e505edaeSJeff LaBundy 	},
407e505edaeSJeff LaBundy 	{
408e505edaeSJeff LaBundy 		.prod_num = IQS7222_PROD_NUM_C,
409e505edaeSJeff LaBundy 		.fw_major = 1,
410e505edaeSJeff LaBundy 		.fw_minor = 13,
411e505edaeSJeff LaBundy 		.sldr_res = U16_MAX,
412e505edaeSJeff LaBundy 		.touch_link = 1674,
413e505edaeSJeff LaBundy 		.wheel_enable = BIT(3),
414e505edaeSJeff LaBundy 		.event_offset = 9,
415e505edaeSJeff LaBundy 		.comms_offset = 10,
416e505edaeSJeff LaBundy 		.reg_grps = {
417e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_STAT] = {
418e505edaeSJeff LaBundy 				.base = IQS7222_SYS_STATUS,
419e505edaeSJeff LaBundy 				.num_row = 1,
420e505edaeSJeff LaBundy 				.num_col = 6,
421e505edaeSJeff LaBundy 			},
422e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_CYCLE] = {
423e505edaeSJeff LaBundy 				.base = 0x8000,
424e505edaeSJeff LaBundy 				.num_row = 5,
425e505edaeSJeff LaBundy 				.num_col = 3,
426e505edaeSJeff LaBundy 			},
427e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_GLBL] = {
428e505edaeSJeff LaBundy 				.base = 0x8500,
429e505edaeSJeff LaBundy 				.num_row = 1,
430e505edaeSJeff LaBundy 				.num_col = 3,
431e505edaeSJeff LaBundy 			},
432e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_BTN] = {
433e505edaeSJeff LaBundy 				.base = 0x9000,
434e505edaeSJeff LaBundy 				.num_row = 10,
435e505edaeSJeff LaBundy 				.num_col = 3,
436e505edaeSJeff LaBundy 			},
437e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_CHAN] = {
438e505edaeSJeff LaBundy 				.base = 0xA000,
439e505edaeSJeff LaBundy 				.num_row = 10,
440e505edaeSJeff LaBundy 				.num_col = 6,
441e505edaeSJeff LaBundy 			},
442e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_FILT] = {
443e505edaeSJeff LaBundy 				.base = 0xAA00,
444e505edaeSJeff LaBundy 				.num_row = 1,
445e505edaeSJeff LaBundy 				.num_col = 2,
446e505edaeSJeff LaBundy 			},
447e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_SLDR] = {
448e505edaeSJeff LaBundy 				.base = 0xB000,
449e505edaeSJeff LaBundy 				.num_row = 2,
450e505edaeSJeff LaBundy 				.num_col = 10,
451e505edaeSJeff LaBundy 			},
452e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_GPIO] = {
453e505edaeSJeff LaBundy 				.base = 0xC000,
454e505edaeSJeff LaBundy 				.num_row = 1,
455e505edaeSJeff LaBundy 				.num_col = 3,
456e505edaeSJeff LaBundy 			},
457e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_SYS] = {
458e505edaeSJeff LaBundy 				.base = IQS7222_SYS_SETUP,
459e505edaeSJeff LaBundy 				.num_row = 1,
460e505edaeSJeff LaBundy 				.num_col = 11,
461e505edaeSJeff LaBundy 			},
462e505edaeSJeff LaBundy 		},
463e505edaeSJeff LaBundy 	},
464e505edaeSJeff LaBundy };
465e505edaeSJeff LaBundy 
466e505edaeSJeff LaBundy struct iqs7222_prop_desc {
467e505edaeSJeff LaBundy 	const char *name;
468e505edaeSJeff LaBundy 	enum iqs7222_reg_grp_id reg_grp;
469e505edaeSJeff LaBundy 	enum iqs7222_reg_key_id reg_key;
470e505edaeSJeff LaBundy 	int reg_offset;
471e505edaeSJeff LaBundy 	int reg_shift;
472e505edaeSJeff LaBundy 	int reg_width;
473e505edaeSJeff LaBundy 	int val_pitch;
474e505edaeSJeff LaBundy 	int val_min;
475e505edaeSJeff LaBundy 	int val_max;
476e505edaeSJeff LaBundy 	bool invert;
477e505edaeSJeff LaBundy 	const char *label;
478e505edaeSJeff LaBundy };
479e505edaeSJeff LaBundy 
480e505edaeSJeff LaBundy static const struct iqs7222_prop_desc iqs7222_props[] = {
481e505edaeSJeff LaBundy 	{
482e505edaeSJeff LaBundy 		.name = "azoteq,conv-period",
483e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CYCLE,
484e505edaeSJeff LaBundy 		.reg_offset = 0,
485e505edaeSJeff LaBundy 		.reg_shift = 8,
486e505edaeSJeff LaBundy 		.reg_width = 8,
487e505edaeSJeff LaBundy 		.label = "conversion period",
488e505edaeSJeff LaBundy 	},
489e505edaeSJeff LaBundy 	{
490e505edaeSJeff LaBundy 		.name = "azoteq,conv-frac",
491e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CYCLE,
492e505edaeSJeff LaBundy 		.reg_offset = 0,
493e505edaeSJeff LaBundy 		.reg_shift = 0,
494e505edaeSJeff LaBundy 		.reg_width = 8,
495e505edaeSJeff LaBundy 		.label = "conversion frequency fractional divider",
496e505edaeSJeff LaBundy 	},
497e505edaeSJeff LaBundy 	{
498e505edaeSJeff LaBundy 		.name = "azoteq,rx-float-inactive",
499e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CYCLE,
500e505edaeSJeff LaBundy 		.reg_offset = 1,
501e505edaeSJeff LaBundy 		.reg_shift = 6,
502e505edaeSJeff LaBundy 		.reg_width = 1,
503e505edaeSJeff LaBundy 		.invert = true,
504e505edaeSJeff LaBundy 	},
505e505edaeSJeff LaBundy 	{
506e505edaeSJeff LaBundy 		.name = "azoteq,dead-time-enable",
507e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CYCLE,
508e505edaeSJeff LaBundy 		.reg_offset = 1,
509e505edaeSJeff LaBundy 		.reg_shift = 5,
510e505edaeSJeff LaBundy 		.reg_width = 1,
511e505edaeSJeff LaBundy 	},
512e505edaeSJeff LaBundy 	{
513e505edaeSJeff LaBundy 		.name = "azoteq,tx-freq-fosc",
514e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CYCLE,
515e505edaeSJeff LaBundy 		.reg_offset = 1,
516e505edaeSJeff LaBundy 		.reg_shift = 4,
517e505edaeSJeff LaBundy 		.reg_width = 1,
518e505edaeSJeff LaBundy 	},
519e505edaeSJeff LaBundy 	{
520e505edaeSJeff LaBundy 		.name = "azoteq,vbias-enable",
521e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CYCLE,
522e505edaeSJeff LaBundy 		.reg_offset = 1,
523e505edaeSJeff LaBundy 		.reg_shift = 3,
524e505edaeSJeff LaBundy 		.reg_width = 1,
525e505edaeSJeff LaBundy 	},
526e505edaeSJeff LaBundy 	{
527e505edaeSJeff LaBundy 		.name = "azoteq,sense-mode",
528e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CYCLE,
529e505edaeSJeff LaBundy 		.reg_offset = 1,
530e505edaeSJeff LaBundy 		.reg_shift = 0,
531e505edaeSJeff LaBundy 		.reg_width = 3,
532e505edaeSJeff LaBundy 		.val_max = 3,
533e505edaeSJeff LaBundy 		.label = "sensing mode",
534e505edaeSJeff LaBundy 	},
535e505edaeSJeff LaBundy 	{
536e505edaeSJeff LaBundy 		.name = "azoteq,iref-enable",
537e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CYCLE,
538e505edaeSJeff LaBundy 		.reg_offset = 2,
539e505edaeSJeff LaBundy 		.reg_shift = 10,
540e505edaeSJeff LaBundy 		.reg_width = 1,
541e505edaeSJeff LaBundy 	},
542e505edaeSJeff LaBundy 	{
543e505edaeSJeff LaBundy 		.name = "azoteq,iref-level",
544e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CYCLE,
545e505edaeSJeff LaBundy 		.reg_offset = 2,
546e505edaeSJeff LaBundy 		.reg_shift = 4,
547e505edaeSJeff LaBundy 		.reg_width = 4,
548e505edaeSJeff LaBundy 		.label = "current reference level",
549e505edaeSJeff LaBundy 	},
550e505edaeSJeff LaBundy 	{
551e505edaeSJeff LaBundy 		.name = "azoteq,iref-trim",
552e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CYCLE,
553e505edaeSJeff LaBundy 		.reg_offset = 2,
554e505edaeSJeff LaBundy 		.reg_shift = 0,
555e505edaeSJeff LaBundy 		.reg_width = 4,
556e505edaeSJeff LaBundy 		.label = "current reference trim",
557e505edaeSJeff LaBundy 	},
558e505edaeSJeff LaBundy 	{
559e505edaeSJeff LaBundy 		.name = "azoteq,rf-filt-enable",
560e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_GLBL,
561e505edaeSJeff LaBundy 		.reg_offset = 0,
562e505edaeSJeff LaBundy 		.reg_shift = 15,
563e505edaeSJeff LaBundy 		.reg_width = 1,
564e505edaeSJeff LaBundy 	},
565e505edaeSJeff LaBundy 	{
566e505edaeSJeff LaBundy 		.name = "azoteq,max-counts",
567e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_GLBL,
568e505edaeSJeff LaBundy 		.reg_offset = 0,
569e505edaeSJeff LaBundy 		.reg_shift = 13,
570e505edaeSJeff LaBundy 		.reg_width = 2,
571e505edaeSJeff LaBundy 		.label = "maximum counts",
572e505edaeSJeff LaBundy 	},
573e505edaeSJeff LaBundy 	{
574e505edaeSJeff LaBundy 		.name = "azoteq,auto-mode",
575e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_GLBL,
576e505edaeSJeff LaBundy 		.reg_offset = 0,
577e505edaeSJeff LaBundy 		.reg_shift = 2,
578e505edaeSJeff LaBundy 		.reg_width = 2,
579e505edaeSJeff LaBundy 		.label = "number of conversions",
580e505edaeSJeff LaBundy 	},
581e505edaeSJeff LaBundy 	{
582e505edaeSJeff LaBundy 		.name = "azoteq,ati-frac-div-fine",
583e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_GLBL,
584e505edaeSJeff LaBundy 		.reg_offset = 1,
585e505edaeSJeff LaBundy 		.reg_shift = 9,
586e505edaeSJeff LaBundy 		.reg_width = 5,
587e505edaeSJeff LaBundy 		.label = "ATI fine fractional divider",
588e505edaeSJeff LaBundy 	},
589e505edaeSJeff LaBundy 	{
590e505edaeSJeff LaBundy 		.name = "azoteq,ati-frac-div-coarse",
591e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_GLBL,
592e505edaeSJeff LaBundy 		.reg_offset = 1,
593e505edaeSJeff LaBundy 		.reg_shift = 0,
594e505edaeSJeff LaBundy 		.reg_width = 5,
595e505edaeSJeff LaBundy 		.label = "ATI coarse fractional divider",
596e505edaeSJeff LaBundy 	},
597e505edaeSJeff LaBundy 	{
598e505edaeSJeff LaBundy 		.name = "azoteq,ati-comp-select",
599e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_GLBL,
600e505edaeSJeff LaBundy 		.reg_offset = 2,
601e505edaeSJeff LaBundy 		.reg_shift = 0,
602e505edaeSJeff LaBundy 		.reg_width = 10,
603e505edaeSJeff LaBundy 		.label = "ATI compensation selection",
604e505edaeSJeff LaBundy 	},
605e505edaeSJeff LaBundy 	{
606e505edaeSJeff LaBundy 		.name = "azoteq,ati-band",
607e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
608e505edaeSJeff LaBundy 		.reg_offset = 0,
609e505edaeSJeff LaBundy 		.reg_shift = 12,
610e505edaeSJeff LaBundy 		.reg_width = 2,
611e505edaeSJeff LaBundy 		.label = "ATI band",
612e505edaeSJeff LaBundy 	},
613e505edaeSJeff LaBundy 	{
614e505edaeSJeff LaBundy 		.name = "azoteq,global-halt",
615e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
616e505edaeSJeff LaBundy 		.reg_offset = 0,
617e505edaeSJeff LaBundy 		.reg_shift = 11,
618e505edaeSJeff LaBundy 		.reg_width = 1,
619e505edaeSJeff LaBundy 	},
620e505edaeSJeff LaBundy 	{
621e505edaeSJeff LaBundy 		.name = "azoteq,invert-enable",
622e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
623e505edaeSJeff LaBundy 		.reg_offset = 0,
624e505edaeSJeff LaBundy 		.reg_shift = 10,
625e505edaeSJeff LaBundy 		.reg_width = 1,
626e505edaeSJeff LaBundy 	},
627e505edaeSJeff LaBundy 	{
628e505edaeSJeff LaBundy 		.name = "azoteq,dual-direction",
629e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
630e505edaeSJeff LaBundy 		.reg_offset = 0,
631e505edaeSJeff LaBundy 		.reg_shift = 9,
632e505edaeSJeff LaBundy 		.reg_width = 1,
633e505edaeSJeff LaBundy 	},
634e505edaeSJeff LaBundy 	{
635e505edaeSJeff LaBundy 		.name = "azoteq,samp-cap-double",
636e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
637e505edaeSJeff LaBundy 		.reg_offset = 0,
638e505edaeSJeff LaBundy 		.reg_shift = 3,
639e505edaeSJeff LaBundy 		.reg_width = 1,
640e505edaeSJeff LaBundy 	},
641e505edaeSJeff LaBundy 	{
642e505edaeSJeff LaBundy 		.name = "azoteq,vref-half",
643e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
644e505edaeSJeff LaBundy 		.reg_offset = 0,
645e505edaeSJeff LaBundy 		.reg_shift = 2,
646e505edaeSJeff LaBundy 		.reg_width = 1,
647e505edaeSJeff LaBundy 	},
648e505edaeSJeff LaBundy 	{
649e505edaeSJeff LaBundy 		.name = "azoteq,proj-bias",
650e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
651e505edaeSJeff LaBundy 		.reg_offset = 0,
652e505edaeSJeff LaBundy 		.reg_shift = 0,
653e505edaeSJeff LaBundy 		.reg_width = 2,
654e505edaeSJeff LaBundy 		.label = "projected bias current",
655e505edaeSJeff LaBundy 	},
656e505edaeSJeff LaBundy 	{
657e505edaeSJeff LaBundy 		.name = "azoteq,ati-target",
658e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
659e505edaeSJeff LaBundy 		.reg_offset = 1,
660e505edaeSJeff LaBundy 		.reg_shift = 8,
661e505edaeSJeff LaBundy 		.reg_width = 8,
662e505edaeSJeff LaBundy 		.val_pitch = 8,
663e505edaeSJeff LaBundy 		.label = "ATI target",
664e505edaeSJeff LaBundy 	},
665e505edaeSJeff LaBundy 	{
666e505edaeSJeff LaBundy 		.name = "azoteq,ati-base",
667e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
668e505edaeSJeff LaBundy 		.reg_offset = 1,
669e505edaeSJeff LaBundy 		.reg_shift = 3,
670e505edaeSJeff LaBundy 		.reg_width = 5,
671e505edaeSJeff LaBundy 		.val_pitch = 16,
672e505edaeSJeff LaBundy 		.label = "ATI base",
673e505edaeSJeff LaBundy 	},
674e505edaeSJeff LaBundy 	{
675e505edaeSJeff LaBundy 		.name = "azoteq,ati-mode",
676e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
677e505edaeSJeff LaBundy 		.reg_offset = 1,
678e505edaeSJeff LaBundy 		.reg_shift = 0,
679e505edaeSJeff LaBundy 		.reg_width = 3,
680e505edaeSJeff LaBundy 		.val_max = 5,
681e505edaeSJeff LaBundy 		.label = "ATI mode",
682e505edaeSJeff LaBundy 	},
683e505edaeSJeff LaBundy 	{
684e505edaeSJeff LaBundy 		.name = "azoteq,ati-frac-div-fine",
685e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
686e505edaeSJeff LaBundy 		.reg_offset = 2,
687e505edaeSJeff LaBundy 		.reg_shift = 9,
688e505edaeSJeff LaBundy 		.reg_width = 5,
689e505edaeSJeff LaBundy 		.label = "ATI fine fractional divider",
690e505edaeSJeff LaBundy 	},
691e505edaeSJeff LaBundy 	{
692e505edaeSJeff LaBundy 		.name = "azoteq,ati-frac-mult-coarse",
693e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
694e505edaeSJeff LaBundy 		.reg_offset = 2,
695e505edaeSJeff LaBundy 		.reg_shift = 5,
696e505edaeSJeff LaBundy 		.reg_width = 4,
697e505edaeSJeff LaBundy 		.label = "ATI coarse fractional multiplier",
698e505edaeSJeff LaBundy 	},
699e505edaeSJeff LaBundy 	{
700e505edaeSJeff LaBundy 		.name = "azoteq,ati-frac-div-coarse",
701e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
702e505edaeSJeff LaBundy 		.reg_offset = 2,
703e505edaeSJeff LaBundy 		.reg_shift = 0,
704e505edaeSJeff LaBundy 		.reg_width = 5,
705e505edaeSJeff LaBundy 		.label = "ATI coarse fractional divider",
706e505edaeSJeff LaBundy 	},
707e505edaeSJeff LaBundy 	{
708e505edaeSJeff LaBundy 		.name = "azoteq,ati-comp-div",
709e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
710e505edaeSJeff LaBundy 		.reg_offset = 3,
711e505edaeSJeff LaBundy 		.reg_shift = 11,
712e505edaeSJeff LaBundy 		.reg_width = 5,
713e505edaeSJeff LaBundy 		.label = "ATI compensation divider",
714e505edaeSJeff LaBundy 	},
715e505edaeSJeff LaBundy 	{
716e505edaeSJeff LaBundy 		.name = "azoteq,ati-comp-select",
717e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
718e505edaeSJeff LaBundy 		.reg_offset = 3,
719e505edaeSJeff LaBundy 		.reg_shift = 0,
720e505edaeSJeff LaBundy 		.reg_width = 10,
721e505edaeSJeff LaBundy 		.label = "ATI compensation selection",
722e505edaeSJeff LaBundy 	},
723e505edaeSJeff LaBundy 	{
724e505edaeSJeff LaBundy 		.name = "azoteq,debounce-exit",
725e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_BTN,
726e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_DEBOUNCE,
727e505edaeSJeff LaBundy 		.reg_offset = 0,
728e505edaeSJeff LaBundy 		.reg_shift = 12,
729e505edaeSJeff LaBundy 		.reg_width = 4,
730e505edaeSJeff LaBundy 		.label = "debounce exit factor",
731e505edaeSJeff LaBundy 	},
732e505edaeSJeff LaBundy 	{
733e505edaeSJeff LaBundy 		.name = "azoteq,debounce-enter",
734e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_BTN,
735e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_DEBOUNCE,
736e505edaeSJeff LaBundy 		.reg_offset = 0,
737e505edaeSJeff LaBundy 		.reg_shift = 8,
738e505edaeSJeff LaBundy 		.reg_width = 4,
739e505edaeSJeff LaBundy 		.label = "debounce entrance factor",
740e505edaeSJeff LaBundy 	},
741e505edaeSJeff LaBundy 	{
742e505edaeSJeff LaBundy 		.name = "azoteq,thresh",
743e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_BTN,
744e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_PROX,
745e505edaeSJeff LaBundy 		.reg_offset = 0,
746e505edaeSJeff LaBundy 		.reg_shift = 0,
747e505edaeSJeff LaBundy 		.reg_width = 8,
748e505edaeSJeff LaBundy 		.val_max = 127,
749e505edaeSJeff LaBundy 		.label = "threshold",
750e505edaeSJeff LaBundy 	},
751e505edaeSJeff LaBundy 	{
752e505edaeSJeff LaBundy 		.name = "azoteq,thresh",
753e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_BTN,
754e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_TOUCH,
755e505edaeSJeff LaBundy 		.reg_offset = 1,
756e505edaeSJeff LaBundy 		.reg_shift = 0,
757e505edaeSJeff LaBundy 		.reg_width = 8,
758e505edaeSJeff LaBundy 		.label = "threshold",
759e505edaeSJeff LaBundy 	},
760e505edaeSJeff LaBundy 	{
761e505edaeSJeff LaBundy 		.name = "azoteq,hyst",
762e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_BTN,
763e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_TOUCH,
764e505edaeSJeff LaBundy 		.reg_offset = 1,
765e505edaeSJeff LaBundy 		.reg_shift = 8,
766e505edaeSJeff LaBundy 		.reg_width = 8,
767e505edaeSJeff LaBundy 		.label = "hysteresis",
768e505edaeSJeff LaBundy 	},
769e505edaeSJeff LaBundy 	{
770e505edaeSJeff LaBundy 		.name = "azoteq,lta-beta-lp",
771e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_FILT,
772e505edaeSJeff LaBundy 		.reg_offset = 0,
773e505edaeSJeff LaBundy 		.reg_shift = 12,
774e505edaeSJeff LaBundy 		.reg_width = 4,
775e505edaeSJeff LaBundy 		.label = "low-power mode long-term average beta",
776e505edaeSJeff LaBundy 	},
777e505edaeSJeff LaBundy 	{
778e505edaeSJeff LaBundy 		.name = "azoteq,lta-beta-np",
779e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_FILT,
780e505edaeSJeff LaBundy 		.reg_offset = 0,
781e505edaeSJeff LaBundy 		.reg_shift = 8,
782e505edaeSJeff LaBundy 		.reg_width = 4,
783e505edaeSJeff LaBundy 		.label = "normal-power mode long-term average beta",
784e505edaeSJeff LaBundy 	},
785e505edaeSJeff LaBundy 	{
786e505edaeSJeff LaBundy 		.name = "azoteq,counts-beta-lp",
787e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_FILT,
788e505edaeSJeff LaBundy 		.reg_offset = 0,
789e505edaeSJeff LaBundy 		.reg_shift = 4,
790e505edaeSJeff LaBundy 		.reg_width = 4,
791e505edaeSJeff LaBundy 		.label = "low-power mode counts beta",
792e505edaeSJeff LaBundy 	},
793e505edaeSJeff LaBundy 	{
794e505edaeSJeff LaBundy 		.name = "azoteq,counts-beta-np",
795e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_FILT,
796e505edaeSJeff LaBundy 		.reg_offset = 0,
797e505edaeSJeff LaBundy 		.reg_shift = 0,
798e505edaeSJeff LaBundy 		.reg_width = 4,
799e505edaeSJeff LaBundy 		.label = "normal-power mode counts beta",
800e505edaeSJeff LaBundy 	},
801e505edaeSJeff LaBundy 	{
802e505edaeSJeff LaBundy 		.name = "azoteq,lta-fast-beta-lp",
803e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_FILT,
804e505edaeSJeff LaBundy 		.reg_offset = 1,
805e505edaeSJeff LaBundy 		.reg_shift = 4,
806e505edaeSJeff LaBundy 		.reg_width = 4,
807e505edaeSJeff LaBundy 		.label = "low-power mode long-term average fast beta",
808e505edaeSJeff LaBundy 	},
809e505edaeSJeff LaBundy 	{
810e505edaeSJeff LaBundy 		.name = "azoteq,lta-fast-beta-np",
811e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_FILT,
812e505edaeSJeff LaBundy 		.reg_offset = 1,
813e505edaeSJeff LaBundy 		.reg_shift = 0,
814e505edaeSJeff LaBundy 		.reg_width = 4,
815e505edaeSJeff LaBundy 		.label = "normal-power mode long-term average fast beta",
816e505edaeSJeff LaBundy 	},
817e505edaeSJeff LaBundy 	{
818e505edaeSJeff LaBundy 		.name = "azoteq,lower-cal",
819e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
820e505edaeSJeff LaBundy 		.reg_offset = 0,
821e505edaeSJeff LaBundy 		.reg_shift = 8,
822e505edaeSJeff LaBundy 		.reg_width = 8,
823e505edaeSJeff LaBundy 		.label = "lower calibration",
824e505edaeSJeff LaBundy 	},
825e505edaeSJeff LaBundy 	{
826e505edaeSJeff LaBundy 		.name = "azoteq,static-beta",
827e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
828e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_NO_WHEEL,
829e505edaeSJeff LaBundy 		.reg_offset = 0,
830e505edaeSJeff LaBundy 		.reg_shift = 6,
831e505edaeSJeff LaBundy 		.reg_width = 1,
832e505edaeSJeff LaBundy 	},
833e505edaeSJeff LaBundy 	{
834e505edaeSJeff LaBundy 		.name = "azoteq,bottom-beta",
835e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
836e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_NO_WHEEL,
837e505edaeSJeff LaBundy 		.reg_offset = 0,
838e505edaeSJeff LaBundy 		.reg_shift = 3,
839e505edaeSJeff LaBundy 		.reg_width = 3,
840e505edaeSJeff LaBundy 		.label = "bottom beta",
841e505edaeSJeff LaBundy 	},
842e505edaeSJeff LaBundy 	{
843e505edaeSJeff LaBundy 		.name = "azoteq,static-beta",
844e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
845e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_WHEEL,
846e505edaeSJeff LaBundy 		.reg_offset = 0,
847e505edaeSJeff LaBundy 		.reg_shift = 7,
848e505edaeSJeff LaBundy 		.reg_width = 1,
849e505edaeSJeff LaBundy 	},
850e505edaeSJeff LaBundy 	{
851e505edaeSJeff LaBundy 		.name = "azoteq,bottom-beta",
852e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
853e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_WHEEL,
854e505edaeSJeff LaBundy 		.reg_offset = 0,
855e505edaeSJeff LaBundy 		.reg_shift = 4,
856e505edaeSJeff LaBundy 		.reg_width = 3,
857e505edaeSJeff LaBundy 		.label = "bottom beta",
858e505edaeSJeff LaBundy 	},
859e505edaeSJeff LaBundy 	{
860e505edaeSJeff LaBundy 		.name = "azoteq,bottom-speed",
861e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
862e505edaeSJeff LaBundy 		.reg_offset = 1,
863e505edaeSJeff LaBundy 		.reg_shift = 8,
864e505edaeSJeff LaBundy 		.reg_width = 8,
865e505edaeSJeff LaBundy 		.label = "bottom speed",
866e505edaeSJeff LaBundy 	},
867e505edaeSJeff LaBundy 	{
868e505edaeSJeff LaBundy 		.name = "azoteq,upper-cal",
869e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
870e505edaeSJeff LaBundy 		.reg_offset = 1,
871e505edaeSJeff LaBundy 		.reg_shift = 0,
872e505edaeSJeff LaBundy 		.reg_width = 8,
873e505edaeSJeff LaBundy 		.label = "upper calibration",
874e505edaeSJeff LaBundy 	},
875e505edaeSJeff LaBundy 	{
876e505edaeSJeff LaBundy 		.name = "azoteq,gesture-max-ms",
877e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
878e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_TAP,
879e505edaeSJeff LaBundy 		.reg_offset = 9,
880e505edaeSJeff LaBundy 		.reg_shift = 8,
881e505edaeSJeff LaBundy 		.reg_width = 8,
882e505edaeSJeff LaBundy 		.val_pitch = 4,
883e505edaeSJeff LaBundy 		.label = "maximum gesture time",
884e505edaeSJeff LaBundy 	},
885e505edaeSJeff LaBundy 	{
886e505edaeSJeff LaBundy 		.name = "azoteq,gesture-min-ms",
887e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
888e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_TAP,
889e505edaeSJeff LaBundy 		.reg_offset = 9,
890e505edaeSJeff LaBundy 		.reg_shift = 3,
891e505edaeSJeff LaBundy 		.reg_width = 5,
892e505edaeSJeff LaBundy 		.val_pitch = 4,
893e505edaeSJeff LaBundy 		.label = "minimum gesture time",
894e505edaeSJeff LaBundy 	},
895e505edaeSJeff LaBundy 	{
896e505edaeSJeff LaBundy 		.name = "azoteq,gesture-dist",
897e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
898e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_AXIAL,
899e505edaeSJeff LaBundy 		.reg_offset = 10,
900e505edaeSJeff LaBundy 		.reg_shift = 8,
901e505edaeSJeff LaBundy 		.reg_width = 8,
902e505edaeSJeff LaBundy 		.val_pitch = 16,
903e505edaeSJeff LaBundy 		.label = "gesture distance",
904e505edaeSJeff LaBundy 	},
905e505edaeSJeff LaBundy 	{
906e505edaeSJeff LaBundy 		.name = "azoteq,gesture-max-ms",
907e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
908e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_AXIAL,
909e505edaeSJeff LaBundy 		.reg_offset = 10,
910e505edaeSJeff LaBundy 		.reg_shift = 0,
911e505edaeSJeff LaBundy 		.reg_width = 8,
912e505edaeSJeff LaBundy 		.val_pitch = 4,
913e505edaeSJeff LaBundy 		.label = "maximum gesture time",
914e505edaeSJeff LaBundy 	},
915e505edaeSJeff LaBundy 	{
916e505edaeSJeff LaBundy 		.name = "drive-open-drain",
917e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_GPIO,
918e505edaeSJeff LaBundy 		.reg_offset = 0,
919e505edaeSJeff LaBundy 		.reg_shift = 1,
920e505edaeSJeff LaBundy 		.reg_width = 1,
921e505edaeSJeff LaBundy 	},
922e505edaeSJeff LaBundy 	{
923e505edaeSJeff LaBundy 		.name = "azoteq,timeout-ati-ms",
924e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SYS,
925e505edaeSJeff LaBundy 		.reg_offset = 1,
926e505edaeSJeff LaBundy 		.reg_shift = 0,
927e505edaeSJeff LaBundy 		.reg_width = 16,
928e505edaeSJeff LaBundy 		.val_pitch = 500,
929e505edaeSJeff LaBundy 		.label = "ATI error timeout",
930e505edaeSJeff LaBundy 	},
931e505edaeSJeff LaBundy 	{
932e505edaeSJeff LaBundy 		.name = "azoteq,rate-ati-ms",
933e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SYS,
934e505edaeSJeff LaBundy 		.reg_offset = 2,
935e505edaeSJeff LaBundy 		.reg_shift = 0,
936e505edaeSJeff LaBundy 		.reg_width = 16,
937e505edaeSJeff LaBundy 		.label = "ATI report rate",
938e505edaeSJeff LaBundy 	},
939e505edaeSJeff LaBundy 	{
940e505edaeSJeff LaBundy 		.name = "azoteq,timeout-np-ms",
941e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SYS,
942e505edaeSJeff LaBundy 		.reg_offset = 3,
943e505edaeSJeff LaBundy 		.reg_shift = 0,
944e505edaeSJeff LaBundy 		.reg_width = 16,
945e505edaeSJeff LaBundy 		.label = "normal-power mode timeout",
946e505edaeSJeff LaBundy 	},
947e505edaeSJeff LaBundy 	{
948e505edaeSJeff LaBundy 		.name = "azoteq,rate-np-ms",
949e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SYS,
950e505edaeSJeff LaBundy 		.reg_offset = 4,
951e505edaeSJeff LaBundy 		.reg_shift = 0,
952e505edaeSJeff LaBundy 		.reg_width = 16,
953e505edaeSJeff LaBundy 		.val_max = 3000,
954e505edaeSJeff LaBundy 		.label = "normal-power mode report rate",
955e505edaeSJeff LaBundy 	},
956e505edaeSJeff LaBundy 	{
957e505edaeSJeff LaBundy 		.name = "azoteq,timeout-lp-ms",
958e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SYS,
959e505edaeSJeff LaBundy 		.reg_offset = 5,
960e505edaeSJeff LaBundy 		.reg_shift = 0,
961e505edaeSJeff LaBundy 		.reg_width = 16,
962e505edaeSJeff LaBundy 		.label = "low-power mode timeout",
963e505edaeSJeff LaBundy 	},
964e505edaeSJeff LaBundy 	{
965e505edaeSJeff LaBundy 		.name = "azoteq,rate-lp-ms",
966e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SYS,
967e505edaeSJeff LaBundy 		.reg_offset = 6,
968e505edaeSJeff LaBundy 		.reg_shift = 0,
969e505edaeSJeff LaBundy 		.reg_width = 16,
970e505edaeSJeff LaBundy 		.val_max = 3000,
971e505edaeSJeff LaBundy 		.label = "low-power mode report rate",
972e505edaeSJeff LaBundy 	},
973e505edaeSJeff LaBundy 	{
974e505edaeSJeff LaBundy 		.name = "azoteq,timeout-ulp-ms",
975e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SYS,
976e505edaeSJeff LaBundy 		.reg_offset = 7,
977e505edaeSJeff LaBundy 		.reg_shift = 0,
978e505edaeSJeff LaBundy 		.reg_width = 16,
979e505edaeSJeff LaBundy 		.label = "ultra-low-power mode timeout",
980e505edaeSJeff LaBundy 	},
981e505edaeSJeff LaBundy 	{
982e505edaeSJeff LaBundy 		.name = "azoteq,rate-ulp-ms",
983e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SYS,
984e505edaeSJeff LaBundy 		.reg_offset = 8,
985e505edaeSJeff LaBundy 		.reg_shift = 0,
986e505edaeSJeff LaBundy 		.reg_width = 16,
987e505edaeSJeff LaBundy 		.val_max = 3000,
988e505edaeSJeff LaBundy 		.label = "ultra-low-power mode report rate",
989e505edaeSJeff LaBundy 	},
990e505edaeSJeff LaBundy };
991e505edaeSJeff LaBundy 
992e505edaeSJeff LaBundy struct iqs7222_private {
993e505edaeSJeff LaBundy 	const struct iqs7222_dev_desc *dev_desc;
994e505edaeSJeff LaBundy 	struct gpio_desc *reset_gpio;
995e505edaeSJeff LaBundy 	struct gpio_desc *irq_gpio;
996e505edaeSJeff LaBundy 	struct i2c_client *client;
997e505edaeSJeff LaBundy 	struct input_dev *keypad;
998e505edaeSJeff LaBundy 	unsigned int kp_type[IQS7222_MAX_CHAN][ARRAY_SIZE(iqs7222_kp_events)];
999e505edaeSJeff LaBundy 	unsigned int kp_code[IQS7222_MAX_CHAN][ARRAY_SIZE(iqs7222_kp_events)];
1000e505edaeSJeff LaBundy 	unsigned int sl_code[IQS7222_MAX_SLDR][ARRAY_SIZE(iqs7222_sl_events)];
1001e505edaeSJeff LaBundy 	unsigned int sl_axis[IQS7222_MAX_SLDR];
1002e505edaeSJeff LaBundy 	u16 cycle_setup[IQS7222_MAX_CHAN / 2][IQS7222_MAX_COLS_CYCLE];
1003e505edaeSJeff LaBundy 	u16 glbl_setup[IQS7222_MAX_COLS_GLBL];
1004e505edaeSJeff LaBundy 	u16 btn_setup[IQS7222_MAX_CHAN][IQS7222_MAX_COLS_BTN];
1005e505edaeSJeff LaBundy 	u16 chan_setup[IQS7222_MAX_CHAN][IQS7222_MAX_COLS_CHAN];
1006e505edaeSJeff LaBundy 	u16 filt_setup[IQS7222_MAX_COLS_FILT];
1007e505edaeSJeff LaBundy 	u16 sldr_setup[IQS7222_MAX_SLDR][IQS7222_MAX_COLS_SLDR];
1008e505edaeSJeff LaBundy 	u16 gpio_setup[ARRAY_SIZE(iqs7222_gpio_links)][IQS7222_MAX_COLS_GPIO];
1009e505edaeSJeff LaBundy 	u16 sys_setup[IQS7222_MAX_COLS_SYS];
1010e505edaeSJeff LaBundy };
1011e505edaeSJeff LaBundy 
1012e505edaeSJeff LaBundy static u16 *iqs7222_setup(struct iqs7222_private *iqs7222,
1013e505edaeSJeff LaBundy 			  enum iqs7222_reg_grp_id reg_grp, int row)
1014e505edaeSJeff LaBundy {
1015e505edaeSJeff LaBundy 	switch (reg_grp) {
1016e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_CYCLE:
1017e505edaeSJeff LaBundy 		return iqs7222->cycle_setup[row];
1018e505edaeSJeff LaBundy 
1019e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_GLBL:
1020e505edaeSJeff LaBundy 		return iqs7222->glbl_setup;
1021e505edaeSJeff LaBundy 
1022e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_BTN:
1023e505edaeSJeff LaBundy 		return iqs7222->btn_setup[row];
1024e505edaeSJeff LaBundy 
1025e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_CHAN:
1026e505edaeSJeff LaBundy 		return iqs7222->chan_setup[row];
1027e505edaeSJeff LaBundy 
1028e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_FILT:
1029e505edaeSJeff LaBundy 		return iqs7222->filt_setup;
1030e505edaeSJeff LaBundy 
1031e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_SLDR:
1032e505edaeSJeff LaBundy 		return iqs7222->sldr_setup[row];
1033e505edaeSJeff LaBundy 
1034e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_GPIO:
1035e505edaeSJeff LaBundy 		return iqs7222->gpio_setup[row];
1036e505edaeSJeff LaBundy 
1037e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_SYS:
1038e505edaeSJeff LaBundy 		return iqs7222->sys_setup;
1039e505edaeSJeff LaBundy 
1040e505edaeSJeff LaBundy 	default:
1041e505edaeSJeff LaBundy 		return NULL;
1042e505edaeSJeff LaBundy 	}
1043e505edaeSJeff LaBundy }
1044e505edaeSJeff LaBundy 
1045e505edaeSJeff LaBundy static int iqs7222_irq_poll(struct iqs7222_private *iqs7222, u16 timeout_ms)
1046e505edaeSJeff LaBundy {
1047e505edaeSJeff LaBundy 	ktime_t irq_timeout = ktime_add_ms(ktime_get(), timeout_ms);
1048e505edaeSJeff LaBundy 	int ret;
1049e505edaeSJeff LaBundy 
1050e505edaeSJeff LaBundy 	do {
1051e505edaeSJeff LaBundy 		usleep_range(1000, 1100);
1052e505edaeSJeff LaBundy 
1053e505edaeSJeff LaBundy 		ret = gpiod_get_value_cansleep(iqs7222->irq_gpio);
1054e505edaeSJeff LaBundy 		if (ret < 0)
1055e505edaeSJeff LaBundy 			return ret;
1056e505edaeSJeff LaBundy 		else if (ret > 0)
1057e505edaeSJeff LaBundy 			return 0;
1058e505edaeSJeff LaBundy 	} while (ktime_compare(ktime_get(), irq_timeout) < 0);
1059e505edaeSJeff LaBundy 
1060e505edaeSJeff LaBundy 	return -EBUSY;
1061e505edaeSJeff LaBundy }
1062e505edaeSJeff LaBundy 
1063e505edaeSJeff LaBundy static int iqs7222_hard_reset(struct iqs7222_private *iqs7222)
1064e505edaeSJeff LaBundy {
1065e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
1066e505edaeSJeff LaBundy 	int error;
1067e505edaeSJeff LaBundy 
1068e505edaeSJeff LaBundy 	if (!iqs7222->reset_gpio)
1069e505edaeSJeff LaBundy 		return 0;
1070e505edaeSJeff LaBundy 
1071e505edaeSJeff LaBundy 	gpiod_set_value_cansleep(iqs7222->reset_gpio, 1);
1072e505edaeSJeff LaBundy 	usleep_range(1000, 1100);
1073e505edaeSJeff LaBundy 
1074e505edaeSJeff LaBundy 	gpiod_set_value_cansleep(iqs7222->reset_gpio, 0);
1075e505edaeSJeff LaBundy 
1076e505edaeSJeff LaBundy 	error = iqs7222_irq_poll(iqs7222, IQS7222_RESET_TIMEOUT_MS);
1077e505edaeSJeff LaBundy 	if (error)
1078e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to reset device: %d\n", error);
1079e505edaeSJeff LaBundy 
1080e505edaeSJeff LaBundy 	return error;
1081e505edaeSJeff LaBundy }
1082e505edaeSJeff LaBundy 
1083e505edaeSJeff LaBundy static int iqs7222_force_comms(struct iqs7222_private *iqs7222)
1084e505edaeSJeff LaBundy {
1085e505edaeSJeff LaBundy 	u8 msg_buf[] = { 0xFF, 0x00, };
1086e505edaeSJeff LaBundy 	int ret;
1087e505edaeSJeff LaBundy 
1088e505edaeSJeff LaBundy 	/*
1089e505edaeSJeff LaBundy 	 * The device cannot communicate until it asserts its interrupt (RDY)
1090e505edaeSJeff LaBundy 	 * pin. Attempts to do so while RDY is deasserted return an ACK; how-
1091e505edaeSJeff LaBundy 	 * ever all write data is ignored, and all read data returns 0xEE.
1092e505edaeSJeff LaBundy 	 *
1093e505edaeSJeff LaBundy 	 * Unsolicited communication must be preceded by a special force com-
1094e505edaeSJeff LaBundy 	 * munication command, after which the device eventually asserts its
1095e505edaeSJeff LaBundy 	 * RDY pin and agrees to communicate.
1096e505edaeSJeff LaBundy 	 *
1097e505edaeSJeff LaBundy 	 * Regardless of whether communication is forced or the result of an
1098e505edaeSJeff LaBundy 	 * interrupt, the device automatically deasserts its RDY pin once it
1099e505edaeSJeff LaBundy 	 * detects an I2C stop condition, or a timeout expires.
1100e505edaeSJeff LaBundy 	 */
1101e505edaeSJeff LaBundy 	ret = gpiod_get_value_cansleep(iqs7222->irq_gpio);
1102e505edaeSJeff LaBundy 	if (ret < 0)
1103e505edaeSJeff LaBundy 		return ret;
1104e505edaeSJeff LaBundy 	else if (ret > 0)
1105e505edaeSJeff LaBundy 		return 0;
1106e505edaeSJeff LaBundy 
1107e505edaeSJeff LaBundy 	ret = i2c_master_send(iqs7222->client, msg_buf, sizeof(msg_buf));
1108e505edaeSJeff LaBundy 	if (ret < (int)sizeof(msg_buf)) {
1109e505edaeSJeff LaBundy 		if (ret >= 0)
1110e505edaeSJeff LaBundy 			ret = -EIO;
1111e505edaeSJeff LaBundy 
1112e505edaeSJeff LaBundy 		/*
1113e505edaeSJeff LaBundy 		 * The datasheet states that the host must wait to retry any
1114e505edaeSJeff LaBundy 		 * failed attempt to communicate over I2C.
1115e505edaeSJeff LaBundy 		 */
1116e505edaeSJeff LaBundy 		msleep(IQS7222_COMMS_RETRY_MS);
1117e505edaeSJeff LaBundy 		return ret;
1118e505edaeSJeff LaBundy 	}
1119e505edaeSJeff LaBundy 
1120e505edaeSJeff LaBundy 	return iqs7222_irq_poll(iqs7222, IQS7222_COMMS_TIMEOUT_MS);
1121e505edaeSJeff LaBundy }
1122e505edaeSJeff LaBundy 
1123e505edaeSJeff LaBundy static int iqs7222_read_burst(struct iqs7222_private *iqs7222,
1124e505edaeSJeff LaBundy 			      u16 reg, void *val, u16 num_val)
1125e505edaeSJeff LaBundy {
1126e505edaeSJeff LaBundy 	u8 reg_buf[sizeof(__be16)];
1127e505edaeSJeff LaBundy 	int ret, i;
1128e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
1129e505edaeSJeff LaBundy 	struct i2c_msg msg[] = {
1130e505edaeSJeff LaBundy 		{
1131e505edaeSJeff LaBundy 			.addr = client->addr,
1132e505edaeSJeff LaBundy 			.flags = 0,
1133e505edaeSJeff LaBundy 			.len = reg > U8_MAX ? sizeof(reg) : sizeof(u8),
1134e505edaeSJeff LaBundy 			.buf = reg_buf,
1135e505edaeSJeff LaBundy 		},
1136e505edaeSJeff LaBundy 		{
1137e505edaeSJeff LaBundy 			.addr = client->addr,
1138e505edaeSJeff LaBundy 			.flags = I2C_M_RD,
1139e505edaeSJeff LaBundy 			.len = num_val * sizeof(__le16),
1140e505edaeSJeff LaBundy 			.buf = (u8 *)val,
1141e505edaeSJeff LaBundy 		},
1142e505edaeSJeff LaBundy 	};
1143e505edaeSJeff LaBundy 
1144e505edaeSJeff LaBundy 	if (reg > U8_MAX)
1145e505edaeSJeff LaBundy 		put_unaligned_be16(reg, reg_buf);
1146e505edaeSJeff LaBundy 	else
1147e505edaeSJeff LaBundy 		*reg_buf = (u8)reg;
1148e505edaeSJeff LaBundy 
1149e505edaeSJeff LaBundy 	/*
1150e505edaeSJeff LaBundy 	 * The following loop protects against an edge case in which the RDY
1151e505edaeSJeff LaBundy 	 * pin is automatically deasserted just as the read is initiated. In
1152e505edaeSJeff LaBundy 	 * that case, the read must be retried using forced communication.
1153e505edaeSJeff LaBundy 	 */
1154e505edaeSJeff LaBundy 	for (i = 0; i < IQS7222_NUM_RETRIES; i++) {
1155e505edaeSJeff LaBundy 		ret = iqs7222_force_comms(iqs7222);
1156e505edaeSJeff LaBundy 		if (ret < 0)
1157e505edaeSJeff LaBundy 			continue;
1158e505edaeSJeff LaBundy 
1159e505edaeSJeff LaBundy 		ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
1160e505edaeSJeff LaBundy 		if (ret < (int)ARRAY_SIZE(msg)) {
1161e505edaeSJeff LaBundy 			if (ret >= 0)
1162e505edaeSJeff LaBundy 				ret = -EIO;
1163e505edaeSJeff LaBundy 
1164e505edaeSJeff LaBundy 			msleep(IQS7222_COMMS_RETRY_MS);
1165e505edaeSJeff LaBundy 			continue;
1166e505edaeSJeff LaBundy 		}
1167e505edaeSJeff LaBundy 
1168e505edaeSJeff LaBundy 		if (get_unaligned_le16(msg[1].buf) == IQS7222_COMMS_ERROR) {
1169e505edaeSJeff LaBundy 			ret = -ENODATA;
1170e505edaeSJeff LaBundy 			continue;
1171e505edaeSJeff LaBundy 		}
1172e505edaeSJeff LaBundy 
1173e505edaeSJeff LaBundy 		ret = 0;
1174e505edaeSJeff LaBundy 		break;
1175e505edaeSJeff LaBundy 	}
1176e505edaeSJeff LaBundy 
1177e505edaeSJeff LaBundy 	/*
1178e505edaeSJeff LaBundy 	 * The following delay ensures the device has deasserted the RDY pin
1179e505edaeSJeff LaBundy 	 * following the I2C stop condition.
1180e505edaeSJeff LaBundy 	 */
1181e505edaeSJeff LaBundy 	usleep_range(50, 100);
1182e505edaeSJeff LaBundy 
1183e505edaeSJeff LaBundy 	if (ret < 0)
1184e505edaeSJeff LaBundy 		dev_err(&client->dev,
1185e505edaeSJeff LaBundy 			"Failed to read from address 0x%04X: %d\n", reg, ret);
1186e505edaeSJeff LaBundy 
1187e505edaeSJeff LaBundy 	return ret;
1188e505edaeSJeff LaBundy }
1189e505edaeSJeff LaBundy 
1190e505edaeSJeff LaBundy static int iqs7222_read_word(struct iqs7222_private *iqs7222, u16 reg, u16 *val)
1191e505edaeSJeff LaBundy {
1192e505edaeSJeff LaBundy 	__le16 val_buf;
1193e505edaeSJeff LaBundy 	int error;
1194e505edaeSJeff LaBundy 
1195e505edaeSJeff LaBundy 	error = iqs7222_read_burst(iqs7222, reg, &val_buf, 1);
1196e505edaeSJeff LaBundy 	if (error)
1197e505edaeSJeff LaBundy 		return error;
1198e505edaeSJeff LaBundy 
1199e505edaeSJeff LaBundy 	*val = le16_to_cpu(val_buf);
1200e505edaeSJeff LaBundy 
1201e505edaeSJeff LaBundy 	return 0;
1202e505edaeSJeff LaBundy }
1203e505edaeSJeff LaBundy 
1204e505edaeSJeff LaBundy static int iqs7222_write_burst(struct iqs7222_private *iqs7222,
1205e505edaeSJeff LaBundy 			       u16 reg, const void *val, u16 num_val)
1206e505edaeSJeff LaBundy {
1207e505edaeSJeff LaBundy 	int reg_len = reg > U8_MAX ? sizeof(reg) : sizeof(u8);
1208e505edaeSJeff LaBundy 	int val_len = num_val * sizeof(__le16);
1209e505edaeSJeff LaBundy 	int msg_len = reg_len + val_len;
1210e505edaeSJeff LaBundy 	int ret, i;
1211e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
1212e505edaeSJeff LaBundy 	u8 *msg_buf;
1213e505edaeSJeff LaBundy 
1214e505edaeSJeff LaBundy 	msg_buf = kzalloc(msg_len, GFP_KERNEL);
1215e505edaeSJeff LaBundy 	if (!msg_buf)
1216e505edaeSJeff LaBundy 		return -ENOMEM;
1217e505edaeSJeff LaBundy 
1218e505edaeSJeff LaBundy 	if (reg > U8_MAX)
1219e505edaeSJeff LaBundy 		put_unaligned_be16(reg, msg_buf);
1220e505edaeSJeff LaBundy 	else
1221e505edaeSJeff LaBundy 		*msg_buf = (u8)reg;
1222e505edaeSJeff LaBundy 
1223e505edaeSJeff LaBundy 	memcpy(msg_buf + reg_len, val, val_len);
1224e505edaeSJeff LaBundy 
1225e505edaeSJeff LaBundy 	/*
1226e505edaeSJeff LaBundy 	 * The following loop protects against an edge case in which the RDY
1227e505edaeSJeff LaBundy 	 * pin is automatically asserted just before the force communication
1228e505edaeSJeff LaBundy 	 * command is sent.
1229e505edaeSJeff LaBundy 	 *
1230e505edaeSJeff LaBundy 	 * In that case, the subsequent I2C stop condition tricks the device
1231e505edaeSJeff LaBundy 	 * into preemptively deasserting the RDY pin and the command must be
1232e505edaeSJeff LaBundy 	 * sent again.
1233e505edaeSJeff LaBundy 	 */
1234e505edaeSJeff LaBundy 	for (i = 0; i < IQS7222_NUM_RETRIES; i++) {
1235e505edaeSJeff LaBundy 		ret = iqs7222_force_comms(iqs7222);
1236e505edaeSJeff LaBundy 		if (ret < 0)
1237e505edaeSJeff LaBundy 			continue;
1238e505edaeSJeff LaBundy 
1239e505edaeSJeff LaBundy 		ret = i2c_master_send(client, msg_buf, msg_len);
1240e505edaeSJeff LaBundy 		if (ret < msg_len) {
1241e505edaeSJeff LaBundy 			if (ret >= 0)
1242e505edaeSJeff LaBundy 				ret = -EIO;
1243e505edaeSJeff LaBundy 
1244e505edaeSJeff LaBundy 			msleep(IQS7222_COMMS_RETRY_MS);
1245e505edaeSJeff LaBundy 			continue;
1246e505edaeSJeff LaBundy 		}
1247e505edaeSJeff LaBundy 
1248e505edaeSJeff LaBundy 		ret = 0;
1249e505edaeSJeff LaBundy 		break;
1250e505edaeSJeff LaBundy 	}
1251e505edaeSJeff LaBundy 
1252e505edaeSJeff LaBundy 	kfree(msg_buf);
1253e505edaeSJeff LaBundy 
1254e505edaeSJeff LaBundy 	usleep_range(50, 100);
1255e505edaeSJeff LaBundy 
1256e505edaeSJeff LaBundy 	if (ret < 0)
1257e505edaeSJeff LaBundy 		dev_err(&client->dev,
1258e505edaeSJeff LaBundy 			"Failed to write to address 0x%04X: %d\n", reg, ret);
1259e505edaeSJeff LaBundy 
1260e505edaeSJeff LaBundy 	return ret;
1261e505edaeSJeff LaBundy }
1262e505edaeSJeff LaBundy 
1263e505edaeSJeff LaBundy static int iqs7222_write_word(struct iqs7222_private *iqs7222, u16 reg, u16 val)
1264e505edaeSJeff LaBundy {
1265e505edaeSJeff LaBundy 	__le16 val_buf = cpu_to_le16(val);
1266e505edaeSJeff LaBundy 
1267e505edaeSJeff LaBundy 	return iqs7222_write_burst(iqs7222, reg, &val_buf, 1);
1268e505edaeSJeff LaBundy }
1269e505edaeSJeff LaBundy 
1270e505edaeSJeff LaBundy static int iqs7222_ati_trigger(struct iqs7222_private *iqs7222)
1271e505edaeSJeff LaBundy {
1272e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
1273e505edaeSJeff LaBundy 	ktime_t ati_timeout;
1274e505edaeSJeff LaBundy 	u16 sys_status = 0;
1275e505edaeSJeff LaBundy 	u16 sys_setup = iqs7222->sys_setup[0] & ~IQS7222_SYS_SETUP_ACK_RESET;
1276e505edaeSJeff LaBundy 	int error, i;
1277e505edaeSJeff LaBundy 
1278e505edaeSJeff LaBundy 	for (i = 0; i < IQS7222_NUM_RETRIES; i++) {
1279e505edaeSJeff LaBundy 		/*
1280e505edaeSJeff LaBundy 		 * Trigger ATI from streaming and normal-power modes so that
1281e505edaeSJeff LaBundy 		 * the RDY pin continues to be asserted during ATI.
1282e505edaeSJeff LaBundy 		 */
1283e505edaeSJeff LaBundy 		error = iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP,
1284e505edaeSJeff LaBundy 					   sys_setup |
1285e505edaeSJeff LaBundy 					   IQS7222_SYS_SETUP_REDO_ATI);
1286e505edaeSJeff LaBundy 		if (error)
1287e505edaeSJeff LaBundy 			return error;
1288e505edaeSJeff LaBundy 
1289e505edaeSJeff LaBundy 		ati_timeout = ktime_add_ms(ktime_get(), IQS7222_ATI_TIMEOUT_MS);
1290e505edaeSJeff LaBundy 
1291e505edaeSJeff LaBundy 		do {
1292e505edaeSJeff LaBundy 			error = iqs7222_irq_poll(iqs7222,
1293e505edaeSJeff LaBundy 						 IQS7222_COMMS_TIMEOUT_MS);
1294e505edaeSJeff LaBundy 			if (error)
1295e505edaeSJeff LaBundy 				continue;
1296e505edaeSJeff LaBundy 
1297e505edaeSJeff LaBundy 			error = iqs7222_read_word(iqs7222, IQS7222_SYS_STATUS,
1298e505edaeSJeff LaBundy 						  &sys_status);
1299e505edaeSJeff LaBundy 			if (error)
1300e505edaeSJeff LaBundy 				return error;
1301e505edaeSJeff LaBundy 
1302e505edaeSJeff LaBundy 			if (sys_status & IQS7222_SYS_STATUS_ATI_ACTIVE)
1303e505edaeSJeff LaBundy 				continue;
1304e505edaeSJeff LaBundy 
1305e505edaeSJeff LaBundy 			if (sys_status & IQS7222_SYS_STATUS_ATI_ERROR)
1306e505edaeSJeff LaBundy 				break;
1307e505edaeSJeff LaBundy 
1308e505edaeSJeff LaBundy 			/*
1309e505edaeSJeff LaBundy 			 * Use stream-in-touch mode if either slider reports
1310e505edaeSJeff LaBundy 			 * absolute position.
1311e505edaeSJeff LaBundy 			 */
1312e505edaeSJeff LaBundy 			sys_setup |= test_bit(EV_ABS, iqs7222->keypad->evbit)
1313e505edaeSJeff LaBundy 				   ? IQS7222_SYS_SETUP_INTF_MODE_TOUCH
1314e505edaeSJeff LaBundy 				   : IQS7222_SYS_SETUP_INTF_MODE_EVENT;
1315e505edaeSJeff LaBundy 			sys_setup |= IQS7222_SYS_SETUP_PWR_MODE_AUTO;
1316e505edaeSJeff LaBundy 
1317e505edaeSJeff LaBundy 			return iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP,
1318e505edaeSJeff LaBundy 						  sys_setup);
1319e505edaeSJeff LaBundy 		} while (ktime_compare(ktime_get(), ati_timeout) < 0);
1320e505edaeSJeff LaBundy 
1321e505edaeSJeff LaBundy 		dev_err(&client->dev,
1322e505edaeSJeff LaBundy 			"ATI attempt %d of %d failed with status 0x%02X, %s\n",
1323e505edaeSJeff LaBundy 			i + 1, IQS7222_NUM_RETRIES, (u8)sys_status,
1324e505edaeSJeff LaBundy 			i < IQS7222_NUM_RETRIES ? "retrying..." : "stopping");
1325e505edaeSJeff LaBundy 	}
1326e505edaeSJeff LaBundy 
1327e505edaeSJeff LaBundy 	return -ETIMEDOUT;
1328e505edaeSJeff LaBundy }
1329e505edaeSJeff LaBundy 
1330e505edaeSJeff LaBundy static int iqs7222_dev_init(struct iqs7222_private *iqs7222, int dir)
1331e505edaeSJeff LaBundy {
1332e505edaeSJeff LaBundy 	const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
1333e505edaeSJeff LaBundy 	int comms_offset = dev_desc->comms_offset;
1334e505edaeSJeff LaBundy 	int error, i, j, k;
1335e505edaeSJeff LaBundy 
1336e505edaeSJeff LaBundy 	/*
1337e505edaeSJeff LaBundy 	 * Take advantage of the stop-bit disable function, if available, to
1338e505edaeSJeff LaBundy 	 * save the trouble of having to reopen a communication window after
1339e505edaeSJeff LaBundy 	 * each burst read or write.
1340e505edaeSJeff LaBundy 	 */
1341e505edaeSJeff LaBundy 	if (comms_offset) {
1342e505edaeSJeff LaBundy 		u16 comms_setup;
1343e505edaeSJeff LaBundy 
1344e505edaeSJeff LaBundy 		error = iqs7222_read_word(iqs7222,
1345e505edaeSJeff LaBundy 					  IQS7222_SYS_SETUP + comms_offset,
1346e505edaeSJeff LaBundy 					  &comms_setup);
1347e505edaeSJeff LaBundy 		if (error)
1348e505edaeSJeff LaBundy 			return error;
1349e505edaeSJeff LaBundy 
1350e505edaeSJeff LaBundy 		error = iqs7222_write_word(iqs7222,
1351e505edaeSJeff LaBundy 					   IQS7222_SYS_SETUP + comms_offset,
1352e505edaeSJeff LaBundy 					   comms_setup | IQS7222_COMMS_HOLD);
1353e505edaeSJeff LaBundy 		if (error)
1354e505edaeSJeff LaBundy 			return error;
1355e505edaeSJeff LaBundy 	}
1356e505edaeSJeff LaBundy 
1357e505edaeSJeff LaBundy 	for (i = 0; i < IQS7222_NUM_REG_GRPS; i++) {
1358e505edaeSJeff LaBundy 		int num_row = dev_desc->reg_grps[i].num_row;
1359e505edaeSJeff LaBundy 		int num_col = dev_desc->reg_grps[i].num_col;
1360e505edaeSJeff LaBundy 		u16 reg = dev_desc->reg_grps[i].base;
1361e505edaeSJeff LaBundy 		__le16 *val_buf;
1362e505edaeSJeff LaBundy 		u16 *val;
1363e505edaeSJeff LaBundy 
1364e505edaeSJeff LaBundy 		if (!num_col)
1365e505edaeSJeff LaBundy 			continue;
1366e505edaeSJeff LaBundy 
1367e505edaeSJeff LaBundy 		val = iqs7222_setup(iqs7222, i, 0);
1368e505edaeSJeff LaBundy 		if (!val)
1369e505edaeSJeff LaBundy 			continue;
1370e505edaeSJeff LaBundy 
1371e505edaeSJeff LaBundy 		val_buf = kcalloc(num_col, sizeof(__le16), GFP_KERNEL);
1372e505edaeSJeff LaBundy 		if (!val_buf)
1373e505edaeSJeff LaBundy 			return -ENOMEM;
1374e505edaeSJeff LaBundy 
1375e505edaeSJeff LaBundy 		for (j = 0; j < num_row; j++) {
1376e505edaeSJeff LaBundy 			switch (dir) {
1377e505edaeSJeff LaBundy 			case READ:
1378e505edaeSJeff LaBundy 				error = iqs7222_read_burst(iqs7222, reg,
1379e505edaeSJeff LaBundy 							   val_buf, num_col);
1380e505edaeSJeff LaBundy 				for (k = 0; k < num_col; k++)
1381e505edaeSJeff LaBundy 					val[k] = le16_to_cpu(val_buf[k]);
1382e505edaeSJeff LaBundy 				break;
1383e505edaeSJeff LaBundy 
1384e505edaeSJeff LaBundy 			case WRITE:
1385e505edaeSJeff LaBundy 				for (k = 0; k < num_col; k++)
1386e505edaeSJeff LaBundy 					val_buf[k] = cpu_to_le16(val[k]);
1387e505edaeSJeff LaBundy 				error = iqs7222_write_burst(iqs7222, reg,
1388e505edaeSJeff LaBundy 							    val_buf, num_col);
1389e505edaeSJeff LaBundy 				break;
1390e505edaeSJeff LaBundy 
1391e505edaeSJeff LaBundy 			default:
1392e505edaeSJeff LaBundy 				error = -EINVAL;
1393e505edaeSJeff LaBundy 			}
1394e505edaeSJeff LaBundy 
1395e505edaeSJeff LaBundy 			if (error)
1396e505edaeSJeff LaBundy 				break;
1397e505edaeSJeff LaBundy 
1398e505edaeSJeff LaBundy 			reg += IQS7222_REG_OFFSET;
1399e505edaeSJeff LaBundy 			val += iqs7222_max_cols[i];
1400e505edaeSJeff LaBundy 		}
1401e505edaeSJeff LaBundy 
1402e505edaeSJeff LaBundy 		kfree(val_buf);
1403e505edaeSJeff LaBundy 
1404e505edaeSJeff LaBundy 		if (error)
1405e505edaeSJeff LaBundy 			return error;
1406e505edaeSJeff LaBundy 	}
1407e505edaeSJeff LaBundy 
1408e505edaeSJeff LaBundy 	if (comms_offset) {
1409e505edaeSJeff LaBundy 		u16 comms_setup;
1410e505edaeSJeff LaBundy 
1411e505edaeSJeff LaBundy 		error = iqs7222_read_word(iqs7222,
1412e505edaeSJeff LaBundy 					  IQS7222_SYS_SETUP + comms_offset,
1413e505edaeSJeff LaBundy 					  &comms_setup);
1414e505edaeSJeff LaBundy 		if (error)
1415e505edaeSJeff LaBundy 			return error;
1416e505edaeSJeff LaBundy 
1417e505edaeSJeff LaBundy 		error = iqs7222_write_word(iqs7222,
1418e505edaeSJeff LaBundy 					   IQS7222_SYS_SETUP + comms_offset,
1419e505edaeSJeff LaBundy 					   comms_setup & ~IQS7222_COMMS_HOLD);
1420e505edaeSJeff LaBundy 		if (error)
1421e505edaeSJeff LaBundy 			return error;
1422e505edaeSJeff LaBundy 	}
1423e505edaeSJeff LaBundy 
1424e505edaeSJeff LaBundy 	if (dir == READ)
1425e505edaeSJeff LaBundy 		return 0;
1426e505edaeSJeff LaBundy 
1427e505edaeSJeff LaBundy 	return iqs7222_ati_trigger(iqs7222);
1428e505edaeSJeff LaBundy }
1429e505edaeSJeff LaBundy 
1430e505edaeSJeff LaBundy static int iqs7222_dev_info(struct iqs7222_private *iqs7222)
1431e505edaeSJeff LaBundy {
1432e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
1433e505edaeSJeff LaBundy 	bool prod_num_valid = false;
1434e505edaeSJeff LaBundy 	__le16 dev_id[3];
1435e505edaeSJeff LaBundy 	int error, i;
1436e505edaeSJeff LaBundy 
1437e505edaeSJeff LaBundy 	error = iqs7222_read_burst(iqs7222, IQS7222_PROD_NUM, dev_id,
1438e505edaeSJeff LaBundy 				   ARRAY_SIZE(dev_id));
1439e505edaeSJeff LaBundy 	if (error)
1440e505edaeSJeff LaBundy 		return error;
1441e505edaeSJeff LaBundy 
1442e505edaeSJeff LaBundy 	for (i = 0; i < ARRAY_SIZE(iqs7222_devs); i++) {
1443e505edaeSJeff LaBundy 		if (le16_to_cpu(dev_id[0]) != iqs7222_devs[i].prod_num)
1444e505edaeSJeff LaBundy 			continue;
1445e505edaeSJeff LaBundy 
1446e505edaeSJeff LaBundy 		prod_num_valid = true;
1447e505edaeSJeff LaBundy 
1448e505edaeSJeff LaBundy 		if (le16_to_cpu(dev_id[1]) < iqs7222_devs[i].fw_major)
1449e505edaeSJeff LaBundy 			continue;
1450e505edaeSJeff LaBundy 
1451e505edaeSJeff LaBundy 		if (le16_to_cpu(dev_id[2]) < iqs7222_devs[i].fw_minor)
1452e505edaeSJeff LaBundy 			continue;
1453e505edaeSJeff LaBundy 
1454e505edaeSJeff LaBundy 		iqs7222->dev_desc = &iqs7222_devs[i];
1455e505edaeSJeff LaBundy 		return 0;
1456e505edaeSJeff LaBundy 	}
1457e505edaeSJeff LaBundy 
1458e505edaeSJeff LaBundy 	if (prod_num_valid)
1459e505edaeSJeff LaBundy 		dev_err(&client->dev, "Unsupported firmware revision: %u.%u\n",
1460e505edaeSJeff LaBundy 			le16_to_cpu(dev_id[1]), le16_to_cpu(dev_id[2]));
1461e505edaeSJeff LaBundy 	else
1462e505edaeSJeff LaBundy 		dev_err(&client->dev, "Unrecognized product number: %u\n",
1463e505edaeSJeff LaBundy 			le16_to_cpu(dev_id[0]));
1464e505edaeSJeff LaBundy 
1465e505edaeSJeff LaBundy 	return -EINVAL;
1466e505edaeSJeff LaBundy }
1467e505edaeSJeff LaBundy 
1468e505edaeSJeff LaBundy static int iqs7222_gpio_select(struct iqs7222_private *iqs7222,
1469e505edaeSJeff LaBundy 			       struct fwnode_handle *child_node,
1470e505edaeSJeff LaBundy 			       int child_enable, u16 child_link)
1471e505edaeSJeff LaBundy {
1472e505edaeSJeff LaBundy 	const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
1473e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
1474e505edaeSJeff LaBundy 	int num_gpio = dev_desc->reg_grps[IQS7222_REG_GRP_GPIO].num_row;
1475e505edaeSJeff LaBundy 	int error, count, i;
1476e505edaeSJeff LaBundy 	unsigned int gpio_sel[ARRAY_SIZE(iqs7222_gpio_links)];
1477e505edaeSJeff LaBundy 
1478e505edaeSJeff LaBundy 	if (!num_gpio)
1479e505edaeSJeff LaBundy 		return 0;
1480e505edaeSJeff LaBundy 
1481e505edaeSJeff LaBundy 	if (!fwnode_property_present(child_node, "azoteq,gpio-select"))
1482e505edaeSJeff LaBundy 		return 0;
1483e505edaeSJeff LaBundy 
1484e505edaeSJeff LaBundy 	count = fwnode_property_count_u32(child_node, "azoteq,gpio-select");
1485e505edaeSJeff LaBundy 	if (count > num_gpio) {
1486e505edaeSJeff LaBundy 		dev_err(&client->dev, "Invalid number of %s GPIOs\n",
1487e505edaeSJeff LaBundy 			fwnode_get_name(child_node));
1488e505edaeSJeff LaBundy 		return -EINVAL;
1489e505edaeSJeff LaBundy 	} else if (count < 0) {
1490e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to count %s GPIOs: %d\n",
1491e505edaeSJeff LaBundy 			fwnode_get_name(child_node), count);
1492e505edaeSJeff LaBundy 		return count;
1493e505edaeSJeff LaBundy 	}
1494e505edaeSJeff LaBundy 
1495e505edaeSJeff LaBundy 	error = fwnode_property_read_u32_array(child_node,
1496e505edaeSJeff LaBundy 					       "azoteq,gpio-select",
1497e505edaeSJeff LaBundy 					       gpio_sel, count);
1498e505edaeSJeff LaBundy 	if (error) {
1499e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to read %s GPIOs: %d\n",
1500e505edaeSJeff LaBundy 			fwnode_get_name(child_node), error);
1501e505edaeSJeff LaBundy 		return error;
1502e505edaeSJeff LaBundy 	}
1503e505edaeSJeff LaBundy 
1504e505edaeSJeff LaBundy 	for (i = 0; i < count; i++) {
1505e505edaeSJeff LaBundy 		u16 *gpio_setup;
1506e505edaeSJeff LaBundy 
1507e505edaeSJeff LaBundy 		if (gpio_sel[i] >= num_gpio) {
1508e505edaeSJeff LaBundy 			dev_err(&client->dev, "Invalid %s GPIO: %u\n",
1509e505edaeSJeff LaBundy 				fwnode_get_name(child_node), gpio_sel[i]);
1510e505edaeSJeff LaBundy 			return -EINVAL;
1511e505edaeSJeff LaBundy 		}
1512e505edaeSJeff LaBundy 
1513e505edaeSJeff LaBundy 		gpio_setup = iqs7222->gpio_setup[gpio_sel[i]];
1514e505edaeSJeff LaBundy 
1515e505edaeSJeff LaBundy 		if (gpio_setup[2] && child_link != gpio_setup[2]) {
1516e505edaeSJeff LaBundy 			dev_err(&client->dev,
1517e505edaeSJeff LaBundy 				"Conflicting GPIO %u event types\n",
1518e505edaeSJeff LaBundy 				gpio_sel[i]);
1519e505edaeSJeff LaBundy 			return -EINVAL;
1520e505edaeSJeff LaBundy 		}
1521e505edaeSJeff LaBundy 
1522e505edaeSJeff LaBundy 		gpio_setup[0] |= IQS7222_GPIO_SETUP_0_GPIO_EN;
1523e505edaeSJeff LaBundy 		gpio_setup[1] |= child_enable;
1524e505edaeSJeff LaBundy 		gpio_setup[2] = child_link;
1525e505edaeSJeff LaBundy 	}
1526e505edaeSJeff LaBundy 
1527e505edaeSJeff LaBundy 	return 0;
1528e505edaeSJeff LaBundy }
1529e505edaeSJeff LaBundy 
1530e505edaeSJeff LaBundy static int iqs7222_parse_props(struct iqs7222_private *iqs7222,
1531e505edaeSJeff LaBundy 			       struct fwnode_handle **child_node,
1532e505edaeSJeff LaBundy 			       int child_index,
1533e505edaeSJeff LaBundy 			       enum iqs7222_reg_grp_id reg_grp,
1534e505edaeSJeff LaBundy 			       enum iqs7222_reg_key_id reg_key)
1535e505edaeSJeff LaBundy {
1536e505edaeSJeff LaBundy 	u16 *setup = iqs7222_setup(iqs7222, reg_grp, child_index);
1537e505edaeSJeff LaBundy 	struct fwnode_handle *reg_grp_node = *child_node;
1538e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
1539e505edaeSJeff LaBundy 	char reg_grp_name[16];
1540e505edaeSJeff LaBundy 	int i;
1541e505edaeSJeff LaBundy 
1542e505edaeSJeff LaBundy 	switch (reg_grp) {
1543e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_CYCLE:
1544e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_CHAN:
1545e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_SLDR:
1546e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_GPIO:
1547e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_BTN:
1548e505edaeSJeff LaBundy 		/*
1549e505edaeSJeff LaBundy 		 * These groups derive a child node and return it to the caller
1550e505edaeSJeff LaBundy 		 * for additional group-specific processing. In some cases, the
1551e505edaeSJeff LaBundy 		 * child node may have already been derived.
1552e505edaeSJeff LaBundy 		 */
1553e505edaeSJeff LaBundy 		if (*child_node)
1554e505edaeSJeff LaBundy 			break;
1555e505edaeSJeff LaBundy 
1556e505edaeSJeff LaBundy 		snprintf(reg_grp_name, sizeof(reg_grp_name), "%s-%d",
1557e505edaeSJeff LaBundy 			 iqs7222_reg_grp_names[reg_grp], child_index);
1558e505edaeSJeff LaBundy 
1559e505edaeSJeff LaBundy 		reg_grp_node = device_get_named_child_node(&client->dev,
1560e505edaeSJeff LaBundy 							   reg_grp_name);
1561e505edaeSJeff LaBundy 		if (!reg_grp_node)
1562e505edaeSJeff LaBundy 			return 0;
1563e505edaeSJeff LaBundy 
1564e505edaeSJeff LaBundy 		*child_node = reg_grp_node;
1565e505edaeSJeff LaBundy 		break;
1566e505edaeSJeff LaBundy 
1567e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_GLBL:
1568e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_FILT:
1569e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_SYS:
1570e505edaeSJeff LaBundy 		/*
1571e505edaeSJeff LaBundy 		 * These groups are not organized beneath a child node, nor are
1572e505edaeSJeff LaBundy 		 * they subject to any additional processing by the caller.
1573e505edaeSJeff LaBundy 		 */
1574e505edaeSJeff LaBundy 		reg_grp_node = dev_fwnode(&client->dev);
1575e505edaeSJeff LaBundy 		break;
1576e505edaeSJeff LaBundy 
1577e505edaeSJeff LaBundy 	default:
1578e505edaeSJeff LaBundy 		return -EINVAL;
1579e505edaeSJeff LaBundy 	}
1580e505edaeSJeff LaBundy 
1581e505edaeSJeff LaBundy 	for (i = 0; i < ARRAY_SIZE(iqs7222_props); i++) {
1582e505edaeSJeff LaBundy 		const char *name = iqs7222_props[i].name;
1583e505edaeSJeff LaBundy 		int reg_offset = iqs7222_props[i].reg_offset;
1584e505edaeSJeff LaBundy 		int reg_shift = iqs7222_props[i].reg_shift;
1585e505edaeSJeff LaBundy 		int reg_width = iqs7222_props[i].reg_width;
1586e505edaeSJeff LaBundy 		int val_pitch = iqs7222_props[i].val_pitch ? : 1;
1587e505edaeSJeff LaBundy 		int val_min = iqs7222_props[i].val_min;
1588e505edaeSJeff LaBundy 		int val_max = iqs7222_props[i].val_max;
1589e505edaeSJeff LaBundy 		bool invert = iqs7222_props[i].invert;
1590e505edaeSJeff LaBundy 		const char *label = iqs7222_props[i].label ? : name;
1591e505edaeSJeff LaBundy 		unsigned int val;
1592e505edaeSJeff LaBundy 		int error;
1593e505edaeSJeff LaBundy 
1594e505edaeSJeff LaBundy 		if (iqs7222_props[i].reg_grp != reg_grp ||
1595e505edaeSJeff LaBundy 		    iqs7222_props[i].reg_key != reg_key)
1596e505edaeSJeff LaBundy 			continue;
1597e505edaeSJeff LaBundy 
1598e505edaeSJeff LaBundy 		/*
1599e505edaeSJeff LaBundy 		 * Boolean register fields are one bit wide; they are forcibly
1600e505edaeSJeff LaBundy 		 * reset to provide a means to undo changes by a bootloader if
1601e505edaeSJeff LaBundy 		 * necessary.
1602e505edaeSJeff LaBundy 		 *
1603e505edaeSJeff LaBundy 		 * Scalar fields, on the other hand, are left untouched unless
1604e505edaeSJeff LaBundy 		 * their corresponding properties are present.
1605e505edaeSJeff LaBundy 		 */
1606e505edaeSJeff LaBundy 		if (reg_width == 1) {
1607e505edaeSJeff LaBundy 			if (invert)
1608e505edaeSJeff LaBundy 				setup[reg_offset] |= BIT(reg_shift);
1609e505edaeSJeff LaBundy 			else
1610e505edaeSJeff LaBundy 				setup[reg_offset] &= ~BIT(reg_shift);
1611e505edaeSJeff LaBundy 		}
1612e505edaeSJeff LaBundy 
1613e505edaeSJeff LaBundy 		if (!fwnode_property_present(reg_grp_node, name))
1614e505edaeSJeff LaBundy 			continue;
1615e505edaeSJeff LaBundy 
1616e505edaeSJeff LaBundy 		if (reg_width == 1) {
1617e505edaeSJeff LaBundy 			if (invert)
1618e505edaeSJeff LaBundy 				setup[reg_offset] &= ~BIT(reg_shift);
1619e505edaeSJeff LaBundy 			else
1620e505edaeSJeff LaBundy 				setup[reg_offset] |= BIT(reg_shift);
1621e505edaeSJeff LaBundy 
1622e505edaeSJeff LaBundy 			continue;
1623e505edaeSJeff LaBundy 		}
1624e505edaeSJeff LaBundy 
1625e505edaeSJeff LaBundy 		error = fwnode_property_read_u32(reg_grp_node, name, &val);
1626e505edaeSJeff LaBundy 		if (error) {
1627e505edaeSJeff LaBundy 			dev_err(&client->dev, "Failed to read %s %s: %d\n",
1628e505edaeSJeff LaBundy 				fwnode_get_name(reg_grp_node), label, error);
1629e505edaeSJeff LaBundy 			return error;
1630e505edaeSJeff LaBundy 		}
1631e505edaeSJeff LaBundy 
1632e505edaeSJeff LaBundy 		if (!val_max)
1633e505edaeSJeff LaBundy 			val_max = GENMASK(reg_width - 1, 0) * val_pitch;
1634e505edaeSJeff LaBundy 
1635e505edaeSJeff LaBundy 		if (val < val_min || val > val_max) {
1636e505edaeSJeff LaBundy 			dev_err(&client->dev, "Invalid %s %s: %u\n",
1637e505edaeSJeff LaBundy 				fwnode_get_name(reg_grp_node), label, val);
1638e505edaeSJeff LaBundy 			return -EINVAL;
1639e505edaeSJeff LaBundy 		}
1640e505edaeSJeff LaBundy 
1641e505edaeSJeff LaBundy 		setup[reg_offset] &= ~GENMASK(reg_shift + reg_width - 1,
1642e505edaeSJeff LaBundy 					      reg_shift);
1643e505edaeSJeff LaBundy 		setup[reg_offset] |= (val / val_pitch << reg_shift);
1644e505edaeSJeff LaBundy 	}
1645e505edaeSJeff LaBundy 
1646e505edaeSJeff LaBundy 	return 0;
1647e505edaeSJeff LaBundy }
1648e505edaeSJeff LaBundy 
1649e505edaeSJeff LaBundy static int iqs7222_parse_cycle(struct iqs7222_private *iqs7222, int cycle_index)
1650e505edaeSJeff LaBundy {
1651e505edaeSJeff LaBundy 	u16 *cycle_setup = iqs7222->cycle_setup[cycle_index];
1652e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
1653e505edaeSJeff LaBundy 	struct fwnode_handle *cycle_node = NULL;
1654e505edaeSJeff LaBundy 	unsigned int pins[9];
1655e505edaeSJeff LaBundy 	int error, count, i;
1656e505edaeSJeff LaBundy 
1657e505edaeSJeff LaBundy 	/*
1658e505edaeSJeff LaBundy 	 * Each channel shares a cycle with one other channel; the mapping of
1659e505edaeSJeff LaBundy 	 * channels to cycles is fixed. Properties defined for a cycle impact
1660e505edaeSJeff LaBundy 	 * both channels tied to the cycle.
1661e505edaeSJeff LaBundy 	 */
1662e505edaeSJeff LaBundy 	error = iqs7222_parse_props(iqs7222, &cycle_node, cycle_index,
1663e505edaeSJeff LaBundy 				    IQS7222_REG_GRP_CYCLE,
1664e505edaeSJeff LaBundy 				    IQS7222_REG_KEY_NONE);
1665e505edaeSJeff LaBundy 	if (error)
1666e505edaeSJeff LaBundy 		return error;
1667e505edaeSJeff LaBundy 
1668e505edaeSJeff LaBundy 	if (!cycle_node)
1669e505edaeSJeff LaBundy 		return 0;
1670e505edaeSJeff LaBundy 
1671e505edaeSJeff LaBundy 	/*
1672e505edaeSJeff LaBundy 	 * Unlike channels which are restricted to a select range of CRx pins
1673e505edaeSJeff LaBundy 	 * based on channel number, any cycle can claim any of the device's 9
1674e505edaeSJeff LaBundy 	 * CTx pins (CTx0-8).
1675e505edaeSJeff LaBundy 	 */
1676e505edaeSJeff LaBundy 	if (!fwnode_property_present(cycle_node, "azoteq,tx-enable"))
1677e505edaeSJeff LaBundy 		return 0;
1678e505edaeSJeff LaBundy 
1679e505edaeSJeff LaBundy 	count = fwnode_property_count_u32(cycle_node, "azoteq,tx-enable");
1680*eba697b3SDan Carpenter 	if (count < 0) {
1681e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to count %s CTx pins: %d\n",
1682e505edaeSJeff LaBundy 			fwnode_get_name(cycle_node), count);
1683e505edaeSJeff LaBundy 		return count;
1684*eba697b3SDan Carpenter 	} else if (count > ARRAY_SIZE(pins)) {
1685*eba697b3SDan Carpenter 		dev_err(&client->dev, "Invalid number of %s CTx pins\n",
1686*eba697b3SDan Carpenter 			fwnode_get_name(cycle_node));
1687*eba697b3SDan Carpenter 		return -EINVAL;
1688e505edaeSJeff LaBundy 	}
1689e505edaeSJeff LaBundy 
1690e505edaeSJeff LaBundy 	error = fwnode_property_read_u32_array(cycle_node, "azoteq,tx-enable",
1691e505edaeSJeff LaBundy 					       pins, count);
1692e505edaeSJeff LaBundy 	if (error) {
1693e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to read %s CTx pins: %d\n",
1694e505edaeSJeff LaBundy 			fwnode_get_name(cycle_node), error);
1695e505edaeSJeff LaBundy 		return error;
1696e505edaeSJeff LaBundy 	}
1697e505edaeSJeff LaBundy 
1698e505edaeSJeff LaBundy 	cycle_setup[1] &= ~GENMASK(7 + ARRAY_SIZE(pins) - 1, 7);
1699e505edaeSJeff LaBundy 
1700e505edaeSJeff LaBundy 	for (i = 0; i < count; i++) {
1701e505edaeSJeff LaBundy 		if (pins[i] > 8) {
1702e505edaeSJeff LaBundy 			dev_err(&client->dev, "Invalid %s CTx pin: %u\n",
1703e505edaeSJeff LaBundy 				fwnode_get_name(cycle_node), pins[i]);
1704e505edaeSJeff LaBundy 			return -EINVAL;
1705e505edaeSJeff LaBundy 		}
1706e505edaeSJeff LaBundy 
1707e505edaeSJeff LaBundy 		cycle_setup[1] |= BIT(pins[i] + 7);
1708e505edaeSJeff LaBundy 	}
1709e505edaeSJeff LaBundy 
1710e505edaeSJeff LaBundy 	return 0;
1711e505edaeSJeff LaBundy }
1712e505edaeSJeff LaBundy 
1713e505edaeSJeff LaBundy static int iqs7222_parse_chan(struct iqs7222_private *iqs7222, int chan_index)
1714e505edaeSJeff LaBundy {
1715e505edaeSJeff LaBundy 	const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
1716e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
1717e505edaeSJeff LaBundy 	struct fwnode_handle *chan_node = NULL;
1718e505edaeSJeff LaBundy 	int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
1719e505edaeSJeff LaBundy 	int ext_chan = rounddown(num_chan, 10);
1720e505edaeSJeff LaBundy 	int error, i;
1721e505edaeSJeff LaBundy 	u16 *chan_setup = iqs7222->chan_setup[chan_index];
1722e505edaeSJeff LaBundy 	u16 *sys_setup = iqs7222->sys_setup;
1723e505edaeSJeff LaBundy 	unsigned int val;
1724e505edaeSJeff LaBundy 
1725e505edaeSJeff LaBundy 	error = iqs7222_parse_props(iqs7222, &chan_node, chan_index,
1726e505edaeSJeff LaBundy 				    IQS7222_REG_GRP_CHAN,
1727e505edaeSJeff LaBundy 				    IQS7222_REG_KEY_NONE);
1728e505edaeSJeff LaBundy 	if (error)
1729e505edaeSJeff LaBundy 		return error;
1730e505edaeSJeff LaBundy 
1731e505edaeSJeff LaBundy 	if (!chan_node)
1732e505edaeSJeff LaBundy 		return 0;
1733e505edaeSJeff LaBundy 
1734e505edaeSJeff LaBundy 	if (dev_desc->allow_offset) {
1735e505edaeSJeff LaBundy 		sys_setup[dev_desc->allow_offset] |= BIT(chan_index);
1736e505edaeSJeff LaBundy 		if (fwnode_property_present(chan_node, "azoteq,ulp-allow"))
1737e505edaeSJeff LaBundy 			sys_setup[dev_desc->allow_offset] &= ~BIT(chan_index);
1738e505edaeSJeff LaBundy 	}
1739e505edaeSJeff LaBundy 
1740e505edaeSJeff LaBundy 	chan_setup[0] |= IQS7222_CHAN_SETUP_0_CHAN_EN;
1741e505edaeSJeff LaBundy 
1742e505edaeSJeff LaBundy 	/*
1743e505edaeSJeff LaBundy 	 * The reference channel function allows for differential measurements
1744e505edaeSJeff LaBundy 	 * and is only available in the case of IQS7222A or IQS7222C.
1745e505edaeSJeff LaBundy 	 */
1746e505edaeSJeff LaBundy 	if (dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_col > 4 &&
1747e505edaeSJeff LaBundy 	    fwnode_property_present(chan_node, "azoteq,ref-select")) {
1748e505edaeSJeff LaBundy 		u16 *ref_setup;
1749e505edaeSJeff LaBundy 
1750e505edaeSJeff LaBundy 		error = fwnode_property_read_u32(chan_node, "azoteq,ref-select",
1751e505edaeSJeff LaBundy 						 &val);
1752e505edaeSJeff LaBundy 		if (error) {
1753e505edaeSJeff LaBundy 			dev_err(&client->dev,
1754e505edaeSJeff LaBundy 				"Failed to read %s reference channel: %d\n",
1755e505edaeSJeff LaBundy 				fwnode_get_name(chan_node), error);
1756e505edaeSJeff LaBundy 			return error;
1757e505edaeSJeff LaBundy 		}
1758e505edaeSJeff LaBundy 
1759e505edaeSJeff LaBundy 		if (val >= ext_chan) {
1760e505edaeSJeff LaBundy 			dev_err(&client->dev,
1761e505edaeSJeff LaBundy 				"Invalid %s reference channel: %u\n",
1762e505edaeSJeff LaBundy 				fwnode_get_name(chan_node), val);
1763e505edaeSJeff LaBundy 			return -EINVAL;
1764e505edaeSJeff LaBundy 		}
1765e505edaeSJeff LaBundy 
1766e505edaeSJeff LaBundy 		ref_setup = iqs7222->chan_setup[val];
1767e505edaeSJeff LaBundy 
1768e505edaeSJeff LaBundy 		/*
1769e505edaeSJeff LaBundy 		 * Configure the current channel as a follower of the selected
1770e505edaeSJeff LaBundy 		 * reference channel.
1771e505edaeSJeff LaBundy 		 */
1772e505edaeSJeff LaBundy 		chan_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_FOLLOW;
1773e505edaeSJeff LaBundy 		chan_setup[4] = val * 42 + 1048;
1774e505edaeSJeff LaBundy 
1775e505edaeSJeff LaBundy 		if (!fwnode_property_read_u32(chan_node, "azoteq,ref-weight",
1776e505edaeSJeff LaBundy 					      &val)) {
1777e505edaeSJeff LaBundy 			if (val > U16_MAX) {
1778e505edaeSJeff LaBundy 				dev_err(&client->dev,
1779e505edaeSJeff LaBundy 					"Invalid %s reference weight: %u\n",
1780e505edaeSJeff LaBundy 					fwnode_get_name(chan_node), val);
1781e505edaeSJeff LaBundy 				return -EINVAL;
1782e505edaeSJeff LaBundy 			}
1783e505edaeSJeff LaBundy 
1784e505edaeSJeff LaBundy 			chan_setup[5] = val;
1785e505edaeSJeff LaBundy 		}
1786e505edaeSJeff LaBundy 
1787e505edaeSJeff LaBundy 		/*
1788e505edaeSJeff LaBundy 		 * Configure the selected channel as a reference channel which
1789e505edaeSJeff LaBundy 		 * serves the current channel.
1790e505edaeSJeff LaBundy 		 */
1791e505edaeSJeff LaBundy 		ref_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_REF;
1792e505edaeSJeff LaBundy 		ref_setup[5] |= BIT(chan_index);
1793e505edaeSJeff LaBundy 
1794e505edaeSJeff LaBundy 		ref_setup[4] = dev_desc->touch_link;
1795e505edaeSJeff LaBundy 		if (fwnode_property_present(chan_node, "azoteq,use-prox"))
1796e505edaeSJeff LaBundy 			ref_setup[4] -= 2;
1797e505edaeSJeff LaBundy 	}
1798e505edaeSJeff LaBundy 
1799e505edaeSJeff LaBundy 	if (fwnode_property_present(chan_node, "azoteq,rx-enable")) {
1800e505edaeSJeff LaBundy 		/*
1801e505edaeSJeff LaBundy 		 * Each channel can claim up to 4 CRx pins. The first half of
1802e505edaeSJeff LaBundy 		 * the channels can use CRx0-3, while the second half can use
1803e505edaeSJeff LaBundy 		 * CRx4-7.
1804e505edaeSJeff LaBundy 		 */
1805e505edaeSJeff LaBundy 		unsigned int pins[4];
1806e505edaeSJeff LaBundy 		int count;
1807e505edaeSJeff LaBundy 
1808e505edaeSJeff LaBundy 		count = fwnode_property_count_u32(chan_node,
1809e505edaeSJeff LaBundy 						  "azoteq,rx-enable");
1810*eba697b3SDan Carpenter 		if (count < 0) {
1811e505edaeSJeff LaBundy 			dev_err(&client->dev,
1812e505edaeSJeff LaBundy 				"Failed to count %s CRx pins: %d\n",
1813e505edaeSJeff LaBundy 				fwnode_get_name(chan_node), count);
1814e505edaeSJeff LaBundy 			return count;
1815*eba697b3SDan Carpenter 		} else if (count > ARRAY_SIZE(pins)) {
1816*eba697b3SDan Carpenter 			dev_err(&client->dev,
1817*eba697b3SDan Carpenter 				"Invalid number of %s CRx pins\n",
1818*eba697b3SDan Carpenter 				fwnode_get_name(chan_node));
1819*eba697b3SDan Carpenter 			return -EINVAL;
1820e505edaeSJeff LaBundy 		}
1821e505edaeSJeff LaBundy 
1822e505edaeSJeff LaBundy 		error = fwnode_property_read_u32_array(chan_node,
1823e505edaeSJeff LaBundy 						       "azoteq,rx-enable",
1824e505edaeSJeff LaBundy 						       pins, count);
1825e505edaeSJeff LaBundy 		if (error) {
1826e505edaeSJeff LaBundy 			dev_err(&client->dev,
1827e505edaeSJeff LaBundy 				"Failed to read %s CRx pins: %d\n",
1828e505edaeSJeff LaBundy 				fwnode_get_name(chan_node), error);
1829e505edaeSJeff LaBundy 			return error;
1830e505edaeSJeff LaBundy 		}
1831e505edaeSJeff LaBundy 
1832e505edaeSJeff LaBundy 		chan_setup[0] &= ~GENMASK(4 + ARRAY_SIZE(pins) - 1, 4);
1833e505edaeSJeff LaBundy 
1834e505edaeSJeff LaBundy 		for (i = 0; i < count; i++) {
1835e505edaeSJeff LaBundy 			int min_crx = chan_index < ext_chan / 2 ? 0 : 4;
1836e505edaeSJeff LaBundy 
1837e505edaeSJeff LaBundy 			if (pins[i] < min_crx || pins[i] > min_crx + 3) {
1838e505edaeSJeff LaBundy 				dev_err(&client->dev,
1839e505edaeSJeff LaBundy 					"Invalid %s CRx pin: %u\n",
1840e505edaeSJeff LaBundy 					fwnode_get_name(chan_node), pins[i]);
1841e505edaeSJeff LaBundy 				return -EINVAL;
1842e505edaeSJeff LaBundy 			}
1843e505edaeSJeff LaBundy 
1844e505edaeSJeff LaBundy 			chan_setup[0] |= BIT(pins[i] + 4 - min_crx);
1845e505edaeSJeff LaBundy 		}
1846e505edaeSJeff LaBundy 	}
1847e505edaeSJeff LaBundy 
1848e505edaeSJeff LaBundy 	for (i = 0; i < ARRAY_SIZE(iqs7222_kp_events); i++) {
1849e505edaeSJeff LaBundy 		const char *event_name = iqs7222_kp_events[i].name;
1850e505edaeSJeff LaBundy 		u16 event_enable = iqs7222_kp_events[i].enable;
1851e505edaeSJeff LaBundy 		struct fwnode_handle *event_node;
1852e505edaeSJeff LaBundy 
1853e505edaeSJeff LaBundy 		event_node = fwnode_get_named_child_node(chan_node, event_name);
1854e505edaeSJeff LaBundy 		if (!event_node)
1855e505edaeSJeff LaBundy 			continue;
1856e505edaeSJeff LaBundy 
1857e505edaeSJeff LaBundy 		error = iqs7222_parse_props(iqs7222, &event_node, chan_index,
1858e505edaeSJeff LaBundy 					    IQS7222_REG_GRP_BTN,
1859e505edaeSJeff LaBundy 					    iqs7222_kp_events[i].reg_key);
1860e505edaeSJeff LaBundy 		if (error)
1861e505edaeSJeff LaBundy 			return error;
1862e505edaeSJeff LaBundy 
1863e505edaeSJeff LaBundy 		error = iqs7222_gpio_select(iqs7222, event_node,
1864e505edaeSJeff LaBundy 					    BIT(chan_index),
1865e505edaeSJeff LaBundy 					    dev_desc->touch_link - (i ? 0 : 2));
1866e505edaeSJeff LaBundy 		if (error)
1867e505edaeSJeff LaBundy 			return error;
1868e505edaeSJeff LaBundy 
1869e505edaeSJeff LaBundy 		if (!fwnode_property_read_u32(event_node,
1870e505edaeSJeff LaBundy 					      "azoteq,timeout-press-ms",
1871e505edaeSJeff LaBundy 					      &val)) {
1872e505edaeSJeff LaBundy 			/*
1873e505edaeSJeff LaBundy 			 * The IQS7222B employs a global pair of press timeout
1874e505edaeSJeff LaBundy 			 * registers as opposed to channel-specific registers.
1875e505edaeSJeff LaBundy 			 */
1876e505edaeSJeff LaBundy 			u16 *setup = dev_desc->reg_grps
1877e505edaeSJeff LaBundy 				     [IQS7222_REG_GRP_BTN].num_col > 2 ?
1878e505edaeSJeff LaBundy 				     &iqs7222->btn_setup[chan_index][2] :
1879e505edaeSJeff LaBundy 				     &sys_setup[9];
1880e505edaeSJeff LaBundy 
1881e505edaeSJeff LaBundy 			if (val > U8_MAX * 500) {
1882e505edaeSJeff LaBundy 				dev_err(&client->dev,
1883e505edaeSJeff LaBundy 					"Invalid %s press timeout: %u\n",
1884e505edaeSJeff LaBundy 					fwnode_get_name(chan_node), val);
1885e505edaeSJeff LaBundy 				return -EINVAL;
1886e505edaeSJeff LaBundy 			}
1887e505edaeSJeff LaBundy 
1888e505edaeSJeff LaBundy 			*setup &= ~(U8_MAX << i * 8);
1889e505edaeSJeff LaBundy 			*setup |= (val / 500 << i * 8);
1890e505edaeSJeff LaBundy 		}
1891e505edaeSJeff LaBundy 
1892e505edaeSJeff LaBundy 		error = fwnode_property_read_u32(event_node, "linux,code",
1893e505edaeSJeff LaBundy 						 &val);
1894e505edaeSJeff LaBundy 		if (error) {
1895e505edaeSJeff LaBundy 			dev_err(&client->dev, "Failed to read %s code: %d\n",
1896e505edaeSJeff LaBundy 				fwnode_get_name(chan_node), error);
1897e505edaeSJeff LaBundy 			return error;
1898e505edaeSJeff LaBundy 		}
1899e505edaeSJeff LaBundy 
1900e505edaeSJeff LaBundy 		iqs7222->kp_code[chan_index][i] = val;
1901e505edaeSJeff LaBundy 		iqs7222->kp_type[chan_index][i] = EV_KEY;
1902e505edaeSJeff LaBundy 
1903e505edaeSJeff LaBundy 		if (fwnode_property_present(event_node, "linux,input-type")) {
1904e505edaeSJeff LaBundy 			error = fwnode_property_read_u32(event_node,
1905e505edaeSJeff LaBundy 							 "linux,input-type",
1906e505edaeSJeff LaBundy 							 &val);
1907e505edaeSJeff LaBundy 			if (error) {
1908e505edaeSJeff LaBundy 				dev_err(&client->dev,
1909e505edaeSJeff LaBundy 					"Failed to read %s input type: %d\n",
1910e505edaeSJeff LaBundy 					fwnode_get_name(chan_node), error);
1911e505edaeSJeff LaBundy 				return error;
1912e505edaeSJeff LaBundy 			}
1913e505edaeSJeff LaBundy 
1914e505edaeSJeff LaBundy 			if (val != EV_KEY && val != EV_SW) {
1915e505edaeSJeff LaBundy 				dev_err(&client->dev,
1916e505edaeSJeff LaBundy 					"Invalid %s input type: %u\n",
1917e505edaeSJeff LaBundy 					fwnode_get_name(chan_node), val);
1918e505edaeSJeff LaBundy 				return -EINVAL;
1919e505edaeSJeff LaBundy 			}
1920e505edaeSJeff LaBundy 
1921e505edaeSJeff LaBundy 			iqs7222->kp_type[chan_index][i] = val;
1922e505edaeSJeff LaBundy 		}
1923e505edaeSJeff LaBundy 
1924e505edaeSJeff LaBundy 		/*
1925e505edaeSJeff LaBundy 		 * Reference channels can opt out of event reporting by using
1926e505edaeSJeff LaBundy 		 * KEY_RESERVED in place of a true key or switch code.
1927e505edaeSJeff LaBundy 		 */
1928e505edaeSJeff LaBundy 		if (iqs7222->kp_type[chan_index][i] == EV_KEY &&
1929e505edaeSJeff LaBundy 		    iqs7222->kp_code[chan_index][i] == KEY_RESERVED)
1930e505edaeSJeff LaBundy 			continue;
1931e505edaeSJeff LaBundy 
1932e505edaeSJeff LaBundy 		input_set_capability(iqs7222->keypad,
1933e505edaeSJeff LaBundy 				     iqs7222->kp_type[chan_index][i],
1934e505edaeSJeff LaBundy 				     iqs7222->kp_code[chan_index][i]);
1935e505edaeSJeff LaBundy 
1936e505edaeSJeff LaBundy 		if (!dev_desc->event_offset)
1937e505edaeSJeff LaBundy 			continue;
1938e505edaeSJeff LaBundy 
1939e505edaeSJeff LaBundy 		sys_setup[dev_desc->event_offset] |= event_enable;
1940e505edaeSJeff LaBundy 	}
1941e505edaeSJeff LaBundy 
1942e505edaeSJeff LaBundy 	/*
1943e505edaeSJeff LaBundy 	 * The following call handles a special pair of properties that apply
1944e505edaeSJeff LaBundy 	 * to a channel node, but reside within the button (event) group.
1945e505edaeSJeff LaBundy 	 */
1946e505edaeSJeff LaBundy 	return iqs7222_parse_props(iqs7222, &chan_node, chan_index,
1947e505edaeSJeff LaBundy 				   IQS7222_REG_GRP_BTN,
1948e505edaeSJeff LaBundy 				   IQS7222_REG_KEY_DEBOUNCE);
1949e505edaeSJeff LaBundy }
1950e505edaeSJeff LaBundy 
1951e505edaeSJeff LaBundy static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222, int sldr_index)
1952e505edaeSJeff LaBundy {
1953e505edaeSJeff LaBundy 	const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
1954e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
1955e505edaeSJeff LaBundy 	struct fwnode_handle *sldr_node = NULL;
1956e505edaeSJeff LaBundy 	int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
1957e505edaeSJeff LaBundy 	int ext_chan = rounddown(num_chan, 10);
1958e505edaeSJeff LaBundy 	int count, error, reg_offset, i;
1959e505edaeSJeff LaBundy 	u16 *sldr_setup = iqs7222->sldr_setup[sldr_index];
1960e505edaeSJeff LaBundy 	u16 *sys_setup = iqs7222->sys_setup;
1961e505edaeSJeff LaBundy 	unsigned int chan_sel[4], val;
1962e505edaeSJeff LaBundy 
1963e505edaeSJeff LaBundy 	error = iqs7222_parse_props(iqs7222, &sldr_node, sldr_index,
1964e505edaeSJeff LaBundy 				    IQS7222_REG_GRP_SLDR,
1965e505edaeSJeff LaBundy 				    IQS7222_REG_KEY_NONE);
1966e505edaeSJeff LaBundy 	if (error)
1967e505edaeSJeff LaBundy 		return error;
1968e505edaeSJeff LaBundy 
1969e505edaeSJeff LaBundy 	if (!sldr_node)
1970e505edaeSJeff LaBundy 		return 0;
1971e505edaeSJeff LaBundy 
1972e505edaeSJeff LaBundy 	/*
1973e505edaeSJeff LaBundy 	 * Each slider can be spread across 3 to 4 channels. It is possible to
1974e505edaeSJeff LaBundy 	 * select only 2 channels, but doing so prevents the slider from using
1975e505edaeSJeff LaBundy 	 * the specified resolution.
1976e505edaeSJeff LaBundy 	 */
1977e505edaeSJeff LaBundy 	count = fwnode_property_count_u32(sldr_node, "azoteq,channel-select");
1978*eba697b3SDan Carpenter 	if (count < 0) {
1979e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to count %s channels: %d\n",
1980e505edaeSJeff LaBundy 			fwnode_get_name(sldr_node), count);
1981e505edaeSJeff LaBundy 		return count;
1982*eba697b3SDan Carpenter 	} else if (count < 3 || count > ARRAY_SIZE(chan_sel)) {
1983*eba697b3SDan Carpenter 		dev_err(&client->dev, "Invalid number of %s channels\n",
1984*eba697b3SDan Carpenter 			fwnode_get_name(sldr_node));
1985*eba697b3SDan Carpenter 		return -EINVAL;
1986e505edaeSJeff LaBundy 	}
1987e505edaeSJeff LaBundy 
1988e505edaeSJeff LaBundy 	error = fwnode_property_read_u32_array(sldr_node,
1989e505edaeSJeff LaBundy 					       "azoteq,channel-select",
1990e505edaeSJeff LaBundy 					       chan_sel, count);
1991e505edaeSJeff LaBundy 	if (error) {
1992e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to read %s channels: %d\n",
1993e505edaeSJeff LaBundy 			fwnode_get_name(sldr_node), error);
1994e505edaeSJeff LaBundy 		return error;
1995e505edaeSJeff LaBundy 	}
1996e505edaeSJeff LaBundy 
1997e505edaeSJeff LaBundy 	/*
1998e505edaeSJeff LaBundy 	 * Resolution and top speed, if small enough, are packed into a single
1999e505edaeSJeff LaBundy 	 * register. Otherwise, each occupies its own register and the rest of
2000e505edaeSJeff LaBundy 	 * the slider-related register addresses are offset by one.
2001e505edaeSJeff LaBundy 	 */
2002e505edaeSJeff LaBundy 	reg_offset = dev_desc->sldr_res < U16_MAX ? 0 : 1;
2003e505edaeSJeff LaBundy 
2004e505edaeSJeff LaBundy 	sldr_setup[0] |= count;
2005e505edaeSJeff LaBundy 	sldr_setup[3 + reg_offset] &= ~IQS7222_SLDR_SETUP_3_CHAN_SEL_MASK;
2006e505edaeSJeff LaBundy 
2007e505edaeSJeff LaBundy 	for (i = 0; i < ARRAY_SIZE(chan_sel); i++) {
2008e505edaeSJeff LaBundy 		sldr_setup[5 + reg_offset + i] = 0;
2009e505edaeSJeff LaBundy 		if (i >= count)
2010e505edaeSJeff LaBundy 			continue;
2011e505edaeSJeff LaBundy 
2012e505edaeSJeff LaBundy 		if (chan_sel[i] >= ext_chan) {
2013e505edaeSJeff LaBundy 			dev_err(&client->dev, "Invalid %s channel: %u\n",
2014e505edaeSJeff LaBundy 				fwnode_get_name(sldr_node), chan_sel[i]);
2015e505edaeSJeff LaBundy 			return -EINVAL;
2016e505edaeSJeff LaBundy 		}
2017e505edaeSJeff LaBundy 
2018e505edaeSJeff LaBundy 		/*
2019e505edaeSJeff LaBundy 		 * The following fields indicate which channels participate in
2020e505edaeSJeff LaBundy 		 * the slider, as well as each channel's relative placement.
2021e505edaeSJeff LaBundy 		 */
2022e505edaeSJeff LaBundy 		sldr_setup[3 + reg_offset] |= BIT(chan_sel[i]);
2023e505edaeSJeff LaBundy 		sldr_setup[5 + reg_offset + i] = chan_sel[i] * 42 + 1080;
2024e505edaeSJeff LaBundy 	}
2025e505edaeSJeff LaBundy 
2026e505edaeSJeff LaBundy 	sldr_setup[4 + reg_offset] = dev_desc->touch_link;
2027e505edaeSJeff LaBundy 	if (fwnode_property_present(sldr_node, "azoteq,use-prox"))
2028e505edaeSJeff LaBundy 		sldr_setup[4 + reg_offset] -= 2;
2029e505edaeSJeff LaBundy 
2030e505edaeSJeff LaBundy 	if (!fwnode_property_read_u32(sldr_node, "azoteq,slider-size", &val)) {
2031e505edaeSJeff LaBundy 		if (!val || val > dev_desc->sldr_res) {
2032e505edaeSJeff LaBundy 			dev_err(&client->dev, "Invalid %s size: %u\n",
2033e505edaeSJeff LaBundy 				fwnode_get_name(sldr_node), val);
2034e505edaeSJeff LaBundy 			return -EINVAL;
2035e505edaeSJeff LaBundy 		}
2036e505edaeSJeff LaBundy 
2037e505edaeSJeff LaBundy 		if (reg_offset) {
2038e505edaeSJeff LaBundy 			sldr_setup[3] = val;
2039e505edaeSJeff LaBundy 		} else {
2040e505edaeSJeff LaBundy 			sldr_setup[2] &= ~IQS7222_SLDR_SETUP_2_RES_MASK;
2041e505edaeSJeff LaBundy 			sldr_setup[2] |= (val / 16 <<
2042e505edaeSJeff LaBundy 					  IQS7222_SLDR_SETUP_2_RES_SHIFT);
2043e505edaeSJeff LaBundy 		}
2044e505edaeSJeff LaBundy 	}
2045e505edaeSJeff LaBundy 
2046e505edaeSJeff LaBundy 	if (!fwnode_property_read_u32(sldr_node, "azoteq,top-speed", &val)) {
2047e505edaeSJeff LaBundy 		if (val > (reg_offset ? U16_MAX : U8_MAX * 4)) {
2048e505edaeSJeff LaBundy 			dev_err(&client->dev, "Invalid %s top speed: %u\n",
2049e505edaeSJeff LaBundy 				fwnode_get_name(sldr_node), val);
2050e505edaeSJeff LaBundy 			return -EINVAL;
2051e505edaeSJeff LaBundy 		}
2052e505edaeSJeff LaBundy 
2053e505edaeSJeff LaBundy 		if (reg_offset) {
2054e505edaeSJeff LaBundy 			sldr_setup[2] = val;
2055e505edaeSJeff LaBundy 		} else {
2056e505edaeSJeff LaBundy 			sldr_setup[2] &= ~IQS7222_SLDR_SETUP_2_TOP_SPEED_MASK;
2057e505edaeSJeff LaBundy 			sldr_setup[2] |= (val / 4);
2058e505edaeSJeff LaBundy 		}
2059e505edaeSJeff LaBundy 	}
2060e505edaeSJeff LaBundy 
2061e505edaeSJeff LaBundy 	if (!fwnode_property_read_u32(sldr_node, "linux,axis", &val)) {
2062e505edaeSJeff LaBundy 		u16 sldr_max = sldr_setup[3] - 1;
2063e505edaeSJeff LaBundy 
2064e505edaeSJeff LaBundy 		if (!reg_offset) {
2065e505edaeSJeff LaBundy 			sldr_max = sldr_setup[2];
2066e505edaeSJeff LaBundy 
2067e505edaeSJeff LaBundy 			sldr_max &= IQS7222_SLDR_SETUP_2_RES_MASK;
2068e505edaeSJeff LaBundy 			sldr_max >>= IQS7222_SLDR_SETUP_2_RES_SHIFT;
2069e505edaeSJeff LaBundy 
2070e505edaeSJeff LaBundy 			sldr_max = sldr_max * 16 - 1;
2071e505edaeSJeff LaBundy 		}
2072e505edaeSJeff LaBundy 
2073e505edaeSJeff LaBundy 		input_set_abs_params(iqs7222->keypad, val, 0, sldr_max, 0, 0);
2074e505edaeSJeff LaBundy 		iqs7222->sl_axis[sldr_index] = val;
2075e505edaeSJeff LaBundy 	}
2076e505edaeSJeff LaBundy 
2077e505edaeSJeff LaBundy 	if (dev_desc->wheel_enable) {
2078e505edaeSJeff LaBundy 		sldr_setup[0] &= ~dev_desc->wheel_enable;
2079e505edaeSJeff LaBundy 		if (iqs7222->sl_axis[sldr_index] == ABS_WHEEL)
2080e505edaeSJeff LaBundy 			sldr_setup[0] |= dev_desc->wheel_enable;
2081e505edaeSJeff LaBundy 	}
2082e505edaeSJeff LaBundy 
2083e505edaeSJeff LaBundy 	for (i = 0; i < ARRAY_SIZE(iqs7222_sl_events); i++) {
2084e505edaeSJeff LaBundy 		const char *event_name = iqs7222_sl_events[i].name;
2085e505edaeSJeff LaBundy 		struct fwnode_handle *event_node;
2086e505edaeSJeff LaBundy 
2087e505edaeSJeff LaBundy 		/*
2088e505edaeSJeff LaBundy 		 * The absence of a register offset means the remaining fields
2089e505edaeSJeff LaBundy 		 * in the group represent gesture settings.
2090e505edaeSJeff LaBundy 		 */
2091e505edaeSJeff LaBundy 		if (iqs7222_sl_events[i].enable && !reg_offset)
2092e505edaeSJeff LaBundy 			sldr_setup[9] &= ~iqs7222_sl_events[i].enable;
2093e505edaeSJeff LaBundy 
2094e505edaeSJeff LaBundy 		event_node = fwnode_get_named_child_node(sldr_node, event_name);
2095e505edaeSJeff LaBundy 		if (!event_node)
2096e505edaeSJeff LaBundy 			continue;
2097e505edaeSJeff LaBundy 
2098e505edaeSJeff LaBundy 		error = iqs7222_parse_props(iqs7222, &event_node, sldr_index,
2099e505edaeSJeff LaBundy 					    IQS7222_REG_GRP_SLDR,
2100e505edaeSJeff LaBundy 					    reg_offset ?
2101e505edaeSJeff LaBundy 					    IQS7222_REG_KEY_RESERVED :
2102e505edaeSJeff LaBundy 					    iqs7222_sl_events[i].reg_key);
2103e505edaeSJeff LaBundy 		if (error)
2104e505edaeSJeff LaBundy 			return error;
2105e505edaeSJeff LaBundy 
2106e505edaeSJeff LaBundy 		error = fwnode_property_read_u32(event_node, "linux,code",
2107e505edaeSJeff LaBundy 						 &val);
2108e505edaeSJeff LaBundy 		if (error) {
2109e505edaeSJeff LaBundy 			dev_err(&client->dev, "Failed to read %s code: %d\n",
2110e505edaeSJeff LaBundy 				fwnode_get_name(sldr_node), error);
2111e505edaeSJeff LaBundy 			return error;
2112e505edaeSJeff LaBundy 		}
2113e505edaeSJeff LaBundy 
2114e505edaeSJeff LaBundy 		iqs7222->sl_code[sldr_index][i] = val;
2115e505edaeSJeff LaBundy 		input_set_capability(iqs7222->keypad, EV_KEY, val);
2116e505edaeSJeff LaBundy 
2117e505edaeSJeff LaBundy 		/*
2118e505edaeSJeff LaBundy 		 * The press/release event is determined based on whether the
2119e505edaeSJeff LaBundy 		 * coordinate field reports 0xFFFF and has no explicit enable
2120e505edaeSJeff LaBundy 		 * control.
2121e505edaeSJeff LaBundy 		 */
2122e505edaeSJeff LaBundy 		if (!iqs7222_sl_events[i].enable || reg_offset)
2123e505edaeSJeff LaBundy 			continue;
2124e505edaeSJeff LaBundy 
2125e505edaeSJeff LaBundy 		sldr_setup[9] |= iqs7222_sl_events[i].enable;
2126e505edaeSJeff LaBundy 
2127e505edaeSJeff LaBundy 		error = iqs7222_gpio_select(iqs7222, event_node,
2128e505edaeSJeff LaBundy 					    iqs7222_sl_events[i].enable,
2129e505edaeSJeff LaBundy 					    1568 + sldr_index * 30);
2130e505edaeSJeff LaBundy 		if (error)
2131e505edaeSJeff LaBundy 			return error;
2132e505edaeSJeff LaBundy 
2133e505edaeSJeff LaBundy 		if (!dev_desc->event_offset)
2134e505edaeSJeff LaBundy 			continue;
2135e505edaeSJeff LaBundy 
2136e505edaeSJeff LaBundy 		sys_setup[dev_desc->event_offset] |= BIT(10 + sldr_index);
2137e505edaeSJeff LaBundy 	}
2138e505edaeSJeff LaBundy 
2139e505edaeSJeff LaBundy 	/*
2140e505edaeSJeff LaBundy 	 * The following call handles a special pair of properties that shift
2141e505edaeSJeff LaBundy 	 * to make room for a wheel enable control in the case of IQS7222C.
2142e505edaeSJeff LaBundy 	 */
2143e505edaeSJeff LaBundy 	return iqs7222_parse_props(iqs7222, &sldr_node, sldr_index,
2144e505edaeSJeff LaBundy 				   IQS7222_REG_GRP_SLDR,
2145e505edaeSJeff LaBundy 				   dev_desc->wheel_enable ?
2146e505edaeSJeff LaBundy 				   IQS7222_REG_KEY_WHEEL :
2147e505edaeSJeff LaBundy 				   IQS7222_REG_KEY_NO_WHEEL);
2148e505edaeSJeff LaBundy }
2149e505edaeSJeff LaBundy 
2150e505edaeSJeff LaBundy static int iqs7222_parse_all(struct iqs7222_private *iqs7222)
2151e505edaeSJeff LaBundy {
2152e505edaeSJeff LaBundy 	const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
2153e505edaeSJeff LaBundy 	const struct iqs7222_reg_grp_desc *reg_grps = dev_desc->reg_grps;
2154e505edaeSJeff LaBundy 	u16 *sys_setup = iqs7222->sys_setup;
2155e505edaeSJeff LaBundy 	int error, i;
2156e505edaeSJeff LaBundy 
2157e505edaeSJeff LaBundy 	if (dev_desc->event_offset)
2158e505edaeSJeff LaBundy 		sys_setup[dev_desc->event_offset] = IQS7222_EVENT_MASK_ATI;
2159e505edaeSJeff LaBundy 
2160e505edaeSJeff LaBundy 	for (i = 0; i < reg_grps[IQS7222_REG_GRP_CYCLE].num_row; i++) {
2161e505edaeSJeff LaBundy 		error = iqs7222_parse_cycle(iqs7222, i);
2162e505edaeSJeff LaBundy 		if (error)
2163e505edaeSJeff LaBundy 			return error;
2164e505edaeSJeff LaBundy 	}
2165e505edaeSJeff LaBundy 
2166e505edaeSJeff LaBundy 	error = iqs7222_parse_props(iqs7222, NULL, 0, IQS7222_REG_GRP_GLBL,
2167e505edaeSJeff LaBundy 				    IQS7222_REG_KEY_NONE);
2168e505edaeSJeff LaBundy 	if (error)
2169e505edaeSJeff LaBundy 		return error;
2170e505edaeSJeff LaBundy 
2171e505edaeSJeff LaBundy 	for (i = 0; i < reg_grps[IQS7222_REG_GRP_GPIO].num_row; i++) {
2172e505edaeSJeff LaBundy 		struct fwnode_handle *gpio_node = NULL;
2173e505edaeSJeff LaBundy 		u16 *gpio_setup = iqs7222->gpio_setup[i];
2174e505edaeSJeff LaBundy 		int j;
2175e505edaeSJeff LaBundy 
2176e505edaeSJeff LaBundy 		gpio_setup[0] &= ~IQS7222_GPIO_SETUP_0_GPIO_EN;
2177e505edaeSJeff LaBundy 		gpio_setup[1] = 0;
2178e505edaeSJeff LaBundy 		gpio_setup[2] = 0;
2179e505edaeSJeff LaBundy 
2180e505edaeSJeff LaBundy 		error = iqs7222_parse_props(iqs7222, &gpio_node, i,
2181e505edaeSJeff LaBundy 					    IQS7222_REG_GRP_GPIO,
2182e505edaeSJeff LaBundy 					    IQS7222_REG_KEY_NONE);
2183e505edaeSJeff LaBundy 		if (error)
2184e505edaeSJeff LaBundy 			return error;
2185e505edaeSJeff LaBundy 
2186e505edaeSJeff LaBundy 		if (reg_grps[IQS7222_REG_GRP_GPIO].num_row == 1)
2187e505edaeSJeff LaBundy 			continue;
2188e505edaeSJeff LaBundy 
2189e505edaeSJeff LaBundy 		/*
2190e505edaeSJeff LaBundy 		 * The IQS7222C exposes multiple GPIO and must be informed
2191e505edaeSJeff LaBundy 		 * as to which GPIO this group represents.
2192e505edaeSJeff LaBundy 		 */
2193e505edaeSJeff LaBundy 		for (j = 0; j < ARRAY_SIZE(iqs7222_gpio_links); j++)
2194e505edaeSJeff LaBundy 			gpio_setup[0] &= ~BIT(iqs7222_gpio_links[j]);
2195e505edaeSJeff LaBundy 
2196e505edaeSJeff LaBundy 		gpio_setup[0] |= BIT(iqs7222_gpio_links[i]);
2197e505edaeSJeff LaBundy 	}
2198e505edaeSJeff LaBundy 
2199e505edaeSJeff LaBundy 	for (i = 0; i < reg_grps[IQS7222_REG_GRP_CHAN].num_row; i++) {
2200e505edaeSJeff LaBundy 		u16 *chan_setup = iqs7222->chan_setup[i];
2201e505edaeSJeff LaBundy 
2202e505edaeSJeff LaBundy 		chan_setup[0] &= ~IQS7222_CHAN_SETUP_0_REF_MODE_MASK;
2203e505edaeSJeff LaBundy 		chan_setup[0] &= ~IQS7222_CHAN_SETUP_0_CHAN_EN;
2204e505edaeSJeff LaBundy 
2205e505edaeSJeff LaBundy 		chan_setup[5] = 0;
2206e505edaeSJeff LaBundy 	}
2207e505edaeSJeff LaBundy 
2208e505edaeSJeff LaBundy 	for (i = 0; i < reg_grps[IQS7222_REG_GRP_CHAN].num_row; i++) {
2209e505edaeSJeff LaBundy 		error = iqs7222_parse_chan(iqs7222, i);
2210e505edaeSJeff LaBundy 		if (error)
2211e505edaeSJeff LaBundy 			return error;
2212e505edaeSJeff LaBundy 	}
2213e505edaeSJeff LaBundy 
2214e505edaeSJeff LaBundy 	error = iqs7222_parse_props(iqs7222, NULL, 0, IQS7222_REG_GRP_FILT,
2215e505edaeSJeff LaBundy 				    IQS7222_REG_KEY_NONE);
2216e505edaeSJeff LaBundy 	if (error)
2217e505edaeSJeff LaBundy 		return error;
2218e505edaeSJeff LaBundy 
2219e505edaeSJeff LaBundy 	for (i = 0; i < reg_grps[IQS7222_REG_GRP_SLDR].num_row; i++) {
2220e505edaeSJeff LaBundy 		u16 *sldr_setup = iqs7222->sldr_setup[i];
2221e505edaeSJeff LaBundy 
2222e505edaeSJeff LaBundy 		sldr_setup[0] &= ~IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK;
2223e505edaeSJeff LaBundy 
2224e505edaeSJeff LaBundy 		error = iqs7222_parse_sldr(iqs7222, i);
2225e505edaeSJeff LaBundy 		if (error)
2226e505edaeSJeff LaBundy 			return error;
2227e505edaeSJeff LaBundy 	}
2228e505edaeSJeff LaBundy 
2229e505edaeSJeff LaBundy 	sys_setup[0] &= ~IQS7222_SYS_SETUP_INTF_MODE_MASK;
2230e505edaeSJeff LaBundy 	sys_setup[0] &= ~IQS7222_SYS_SETUP_PWR_MODE_MASK;
2231e505edaeSJeff LaBundy 
2232e505edaeSJeff LaBundy 	sys_setup[0] |= IQS7222_SYS_SETUP_ACK_RESET;
2233e505edaeSJeff LaBundy 
2234e505edaeSJeff LaBundy 	return iqs7222_parse_props(iqs7222, NULL, 0, IQS7222_REG_GRP_SYS,
2235e505edaeSJeff LaBundy 				   IQS7222_REG_KEY_NONE);
2236e505edaeSJeff LaBundy }
2237e505edaeSJeff LaBundy 
2238e505edaeSJeff LaBundy static int iqs7222_report(struct iqs7222_private *iqs7222)
2239e505edaeSJeff LaBundy {
2240e505edaeSJeff LaBundy 	const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
2241e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
2242e505edaeSJeff LaBundy 	int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
2243e505edaeSJeff LaBundy 	int num_stat = dev_desc->reg_grps[IQS7222_REG_GRP_STAT].num_col;
2244e505edaeSJeff LaBundy 	int error, i, j;
2245e505edaeSJeff LaBundy 	__le16 status[IQS7222_MAX_COLS_STAT];
2246e505edaeSJeff LaBundy 
2247e505edaeSJeff LaBundy 	error = iqs7222_read_burst(iqs7222, IQS7222_SYS_STATUS, status,
2248e505edaeSJeff LaBundy 				   num_stat);
2249e505edaeSJeff LaBundy 	if (error)
2250e505edaeSJeff LaBundy 		return error;
2251e505edaeSJeff LaBundy 
2252e505edaeSJeff LaBundy 	if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_RESET) {
2253e505edaeSJeff LaBundy 		dev_err(&client->dev, "Unexpected device reset\n");
2254e505edaeSJeff LaBundy 		return iqs7222_dev_init(iqs7222, WRITE);
2255e505edaeSJeff LaBundy 	}
2256e505edaeSJeff LaBundy 
2257e505edaeSJeff LaBundy 	if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_ATI_ERROR) {
2258e505edaeSJeff LaBundy 		dev_err(&client->dev, "Unexpected ATI error\n");
2259e505edaeSJeff LaBundy 		return iqs7222_ati_trigger(iqs7222);
2260e505edaeSJeff LaBundy 	}
2261e505edaeSJeff LaBundy 
2262e505edaeSJeff LaBundy 	if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_ATI_ACTIVE)
2263e505edaeSJeff LaBundy 		return 0;
2264e505edaeSJeff LaBundy 
2265e505edaeSJeff LaBundy 	for (i = 0; i < num_chan; i++) {
2266e505edaeSJeff LaBundy 		u16 *chan_setup = iqs7222->chan_setup[i];
2267e505edaeSJeff LaBundy 
2268e505edaeSJeff LaBundy 		if (!(chan_setup[0] & IQS7222_CHAN_SETUP_0_CHAN_EN))
2269e505edaeSJeff LaBundy 			continue;
2270e505edaeSJeff LaBundy 
2271e505edaeSJeff LaBundy 		for (j = 0; j < ARRAY_SIZE(iqs7222_kp_events); j++) {
2272e505edaeSJeff LaBundy 			/*
2273e505edaeSJeff LaBundy 			 * Proximity state begins at offset 2 and spills into
2274e505edaeSJeff LaBundy 			 * offset 3 for devices with more than 16 channels.
2275e505edaeSJeff LaBundy 			 *
2276e505edaeSJeff LaBundy 			 * Touch state begins at the first offset immediately
2277e505edaeSJeff LaBundy 			 * following proximity state.
2278e505edaeSJeff LaBundy 			 */
2279e505edaeSJeff LaBundy 			int k = 2 + j * (num_chan > 16 ? 2 : 1);
2280e505edaeSJeff LaBundy 			u16 state = le16_to_cpu(status[k + i / 16]);
2281e505edaeSJeff LaBundy 
2282e505edaeSJeff LaBundy 			input_event(iqs7222->keypad,
2283e505edaeSJeff LaBundy 				    iqs7222->kp_type[i][j],
2284e505edaeSJeff LaBundy 				    iqs7222->kp_code[i][j],
2285e505edaeSJeff LaBundy 				    !!(state & BIT(i % 16)));
2286e505edaeSJeff LaBundy 		}
2287e505edaeSJeff LaBundy 	}
2288e505edaeSJeff LaBundy 
2289e505edaeSJeff LaBundy 	for (i = 0; i < dev_desc->reg_grps[IQS7222_REG_GRP_SLDR].num_row; i++) {
2290e505edaeSJeff LaBundy 		u16 *sldr_setup = iqs7222->sldr_setup[i];
2291e505edaeSJeff LaBundy 		u16 sldr_pos = le16_to_cpu(status[4 + i]);
2292e505edaeSJeff LaBundy 		u16 state = le16_to_cpu(status[6 + i]);
2293e505edaeSJeff LaBundy 
2294e505edaeSJeff LaBundy 		if (!(sldr_setup[0] & IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK))
2295e505edaeSJeff LaBundy 			continue;
2296e505edaeSJeff LaBundy 
2297e505edaeSJeff LaBundy 		if (sldr_pos < dev_desc->sldr_res)
2298e505edaeSJeff LaBundy 			input_report_abs(iqs7222->keypad, iqs7222->sl_axis[i],
2299e505edaeSJeff LaBundy 					 sldr_pos);
2300e505edaeSJeff LaBundy 
2301e505edaeSJeff LaBundy 		for (j = 0; j < ARRAY_SIZE(iqs7222_sl_events); j++) {
2302e505edaeSJeff LaBundy 			u16 mask = iqs7222_sl_events[j].mask;
2303e505edaeSJeff LaBundy 			u16 val = iqs7222_sl_events[j].val;
2304e505edaeSJeff LaBundy 
2305e505edaeSJeff LaBundy 			if (!iqs7222_sl_events[j].enable) {
2306e505edaeSJeff LaBundy 				input_report_key(iqs7222->keypad,
2307e505edaeSJeff LaBundy 						 iqs7222->sl_code[i][j],
2308e505edaeSJeff LaBundy 						 sldr_pos < dev_desc->sldr_res);
2309e505edaeSJeff LaBundy 				continue;
2310e505edaeSJeff LaBundy 			}
2311e505edaeSJeff LaBundy 
2312e505edaeSJeff LaBundy 			/*
2313e505edaeSJeff LaBundy 			 * The remaining offsets represent gesture state, and
2314e505edaeSJeff LaBundy 			 * are discarded in the case of IQS7222C because only
2315e505edaeSJeff LaBundy 			 * absolute position is reported.
2316e505edaeSJeff LaBundy 			 */
2317e505edaeSJeff LaBundy 			if (num_stat < IQS7222_MAX_COLS_STAT)
2318e505edaeSJeff LaBundy 				continue;
2319e505edaeSJeff LaBundy 
2320e505edaeSJeff LaBundy 			input_report_key(iqs7222->keypad,
2321e505edaeSJeff LaBundy 					 iqs7222->sl_code[i][j],
2322e505edaeSJeff LaBundy 					 (state & mask) == val);
2323e505edaeSJeff LaBundy 		}
2324e505edaeSJeff LaBundy 	}
2325e505edaeSJeff LaBundy 
2326e505edaeSJeff LaBundy 	input_sync(iqs7222->keypad);
2327e505edaeSJeff LaBundy 
2328e505edaeSJeff LaBundy 	return 0;
2329e505edaeSJeff LaBundy }
2330e505edaeSJeff LaBundy 
2331e505edaeSJeff LaBundy static irqreturn_t iqs7222_irq(int irq, void *context)
2332e505edaeSJeff LaBundy {
2333e505edaeSJeff LaBundy 	struct iqs7222_private *iqs7222 = context;
2334e505edaeSJeff LaBundy 
2335e505edaeSJeff LaBundy 	return iqs7222_report(iqs7222) ? IRQ_NONE : IRQ_HANDLED;
2336e505edaeSJeff LaBundy }
2337e505edaeSJeff LaBundy 
2338e505edaeSJeff LaBundy static int iqs7222_probe(struct i2c_client *client)
2339e505edaeSJeff LaBundy {
2340e505edaeSJeff LaBundy 	struct iqs7222_private *iqs7222;
2341e505edaeSJeff LaBundy 	unsigned long irq_flags;
2342e505edaeSJeff LaBundy 	int error, irq;
2343e505edaeSJeff LaBundy 
2344e505edaeSJeff LaBundy 	iqs7222 = devm_kzalloc(&client->dev, sizeof(*iqs7222), GFP_KERNEL);
2345e505edaeSJeff LaBundy 	if (!iqs7222)
2346e505edaeSJeff LaBundy 		return -ENOMEM;
2347e505edaeSJeff LaBundy 
2348e505edaeSJeff LaBundy 	i2c_set_clientdata(client, iqs7222);
2349e505edaeSJeff LaBundy 	iqs7222->client = client;
2350e505edaeSJeff LaBundy 
2351e505edaeSJeff LaBundy 	iqs7222->keypad = devm_input_allocate_device(&client->dev);
2352e505edaeSJeff LaBundy 	if (!iqs7222->keypad)
2353e505edaeSJeff LaBundy 		return -ENOMEM;
2354e505edaeSJeff LaBundy 
2355e505edaeSJeff LaBundy 	iqs7222->keypad->name = client->name;
2356e505edaeSJeff LaBundy 	iqs7222->keypad->id.bustype = BUS_I2C;
2357e505edaeSJeff LaBundy 
2358e505edaeSJeff LaBundy 	/*
2359e505edaeSJeff LaBundy 	 * The RDY pin behaves as an interrupt, but must also be polled ahead
2360e505edaeSJeff LaBundy 	 * of unsolicited I2C communication. As such, it is first opened as a
2361e505edaeSJeff LaBundy 	 * GPIO and then passed to gpiod_to_irq() to register the interrupt.
2362e505edaeSJeff LaBundy 	 */
2363e505edaeSJeff LaBundy 	iqs7222->irq_gpio = devm_gpiod_get(&client->dev, "irq", GPIOD_IN);
2364e505edaeSJeff LaBundy 	if (IS_ERR(iqs7222->irq_gpio)) {
2365e505edaeSJeff LaBundy 		error = PTR_ERR(iqs7222->irq_gpio);
2366e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to request IRQ GPIO: %d\n",
2367e505edaeSJeff LaBundy 			error);
2368e505edaeSJeff LaBundy 		return error;
2369e505edaeSJeff LaBundy 	}
2370e505edaeSJeff LaBundy 
2371e505edaeSJeff LaBundy 	iqs7222->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
2372e505edaeSJeff LaBundy 						      GPIOD_OUT_HIGH);
2373e505edaeSJeff LaBundy 	if (IS_ERR(iqs7222->reset_gpio)) {
2374e505edaeSJeff LaBundy 		error = PTR_ERR(iqs7222->reset_gpio);
2375e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to request reset GPIO: %d\n",
2376e505edaeSJeff LaBundy 			error);
2377e505edaeSJeff LaBundy 		return error;
2378e505edaeSJeff LaBundy 	}
2379e505edaeSJeff LaBundy 
2380e505edaeSJeff LaBundy 	error = iqs7222_hard_reset(iqs7222);
2381e505edaeSJeff LaBundy 	if (error)
2382e505edaeSJeff LaBundy 		return error;
2383e505edaeSJeff LaBundy 
2384e505edaeSJeff LaBundy 	error = iqs7222_dev_info(iqs7222);
2385e505edaeSJeff LaBundy 	if (error)
2386e505edaeSJeff LaBundy 		return error;
2387e505edaeSJeff LaBundy 
2388e505edaeSJeff LaBundy 	error = iqs7222_dev_init(iqs7222, READ);
2389e505edaeSJeff LaBundy 	if (error)
2390e505edaeSJeff LaBundy 		return error;
2391e505edaeSJeff LaBundy 
2392e505edaeSJeff LaBundy 	error = iqs7222_parse_all(iqs7222);
2393e505edaeSJeff LaBundy 	if (error)
2394e505edaeSJeff LaBundy 		return error;
2395e505edaeSJeff LaBundy 
2396e505edaeSJeff LaBundy 	error = iqs7222_dev_init(iqs7222, WRITE);
2397e505edaeSJeff LaBundy 	if (error)
2398e505edaeSJeff LaBundy 		return error;
2399e505edaeSJeff LaBundy 
2400e505edaeSJeff LaBundy 	error = iqs7222_report(iqs7222);
2401e505edaeSJeff LaBundy 	if (error)
2402e505edaeSJeff LaBundy 		return error;
2403e505edaeSJeff LaBundy 
2404e505edaeSJeff LaBundy 	error = input_register_device(iqs7222->keypad);
2405e505edaeSJeff LaBundy 	if (error) {
2406e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to register device: %d\n", error);
2407e505edaeSJeff LaBundy 		return error;
2408e505edaeSJeff LaBundy 	}
2409e505edaeSJeff LaBundy 
2410e505edaeSJeff LaBundy 	irq = gpiod_to_irq(iqs7222->irq_gpio);
2411e505edaeSJeff LaBundy 	if (irq < 0)
2412e505edaeSJeff LaBundy 		return irq;
2413e505edaeSJeff LaBundy 
2414e505edaeSJeff LaBundy 	irq_flags = gpiod_is_active_low(iqs7222->irq_gpio) ? IRQF_TRIGGER_LOW
2415e505edaeSJeff LaBundy 							   : IRQF_TRIGGER_HIGH;
2416e505edaeSJeff LaBundy 	irq_flags |= IRQF_ONESHOT;
2417e505edaeSJeff LaBundy 
2418e505edaeSJeff LaBundy 	error = devm_request_threaded_irq(&client->dev, irq, NULL, iqs7222_irq,
2419e505edaeSJeff LaBundy 					  irq_flags, client->name, iqs7222);
2420e505edaeSJeff LaBundy 	if (error)
2421e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to request IRQ: %d\n", error);
2422e505edaeSJeff LaBundy 
2423e505edaeSJeff LaBundy 	return error;
2424e505edaeSJeff LaBundy }
2425e505edaeSJeff LaBundy 
2426e505edaeSJeff LaBundy static const struct of_device_id iqs7222_of_match[] = {
2427e505edaeSJeff LaBundy 	{ .compatible = "azoteq,iqs7222a" },
2428e505edaeSJeff LaBundy 	{ .compatible = "azoteq,iqs7222b" },
2429e505edaeSJeff LaBundy 	{ .compatible = "azoteq,iqs7222c" },
2430e505edaeSJeff LaBundy 	{ }
2431e505edaeSJeff LaBundy };
2432e505edaeSJeff LaBundy MODULE_DEVICE_TABLE(of, iqs7222_of_match);
2433e505edaeSJeff LaBundy 
2434e505edaeSJeff LaBundy static struct i2c_driver iqs7222_i2c_driver = {
2435e505edaeSJeff LaBundy 	.driver = {
2436e505edaeSJeff LaBundy 		.name = "iqs7222",
2437e505edaeSJeff LaBundy 		.of_match_table = iqs7222_of_match,
2438e505edaeSJeff LaBundy 	},
2439e505edaeSJeff LaBundy 	.probe_new = iqs7222_probe,
2440e505edaeSJeff LaBundy };
2441e505edaeSJeff LaBundy module_i2c_driver(iqs7222_i2c_driver);
2442e505edaeSJeff LaBundy 
2443e505edaeSJeff LaBundy MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
2444e505edaeSJeff LaBundy MODULE_DESCRIPTION("Azoteq IQS7222A/B/C Capacitive Touch Controller");
2445e505edaeSJeff LaBundy MODULE_LICENSE("GPL");
2446