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