xref: /openbmc/linux/drivers/input/misc/iqs7222.c (revision 2e00b8bf)
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,
898d4c313cSJeff LaBundy 	IQS7222_REG_KEY_TAP_LEGACY,
90e505edaeSJeff LaBundy 	IQS7222_REG_KEY_AXIAL,
918d4c313cSJeff LaBundy 	IQS7222_REG_KEY_AXIAL_LEGACY,
92e505edaeSJeff LaBundy 	IQS7222_REG_KEY_WHEEL,
93e505edaeSJeff LaBundy 	IQS7222_REG_KEY_NO_WHEEL,
94e505edaeSJeff LaBundy 	IQS7222_REG_KEY_RESERVED
95e505edaeSJeff LaBundy };
96e505edaeSJeff LaBundy 
97e505edaeSJeff LaBundy enum iqs7222_reg_grp_id {
98e505edaeSJeff LaBundy 	IQS7222_REG_GRP_STAT,
992e70ef52SJeff LaBundy 	IQS7222_REG_GRP_FILT,
100e505edaeSJeff LaBundy 	IQS7222_REG_GRP_CYCLE,
101e505edaeSJeff LaBundy 	IQS7222_REG_GRP_GLBL,
102e505edaeSJeff LaBundy 	IQS7222_REG_GRP_BTN,
103e505edaeSJeff LaBundy 	IQS7222_REG_GRP_CHAN,
104e505edaeSJeff LaBundy 	IQS7222_REG_GRP_SLDR,
105e505edaeSJeff LaBundy 	IQS7222_REG_GRP_GPIO,
106e505edaeSJeff LaBundy 	IQS7222_REG_GRP_SYS,
107e505edaeSJeff LaBundy 	IQS7222_NUM_REG_GRPS
108e505edaeSJeff LaBundy };
109e505edaeSJeff LaBundy 
110bbd16b0dSJeff LaBundy static const char * const iqs7222_reg_grp_names[IQS7222_NUM_REG_GRPS] = {
111e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_CYCLE] = "cycle",
112e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_CHAN] = "channel",
113e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_SLDR] = "slider",
114e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_GPIO] = "gpio",
115e505edaeSJeff LaBundy };
116e505edaeSJeff LaBundy 
117bbd16b0dSJeff LaBundy static const unsigned int iqs7222_max_cols[IQS7222_NUM_REG_GRPS] = {
118e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_STAT] = IQS7222_MAX_COLS_STAT,
119e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_CYCLE] = IQS7222_MAX_COLS_CYCLE,
120e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_GLBL] = IQS7222_MAX_COLS_GLBL,
121e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_BTN] = IQS7222_MAX_COLS_BTN,
122e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_CHAN] = IQS7222_MAX_COLS_CHAN,
123e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_FILT] = IQS7222_MAX_COLS_FILT,
124e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_SLDR] = IQS7222_MAX_COLS_SLDR,
125e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_GPIO] = IQS7222_MAX_COLS_GPIO,
126e505edaeSJeff LaBundy 	[IQS7222_REG_GRP_SYS] = IQS7222_MAX_COLS_SYS,
127e505edaeSJeff LaBundy };
128e505edaeSJeff LaBundy 
129e505edaeSJeff LaBundy static const unsigned int iqs7222_gpio_links[] = { 2, 5, 6, };
130e505edaeSJeff LaBundy 
131e505edaeSJeff LaBundy struct iqs7222_event_desc {
132e505edaeSJeff LaBundy 	const char *name;
133e505edaeSJeff LaBundy 	u16 mask;
134e505edaeSJeff LaBundy 	u16 val;
135e505edaeSJeff LaBundy 	u16 enable;
136e505edaeSJeff LaBundy 	enum iqs7222_reg_key_id reg_key;
137e505edaeSJeff LaBundy };
138e505edaeSJeff LaBundy 
139e505edaeSJeff LaBundy static const struct iqs7222_event_desc iqs7222_kp_events[] = {
140e505edaeSJeff LaBundy 	{
141e505edaeSJeff LaBundy 		.name = "event-prox",
14295215d3dSJeff LaBundy 		.enable = IQS7222_EVENT_MASK_PROX,
143e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_PROX,
144e505edaeSJeff LaBundy 	},
145e505edaeSJeff LaBundy 	{
146e505edaeSJeff LaBundy 		.name = "event-touch",
14795215d3dSJeff LaBundy 		.enable = IQS7222_EVENT_MASK_TOUCH,
148e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_TOUCH,
149e505edaeSJeff LaBundy 	},
150e505edaeSJeff LaBundy };
151e505edaeSJeff LaBundy 
152e505edaeSJeff LaBundy static const struct iqs7222_event_desc iqs7222_sl_events[] = {
153e505edaeSJeff LaBundy 	{ .name = "event-press", },
154e505edaeSJeff LaBundy 	{
155e505edaeSJeff LaBundy 		.name = "event-tap",
156e505edaeSJeff LaBundy 		.mask = BIT(0),
157e505edaeSJeff LaBundy 		.val = BIT(0),
158e505edaeSJeff LaBundy 		.enable = BIT(0),
159e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_TAP,
160e505edaeSJeff LaBundy 	},
161e505edaeSJeff LaBundy 	{
162e505edaeSJeff LaBundy 		.name = "event-swipe-pos",
163e505edaeSJeff LaBundy 		.mask = BIT(5) | BIT(1),
164e505edaeSJeff LaBundy 		.val = BIT(1),
165e505edaeSJeff LaBundy 		.enable = BIT(1),
166e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_AXIAL,
167e505edaeSJeff LaBundy 	},
168e505edaeSJeff LaBundy 	{
169e505edaeSJeff LaBundy 		.name = "event-swipe-neg",
170e505edaeSJeff LaBundy 		.mask = BIT(5) | BIT(1),
171e505edaeSJeff LaBundy 		.val = BIT(5) | BIT(1),
172e505edaeSJeff LaBundy 		.enable = BIT(1),
173e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_AXIAL,
174e505edaeSJeff LaBundy 	},
175e505edaeSJeff LaBundy 	{
176e505edaeSJeff LaBundy 		.name = "event-flick-pos",
177e505edaeSJeff LaBundy 		.mask = BIT(5) | BIT(2),
178e505edaeSJeff LaBundy 		.val = BIT(2),
179e505edaeSJeff LaBundy 		.enable = BIT(2),
180e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_AXIAL,
181e505edaeSJeff LaBundy 	},
182e505edaeSJeff LaBundy 	{
183e505edaeSJeff LaBundy 		.name = "event-flick-neg",
184e505edaeSJeff LaBundy 		.mask = BIT(5) | BIT(2),
185e505edaeSJeff LaBundy 		.val = BIT(5) | BIT(2),
186e505edaeSJeff LaBundy 		.enable = BIT(2),
187e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_AXIAL,
188e505edaeSJeff LaBundy 	},
189e505edaeSJeff LaBundy };
190e505edaeSJeff LaBundy 
191e505edaeSJeff LaBundy struct iqs7222_reg_grp_desc {
192e505edaeSJeff LaBundy 	u16 base;
193e505edaeSJeff LaBundy 	int num_row;
194e505edaeSJeff LaBundy 	int num_col;
195e505edaeSJeff LaBundy };
196e505edaeSJeff LaBundy 
197e505edaeSJeff LaBundy struct iqs7222_dev_desc {
198e505edaeSJeff LaBundy 	u16 prod_num;
199e505edaeSJeff LaBundy 	u16 fw_major;
200e505edaeSJeff LaBundy 	u16 fw_minor;
201e505edaeSJeff LaBundy 	u16 sldr_res;
202e505edaeSJeff LaBundy 	u16 touch_link;
203e505edaeSJeff LaBundy 	u16 wheel_enable;
204e505edaeSJeff LaBundy 	int allow_offset;
205e505edaeSJeff LaBundy 	int event_offset;
206e505edaeSJeff LaBundy 	int comms_offset;
2078d4c313cSJeff LaBundy 	bool legacy_gesture;
208e505edaeSJeff LaBundy 	struct iqs7222_reg_grp_desc reg_grps[IQS7222_NUM_REG_GRPS];
209e505edaeSJeff LaBundy };
210e505edaeSJeff LaBundy 
211e505edaeSJeff LaBundy static const struct iqs7222_dev_desc iqs7222_devs[] = {
212e505edaeSJeff LaBundy 	{
213e505edaeSJeff LaBundy 		.prod_num = IQS7222_PROD_NUM_A,
214e505edaeSJeff LaBundy 		.fw_major = 1,
2158d4c313cSJeff LaBundy 		.fw_minor = 13,
2168d4c313cSJeff LaBundy 		.sldr_res = U8_MAX * 16,
2178d4c313cSJeff LaBundy 		.touch_link = 1768,
2188d4c313cSJeff LaBundy 		.allow_offset = 9,
2198d4c313cSJeff LaBundy 		.event_offset = 10,
2208d4c313cSJeff LaBundy 		.comms_offset = 12,
2218d4c313cSJeff LaBundy 		.reg_grps = {
2228d4c313cSJeff LaBundy 			[IQS7222_REG_GRP_STAT] = {
2238d4c313cSJeff LaBundy 				.base = IQS7222_SYS_STATUS,
2248d4c313cSJeff LaBundy 				.num_row = 1,
2258d4c313cSJeff LaBundy 				.num_col = 8,
2268d4c313cSJeff LaBundy 			},
2278d4c313cSJeff LaBundy 			[IQS7222_REG_GRP_CYCLE] = {
2288d4c313cSJeff LaBundy 				.base = 0x8000,
2298d4c313cSJeff LaBundy 				.num_row = 7,
2308d4c313cSJeff LaBundy 				.num_col = 3,
2318d4c313cSJeff LaBundy 			},
2328d4c313cSJeff LaBundy 			[IQS7222_REG_GRP_GLBL] = {
2338d4c313cSJeff LaBundy 				.base = 0x8700,
2348d4c313cSJeff LaBundy 				.num_row = 1,
2358d4c313cSJeff LaBundy 				.num_col = 3,
2368d4c313cSJeff LaBundy 			},
2378d4c313cSJeff LaBundy 			[IQS7222_REG_GRP_BTN] = {
2388d4c313cSJeff LaBundy 				.base = 0x9000,
2398d4c313cSJeff LaBundy 				.num_row = 12,
2408d4c313cSJeff LaBundy 				.num_col = 3,
2418d4c313cSJeff LaBundy 			},
2428d4c313cSJeff LaBundy 			[IQS7222_REG_GRP_CHAN] = {
2438d4c313cSJeff LaBundy 				.base = 0xA000,
2448d4c313cSJeff LaBundy 				.num_row = 12,
2458d4c313cSJeff LaBundy 				.num_col = 6,
2468d4c313cSJeff LaBundy 			},
2478d4c313cSJeff LaBundy 			[IQS7222_REG_GRP_FILT] = {
2488d4c313cSJeff LaBundy 				.base = 0xAC00,
2498d4c313cSJeff LaBundy 				.num_row = 1,
2508d4c313cSJeff LaBundy 				.num_col = 2,
2518d4c313cSJeff LaBundy 			},
2528d4c313cSJeff LaBundy 			[IQS7222_REG_GRP_SLDR] = {
2538d4c313cSJeff LaBundy 				.base = 0xB000,
2548d4c313cSJeff LaBundy 				.num_row = 2,
2558d4c313cSJeff LaBundy 				.num_col = 11,
2568d4c313cSJeff LaBundy 			},
2578d4c313cSJeff LaBundy 			[IQS7222_REG_GRP_GPIO] = {
2588d4c313cSJeff LaBundy 				.base = 0xC000,
2598d4c313cSJeff LaBundy 				.num_row = 1,
2608d4c313cSJeff LaBundy 				.num_col = 3,
2618d4c313cSJeff LaBundy 			},
2628d4c313cSJeff LaBundy 			[IQS7222_REG_GRP_SYS] = {
2638d4c313cSJeff LaBundy 				.base = IQS7222_SYS_SETUP,
2648d4c313cSJeff LaBundy 				.num_row = 1,
2658d4c313cSJeff LaBundy 				.num_col = 13,
2668d4c313cSJeff LaBundy 			},
2678d4c313cSJeff LaBundy 		},
2688d4c313cSJeff LaBundy 	},
2698d4c313cSJeff LaBundy 	{
2708d4c313cSJeff LaBundy 		.prod_num = IQS7222_PROD_NUM_A,
2718d4c313cSJeff LaBundy 		.fw_major = 1,
272e505edaeSJeff LaBundy 		.fw_minor = 12,
273e505edaeSJeff LaBundy 		.sldr_res = U8_MAX * 16,
274e505edaeSJeff LaBundy 		.touch_link = 1768,
275e505edaeSJeff LaBundy 		.allow_offset = 9,
276e505edaeSJeff LaBundy 		.event_offset = 10,
277e505edaeSJeff LaBundy 		.comms_offset = 12,
2788d4c313cSJeff LaBundy 		.legacy_gesture = true,
279e505edaeSJeff LaBundy 		.reg_grps = {
280e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_STAT] = {
281e505edaeSJeff LaBundy 				.base = IQS7222_SYS_STATUS,
282e505edaeSJeff LaBundy 				.num_row = 1,
283e505edaeSJeff LaBundy 				.num_col = 8,
284e505edaeSJeff LaBundy 			},
285e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_CYCLE] = {
286e505edaeSJeff LaBundy 				.base = 0x8000,
287e505edaeSJeff LaBundy 				.num_row = 7,
288e505edaeSJeff LaBundy 				.num_col = 3,
289e505edaeSJeff LaBundy 			},
290e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_GLBL] = {
291e505edaeSJeff LaBundy 				.base = 0x8700,
292e505edaeSJeff LaBundy 				.num_row = 1,
293e505edaeSJeff LaBundy 				.num_col = 3,
294e505edaeSJeff LaBundy 			},
295e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_BTN] = {
296e505edaeSJeff LaBundy 				.base = 0x9000,
297e505edaeSJeff LaBundy 				.num_row = 12,
298e505edaeSJeff LaBundy 				.num_col = 3,
299e505edaeSJeff LaBundy 			},
300e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_CHAN] = {
301e505edaeSJeff LaBundy 				.base = 0xA000,
302e505edaeSJeff LaBundy 				.num_row = 12,
303e505edaeSJeff LaBundy 				.num_col = 6,
304e505edaeSJeff LaBundy 			},
305e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_FILT] = {
306e505edaeSJeff LaBundy 				.base = 0xAC00,
307e505edaeSJeff LaBundy 				.num_row = 1,
308e505edaeSJeff LaBundy 				.num_col = 2,
309e505edaeSJeff LaBundy 			},
310e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_SLDR] = {
311e505edaeSJeff LaBundy 				.base = 0xB000,
312e505edaeSJeff LaBundy 				.num_row = 2,
313e505edaeSJeff LaBundy 				.num_col = 11,
314e505edaeSJeff LaBundy 			},
315e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_GPIO] = {
316e505edaeSJeff LaBundy 				.base = 0xC000,
317e505edaeSJeff LaBundy 				.num_row = 1,
318e505edaeSJeff LaBundy 				.num_col = 3,
319e505edaeSJeff LaBundy 			},
320e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_SYS] = {
321e505edaeSJeff LaBundy 				.base = IQS7222_SYS_SETUP,
322e505edaeSJeff LaBundy 				.num_row = 1,
323e505edaeSJeff LaBundy 				.num_col = 13,
324e505edaeSJeff LaBundy 			},
325e505edaeSJeff LaBundy 		},
326e505edaeSJeff LaBundy 	},
327e505edaeSJeff LaBundy 	{
328e505edaeSJeff LaBundy 		.prod_num = IQS7222_PROD_NUM_B,
329e505edaeSJeff LaBundy 		.fw_major = 1,
330e505edaeSJeff LaBundy 		.fw_minor = 43,
331e505edaeSJeff LaBundy 		.event_offset = 10,
332e505edaeSJeff LaBundy 		.comms_offset = 11,
333e505edaeSJeff LaBundy 		.reg_grps = {
334e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_STAT] = {
335e505edaeSJeff LaBundy 				.base = IQS7222_SYS_STATUS,
336e505edaeSJeff LaBundy 				.num_row = 1,
337e505edaeSJeff LaBundy 				.num_col = 6,
338e505edaeSJeff LaBundy 			},
339e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_CYCLE] = {
340e505edaeSJeff LaBundy 				.base = 0x8000,
341e505edaeSJeff LaBundy 				.num_row = 10,
342e505edaeSJeff LaBundy 				.num_col = 2,
343e505edaeSJeff LaBundy 			},
344e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_GLBL] = {
345e505edaeSJeff LaBundy 				.base = 0x8A00,
346e505edaeSJeff LaBundy 				.num_row = 1,
347e505edaeSJeff LaBundy 				.num_col = 3,
348e505edaeSJeff LaBundy 			},
349e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_BTN] = {
350e505edaeSJeff LaBundy 				.base = 0x9000,
351e505edaeSJeff LaBundy 				.num_row = 20,
352e505edaeSJeff LaBundy 				.num_col = 2,
353e505edaeSJeff LaBundy 			},
354e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_CHAN] = {
355e505edaeSJeff LaBundy 				.base = 0xB000,
356e505edaeSJeff LaBundy 				.num_row = 20,
357e505edaeSJeff LaBundy 				.num_col = 4,
358e505edaeSJeff LaBundy 			},
359e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_FILT] = {
360e505edaeSJeff LaBundy 				.base = 0xC400,
361e505edaeSJeff LaBundy 				.num_row = 1,
362e505edaeSJeff LaBundy 				.num_col = 2,
363e505edaeSJeff LaBundy 			},
364e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_SYS] = {
365e505edaeSJeff LaBundy 				.base = IQS7222_SYS_SETUP,
366e505edaeSJeff LaBundy 				.num_row = 1,
367e505edaeSJeff LaBundy 				.num_col = 13,
368e505edaeSJeff LaBundy 			},
369e505edaeSJeff LaBundy 		},
370e505edaeSJeff LaBundy 	},
371e505edaeSJeff LaBundy 	{
372e505edaeSJeff LaBundy 		.prod_num = IQS7222_PROD_NUM_B,
373e505edaeSJeff LaBundy 		.fw_major = 1,
374e505edaeSJeff LaBundy 		.fw_minor = 27,
375e505edaeSJeff LaBundy 		.reg_grps = {
376e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_STAT] = {
377e505edaeSJeff LaBundy 				.base = IQS7222_SYS_STATUS,
378e505edaeSJeff LaBundy 				.num_row = 1,
379e505edaeSJeff LaBundy 				.num_col = 6,
380e505edaeSJeff LaBundy 			},
381e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_CYCLE] = {
382e505edaeSJeff LaBundy 				.base = 0x8000,
383e505edaeSJeff LaBundy 				.num_row = 10,
384e505edaeSJeff LaBundy 				.num_col = 2,
385e505edaeSJeff LaBundy 			},
386e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_GLBL] = {
387e505edaeSJeff LaBundy 				.base = 0x8A00,
388e505edaeSJeff LaBundy 				.num_row = 1,
389e505edaeSJeff LaBundy 				.num_col = 3,
390e505edaeSJeff LaBundy 			},
391e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_BTN] = {
392e505edaeSJeff LaBundy 				.base = 0x9000,
393e505edaeSJeff LaBundy 				.num_row = 20,
394e505edaeSJeff LaBundy 				.num_col = 2,
395e505edaeSJeff LaBundy 			},
396e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_CHAN] = {
397e505edaeSJeff LaBundy 				.base = 0xB000,
398e505edaeSJeff LaBundy 				.num_row = 20,
399e505edaeSJeff LaBundy 				.num_col = 4,
400e505edaeSJeff LaBundy 			},
401e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_FILT] = {
402e505edaeSJeff LaBundy 				.base = 0xC400,
403e505edaeSJeff LaBundy 				.num_row = 1,
404e505edaeSJeff LaBundy 				.num_col = 2,
405e505edaeSJeff LaBundy 			},
406e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_SYS] = {
407e505edaeSJeff LaBundy 				.base = IQS7222_SYS_SETUP,
408e505edaeSJeff LaBundy 				.num_row = 1,
409e505edaeSJeff LaBundy 				.num_col = 10,
410e505edaeSJeff LaBundy 			},
411e505edaeSJeff LaBundy 		},
412e505edaeSJeff LaBundy 	},
413e505edaeSJeff LaBundy 	{
414e505edaeSJeff LaBundy 		.prod_num = IQS7222_PROD_NUM_C,
415e505edaeSJeff LaBundy 		.fw_major = 2,
416e505edaeSJeff LaBundy 		.fw_minor = 6,
417e505edaeSJeff LaBundy 		.sldr_res = U16_MAX,
418e505edaeSJeff LaBundy 		.touch_link = 1686,
419e505edaeSJeff LaBundy 		.wheel_enable = BIT(3),
420e505edaeSJeff LaBundy 		.event_offset = 9,
421e505edaeSJeff LaBundy 		.comms_offset = 10,
422e505edaeSJeff LaBundy 		.reg_grps = {
423e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_STAT] = {
424e505edaeSJeff LaBundy 				.base = IQS7222_SYS_STATUS,
425e505edaeSJeff LaBundy 				.num_row = 1,
426e505edaeSJeff LaBundy 				.num_col = 6,
427e505edaeSJeff LaBundy 			},
428e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_CYCLE] = {
429e505edaeSJeff LaBundy 				.base = 0x8000,
430e505edaeSJeff LaBundy 				.num_row = 5,
431e505edaeSJeff LaBundy 				.num_col = 3,
432e505edaeSJeff LaBundy 			},
433e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_GLBL] = {
434e505edaeSJeff LaBundy 				.base = 0x8500,
435e505edaeSJeff LaBundy 				.num_row = 1,
436e505edaeSJeff LaBundy 				.num_col = 3,
437e505edaeSJeff LaBundy 			},
438e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_BTN] = {
439e505edaeSJeff LaBundy 				.base = 0x9000,
440e505edaeSJeff LaBundy 				.num_row = 10,
441e505edaeSJeff LaBundy 				.num_col = 3,
442e505edaeSJeff LaBundy 			},
443e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_CHAN] = {
444e505edaeSJeff LaBundy 				.base = 0xA000,
445e505edaeSJeff LaBundy 				.num_row = 10,
446e505edaeSJeff LaBundy 				.num_col = 6,
447e505edaeSJeff LaBundy 			},
448e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_FILT] = {
449e505edaeSJeff LaBundy 				.base = 0xAA00,
450e505edaeSJeff LaBundy 				.num_row = 1,
451e505edaeSJeff LaBundy 				.num_col = 2,
452e505edaeSJeff LaBundy 			},
453e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_SLDR] = {
454e505edaeSJeff LaBundy 				.base = 0xB000,
455e505edaeSJeff LaBundy 				.num_row = 2,
456e505edaeSJeff LaBundy 				.num_col = 10,
457e505edaeSJeff LaBundy 			},
458e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_GPIO] = {
459e505edaeSJeff LaBundy 				.base = 0xC000,
460e505edaeSJeff LaBundy 				.num_row = 3,
461e505edaeSJeff LaBundy 				.num_col = 3,
462e505edaeSJeff LaBundy 			},
463e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_SYS] = {
464e505edaeSJeff LaBundy 				.base = IQS7222_SYS_SETUP,
465e505edaeSJeff LaBundy 				.num_row = 1,
466e505edaeSJeff LaBundy 				.num_col = 12,
467e505edaeSJeff LaBundy 			},
468e505edaeSJeff LaBundy 		},
469e505edaeSJeff LaBundy 	},
470e505edaeSJeff LaBundy 	{
471e505edaeSJeff LaBundy 		.prod_num = IQS7222_PROD_NUM_C,
472e505edaeSJeff LaBundy 		.fw_major = 1,
473e505edaeSJeff LaBundy 		.fw_minor = 13,
474e505edaeSJeff LaBundy 		.sldr_res = U16_MAX,
475e505edaeSJeff LaBundy 		.touch_link = 1674,
476e505edaeSJeff LaBundy 		.wheel_enable = BIT(3),
477e505edaeSJeff LaBundy 		.event_offset = 9,
478e505edaeSJeff LaBundy 		.comms_offset = 10,
479e505edaeSJeff LaBundy 		.reg_grps = {
480e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_STAT] = {
481e505edaeSJeff LaBundy 				.base = IQS7222_SYS_STATUS,
482e505edaeSJeff LaBundy 				.num_row = 1,
483e505edaeSJeff LaBundy 				.num_col = 6,
484e505edaeSJeff LaBundy 			},
485e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_CYCLE] = {
486e505edaeSJeff LaBundy 				.base = 0x8000,
487e505edaeSJeff LaBundy 				.num_row = 5,
488e505edaeSJeff LaBundy 				.num_col = 3,
489e505edaeSJeff LaBundy 			},
490e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_GLBL] = {
491e505edaeSJeff LaBundy 				.base = 0x8500,
492e505edaeSJeff LaBundy 				.num_row = 1,
493e505edaeSJeff LaBundy 				.num_col = 3,
494e505edaeSJeff LaBundy 			},
495e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_BTN] = {
496e505edaeSJeff LaBundy 				.base = 0x9000,
497e505edaeSJeff LaBundy 				.num_row = 10,
498e505edaeSJeff LaBundy 				.num_col = 3,
499e505edaeSJeff LaBundy 			},
500e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_CHAN] = {
501e505edaeSJeff LaBundy 				.base = 0xA000,
502e505edaeSJeff LaBundy 				.num_row = 10,
503e505edaeSJeff LaBundy 				.num_col = 6,
504e505edaeSJeff LaBundy 			},
505e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_FILT] = {
506e505edaeSJeff LaBundy 				.base = 0xAA00,
507e505edaeSJeff LaBundy 				.num_row = 1,
508e505edaeSJeff LaBundy 				.num_col = 2,
509e505edaeSJeff LaBundy 			},
510e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_SLDR] = {
511e505edaeSJeff LaBundy 				.base = 0xB000,
512e505edaeSJeff LaBundy 				.num_row = 2,
513e505edaeSJeff LaBundy 				.num_col = 10,
514e505edaeSJeff LaBundy 			},
515e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_GPIO] = {
516e505edaeSJeff LaBundy 				.base = 0xC000,
517e505edaeSJeff LaBundy 				.num_row = 1,
518e505edaeSJeff LaBundy 				.num_col = 3,
519e505edaeSJeff LaBundy 			},
520e505edaeSJeff LaBundy 			[IQS7222_REG_GRP_SYS] = {
521e505edaeSJeff LaBundy 				.base = IQS7222_SYS_SETUP,
522e505edaeSJeff LaBundy 				.num_row = 1,
523e505edaeSJeff LaBundy 				.num_col = 11,
524e505edaeSJeff LaBundy 			},
525e505edaeSJeff LaBundy 		},
526e505edaeSJeff LaBundy 	},
527e505edaeSJeff LaBundy };
528e505edaeSJeff LaBundy 
529e505edaeSJeff LaBundy struct iqs7222_prop_desc {
530e505edaeSJeff LaBundy 	const char *name;
531e505edaeSJeff LaBundy 	enum iqs7222_reg_grp_id reg_grp;
532e505edaeSJeff LaBundy 	enum iqs7222_reg_key_id reg_key;
533e505edaeSJeff LaBundy 	int reg_offset;
534e505edaeSJeff LaBundy 	int reg_shift;
535e505edaeSJeff LaBundy 	int reg_width;
536e505edaeSJeff LaBundy 	int val_pitch;
537e505edaeSJeff LaBundy 	int val_min;
538e505edaeSJeff LaBundy 	int val_max;
539e505edaeSJeff LaBundy 	bool invert;
540e505edaeSJeff LaBundy 	const char *label;
541e505edaeSJeff LaBundy };
542e505edaeSJeff LaBundy 
543e505edaeSJeff LaBundy static const struct iqs7222_prop_desc iqs7222_props[] = {
544e505edaeSJeff LaBundy 	{
545e505edaeSJeff LaBundy 		.name = "azoteq,conv-period",
546e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CYCLE,
547e505edaeSJeff LaBundy 		.reg_offset = 0,
548e505edaeSJeff LaBundy 		.reg_shift = 8,
549e505edaeSJeff LaBundy 		.reg_width = 8,
550e505edaeSJeff LaBundy 		.label = "conversion period",
551e505edaeSJeff LaBundy 	},
552e505edaeSJeff LaBundy 	{
553e505edaeSJeff LaBundy 		.name = "azoteq,conv-frac",
554e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CYCLE,
555e505edaeSJeff LaBundy 		.reg_offset = 0,
556e505edaeSJeff LaBundy 		.reg_shift = 0,
557e505edaeSJeff LaBundy 		.reg_width = 8,
558e505edaeSJeff LaBundy 		.label = "conversion frequency fractional divider",
559e505edaeSJeff LaBundy 	},
560e505edaeSJeff LaBundy 	{
561e505edaeSJeff LaBundy 		.name = "azoteq,rx-float-inactive",
562e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CYCLE,
563e505edaeSJeff LaBundy 		.reg_offset = 1,
564e505edaeSJeff LaBundy 		.reg_shift = 6,
565e505edaeSJeff LaBundy 		.reg_width = 1,
566e505edaeSJeff LaBundy 		.invert = true,
567e505edaeSJeff LaBundy 	},
568e505edaeSJeff LaBundy 	{
569e505edaeSJeff LaBundy 		.name = "azoteq,dead-time-enable",
570e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CYCLE,
571e505edaeSJeff LaBundy 		.reg_offset = 1,
572e505edaeSJeff LaBundy 		.reg_shift = 5,
573e505edaeSJeff LaBundy 		.reg_width = 1,
574e505edaeSJeff LaBundy 	},
575e505edaeSJeff LaBundy 	{
576e505edaeSJeff LaBundy 		.name = "azoteq,tx-freq-fosc",
577e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CYCLE,
578e505edaeSJeff LaBundy 		.reg_offset = 1,
579e505edaeSJeff LaBundy 		.reg_shift = 4,
580e505edaeSJeff LaBundy 		.reg_width = 1,
581e505edaeSJeff LaBundy 	},
582e505edaeSJeff LaBundy 	{
583e505edaeSJeff LaBundy 		.name = "azoteq,vbias-enable",
584e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CYCLE,
585e505edaeSJeff LaBundy 		.reg_offset = 1,
586e505edaeSJeff LaBundy 		.reg_shift = 3,
587e505edaeSJeff LaBundy 		.reg_width = 1,
588e505edaeSJeff LaBundy 	},
589e505edaeSJeff LaBundy 	{
590e505edaeSJeff LaBundy 		.name = "azoteq,sense-mode",
591e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CYCLE,
592e505edaeSJeff LaBundy 		.reg_offset = 1,
593e505edaeSJeff LaBundy 		.reg_shift = 0,
594e505edaeSJeff LaBundy 		.reg_width = 3,
595e505edaeSJeff LaBundy 		.val_max = 3,
596e505edaeSJeff LaBundy 		.label = "sensing mode",
597e505edaeSJeff LaBundy 	},
598e505edaeSJeff LaBundy 	{
599e505edaeSJeff LaBundy 		.name = "azoteq,iref-enable",
600e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CYCLE,
601e505edaeSJeff LaBundy 		.reg_offset = 2,
602e505edaeSJeff LaBundy 		.reg_shift = 10,
603e505edaeSJeff LaBundy 		.reg_width = 1,
604e505edaeSJeff LaBundy 	},
605e505edaeSJeff LaBundy 	{
606e505edaeSJeff LaBundy 		.name = "azoteq,iref-level",
607e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CYCLE,
608e505edaeSJeff LaBundy 		.reg_offset = 2,
609e505edaeSJeff LaBundy 		.reg_shift = 4,
610e505edaeSJeff LaBundy 		.reg_width = 4,
611e505edaeSJeff LaBundy 		.label = "current reference level",
612e505edaeSJeff LaBundy 	},
613e505edaeSJeff LaBundy 	{
614e505edaeSJeff LaBundy 		.name = "azoteq,iref-trim",
615e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CYCLE,
616e505edaeSJeff LaBundy 		.reg_offset = 2,
617e505edaeSJeff LaBundy 		.reg_shift = 0,
618e505edaeSJeff LaBundy 		.reg_width = 4,
619e505edaeSJeff LaBundy 		.label = "current reference trim",
620e505edaeSJeff LaBundy 	},
621e505edaeSJeff LaBundy 	{
622e505edaeSJeff LaBundy 		.name = "azoteq,max-counts",
623e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_GLBL,
624e505edaeSJeff LaBundy 		.reg_offset = 0,
625e505edaeSJeff LaBundy 		.reg_shift = 13,
626e505edaeSJeff LaBundy 		.reg_width = 2,
627e505edaeSJeff LaBundy 		.label = "maximum counts",
628e505edaeSJeff LaBundy 	},
629e505edaeSJeff LaBundy 	{
630e505edaeSJeff LaBundy 		.name = "azoteq,auto-mode",
631e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_GLBL,
632e505edaeSJeff LaBundy 		.reg_offset = 0,
633e505edaeSJeff LaBundy 		.reg_shift = 2,
634e505edaeSJeff LaBundy 		.reg_width = 2,
635e505edaeSJeff LaBundy 		.label = "number of conversions",
636e505edaeSJeff LaBundy 	},
637e505edaeSJeff LaBundy 	{
638e505edaeSJeff LaBundy 		.name = "azoteq,ati-frac-div-fine",
639e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_GLBL,
640e505edaeSJeff LaBundy 		.reg_offset = 1,
641e505edaeSJeff LaBundy 		.reg_shift = 9,
642e505edaeSJeff LaBundy 		.reg_width = 5,
643e505edaeSJeff LaBundy 		.label = "ATI fine fractional divider",
644e505edaeSJeff LaBundy 	},
645e505edaeSJeff LaBundy 	{
646e505edaeSJeff LaBundy 		.name = "azoteq,ati-frac-div-coarse",
647e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_GLBL,
648e505edaeSJeff LaBundy 		.reg_offset = 1,
649e505edaeSJeff LaBundy 		.reg_shift = 0,
650e505edaeSJeff LaBundy 		.reg_width = 5,
651e505edaeSJeff LaBundy 		.label = "ATI coarse fractional divider",
652e505edaeSJeff LaBundy 	},
653e505edaeSJeff LaBundy 	{
654e505edaeSJeff LaBundy 		.name = "azoteq,ati-comp-select",
655e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_GLBL,
656e505edaeSJeff LaBundy 		.reg_offset = 2,
657e505edaeSJeff LaBundy 		.reg_shift = 0,
658e505edaeSJeff LaBundy 		.reg_width = 10,
659e505edaeSJeff LaBundy 		.label = "ATI compensation selection",
660e505edaeSJeff LaBundy 	},
661e505edaeSJeff LaBundy 	{
662e505edaeSJeff LaBundy 		.name = "azoteq,ati-band",
663e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
664e505edaeSJeff LaBundy 		.reg_offset = 0,
665e505edaeSJeff LaBundy 		.reg_shift = 12,
666e505edaeSJeff LaBundy 		.reg_width = 2,
667e505edaeSJeff LaBundy 		.label = "ATI band",
668e505edaeSJeff LaBundy 	},
669e505edaeSJeff LaBundy 	{
670e505edaeSJeff LaBundy 		.name = "azoteq,global-halt",
671e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
672e505edaeSJeff LaBundy 		.reg_offset = 0,
673e505edaeSJeff LaBundy 		.reg_shift = 11,
674e505edaeSJeff LaBundy 		.reg_width = 1,
675e505edaeSJeff LaBundy 	},
676e505edaeSJeff LaBundy 	{
677e505edaeSJeff LaBundy 		.name = "azoteq,invert-enable",
678e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
679e505edaeSJeff LaBundy 		.reg_offset = 0,
680e505edaeSJeff LaBundy 		.reg_shift = 10,
681e505edaeSJeff LaBundy 		.reg_width = 1,
682e505edaeSJeff LaBundy 	},
683e505edaeSJeff LaBundy 	{
684e505edaeSJeff LaBundy 		.name = "azoteq,dual-direction",
685e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
686e505edaeSJeff LaBundy 		.reg_offset = 0,
687e505edaeSJeff LaBundy 		.reg_shift = 9,
688e505edaeSJeff LaBundy 		.reg_width = 1,
689e505edaeSJeff LaBundy 	},
690e505edaeSJeff LaBundy 	{
691e505edaeSJeff LaBundy 		.name = "azoteq,samp-cap-double",
692e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
693e505edaeSJeff LaBundy 		.reg_offset = 0,
694e505edaeSJeff LaBundy 		.reg_shift = 3,
695e505edaeSJeff LaBundy 		.reg_width = 1,
696e505edaeSJeff LaBundy 	},
697e505edaeSJeff LaBundy 	{
698e505edaeSJeff LaBundy 		.name = "azoteq,vref-half",
699e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
700e505edaeSJeff LaBundy 		.reg_offset = 0,
701e505edaeSJeff LaBundy 		.reg_shift = 2,
702e505edaeSJeff LaBundy 		.reg_width = 1,
703e505edaeSJeff LaBundy 	},
704e505edaeSJeff LaBundy 	{
705e505edaeSJeff LaBundy 		.name = "azoteq,proj-bias",
706e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
707e505edaeSJeff LaBundy 		.reg_offset = 0,
708e505edaeSJeff LaBundy 		.reg_shift = 0,
709e505edaeSJeff LaBundy 		.reg_width = 2,
710e505edaeSJeff LaBundy 		.label = "projected bias current",
711e505edaeSJeff LaBundy 	},
712e505edaeSJeff LaBundy 	{
713e505edaeSJeff LaBundy 		.name = "azoteq,ati-target",
714e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
715e505edaeSJeff LaBundy 		.reg_offset = 1,
716e505edaeSJeff LaBundy 		.reg_shift = 8,
717e505edaeSJeff LaBundy 		.reg_width = 8,
718e505edaeSJeff LaBundy 		.val_pitch = 8,
719e505edaeSJeff LaBundy 		.label = "ATI target",
720e505edaeSJeff LaBundy 	},
721e505edaeSJeff LaBundy 	{
722e505edaeSJeff LaBundy 		.name = "azoteq,ati-base",
723e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
724e505edaeSJeff LaBundy 		.reg_offset = 1,
725e505edaeSJeff LaBundy 		.reg_shift = 3,
726e505edaeSJeff LaBundy 		.reg_width = 5,
727e505edaeSJeff LaBundy 		.val_pitch = 16,
728e505edaeSJeff LaBundy 		.label = "ATI base",
729e505edaeSJeff LaBundy 	},
730e505edaeSJeff LaBundy 	{
731e505edaeSJeff LaBundy 		.name = "azoteq,ati-mode",
732e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
733e505edaeSJeff LaBundy 		.reg_offset = 1,
734e505edaeSJeff LaBundy 		.reg_shift = 0,
735e505edaeSJeff LaBundy 		.reg_width = 3,
736e505edaeSJeff LaBundy 		.val_max = 5,
737e505edaeSJeff LaBundy 		.label = "ATI mode",
738e505edaeSJeff LaBundy 	},
739e505edaeSJeff LaBundy 	{
740e505edaeSJeff LaBundy 		.name = "azoteq,ati-frac-div-fine",
741e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
742e505edaeSJeff LaBundy 		.reg_offset = 2,
743e505edaeSJeff LaBundy 		.reg_shift = 9,
744e505edaeSJeff LaBundy 		.reg_width = 5,
745e505edaeSJeff LaBundy 		.label = "ATI fine fractional divider",
746e505edaeSJeff LaBundy 	},
747e505edaeSJeff LaBundy 	{
748e505edaeSJeff LaBundy 		.name = "azoteq,ati-frac-mult-coarse",
749e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
750e505edaeSJeff LaBundy 		.reg_offset = 2,
751e505edaeSJeff LaBundy 		.reg_shift = 5,
752e505edaeSJeff LaBundy 		.reg_width = 4,
753e505edaeSJeff LaBundy 		.label = "ATI coarse fractional multiplier",
754e505edaeSJeff LaBundy 	},
755e505edaeSJeff LaBundy 	{
756e505edaeSJeff LaBundy 		.name = "azoteq,ati-frac-div-coarse",
757e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
758e505edaeSJeff LaBundy 		.reg_offset = 2,
759e505edaeSJeff LaBundy 		.reg_shift = 0,
760e505edaeSJeff LaBundy 		.reg_width = 5,
761e505edaeSJeff LaBundy 		.label = "ATI coarse fractional divider",
762e505edaeSJeff LaBundy 	},
763e505edaeSJeff LaBundy 	{
764e505edaeSJeff LaBundy 		.name = "azoteq,ati-comp-div",
765e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
766e505edaeSJeff LaBundy 		.reg_offset = 3,
767e505edaeSJeff LaBundy 		.reg_shift = 11,
768e505edaeSJeff LaBundy 		.reg_width = 5,
769e505edaeSJeff LaBundy 		.label = "ATI compensation divider",
770e505edaeSJeff LaBundy 	},
771e505edaeSJeff LaBundy 	{
772e505edaeSJeff LaBundy 		.name = "azoteq,ati-comp-select",
773e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_CHAN,
774e505edaeSJeff LaBundy 		.reg_offset = 3,
775e505edaeSJeff LaBundy 		.reg_shift = 0,
776e505edaeSJeff LaBundy 		.reg_width = 10,
777e505edaeSJeff LaBundy 		.label = "ATI compensation selection",
778e505edaeSJeff LaBundy 	},
779e505edaeSJeff LaBundy 	{
780e505edaeSJeff LaBundy 		.name = "azoteq,debounce-exit",
781e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_BTN,
782e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_DEBOUNCE,
783e505edaeSJeff LaBundy 		.reg_offset = 0,
784e505edaeSJeff LaBundy 		.reg_shift = 12,
785e505edaeSJeff LaBundy 		.reg_width = 4,
786e505edaeSJeff LaBundy 		.label = "debounce exit factor",
787e505edaeSJeff LaBundy 	},
788e505edaeSJeff LaBundy 	{
789e505edaeSJeff LaBundy 		.name = "azoteq,debounce-enter",
790e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_BTN,
791e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_DEBOUNCE,
792e505edaeSJeff LaBundy 		.reg_offset = 0,
793e505edaeSJeff LaBundy 		.reg_shift = 8,
794e505edaeSJeff LaBundy 		.reg_width = 4,
795e505edaeSJeff LaBundy 		.label = "debounce entrance factor",
796e505edaeSJeff LaBundy 	},
797e505edaeSJeff LaBundy 	{
798e505edaeSJeff LaBundy 		.name = "azoteq,thresh",
799e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_BTN,
800e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_PROX,
801e505edaeSJeff LaBundy 		.reg_offset = 0,
802e505edaeSJeff LaBundy 		.reg_shift = 0,
803e505edaeSJeff LaBundy 		.reg_width = 8,
804e505edaeSJeff LaBundy 		.val_max = 127,
805e505edaeSJeff LaBundy 		.label = "threshold",
806e505edaeSJeff LaBundy 	},
807e505edaeSJeff LaBundy 	{
808e505edaeSJeff LaBundy 		.name = "azoteq,thresh",
809e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_BTN,
810e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_TOUCH,
811e505edaeSJeff LaBundy 		.reg_offset = 1,
812e505edaeSJeff LaBundy 		.reg_shift = 0,
813e505edaeSJeff LaBundy 		.reg_width = 8,
814e505edaeSJeff LaBundy 		.label = "threshold",
815e505edaeSJeff LaBundy 	},
816e505edaeSJeff LaBundy 	{
817e505edaeSJeff LaBundy 		.name = "azoteq,hyst",
818e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_BTN,
819e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_TOUCH,
820e505edaeSJeff LaBundy 		.reg_offset = 1,
821e505edaeSJeff LaBundy 		.reg_shift = 8,
822e505edaeSJeff LaBundy 		.reg_width = 8,
823e505edaeSJeff LaBundy 		.label = "hysteresis",
824e505edaeSJeff LaBundy 	},
825e505edaeSJeff LaBundy 	{
826e505edaeSJeff LaBundy 		.name = "azoteq,lta-beta-lp",
827e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_FILT,
828e505edaeSJeff LaBundy 		.reg_offset = 0,
829e505edaeSJeff LaBundy 		.reg_shift = 12,
830e505edaeSJeff LaBundy 		.reg_width = 4,
831e505edaeSJeff LaBundy 		.label = "low-power mode long-term average beta",
832e505edaeSJeff LaBundy 	},
833e505edaeSJeff LaBundy 	{
834e505edaeSJeff LaBundy 		.name = "azoteq,lta-beta-np",
835e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_FILT,
836e505edaeSJeff LaBundy 		.reg_offset = 0,
837e505edaeSJeff LaBundy 		.reg_shift = 8,
838e505edaeSJeff LaBundy 		.reg_width = 4,
839e505edaeSJeff LaBundy 		.label = "normal-power mode long-term average beta",
840e505edaeSJeff LaBundy 	},
841e505edaeSJeff LaBundy 	{
842e505edaeSJeff LaBundy 		.name = "azoteq,counts-beta-lp",
843e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_FILT,
844e505edaeSJeff LaBundy 		.reg_offset = 0,
845e505edaeSJeff LaBundy 		.reg_shift = 4,
846e505edaeSJeff LaBundy 		.reg_width = 4,
847e505edaeSJeff LaBundy 		.label = "low-power mode counts beta",
848e505edaeSJeff LaBundy 	},
849e505edaeSJeff LaBundy 	{
850e505edaeSJeff LaBundy 		.name = "azoteq,counts-beta-np",
851e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_FILT,
852e505edaeSJeff LaBundy 		.reg_offset = 0,
853e505edaeSJeff LaBundy 		.reg_shift = 0,
854e505edaeSJeff LaBundy 		.reg_width = 4,
855e505edaeSJeff LaBundy 		.label = "normal-power mode counts beta",
856e505edaeSJeff LaBundy 	},
857e505edaeSJeff LaBundy 	{
858e505edaeSJeff LaBundy 		.name = "azoteq,lta-fast-beta-lp",
859e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_FILT,
860e505edaeSJeff LaBundy 		.reg_offset = 1,
861e505edaeSJeff LaBundy 		.reg_shift = 4,
862e505edaeSJeff LaBundy 		.reg_width = 4,
863e505edaeSJeff LaBundy 		.label = "low-power mode long-term average fast beta",
864e505edaeSJeff LaBundy 	},
865e505edaeSJeff LaBundy 	{
866e505edaeSJeff LaBundy 		.name = "azoteq,lta-fast-beta-np",
867e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_FILT,
868e505edaeSJeff LaBundy 		.reg_offset = 1,
869e505edaeSJeff LaBundy 		.reg_shift = 0,
870e505edaeSJeff LaBundy 		.reg_width = 4,
871e505edaeSJeff LaBundy 		.label = "normal-power mode long-term average fast beta",
872e505edaeSJeff LaBundy 	},
873e505edaeSJeff LaBundy 	{
874e505edaeSJeff LaBundy 		.name = "azoteq,lower-cal",
875e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
876e505edaeSJeff LaBundy 		.reg_offset = 0,
877e505edaeSJeff LaBundy 		.reg_shift = 8,
878e505edaeSJeff LaBundy 		.reg_width = 8,
879e505edaeSJeff LaBundy 		.label = "lower calibration",
880e505edaeSJeff LaBundy 	},
881e505edaeSJeff LaBundy 	{
882e505edaeSJeff LaBundy 		.name = "azoteq,static-beta",
883e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
884e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_NO_WHEEL,
885e505edaeSJeff LaBundy 		.reg_offset = 0,
886e505edaeSJeff LaBundy 		.reg_shift = 6,
887e505edaeSJeff LaBundy 		.reg_width = 1,
888e505edaeSJeff LaBundy 	},
889e505edaeSJeff LaBundy 	{
890e505edaeSJeff LaBundy 		.name = "azoteq,bottom-beta",
891e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
892e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_NO_WHEEL,
893e505edaeSJeff LaBundy 		.reg_offset = 0,
894e505edaeSJeff LaBundy 		.reg_shift = 3,
895e505edaeSJeff LaBundy 		.reg_width = 3,
896e505edaeSJeff LaBundy 		.label = "bottom beta",
897e505edaeSJeff LaBundy 	},
898e505edaeSJeff LaBundy 	{
899e505edaeSJeff LaBundy 		.name = "azoteq,static-beta",
900e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
901e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_WHEEL,
902e505edaeSJeff LaBundy 		.reg_offset = 0,
903e505edaeSJeff LaBundy 		.reg_shift = 7,
904e505edaeSJeff LaBundy 		.reg_width = 1,
905e505edaeSJeff LaBundy 	},
906e505edaeSJeff LaBundy 	{
907e505edaeSJeff LaBundy 		.name = "azoteq,bottom-beta",
908e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
909e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_WHEEL,
910e505edaeSJeff LaBundy 		.reg_offset = 0,
911e505edaeSJeff LaBundy 		.reg_shift = 4,
912e505edaeSJeff LaBundy 		.reg_width = 3,
913e505edaeSJeff LaBundy 		.label = "bottom beta",
914e505edaeSJeff LaBundy 	},
915e505edaeSJeff LaBundy 	{
916e505edaeSJeff LaBundy 		.name = "azoteq,bottom-speed",
917e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
918e505edaeSJeff LaBundy 		.reg_offset = 1,
919e505edaeSJeff LaBundy 		.reg_shift = 8,
920e505edaeSJeff LaBundy 		.reg_width = 8,
921e505edaeSJeff LaBundy 		.label = "bottom speed",
922e505edaeSJeff LaBundy 	},
923e505edaeSJeff LaBundy 	{
924e505edaeSJeff LaBundy 		.name = "azoteq,upper-cal",
925e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
926e505edaeSJeff LaBundy 		.reg_offset = 1,
927e505edaeSJeff LaBundy 		.reg_shift = 0,
928e505edaeSJeff LaBundy 		.reg_width = 8,
929e505edaeSJeff LaBundy 		.label = "upper calibration",
930e505edaeSJeff LaBundy 	},
931e505edaeSJeff LaBundy 	{
932e505edaeSJeff LaBundy 		.name = "azoteq,gesture-max-ms",
933e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
934e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_TAP,
935e505edaeSJeff LaBundy 		.reg_offset = 9,
936e505edaeSJeff LaBundy 		.reg_shift = 8,
937e505edaeSJeff LaBundy 		.reg_width = 8,
9388d4c313cSJeff LaBundy 		.val_pitch = 16,
9398d4c313cSJeff LaBundy 		.label = "maximum gesture time",
9408d4c313cSJeff LaBundy 	},
9418d4c313cSJeff LaBundy 	{
9428d4c313cSJeff LaBundy 		.name = "azoteq,gesture-max-ms",
9438d4c313cSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
9448d4c313cSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_TAP_LEGACY,
9458d4c313cSJeff LaBundy 		.reg_offset = 9,
9468d4c313cSJeff LaBundy 		.reg_shift = 8,
9478d4c313cSJeff LaBundy 		.reg_width = 8,
948e505edaeSJeff LaBundy 		.val_pitch = 4,
949e505edaeSJeff LaBundy 		.label = "maximum gesture time",
950e505edaeSJeff LaBundy 	},
951e505edaeSJeff LaBundy 	{
952e505edaeSJeff LaBundy 		.name = "azoteq,gesture-min-ms",
953e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
954e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_TAP,
955e505edaeSJeff LaBundy 		.reg_offset = 9,
956e505edaeSJeff LaBundy 		.reg_shift = 3,
957e505edaeSJeff LaBundy 		.reg_width = 5,
9588d4c313cSJeff LaBundy 		.val_pitch = 16,
9598d4c313cSJeff LaBundy 		.label = "minimum gesture time",
9608d4c313cSJeff LaBundy 	},
9618d4c313cSJeff LaBundy 	{
9628d4c313cSJeff LaBundy 		.name = "azoteq,gesture-min-ms",
9638d4c313cSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
9648d4c313cSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_TAP_LEGACY,
9658d4c313cSJeff LaBundy 		.reg_offset = 9,
9668d4c313cSJeff LaBundy 		.reg_shift = 3,
9678d4c313cSJeff LaBundy 		.reg_width = 5,
968e505edaeSJeff LaBundy 		.val_pitch = 4,
969e505edaeSJeff LaBundy 		.label = "minimum gesture time",
970e505edaeSJeff LaBundy 	},
971e505edaeSJeff LaBundy 	{
972e505edaeSJeff LaBundy 		.name = "azoteq,gesture-dist",
973e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
974e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_AXIAL,
975e505edaeSJeff LaBundy 		.reg_offset = 10,
976e505edaeSJeff LaBundy 		.reg_shift = 8,
977e505edaeSJeff LaBundy 		.reg_width = 8,
978e505edaeSJeff LaBundy 		.val_pitch = 16,
979e505edaeSJeff LaBundy 		.label = "gesture distance",
980e505edaeSJeff LaBundy 	},
981e505edaeSJeff LaBundy 	{
9828d4c313cSJeff LaBundy 		.name = "azoteq,gesture-dist",
9838d4c313cSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
9848d4c313cSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_AXIAL_LEGACY,
9858d4c313cSJeff LaBundy 		.reg_offset = 10,
9868d4c313cSJeff LaBundy 		.reg_shift = 8,
9878d4c313cSJeff LaBundy 		.reg_width = 8,
9888d4c313cSJeff LaBundy 		.val_pitch = 16,
9898d4c313cSJeff LaBundy 		.label = "gesture distance",
9908d4c313cSJeff LaBundy 	},
9918d4c313cSJeff LaBundy 	{
992e505edaeSJeff LaBundy 		.name = "azoteq,gesture-max-ms",
993e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
994e505edaeSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_AXIAL,
995e505edaeSJeff LaBundy 		.reg_offset = 10,
996e505edaeSJeff LaBundy 		.reg_shift = 0,
997e505edaeSJeff LaBundy 		.reg_width = 8,
9988d4c313cSJeff LaBundy 		.val_pitch = 16,
9998d4c313cSJeff LaBundy 		.label = "maximum gesture time",
10008d4c313cSJeff LaBundy 	},
10018d4c313cSJeff LaBundy 	{
10028d4c313cSJeff LaBundy 		.name = "azoteq,gesture-max-ms",
10038d4c313cSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SLDR,
10048d4c313cSJeff LaBundy 		.reg_key = IQS7222_REG_KEY_AXIAL_LEGACY,
10058d4c313cSJeff LaBundy 		.reg_offset = 10,
10068d4c313cSJeff LaBundy 		.reg_shift = 0,
10078d4c313cSJeff LaBundy 		.reg_width = 8,
1008e505edaeSJeff LaBundy 		.val_pitch = 4,
1009e505edaeSJeff LaBundy 		.label = "maximum gesture time",
1010e505edaeSJeff LaBundy 	},
1011e505edaeSJeff LaBundy 	{
1012e505edaeSJeff LaBundy 		.name = "drive-open-drain",
1013e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_GPIO,
1014e505edaeSJeff LaBundy 		.reg_offset = 0,
1015e505edaeSJeff LaBundy 		.reg_shift = 1,
1016e505edaeSJeff LaBundy 		.reg_width = 1,
1017e505edaeSJeff LaBundy 	},
1018e505edaeSJeff LaBundy 	{
1019e505edaeSJeff LaBundy 		.name = "azoteq,timeout-ati-ms",
1020e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SYS,
1021e505edaeSJeff LaBundy 		.reg_offset = 1,
1022e505edaeSJeff LaBundy 		.reg_shift = 0,
1023e505edaeSJeff LaBundy 		.reg_width = 16,
1024e505edaeSJeff LaBundy 		.val_pitch = 500,
1025e505edaeSJeff LaBundy 		.label = "ATI error timeout",
1026e505edaeSJeff LaBundy 	},
1027e505edaeSJeff LaBundy 	{
1028e505edaeSJeff LaBundy 		.name = "azoteq,rate-ati-ms",
1029e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SYS,
1030e505edaeSJeff LaBundy 		.reg_offset = 2,
1031e505edaeSJeff LaBundy 		.reg_shift = 0,
1032e505edaeSJeff LaBundy 		.reg_width = 16,
1033e505edaeSJeff LaBundy 		.label = "ATI report rate",
1034e505edaeSJeff LaBundy 	},
1035e505edaeSJeff LaBundy 	{
1036e505edaeSJeff LaBundy 		.name = "azoteq,timeout-np-ms",
1037e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SYS,
1038e505edaeSJeff LaBundy 		.reg_offset = 3,
1039e505edaeSJeff LaBundy 		.reg_shift = 0,
1040e505edaeSJeff LaBundy 		.reg_width = 16,
1041e505edaeSJeff LaBundy 		.label = "normal-power mode timeout",
1042e505edaeSJeff LaBundy 	},
1043e505edaeSJeff LaBundy 	{
1044e505edaeSJeff LaBundy 		.name = "azoteq,rate-np-ms",
1045e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SYS,
1046e505edaeSJeff LaBundy 		.reg_offset = 4,
1047e505edaeSJeff LaBundy 		.reg_shift = 0,
1048e505edaeSJeff LaBundy 		.reg_width = 16,
1049e505edaeSJeff LaBundy 		.val_max = 3000,
1050e505edaeSJeff LaBundy 		.label = "normal-power mode report rate",
1051e505edaeSJeff LaBundy 	},
1052e505edaeSJeff LaBundy 	{
1053e505edaeSJeff LaBundy 		.name = "azoteq,timeout-lp-ms",
1054e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SYS,
1055e505edaeSJeff LaBundy 		.reg_offset = 5,
1056e505edaeSJeff LaBundy 		.reg_shift = 0,
1057e505edaeSJeff LaBundy 		.reg_width = 16,
1058e505edaeSJeff LaBundy 		.label = "low-power mode timeout",
1059e505edaeSJeff LaBundy 	},
1060e505edaeSJeff LaBundy 	{
1061e505edaeSJeff LaBundy 		.name = "azoteq,rate-lp-ms",
1062e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SYS,
1063e505edaeSJeff LaBundy 		.reg_offset = 6,
1064e505edaeSJeff LaBundy 		.reg_shift = 0,
1065e505edaeSJeff LaBundy 		.reg_width = 16,
1066e505edaeSJeff LaBundy 		.val_max = 3000,
1067e505edaeSJeff LaBundy 		.label = "low-power mode report rate",
1068e505edaeSJeff LaBundy 	},
1069e505edaeSJeff LaBundy 	{
1070e505edaeSJeff LaBundy 		.name = "azoteq,timeout-ulp-ms",
1071e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SYS,
1072e505edaeSJeff LaBundy 		.reg_offset = 7,
1073e505edaeSJeff LaBundy 		.reg_shift = 0,
1074e505edaeSJeff LaBundy 		.reg_width = 16,
1075e505edaeSJeff LaBundy 		.label = "ultra-low-power mode timeout",
1076e505edaeSJeff LaBundy 	},
1077e505edaeSJeff LaBundy 	{
1078e505edaeSJeff LaBundy 		.name = "azoteq,rate-ulp-ms",
1079e505edaeSJeff LaBundy 		.reg_grp = IQS7222_REG_GRP_SYS,
1080e505edaeSJeff LaBundy 		.reg_offset = 8,
1081e505edaeSJeff LaBundy 		.reg_shift = 0,
1082e505edaeSJeff LaBundy 		.reg_width = 16,
1083e505edaeSJeff LaBundy 		.val_max = 3000,
1084e505edaeSJeff LaBundy 		.label = "ultra-low-power mode report rate",
1085e505edaeSJeff LaBundy 	},
1086e505edaeSJeff LaBundy };
1087e505edaeSJeff LaBundy 
1088e505edaeSJeff LaBundy struct iqs7222_private {
1089e505edaeSJeff LaBundy 	const struct iqs7222_dev_desc *dev_desc;
1090e505edaeSJeff LaBundy 	struct gpio_desc *reset_gpio;
1091e505edaeSJeff LaBundy 	struct gpio_desc *irq_gpio;
1092e505edaeSJeff LaBundy 	struct i2c_client *client;
1093e505edaeSJeff LaBundy 	struct input_dev *keypad;
1094e505edaeSJeff LaBundy 	unsigned int kp_type[IQS7222_MAX_CHAN][ARRAY_SIZE(iqs7222_kp_events)];
1095e505edaeSJeff LaBundy 	unsigned int kp_code[IQS7222_MAX_CHAN][ARRAY_SIZE(iqs7222_kp_events)];
1096e505edaeSJeff LaBundy 	unsigned int sl_code[IQS7222_MAX_SLDR][ARRAY_SIZE(iqs7222_sl_events)];
1097e505edaeSJeff LaBundy 	unsigned int sl_axis[IQS7222_MAX_SLDR];
1098e505edaeSJeff LaBundy 	u16 cycle_setup[IQS7222_MAX_CHAN / 2][IQS7222_MAX_COLS_CYCLE];
1099e505edaeSJeff LaBundy 	u16 glbl_setup[IQS7222_MAX_COLS_GLBL];
1100e505edaeSJeff LaBundy 	u16 btn_setup[IQS7222_MAX_CHAN][IQS7222_MAX_COLS_BTN];
1101e505edaeSJeff LaBundy 	u16 chan_setup[IQS7222_MAX_CHAN][IQS7222_MAX_COLS_CHAN];
1102e505edaeSJeff LaBundy 	u16 filt_setup[IQS7222_MAX_COLS_FILT];
1103e505edaeSJeff LaBundy 	u16 sldr_setup[IQS7222_MAX_SLDR][IQS7222_MAX_COLS_SLDR];
1104e505edaeSJeff LaBundy 	u16 gpio_setup[ARRAY_SIZE(iqs7222_gpio_links)][IQS7222_MAX_COLS_GPIO];
1105e505edaeSJeff LaBundy 	u16 sys_setup[IQS7222_MAX_COLS_SYS];
1106e505edaeSJeff LaBundy };
1107e505edaeSJeff LaBundy 
1108e505edaeSJeff LaBundy static u16 *iqs7222_setup(struct iqs7222_private *iqs7222,
1109e505edaeSJeff LaBundy 			  enum iqs7222_reg_grp_id reg_grp, int row)
1110e505edaeSJeff LaBundy {
1111e505edaeSJeff LaBundy 	switch (reg_grp) {
1112e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_CYCLE:
1113e505edaeSJeff LaBundy 		return iqs7222->cycle_setup[row];
1114e505edaeSJeff LaBundy 
1115e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_GLBL:
1116e505edaeSJeff LaBundy 		return iqs7222->glbl_setup;
1117e505edaeSJeff LaBundy 
1118e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_BTN:
1119e505edaeSJeff LaBundy 		return iqs7222->btn_setup[row];
1120e505edaeSJeff LaBundy 
1121e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_CHAN:
1122e505edaeSJeff LaBundy 		return iqs7222->chan_setup[row];
1123e505edaeSJeff LaBundy 
1124e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_FILT:
1125e505edaeSJeff LaBundy 		return iqs7222->filt_setup;
1126e505edaeSJeff LaBundy 
1127e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_SLDR:
1128e505edaeSJeff LaBundy 		return iqs7222->sldr_setup[row];
1129e505edaeSJeff LaBundy 
1130e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_GPIO:
1131e505edaeSJeff LaBundy 		return iqs7222->gpio_setup[row];
1132e505edaeSJeff LaBundy 
1133e505edaeSJeff LaBundy 	case IQS7222_REG_GRP_SYS:
1134e505edaeSJeff LaBundy 		return iqs7222->sys_setup;
1135e505edaeSJeff LaBundy 
1136e505edaeSJeff LaBundy 	default:
1137e505edaeSJeff LaBundy 		return NULL;
1138e505edaeSJeff LaBundy 	}
1139e505edaeSJeff LaBundy }
1140e505edaeSJeff LaBundy 
1141e505edaeSJeff LaBundy static int iqs7222_irq_poll(struct iqs7222_private *iqs7222, u16 timeout_ms)
1142e505edaeSJeff LaBundy {
1143e505edaeSJeff LaBundy 	ktime_t irq_timeout = ktime_add_ms(ktime_get(), timeout_ms);
1144e505edaeSJeff LaBundy 	int ret;
1145e505edaeSJeff LaBundy 
1146e505edaeSJeff LaBundy 	do {
1147e505edaeSJeff LaBundy 		usleep_range(1000, 1100);
1148e505edaeSJeff LaBundy 
1149e505edaeSJeff LaBundy 		ret = gpiod_get_value_cansleep(iqs7222->irq_gpio);
1150e505edaeSJeff LaBundy 		if (ret < 0)
1151e505edaeSJeff LaBundy 			return ret;
1152e505edaeSJeff LaBundy 		else if (ret > 0)
1153e505edaeSJeff LaBundy 			return 0;
1154e505edaeSJeff LaBundy 	} while (ktime_compare(ktime_get(), irq_timeout) < 0);
1155e505edaeSJeff LaBundy 
1156e505edaeSJeff LaBundy 	return -EBUSY;
1157e505edaeSJeff LaBundy }
1158e505edaeSJeff LaBundy 
1159e505edaeSJeff LaBundy static int iqs7222_hard_reset(struct iqs7222_private *iqs7222)
1160e505edaeSJeff LaBundy {
1161e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
1162e505edaeSJeff LaBundy 	int error;
1163e505edaeSJeff LaBundy 
1164e505edaeSJeff LaBundy 	if (!iqs7222->reset_gpio)
1165e505edaeSJeff LaBundy 		return 0;
1166e505edaeSJeff LaBundy 
1167e505edaeSJeff LaBundy 	gpiod_set_value_cansleep(iqs7222->reset_gpio, 1);
1168e505edaeSJeff LaBundy 	usleep_range(1000, 1100);
1169e505edaeSJeff LaBundy 
1170e505edaeSJeff LaBundy 	gpiod_set_value_cansleep(iqs7222->reset_gpio, 0);
1171e505edaeSJeff LaBundy 
1172e505edaeSJeff LaBundy 	error = iqs7222_irq_poll(iqs7222, IQS7222_RESET_TIMEOUT_MS);
1173e505edaeSJeff LaBundy 	if (error)
1174e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to reset device: %d\n", error);
1175e505edaeSJeff LaBundy 
1176e505edaeSJeff LaBundy 	return error;
1177e505edaeSJeff LaBundy }
1178e505edaeSJeff LaBundy 
1179e505edaeSJeff LaBundy static int iqs7222_force_comms(struct iqs7222_private *iqs7222)
1180e505edaeSJeff LaBundy {
118110e629d3SJeff LaBundy 	u8 msg_buf[] = { 0xFF, };
1182e505edaeSJeff LaBundy 	int ret;
1183e505edaeSJeff LaBundy 
1184e505edaeSJeff LaBundy 	/*
1185e505edaeSJeff LaBundy 	 * The device cannot communicate until it asserts its interrupt (RDY)
1186e505edaeSJeff LaBundy 	 * pin. Attempts to do so while RDY is deasserted return an ACK; how-
1187e505edaeSJeff LaBundy 	 * ever all write data is ignored, and all read data returns 0xEE.
1188e505edaeSJeff LaBundy 	 *
1189e505edaeSJeff LaBundy 	 * Unsolicited communication must be preceded by a special force com-
1190e505edaeSJeff LaBundy 	 * munication command, after which the device eventually asserts its
1191e505edaeSJeff LaBundy 	 * RDY pin and agrees to communicate.
1192e505edaeSJeff LaBundy 	 *
1193e505edaeSJeff LaBundy 	 * Regardless of whether communication is forced or the result of an
1194e505edaeSJeff LaBundy 	 * interrupt, the device automatically deasserts its RDY pin once it
1195e505edaeSJeff LaBundy 	 * detects an I2C stop condition, or a timeout expires.
1196e505edaeSJeff LaBundy 	 */
1197e505edaeSJeff LaBundy 	ret = gpiod_get_value_cansleep(iqs7222->irq_gpio);
1198e505edaeSJeff LaBundy 	if (ret < 0)
1199e505edaeSJeff LaBundy 		return ret;
1200e505edaeSJeff LaBundy 	else if (ret > 0)
1201e505edaeSJeff LaBundy 		return 0;
1202e505edaeSJeff LaBundy 
1203e505edaeSJeff LaBundy 	ret = i2c_master_send(iqs7222->client, msg_buf, sizeof(msg_buf));
1204e505edaeSJeff LaBundy 	if (ret < (int)sizeof(msg_buf)) {
1205e505edaeSJeff LaBundy 		if (ret >= 0)
1206e505edaeSJeff LaBundy 			ret = -EIO;
1207e505edaeSJeff LaBundy 
1208e505edaeSJeff LaBundy 		/*
1209e505edaeSJeff LaBundy 		 * The datasheet states that the host must wait to retry any
1210e505edaeSJeff LaBundy 		 * failed attempt to communicate over I2C.
1211e505edaeSJeff LaBundy 		 */
1212e505edaeSJeff LaBundy 		msleep(IQS7222_COMMS_RETRY_MS);
1213e505edaeSJeff LaBundy 		return ret;
1214e505edaeSJeff LaBundy 	}
1215e505edaeSJeff LaBundy 
1216e505edaeSJeff LaBundy 	return iqs7222_irq_poll(iqs7222, IQS7222_COMMS_TIMEOUT_MS);
1217e505edaeSJeff LaBundy }
1218e505edaeSJeff LaBundy 
1219e505edaeSJeff LaBundy static int iqs7222_read_burst(struct iqs7222_private *iqs7222,
1220e505edaeSJeff LaBundy 			      u16 reg, void *val, u16 num_val)
1221e505edaeSJeff LaBundy {
1222e505edaeSJeff LaBundy 	u8 reg_buf[sizeof(__be16)];
1223e505edaeSJeff LaBundy 	int ret, i;
1224e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
1225e505edaeSJeff LaBundy 	struct i2c_msg msg[] = {
1226e505edaeSJeff LaBundy 		{
1227e505edaeSJeff LaBundy 			.addr = client->addr,
1228e505edaeSJeff LaBundy 			.flags = 0,
1229e505edaeSJeff LaBundy 			.len = reg > U8_MAX ? sizeof(reg) : sizeof(u8),
1230e505edaeSJeff LaBundy 			.buf = reg_buf,
1231e505edaeSJeff LaBundy 		},
1232e505edaeSJeff LaBundy 		{
1233e505edaeSJeff LaBundy 			.addr = client->addr,
1234e505edaeSJeff LaBundy 			.flags = I2C_M_RD,
1235e505edaeSJeff LaBundy 			.len = num_val * sizeof(__le16),
1236e505edaeSJeff LaBundy 			.buf = (u8 *)val,
1237e505edaeSJeff LaBundy 		},
1238e505edaeSJeff LaBundy 	};
1239e505edaeSJeff LaBundy 
1240e505edaeSJeff LaBundy 	if (reg > U8_MAX)
1241e505edaeSJeff LaBundy 		put_unaligned_be16(reg, reg_buf);
1242e505edaeSJeff LaBundy 	else
1243e505edaeSJeff LaBundy 		*reg_buf = (u8)reg;
1244e505edaeSJeff LaBundy 
1245e505edaeSJeff LaBundy 	/*
1246e505edaeSJeff LaBundy 	 * The following loop protects against an edge case in which the RDY
1247e505edaeSJeff LaBundy 	 * pin is automatically deasserted just as the read is initiated. In
1248e505edaeSJeff LaBundy 	 * that case, the read must be retried using forced communication.
1249e505edaeSJeff LaBundy 	 */
1250e505edaeSJeff LaBundy 	for (i = 0; i < IQS7222_NUM_RETRIES; i++) {
1251e505edaeSJeff LaBundy 		ret = iqs7222_force_comms(iqs7222);
1252e505edaeSJeff LaBundy 		if (ret < 0)
1253e505edaeSJeff LaBundy 			continue;
1254e505edaeSJeff LaBundy 
1255e505edaeSJeff LaBundy 		ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
1256e505edaeSJeff LaBundy 		if (ret < (int)ARRAY_SIZE(msg)) {
1257e505edaeSJeff LaBundy 			if (ret >= 0)
1258e505edaeSJeff LaBundy 				ret = -EIO;
1259e505edaeSJeff LaBundy 
1260e505edaeSJeff LaBundy 			msleep(IQS7222_COMMS_RETRY_MS);
1261e505edaeSJeff LaBundy 			continue;
1262e505edaeSJeff LaBundy 		}
1263e505edaeSJeff LaBundy 
1264e505edaeSJeff LaBundy 		if (get_unaligned_le16(msg[1].buf) == IQS7222_COMMS_ERROR) {
1265e505edaeSJeff LaBundy 			ret = -ENODATA;
1266e505edaeSJeff LaBundy 			continue;
1267e505edaeSJeff LaBundy 		}
1268e505edaeSJeff LaBundy 
1269e505edaeSJeff LaBundy 		ret = 0;
1270e505edaeSJeff LaBundy 		break;
1271e505edaeSJeff LaBundy 	}
1272e505edaeSJeff LaBundy 
1273e505edaeSJeff LaBundy 	/*
1274e505edaeSJeff LaBundy 	 * The following delay ensures the device has deasserted the RDY pin
1275e505edaeSJeff LaBundy 	 * following the I2C stop condition.
1276e505edaeSJeff LaBundy 	 */
1277e505edaeSJeff LaBundy 	usleep_range(50, 100);
1278e505edaeSJeff LaBundy 
1279e505edaeSJeff LaBundy 	if (ret < 0)
1280e505edaeSJeff LaBundy 		dev_err(&client->dev,
1281e505edaeSJeff LaBundy 			"Failed to read from address 0x%04X: %d\n", reg, ret);
1282e505edaeSJeff LaBundy 
1283e505edaeSJeff LaBundy 	return ret;
1284e505edaeSJeff LaBundy }
1285e505edaeSJeff LaBundy 
1286e505edaeSJeff LaBundy static int iqs7222_read_word(struct iqs7222_private *iqs7222, u16 reg, u16 *val)
1287e505edaeSJeff LaBundy {
1288e505edaeSJeff LaBundy 	__le16 val_buf;
1289e505edaeSJeff LaBundy 	int error;
1290e505edaeSJeff LaBundy 
1291e505edaeSJeff LaBundy 	error = iqs7222_read_burst(iqs7222, reg, &val_buf, 1);
1292e505edaeSJeff LaBundy 	if (error)
1293e505edaeSJeff LaBundy 		return error;
1294e505edaeSJeff LaBundy 
1295e505edaeSJeff LaBundy 	*val = le16_to_cpu(val_buf);
1296e505edaeSJeff LaBundy 
1297e505edaeSJeff LaBundy 	return 0;
1298e505edaeSJeff LaBundy }
1299e505edaeSJeff LaBundy 
1300e505edaeSJeff LaBundy static int iqs7222_write_burst(struct iqs7222_private *iqs7222,
1301e505edaeSJeff LaBundy 			       u16 reg, const void *val, u16 num_val)
1302e505edaeSJeff LaBundy {
1303e505edaeSJeff LaBundy 	int reg_len = reg > U8_MAX ? sizeof(reg) : sizeof(u8);
1304e505edaeSJeff LaBundy 	int val_len = num_val * sizeof(__le16);
1305e505edaeSJeff LaBundy 	int msg_len = reg_len + val_len;
1306e505edaeSJeff LaBundy 	int ret, i;
1307e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
1308e505edaeSJeff LaBundy 	u8 *msg_buf;
1309e505edaeSJeff LaBundy 
1310e505edaeSJeff LaBundy 	msg_buf = kzalloc(msg_len, GFP_KERNEL);
1311e505edaeSJeff LaBundy 	if (!msg_buf)
1312e505edaeSJeff LaBundy 		return -ENOMEM;
1313e505edaeSJeff LaBundy 
1314e505edaeSJeff LaBundy 	if (reg > U8_MAX)
1315e505edaeSJeff LaBundy 		put_unaligned_be16(reg, msg_buf);
1316e505edaeSJeff LaBundy 	else
1317e505edaeSJeff LaBundy 		*msg_buf = (u8)reg;
1318e505edaeSJeff LaBundy 
1319e505edaeSJeff LaBundy 	memcpy(msg_buf + reg_len, val, val_len);
1320e505edaeSJeff LaBundy 
1321e505edaeSJeff LaBundy 	/*
1322e505edaeSJeff LaBundy 	 * The following loop protects against an edge case in which the RDY
1323e505edaeSJeff LaBundy 	 * pin is automatically asserted just before the force communication
1324e505edaeSJeff LaBundy 	 * command is sent.
1325e505edaeSJeff LaBundy 	 *
1326e505edaeSJeff LaBundy 	 * In that case, the subsequent I2C stop condition tricks the device
1327e505edaeSJeff LaBundy 	 * into preemptively deasserting the RDY pin and the command must be
1328e505edaeSJeff LaBundy 	 * sent again.
1329e505edaeSJeff LaBundy 	 */
1330e505edaeSJeff LaBundy 	for (i = 0; i < IQS7222_NUM_RETRIES; i++) {
1331e505edaeSJeff LaBundy 		ret = iqs7222_force_comms(iqs7222);
1332e505edaeSJeff LaBundy 		if (ret < 0)
1333e505edaeSJeff LaBundy 			continue;
1334e505edaeSJeff LaBundy 
1335e505edaeSJeff LaBundy 		ret = i2c_master_send(client, msg_buf, msg_len);
1336e505edaeSJeff LaBundy 		if (ret < msg_len) {
1337e505edaeSJeff LaBundy 			if (ret >= 0)
1338e505edaeSJeff LaBundy 				ret = -EIO;
1339e505edaeSJeff LaBundy 
1340e505edaeSJeff LaBundy 			msleep(IQS7222_COMMS_RETRY_MS);
1341e505edaeSJeff LaBundy 			continue;
1342e505edaeSJeff LaBundy 		}
1343e505edaeSJeff LaBundy 
1344e505edaeSJeff LaBundy 		ret = 0;
1345e505edaeSJeff LaBundy 		break;
1346e505edaeSJeff LaBundy 	}
1347e505edaeSJeff LaBundy 
1348e505edaeSJeff LaBundy 	kfree(msg_buf);
1349e505edaeSJeff LaBundy 
1350e505edaeSJeff LaBundy 	usleep_range(50, 100);
1351e505edaeSJeff LaBundy 
1352e505edaeSJeff LaBundy 	if (ret < 0)
1353e505edaeSJeff LaBundy 		dev_err(&client->dev,
1354e505edaeSJeff LaBundy 			"Failed to write to address 0x%04X: %d\n", reg, ret);
1355e505edaeSJeff LaBundy 
1356e505edaeSJeff LaBundy 	return ret;
1357e505edaeSJeff LaBundy }
1358e505edaeSJeff LaBundy 
1359e505edaeSJeff LaBundy static int iqs7222_write_word(struct iqs7222_private *iqs7222, u16 reg, u16 val)
1360e505edaeSJeff LaBundy {
1361e505edaeSJeff LaBundy 	__le16 val_buf = cpu_to_le16(val);
1362e505edaeSJeff LaBundy 
1363e505edaeSJeff LaBundy 	return iqs7222_write_burst(iqs7222, reg, &val_buf, 1);
1364e505edaeSJeff LaBundy }
1365e505edaeSJeff LaBundy 
1366e505edaeSJeff LaBundy static int iqs7222_ati_trigger(struct iqs7222_private *iqs7222)
1367e505edaeSJeff LaBundy {
1368e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
1369e505edaeSJeff LaBundy 	ktime_t ati_timeout;
1370e505edaeSJeff LaBundy 	u16 sys_status = 0;
13711e4189d8SJeff LaBundy 	u16 sys_setup;
1372e505edaeSJeff LaBundy 	int error, i;
1373e505edaeSJeff LaBundy 
13741e4189d8SJeff LaBundy 	/*
13751e4189d8SJeff LaBundy 	 * The reserved fields of the system setup register may have changed
13761e4189d8SJeff LaBundy 	 * as a result of other registers having been written. As such, read
13771e4189d8SJeff LaBundy 	 * the register's latest value to avoid unexpected behavior when the
13781e4189d8SJeff LaBundy 	 * register is written in the loop that follows.
13791e4189d8SJeff LaBundy 	 */
13801e4189d8SJeff LaBundy 	error = iqs7222_read_word(iqs7222, IQS7222_SYS_SETUP, &sys_setup);
13811e4189d8SJeff LaBundy 	if (error)
13821e4189d8SJeff LaBundy 		return error;
13831e4189d8SJeff LaBundy 
1384e505edaeSJeff LaBundy 	for (i = 0; i < IQS7222_NUM_RETRIES; i++) {
1385e505edaeSJeff LaBundy 		/*
1386e505edaeSJeff LaBundy 		 * Trigger ATI from streaming and normal-power modes so that
1387e505edaeSJeff LaBundy 		 * the RDY pin continues to be asserted during ATI.
1388e505edaeSJeff LaBundy 		 */
1389e505edaeSJeff LaBundy 		error = iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP,
1390e505edaeSJeff LaBundy 					   sys_setup |
1391e505edaeSJeff LaBundy 					   IQS7222_SYS_SETUP_REDO_ATI);
1392e505edaeSJeff LaBundy 		if (error)
1393e505edaeSJeff LaBundy 			return error;
1394e505edaeSJeff LaBundy 
1395e505edaeSJeff LaBundy 		ati_timeout = ktime_add_ms(ktime_get(), IQS7222_ATI_TIMEOUT_MS);
1396e505edaeSJeff LaBundy 
1397e505edaeSJeff LaBundy 		do {
1398e505edaeSJeff LaBundy 			error = iqs7222_irq_poll(iqs7222,
1399e505edaeSJeff LaBundy 						 IQS7222_COMMS_TIMEOUT_MS);
1400e505edaeSJeff LaBundy 			if (error)
1401e505edaeSJeff LaBundy 				continue;
1402e505edaeSJeff LaBundy 
1403e505edaeSJeff LaBundy 			error = iqs7222_read_word(iqs7222, IQS7222_SYS_STATUS,
1404e505edaeSJeff LaBundy 						  &sys_status);
1405e505edaeSJeff LaBundy 			if (error)
1406e505edaeSJeff LaBundy 				return error;
1407e505edaeSJeff LaBundy 
14088635c688SJeff LaBundy 			if (sys_status & IQS7222_SYS_STATUS_RESET)
14098635c688SJeff LaBundy 				return 0;
1410e505edaeSJeff LaBundy 
1411e505edaeSJeff LaBundy 			if (sys_status & IQS7222_SYS_STATUS_ATI_ERROR)
1412e505edaeSJeff LaBundy 				break;
1413e505edaeSJeff LaBundy 
14148635c688SJeff LaBundy 			if (sys_status & IQS7222_SYS_STATUS_ATI_ACTIVE)
14158635c688SJeff LaBundy 				continue;
14168635c688SJeff LaBundy 
1417e505edaeSJeff LaBundy 			/*
1418e505edaeSJeff LaBundy 			 * Use stream-in-touch mode if either slider reports
1419e505edaeSJeff LaBundy 			 * absolute position.
1420e505edaeSJeff LaBundy 			 */
1421e505edaeSJeff LaBundy 			sys_setup |= test_bit(EV_ABS, iqs7222->keypad->evbit)
1422e505edaeSJeff LaBundy 				   ? IQS7222_SYS_SETUP_INTF_MODE_TOUCH
1423e505edaeSJeff LaBundy 				   : IQS7222_SYS_SETUP_INTF_MODE_EVENT;
1424e505edaeSJeff LaBundy 			sys_setup |= IQS7222_SYS_SETUP_PWR_MODE_AUTO;
1425e505edaeSJeff LaBundy 
1426e505edaeSJeff LaBundy 			return iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP,
1427e505edaeSJeff LaBundy 						  sys_setup);
1428e505edaeSJeff LaBundy 		} while (ktime_compare(ktime_get(), ati_timeout) < 0);
1429e505edaeSJeff LaBundy 
1430e505edaeSJeff LaBundy 		dev_err(&client->dev,
1431e505edaeSJeff LaBundy 			"ATI attempt %d of %d failed with status 0x%02X, %s\n",
1432e505edaeSJeff LaBundy 			i + 1, IQS7222_NUM_RETRIES, (u8)sys_status,
14338635c688SJeff LaBundy 			i + 1 < IQS7222_NUM_RETRIES ? "retrying" : "stopping");
1434e505edaeSJeff LaBundy 	}
1435e505edaeSJeff LaBundy 
1436e505edaeSJeff LaBundy 	return -ETIMEDOUT;
1437e505edaeSJeff LaBundy }
1438e505edaeSJeff LaBundy 
1439e505edaeSJeff LaBundy static int iqs7222_dev_init(struct iqs7222_private *iqs7222, int dir)
1440e505edaeSJeff LaBundy {
1441e505edaeSJeff LaBundy 	const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
1442e505edaeSJeff LaBundy 	int comms_offset = dev_desc->comms_offset;
1443e505edaeSJeff LaBundy 	int error, i, j, k;
1444e505edaeSJeff LaBundy 
1445e505edaeSJeff LaBundy 	/*
14462e70ef52SJeff LaBundy 	 * Acknowledge reset before writing any registers in case the device
14472e70ef52SJeff LaBundy 	 * suffers a spurious reset during initialization. Because this step
14482e70ef52SJeff LaBundy 	 * may change the reserved fields of the second filter beta register,
14492e70ef52SJeff LaBundy 	 * its cache must be updated.
14502e70ef52SJeff LaBundy 	 *
14512e70ef52SJeff LaBundy 	 * Writing the second filter beta register, in turn, may clobber the
14522e70ef52SJeff LaBundy 	 * system status register. As such, the filter beta register pair is
14532e70ef52SJeff LaBundy 	 * written first to protect against this hazard.
14542e70ef52SJeff LaBundy 	 */
14552e70ef52SJeff LaBundy 	if (dir == WRITE) {
14562e70ef52SJeff LaBundy 		u16 reg = dev_desc->reg_grps[IQS7222_REG_GRP_FILT].base + 1;
14572e70ef52SJeff LaBundy 		u16 filt_setup;
14582e70ef52SJeff LaBundy 
14592e70ef52SJeff LaBundy 		error = iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP,
14602e70ef52SJeff LaBundy 					   iqs7222->sys_setup[0] |
14612e70ef52SJeff LaBundy 					   IQS7222_SYS_SETUP_ACK_RESET);
14622e70ef52SJeff LaBundy 		if (error)
14632e70ef52SJeff LaBundy 			return error;
14642e70ef52SJeff LaBundy 
14652e70ef52SJeff LaBundy 		error = iqs7222_read_word(iqs7222, reg, &filt_setup);
14662e70ef52SJeff LaBundy 		if (error)
14672e70ef52SJeff LaBundy 			return error;
14682e70ef52SJeff LaBundy 
14692e70ef52SJeff LaBundy 		iqs7222->filt_setup[1] &= GENMASK(7, 0);
14702e70ef52SJeff LaBundy 		iqs7222->filt_setup[1] |= (filt_setup & ~GENMASK(7, 0));
14712e70ef52SJeff LaBundy 	}
14722e70ef52SJeff LaBundy 
14732e70ef52SJeff LaBundy 	/*
1474e505edaeSJeff LaBundy 	 * Take advantage of the stop-bit disable function, if available, to
1475e505edaeSJeff LaBundy 	 * save the trouble of having to reopen a communication window after
1476e505edaeSJeff LaBundy 	 * each burst read or write.
1477e505edaeSJeff LaBundy 	 */
1478e505edaeSJeff LaBundy 	if (comms_offset) {
1479e505edaeSJeff LaBundy 		u16 comms_setup;
1480e505edaeSJeff LaBundy 
1481e505edaeSJeff LaBundy 		error = iqs7222_read_word(iqs7222,
1482e505edaeSJeff LaBundy 					  IQS7222_SYS_SETUP + comms_offset,
1483e505edaeSJeff LaBundy 					  &comms_setup);
1484e505edaeSJeff LaBundy 		if (error)
1485e505edaeSJeff LaBundy 			return error;
1486e505edaeSJeff LaBundy 
1487e505edaeSJeff LaBundy 		error = iqs7222_write_word(iqs7222,
1488e505edaeSJeff LaBundy 					   IQS7222_SYS_SETUP + comms_offset,
1489e505edaeSJeff LaBundy 					   comms_setup | IQS7222_COMMS_HOLD);
1490e505edaeSJeff LaBundy 		if (error)
1491e505edaeSJeff LaBundy 			return error;
1492e505edaeSJeff LaBundy 	}
1493e505edaeSJeff LaBundy 
1494e505edaeSJeff LaBundy 	for (i = 0; i < IQS7222_NUM_REG_GRPS; i++) {
1495e505edaeSJeff LaBundy 		int num_row = dev_desc->reg_grps[i].num_row;
1496e505edaeSJeff LaBundy 		int num_col = dev_desc->reg_grps[i].num_col;
1497e505edaeSJeff LaBundy 		u16 reg = dev_desc->reg_grps[i].base;
1498e505edaeSJeff LaBundy 		__le16 *val_buf;
1499e505edaeSJeff LaBundy 		u16 *val;
1500e505edaeSJeff LaBundy 
1501e505edaeSJeff LaBundy 		if (!num_col)
1502e505edaeSJeff LaBundy 			continue;
1503e505edaeSJeff LaBundy 
1504e505edaeSJeff LaBundy 		val = iqs7222_setup(iqs7222, i, 0);
1505e505edaeSJeff LaBundy 		if (!val)
1506e505edaeSJeff LaBundy 			continue;
1507e505edaeSJeff LaBundy 
1508e505edaeSJeff LaBundy 		val_buf = kcalloc(num_col, sizeof(__le16), GFP_KERNEL);
1509e505edaeSJeff LaBundy 		if (!val_buf)
1510e505edaeSJeff LaBundy 			return -ENOMEM;
1511e505edaeSJeff LaBundy 
1512e505edaeSJeff LaBundy 		for (j = 0; j < num_row; j++) {
1513e505edaeSJeff LaBundy 			switch (dir) {
1514e505edaeSJeff LaBundy 			case READ:
1515e505edaeSJeff LaBundy 				error = iqs7222_read_burst(iqs7222, reg,
1516e505edaeSJeff LaBundy 							   val_buf, num_col);
1517e505edaeSJeff LaBundy 				for (k = 0; k < num_col; k++)
1518e505edaeSJeff LaBundy 					val[k] = le16_to_cpu(val_buf[k]);
1519e505edaeSJeff LaBundy 				break;
1520e505edaeSJeff LaBundy 
1521e505edaeSJeff LaBundy 			case WRITE:
1522e505edaeSJeff LaBundy 				for (k = 0; k < num_col; k++)
1523e505edaeSJeff LaBundy 					val_buf[k] = cpu_to_le16(val[k]);
1524e505edaeSJeff LaBundy 				error = iqs7222_write_burst(iqs7222, reg,
1525e505edaeSJeff LaBundy 							    val_buf, num_col);
1526e505edaeSJeff LaBundy 				break;
1527e505edaeSJeff LaBundy 
1528e505edaeSJeff LaBundy 			default:
1529e505edaeSJeff LaBundy 				error = -EINVAL;
1530e505edaeSJeff LaBundy 			}
1531e505edaeSJeff LaBundy 
1532e505edaeSJeff LaBundy 			if (error)
1533e505edaeSJeff LaBundy 				break;
1534e505edaeSJeff LaBundy 
1535e505edaeSJeff LaBundy 			reg += IQS7222_REG_OFFSET;
1536e505edaeSJeff LaBundy 			val += iqs7222_max_cols[i];
1537e505edaeSJeff LaBundy 		}
1538e505edaeSJeff LaBundy 
1539e505edaeSJeff LaBundy 		kfree(val_buf);
1540e505edaeSJeff LaBundy 
1541e505edaeSJeff LaBundy 		if (error)
1542e505edaeSJeff LaBundy 			return error;
1543e505edaeSJeff LaBundy 	}
1544e505edaeSJeff LaBundy 
1545e505edaeSJeff LaBundy 	if (comms_offset) {
1546e505edaeSJeff LaBundy 		u16 comms_setup;
1547e505edaeSJeff LaBundy 
1548e505edaeSJeff LaBundy 		error = iqs7222_read_word(iqs7222,
1549e505edaeSJeff LaBundy 					  IQS7222_SYS_SETUP + comms_offset,
1550e505edaeSJeff LaBundy 					  &comms_setup);
1551e505edaeSJeff LaBundy 		if (error)
1552e505edaeSJeff LaBundy 			return error;
1553e505edaeSJeff LaBundy 
1554e505edaeSJeff LaBundy 		error = iqs7222_write_word(iqs7222,
1555e505edaeSJeff LaBundy 					   IQS7222_SYS_SETUP + comms_offset,
1556e505edaeSJeff LaBundy 					   comms_setup & ~IQS7222_COMMS_HOLD);
1557e505edaeSJeff LaBundy 		if (error)
1558e505edaeSJeff LaBundy 			return error;
1559e505edaeSJeff LaBundy 	}
1560e505edaeSJeff LaBundy 
1561*2e00b8bfSJeff LaBundy 	if (dir == READ) {
1562*2e00b8bfSJeff LaBundy 		iqs7222->sys_setup[0] &= ~IQS7222_SYS_SETUP_INTF_MODE_MASK;
1563*2e00b8bfSJeff LaBundy 		iqs7222->sys_setup[0] &= ~IQS7222_SYS_SETUP_PWR_MODE_MASK;
1564e505edaeSJeff LaBundy 		return 0;
1565*2e00b8bfSJeff LaBundy 	}
1566e505edaeSJeff LaBundy 
1567e505edaeSJeff LaBundy 	return iqs7222_ati_trigger(iqs7222);
1568e505edaeSJeff LaBundy }
1569e505edaeSJeff LaBundy 
1570e505edaeSJeff LaBundy static int iqs7222_dev_info(struct iqs7222_private *iqs7222)
1571e505edaeSJeff LaBundy {
1572e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
1573e505edaeSJeff LaBundy 	bool prod_num_valid = false;
1574e505edaeSJeff LaBundy 	__le16 dev_id[3];
1575e505edaeSJeff LaBundy 	int error, i;
1576e505edaeSJeff LaBundy 
1577e505edaeSJeff LaBundy 	error = iqs7222_read_burst(iqs7222, IQS7222_PROD_NUM, dev_id,
1578e505edaeSJeff LaBundy 				   ARRAY_SIZE(dev_id));
1579e505edaeSJeff LaBundy 	if (error)
1580e505edaeSJeff LaBundy 		return error;
1581e505edaeSJeff LaBundy 
1582e505edaeSJeff LaBundy 	for (i = 0; i < ARRAY_SIZE(iqs7222_devs); i++) {
1583e505edaeSJeff LaBundy 		if (le16_to_cpu(dev_id[0]) != iqs7222_devs[i].prod_num)
1584e505edaeSJeff LaBundy 			continue;
1585e505edaeSJeff LaBundy 
1586e505edaeSJeff LaBundy 		prod_num_valid = true;
1587e505edaeSJeff LaBundy 
1588e505edaeSJeff LaBundy 		if (le16_to_cpu(dev_id[1]) < iqs7222_devs[i].fw_major)
1589e505edaeSJeff LaBundy 			continue;
1590e505edaeSJeff LaBundy 
1591e505edaeSJeff LaBundy 		if (le16_to_cpu(dev_id[2]) < iqs7222_devs[i].fw_minor)
1592e505edaeSJeff LaBundy 			continue;
1593e505edaeSJeff LaBundy 
1594e505edaeSJeff LaBundy 		iqs7222->dev_desc = &iqs7222_devs[i];
1595e505edaeSJeff LaBundy 		return 0;
1596e505edaeSJeff LaBundy 	}
1597e505edaeSJeff LaBundy 
1598e505edaeSJeff LaBundy 	if (prod_num_valid)
1599e505edaeSJeff LaBundy 		dev_err(&client->dev, "Unsupported firmware revision: %u.%u\n",
1600e505edaeSJeff LaBundy 			le16_to_cpu(dev_id[1]), le16_to_cpu(dev_id[2]));
1601e505edaeSJeff LaBundy 	else
1602e505edaeSJeff LaBundy 		dev_err(&client->dev, "Unrecognized product number: %u\n",
1603e505edaeSJeff LaBundy 			le16_to_cpu(dev_id[0]));
1604e505edaeSJeff LaBundy 
1605e505edaeSJeff LaBundy 	return -EINVAL;
1606e505edaeSJeff LaBundy }
1607e505edaeSJeff LaBundy 
1608e505edaeSJeff LaBundy static int iqs7222_gpio_select(struct iqs7222_private *iqs7222,
1609e505edaeSJeff LaBundy 			       struct fwnode_handle *child_node,
1610e505edaeSJeff LaBundy 			       int child_enable, u16 child_link)
1611e505edaeSJeff LaBundy {
1612e505edaeSJeff LaBundy 	const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
1613e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
1614e505edaeSJeff LaBundy 	int num_gpio = dev_desc->reg_grps[IQS7222_REG_GRP_GPIO].num_row;
1615e505edaeSJeff LaBundy 	int error, count, i;
1616e505edaeSJeff LaBundy 	unsigned int gpio_sel[ARRAY_SIZE(iqs7222_gpio_links)];
1617e505edaeSJeff LaBundy 
1618e505edaeSJeff LaBundy 	if (!num_gpio)
1619e505edaeSJeff LaBundy 		return 0;
1620e505edaeSJeff LaBundy 
1621e505edaeSJeff LaBundy 	if (!fwnode_property_present(child_node, "azoteq,gpio-select"))
1622e505edaeSJeff LaBundy 		return 0;
1623e505edaeSJeff LaBundy 
1624e505edaeSJeff LaBundy 	count = fwnode_property_count_u32(child_node, "azoteq,gpio-select");
1625e505edaeSJeff LaBundy 	if (count > num_gpio) {
1626e505edaeSJeff LaBundy 		dev_err(&client->dev, "Invalid number of %s GPIOs\n",
1627e505edaeSJeff LaBundy 			fwnode_get_name(child_node));
1628e505edaeSJeff LaBundy 		return -EINVAL;
1629e505edaeSJeff LaBundy 	} else if (count < 0) {
1630e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to count %s GPIOs: %d\n",
1631e505edaeSJeff LaBundy 			fwnode_get_name(child_node), count);
1632e505edaeSJeff LaBundy 		return count;
1633e505edaeSJeff LaBundy 	}
1634e505edaeSJeff LaBundy 
1635e505edaeSJeff LaBundy 	error = fwnode_property_read_u32_array(child_node,
1636e505edaeSJeff LaBundy 					       "azoteq,gpio-select",
1637e505edaeSJeff LaBundy 					       gpio_sel, count);
1638e505edaeSJeff LaBundy 	if (error) {
1639e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to read %s GPIOs: %d\n",
1640e505edaeSJeff LaBundy 			fwnode_get_name(child_node), error);
1641e505edaeSJeff LaBundy 		return error;
1642e505edaeSJeff LaBundy 	}
1643e505edaeSJeff LaBundy 
1644e505edaeSJeff LaBundy 	for (i = 0; i < count; i++) {
1645e505edaeSJeff LaBundy 		u16 *gpio_setup;
1646e505edaeSJeff LaBundy 
1647e505edaeSJeff LaBundy 		if (gpio_sel[i] >= num_gpio) {
1648e505edaeSJeff LaBundy 			dev_err(&client->dev, "Invalid %s GPIO: %u\n",
1649e505edaeSJeff LaBundy 				fwnode_get_name(child_node), gpio_sel[i]);
1650e505edaeSJeff LaBundy 			return -EINVAL;
1651e505edaeSJeff LaBundy 		}
1652e505edaeSJeff LaBundy 
1653e505edaeSJeff LaBundy 		gpio_setup = iqs7222->gpio_setup[gpio_sel[i]];
1654e505edaeSJeff LaBundy 
1655e505edaeSJeff LaBundy 		if (gpio_setup[2] && child_link != gpio_setup[2]) {
1656e505edaeSJeff LaBundy 			dev_err(&client->dev,
1657e505edaeSJeff LaBundy 				"Conflicting GPIO %u event types\n",
1658e505edaeSJeff LaBundy 				gpio_sel[i]);
1659e505edaeSJeff LaBundy 			return -EINVAL;
1660e505edaeSJeff LaBundy 		}
1661e505edaeSJeff LaBundy 
1662e505edaeSJeff LaBundy 		gpio_setup[0] |= IQS7222_GPIO_SETUP_0_GPIO_EN;
1663e505edaeSJeff LaBundy 		gpio_setup[1] |= child_enable;
1664e505edaeSJeff LaBundy 		gpio_setup[2] = child_link;
1665e505edaeSJeff LaBundy 	}
1666e505edaeSJeff LaBundy 
1667e505edaeSJeff LaBundy 	return 0;
1668e505edaeSJeff LaBundy }
1669e505edaeSJeff LaBundy 
1670e505edaeSJeff LaBundy static int iqs7222_parse_props(struct iqs7222_private *iqs7222,
1671bbd16b0dSJeff LaBundy 			       struct fwnode_handle *reg_grp_node,
1672bbd16b0dSJeff LaBundy 			       int reg_grp_index,
1673e505edaeSJeff LaBundy 			       enum iqs7222_reg_grp_id reg_grp,
1674e505edaeSJeff LaBundy 			       enum iqs7222_reg_key_id reg_key)
1675e505edaeSJeff LaBundy {
1676bbd16b0dSJeff LaBundy 	u16 *setup = iqs7222_setup(iqs7222, reg_grp, reg_grp_index);
1677e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
1678e505edaeSJeff LaBundy 	int i;
1679e505edaeSJeff LaBundy 
1680bbd16b0dSJeff LaBundy 	if (!setup)
1681e505edaeSJeff LaBundy 		return 0;
1682e505edaeSJeff LaBundy 
1683e505edaeSJeff LaBundy 	for (i = 0; i < ARRAY_SIZE(iqs7222_props); i++) {
1684e505edaeSJeff LaBundy 		const char *name = iqs7222_props[i].name;
1685e505edaeSJeff LaBundy 		int reg_offset = iqs7222_props[i].reg_offset;
1686e505edaeSJeff LaBundy 		int reg_shift = iqs7222_props[i].reg_shift;
1687e505edaeSJeff LaBundy 		int reg_width = iqs7222_props[i].reg_width;
1688e505edaeSJeff LaBundy 		int val_pitch = iqs7222_props[i].val_pitch ? : 1;
1689e505edaeSJeff LaBundy 		int val_min = iqs7222_props[i].val_min;
1690e505edaeSJeff LaBundy 		int val_max = iqs7222_props[i].val_max;
1691e505edaeSJeff LaBundy 		bool invert = iqs7222_props[i].invert;
1692e505edaeSJeff LaBundy 		const char *label = iqs7222_props[i].label ? : name;
1693e505edaeSJeff LaBundy 		unsigned int val;
1694e505edaeSJeff LaBundy 		int error;
1695e505edaeSJeff LaBundy 
1696e505edaeSJeff LaBundy 		if (iqs7222_props[i].reg_grp != reg_grp ||
1697e505edaeSJeff LaBundy 		    iqs7222_props[i].reg_key != reg_key)
1698e505edaeSJeff LaBundy 			continue;
1699e505edaeSJeff LaBundy 
1700e505edaeSJeff LaBundy 		/*
1701e505edaeSJeff LaBundy 		 * Boolean register fields are one bit wide; they are forcibly
1702e505edaeSJeff LaBundy 		 * reset to provide a means to undo changes by a bootloader if
1703e505edaeSJeff LaBundy 		 * necessary.
1704e505edaeSJeff LaBundy 		 *
1705e505edaeSJeff LaBundy 		 * Scalar fields, on the other hand, are left untouched unless
1706e505edaeSJeff LaBundy 		 * their corresponding properties are present.
1707e505edaeSJeff LaBundy 		 */
1708e505edaeSJeff LaBundy 		if (reg_width == 1) {
1709e505edaeSJeff LaBundy 			if (invert)
1710e505edaeSJeff LaBundy 				setup[reg_offset] |= BIT(reg_shift);
1711e505edaeSJeff LaBundy 			else
1712e505edaeSJeff LaBundy 				setup[reg_offset] &= ~BIT(reg_shift);
1713e505edaeSJeff LaBundy 		}
1714e505edaeSJeff LaBundy 
1715e505edaeSJeff LaBundy 		if (!fwnode_property_present(reg_grp_node, name))
1716e505edaeSJeff LaBundy 			continue;
1717e505edaeSJeff LaBundy 
1718e505edaeSJeff LaBundy 		if (reg_width == 1) {
1719e505edaeSJeff LaBundy 			if (invert)
1720e505edaeSJeff LaBundy 				setup[reg_offset] &= ~BIT(reg_shift);
1721e505edaeSJeff LaBundy 			else
1722e505edaeSJeff LaBundy 				setup[reg_offset] |= BIT(reg_shift);
1723e505edaeSJeff LaBundy 
1724e505edaeSJeff LaBundy 			continue;
1725e505edaeSJeff LaBundy 		}
1726e505edaeSJeff LaBundy 
1727e505edaeSJeff LaBundy 		error = fwnode_property_read_u32(reg_grp_node, name, &val);
1728e505edaeSJeff LaBundy 		if (error) {
1729e505edaeSJeff LaBundy 			dev_err(&client->dev, "Failed to read %s %s: %d\n",
1730e505edaeSJeff LaBundy 				fwnode_get_name(reg_grp_node), label, error);
1731e505edaeSJeff LaBundy 			return error;
1732e505edaeSJeff LaBundy 		}
1733e505edaeSJeff LaBundy 
1734e505edaeSJeff LaBundy 		if (!val_max)
1735e505edaeSJeff LaBundy 			val_max = GENMASK(reg_width - 1, 0) * val_pitch;
1736e505edaeSJeff LaBundy 
1737e505edaeSJeff LaBundy 		if (val < val_min || val > val_max) {
1738e505edaeSJeff LaBundy 			dev_err(&client->dev, "Invalid %s %s: %u\n",
1739e505edaeSJeff LaBundy 				fwnode_get_name(reg_grp_node), label, val);
1740e505edaeSJeff LaBundy 			return -EINVAL;
1741e505edaeSJeff LaBundy 		}
1742e505edaeSJeff LaBundy 
1743e505edaeSJeff LaBundy 		setup[reg_offset] &= ~GENMASK(reg_shift + reg_width - 1,
1744e505edaeSJeff LaBundy 					      reg_shift);
1745e505edaeSJeff LaBundy 		setup[reg_offset] |= (val / val_pitch << reg_shift);
1746e505edaeSJeff LaBundy 	}
1747e505edaeSJeff LaBundy 
1748e505edaeSJeff LaBundy 	return 0;
1749e505edaeSJeff LaBundy }
1750e505edaeSJeff LaBundy 
1751bbd16b0dSJeff LaBundy static int iqs7222_parse_event(struct iqs7222_private *iqs7222,
1752bbd16b0dSJeff LaBundy 			       struct fwnode_handle *event_node,
1753bbd16b0dSJeff LaBundy 			       int reg_grp_index,
1754bbd16b0dSJeff LaBundy 			       enum iqs7222_reg_grp_id reg_grp,
1755bbd16b0dSJeff LaBundy 			       enum iqs7222_reg_key_id reg_key,
1756bbd16b0dSJeff LaBundy 			       u16 event_enable, u16 event_link,
1757bbd16b0dSJeff LaBundy 			       unsigned int *event_type,
1758bbd16b0dSJeff LaBundy 			       unsigned int *event_code)
1759bbd16b0dSJeff LaBundy {
1760bbd16b0dSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
1761bbd16b0dSJeff LaBundy 	int error;
1762bbd16b0dSJeff LaBundy 
1763bbd16b0dSJeff LaBundy 	error = iqs7222_parse_props(iqs7222, event_node, reg_grp_index,
1764bbd16b0dSJeff LaBundy 				    reg_grp, reg_key);
1765bbd16b0dSJeff LaBundy 	if (error)
1766bbd16b0dSJeff LaBundy 		return error;
1767bbd16b0dSJeff LaBundy 
1768bbd16b0dSJeff LaBundy 	error = iqs7222_gpio_select(iqs7222, event_node, event_enable,
1769bbd16b0dSJeff LaBundy 				    event_link);
1770bbd16b0dSJeff LaBundy 	if (error)
1771bbd16b0dSJeff LaBundy 		return error;
1772bbd16b0dSJeff LaBundy 
1773bbd16b0dSJeff LaBundy 	error = fwnode_property_read_u32(event_node, "linux,code", event_code);
1774bbd16b0dSJeff LaBundy 	if (error == -EINVAL) {
1775bbd16b0dSJeff LaBundy 		return 0;
1776bbd16b0dSJeff LaBundy 	} else if (error) {
1777bbd16b0dSJeff LaBundy 		dev_err(&client->dev, "Failed to read %s code: %d\n",
1778bbd16b0dSJeff LaBundy 			fwnode_get_name(event_node), error);
1779bbd16b0dSJeff LaBundy 		return error;
1780bbd16b0dSJeff LaBundy 	}
1781bbd16b0dSJeff LaBundy 
1782bbd16b0dSJeff LaBundy 	if (!event_type) {
1783bbd16b0dSJeff LaBundy 		input_set_capability(iqs7222->keypad, EV_KEY, *event_code);
1784bbd16b0dSJeff LaBundy 		return 0;
1785bbd16b0dSJeff LaBundy 	}
1786bbd16b0dSJeff LaBundy 
1787bbd16b0dSJeff LaBundy 	error = fwnode_property_read_u32(event_node, "linux,input-type",
1788bbd16b0dSJeff LaBundy 					 event_type);
1789bbd16b0dSJeff LaBundy 	if (error == -EINVAL) {
1790bbd16b0dSJeff LaBundy 		*event_type = EV_KEY;
1791bbd16b0dSJeff LaBundy 	} else if (error) {
1792bbd16b0dSJeff LaBundy 		dev_err(&client->dev, "Failed to read %s input type: %d\n",
1793bbd16b0dSJeff LaBundy 			fwnode_get_name(event_node), error);
1794bbd16b0dSJeff LaBundy 		return error;
1795bbd16b0dSJeff LaBundy 	} else if (*event_type != EV_KEY && *event_type != EV_SW) {
1796bbd16b0dSJeff LaBundy 		dev_err(&client->dev, "Invalid %s input type: %d\n",
1797bbd16b0dSJeff LaBundy 			fwnode_get_name(event_node), *event_type);
1798bbd16b0dSJeff LaBundy 		return -EINVAL;
1799bbd16b0dSJeff LaBundy 	}
1800bbd16b0dSJeff LaBundy 
1801bbd16b0dSJeff LaBundy 	input_set_capability(iqs7222->keypad, *event_type, *event_code);
1802bbd16b0dSJeff LaBundy 
1803bbd16b0dSJeff LaBundy 	return 0;
1804bbd16b0dSJeff LaBundy }
1805bbd16b0dSJeff LaBundy 
1806bbd16b0dSJeff LaBundy static int iqs7222_parse_cycle(struct iqs7222_private *iqs7222,
1807bbd16b0dSJeff LaBundy 			       struct fwnode_handle *cycle_node, int cycle_index)
1808e505edaeSJeff LaBundy {
1809e505edaeSJeff LaBundy 	u16 *cycle_setup = iqs7222->cycle_setup[cycle_index];
1810e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
1811e505edaeSJeff LaBundy 	unsigned int pins[9];
1812e505edaeSJeff LaBundy 	int error, count, i;
1813e505edaeSJeff LaBundy 
1814e505edaeSJeff LaBundy 	/*
1815e505edaeSJeff LaBundy 	 * Each channel shares a cycle with one other channel; the mapping of
1816e505edaeSJeff LaBundy 	 * channels to cycles is fixed. Properties defined for a cycle impact
1817e505edaeSJeff LaBundy 	 * both channels tied to the cycle.
1818bbd16b0dSJeff LaBundy 	 *
1819e505edaeSJeff LaBundy 	 * Unlike channels which are restricted to a select range of CRx pins
1820e505edaeSJeff LaBundy 	 * based on channel number, any cycle can claim any of the device's 9
1821e505edaeSJeff LaBundy 	 * CTx pins (CTx0-8).
1822e505edaeSJeff LaBundy 	 */
1823e505edaeSJeff LaBundy 	if (!fwnode_property_present(cycle_node, "azoteq,tx-enable"))
1824e505edaeSJeff LaBundy 		return 0;
1825e505edaeSJeff LaBundy 
1826e505edaeSJeff LaBundy 	count = fwnode_property_count_u32(cycle_node, "azoteq,tx-enable");
1827eba697b3SDan Carpenter 	if (count < 0) {
1828e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to count %s CTx pins: %d\n",
1829e505edaeSJeff LaBundy 			fwnode_get_name(cycle_node), count);
1830e505edaeSJeff LaBundy 		return count;
1831eba697b3SDan Carpenter 	} else if (count > ARRAY_SIZE(pins)) {
1832eba697b3SDan Carpenter 		dev_err(&client->dev, "Invalid number of %s CTx pins\n",
1833eba697b3SDan Carpenter 			fwnode_get_name(cycle_node));
1834eba697b3SDan Carpenter 		return -EINVAL;
1835e505edaeSJeff LaBundy 	}
1836e505edaeSJeff LaBundy 
1837e505edaeSJeff LaBundy 	error = fwnode_property_read_u32_array(cycle_node, "azoteq,tx-enable",
1838e505edaeSJeff LaBundy 					       pins, count);
1839e505edaeSJeff LaBundy 	if (error) {
1840e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to read %s CTx pins: %d\n",
1841e505edaeSJeff LaBundy 			fwnode_get_name(cycle_node), error);
1842e505edaeSJeff LaBundy 		return error;
1843e505edaeSJeff LaBundy 	}
1844e505edaeSJeff LaBundy 
1845e505edaeSJeff LaBundy 	cycle_setup[1] &= ~GENMASK(7 + ARRAY_SIZE(pins) - 1, 7);
1846e505edaeSJeff LaBundy 
1847e505edaeSJeff LaBundy 	for (i = 0; i < count; i++) {
1848e505edaeSJeff LaBundy 		if (pins[i] > 8) {
1849e505edaeSJeff LaBundy 			dev_err(&client->dev, "Invalid %s CTx pin: %u\n",
1850e505edaeSJeff LaBundy 				fwnode_get_name(cycle_node), pins[i]);
1851e505edaeSJeff LaBundy 			return -EINVAL;
1852e505edaeSJeff LaBundy 		}
1853e505edaeSJeff LaBundy 
1854e505edaeSJeff LaBundy 		cycle_setup[1] |= BIT(pins[i] + 7);
1855e505edaeSJeff LaBundy 	}
1856e505edaeSJeff LaBundy 
1857e505edaeSJeff LaBundy 	return 0;
1858e505edaeSJeff LaBundy }
1859e505edaeSJeff LaBundy 
1860bbd16b0dSJeff LaBundy static int iqs7222_parse_chan(struct iqs7222_private *iqs7222,
1861bbd16b0dSJeff LaBundy 			      struct fwnode_handle *chan_node, int chan_index)
1862e505edaeSJeff LaBundy {
1863e505edaeSJeff LaBundy 	const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
1864e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
1865e505edaeSJeff LaBundy 	int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
1866e505edaeSJeff LaBundy 	int ext_chan = rounddown(num_chan, 10);
1867e505edaeSJeff LaBundy 	int error, i;
1868e505edaeSJeff LaBundy 	u16 *chan_setup = iqs7222->chan_setup[chan_index];
1869e505edaeSJeff LaBundy 	u16 *sys_setup = iqs7222->sys_setup;
1870e505edaeSJeff LaBundy 	unsigned int val;
1871e505edaeSJeff LaBundy 
1872d56111edSJeff LaBundy 	if (dev_desc->allow_offset &&
1873d56111edSJeff LaBundy 	    fwnode_property_present(chan_node, "azoteq,ulp-allow"))
1874e505edaeSJeff LaBundy 		sys_setup[dev_desc->allow_offset] &= ~BIT(chan_index);
1875e505edaeSJeff LaBundy 
1876e505edaeSJeff LaBundy 	chan_setup[0] |= IQS7222_CHAN_SETUP_0_CHAN_EN;
1877e505edaeSJeff LaBundy 
1878e505edaeSJeff LaBundy 	/*
1879e505edaeSJeff LaBundy 	 * The reference channel function allows for differential measurements
1880e505edaeSJeff LaBundy 	 * and is only available in the case of IQS7222A or IQS7222C.
1881e505edaeSJeff LaBundy 	 */
1882e505edaeSJeff LaBundy 	if (dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_col > 4 &&
1883e505edaeSJeff LaBundy 	    fwnode_property_present(chan_node, "azoteq,ref-select")) {
1884e505edaeSJeff LaBundy 		u16 *ref_setup;
1885e505edaeSJeff LaBundy 
1886e505edaeSJeff LaBundy 		error = fwnode_property_read_u32(chan_node, "azoteq,ref-select",
1887e505edaeSJeff LaBundy 						 &val);
1888e505edaeSJeff LaBundy 		if (error) {
1889e505edaeSJeff LaBundy 			dev_err(&client->dev,
1890e505edaeSJeff LaBundy 				"Failed to read %s reference channel: %d\n",
1891e505edaeSJeff LaBundy 				fwnode_get_name(chan_node), error);
1892e505edaeSJeff LaBundy 			return error;
1893e505edaeSJeff LaBundy 		}
1894e505edaeSJeff LaBundy 
1895e505edaeSJeff LaBundy 		if (val >= ext_chan) {
1896e505edaeSJeff LaBundy 			dev_err(&client->dev,
1897e505edaeSJeff LaBundy 				"Invalid %s reference channel: %u\n",
1898e505edaeSJeff LaBundy 				fwnode_get_name(chan_node), val);
1899e505edaeSJeff LaBundy 			return -EINVAL;
1900e505edaeSJeff LaBundy 		}
1901e505edaeSJeff LaBundy 
1902e505edaeSJeff LaBundy 		ref_setup = iqs7222->chan_setup[val];
1903e505edaeSJeff LaBundy 
1904e505edaeSJeff LaBundy 		/*
1905e505edaeSJeff LaBundy 		 * Configure the current channel as a follower of the selected
1906e505edaeSJeff LaBundy 		 * reference channel.
1907e505edaeSJeff LaBundy 		 */
1908e505edaeSJeff LaBundy 		chan_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_FOLLOW;
1909e505edaeSJeff LaBundy 		chan_setup[4] = val * 42 + 1048;
1910e505edaeSJeff LaBundy 
1911404f3b48SJeff LaBundy 		error = fwnode_property_read_u32(chan_node, "azoteq,ref-weight",
1912404f3b48SJeff LaBundy 						 &val);
1913404f3b48SJeff LaBundy 		if (!error) {
1914e505edaeSJeff LaBundy 			if (val > U16_MAX) {
1915e505edaeSJeff LaBundy 				dev_err(&client->dev,
1916e505edaeSJeff LaBundy 					"Invalid %s reference weight: %u\n",
1917e505edaeSJeff LaBundy 					fwnode_get_name(chan_node), val);
1918e505edaeSJeff LaBundy 				return -EINVAL;
1919e505edaeSJeff LaBundy 			}
1920e505edaeSJeff LaBundy 
1921e505edaeSJeff LaBundy 			chan_setup[5] = val;
1922404f3b48SJeff LaBundy 		} else if (error != -EINVAL) {
1923404f3b48SJeff LaBundy 			dev_err(&client->dev,
1924404f3b48SJeff LaBundy 				"Failed to read %s reference weight: %d\n",
1925404f3b48SJeff LaBundy 				fwnode_get_name(chan_node), error);
1926404f3b48SJeff LaBundy 			return error;
1927e505edaeSJeff LaBundy 		}
1928e505edaeSJeff LaBundy 
1929e505edaeSJeff LaBundy 		/*
1930e505edaeSJeff LaBundy 		 * Configure the selected channel as a reference channel which
1931e505edaeSJeff LaBundy 		 * serves the current channel.
1932e505edaeSJeff LaBundy 		 */
1933e505edaeSJeff LaBundy 		ref_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_REF;
1934e505edaeSJeff LaBundy 		ref_setup[5] |= BIT(chan_index);
1935e505edaeSJeff LaBundy 
1936e505edaeSJeff LaBundy 		ref_setup[4] = dev_desc->touch_link;
1937e505edaeSJeff LaBundy 		if (fwnode_property_present(chan_node, "azoteq,use-prox"))
1938e505edaeSJeff LaBundy 			ref_setup[4] -= 2;
1939e505edaeSJeff LaBundy 	}
1940e505edaeSJeff LaBundy 
1941e505edaeSJeff LaBundy 	if (fwnode_property_present(chan_node, "azoteq,rx-enable")) {
1942e505edaeSJeff LaBundy 		/*
1943e505edaeSJeff LaBundy 		 * Each channel can claim up to 4 CRx pins. The first half of
1944e505edaeSJeff LaBundy 		 * the channels can use CRx0-3, while the second half can use
1945e505edaeSJeff LaBundy 		 * CRx4-7.
1946e505edaeSJeff LaBundy 		 */
1947e505edaeSJeff LaBundy 		unsigned int pins[4];
1948e505edaeSJeff LaBundy 		int count;
1949e505edaeSJeff LaBundy 
1950e505edaeSJeff LaBundy 		count = fwnode_property_count_u32(chan_node,
1951e505edaeSJeff LaBundy 						  "azoteq,rx-enable");
1952eba697b3SDan Carpenter 		if (count < 0) {
1953e505edaeSJeff LaBundy 			dev_err(&client->dev,
1954e505edaeSJeff LaBundy 				"Failed to count %s CRx pins: %d\n",
1955e505edaeSJeff LaBundy 				fwnode_get_name(chan_node), count);
1956e505edaeSJeff LaBundy 			return count;
1957eba697b3SDan Carpenter 		} else if (count > ARRAY_SIZE(pins)) {
1958eba697b3SDan Carpenter 			dev_err(&client->dev,
1959eba697b3SDan Carpenter 				"Invalid number of %s CRx pins\n",
1960eba697b3SDan Carpenter 				fwnode_get_name(chan_node));
1961eba697b3SDan Carpenter 			return -EINVAL;
1962e505edaeSJeff LaBundy 		}
1963e505edaeSJeff LaBundy 
1964e505edaeSJeff LaBundy 		error = fwnode_property_read_u32_array(chan_node,
1965e505edaeSJeff LaBundy 						       "azoteq,rx-enable",
1966e505edaeSJeff LaBundy 						       pins, count);
1967e505edaeSJeff LaBundy 		if (error) {
1968e505edaeSJeff LaBundy 			dev_err(&client->dev,
1969e505edaeSJeff LaBundy 				"Failed to read %s CRx pins: %d\n",
1970e505edaeSJeff LaBundy 				fwnode_get_name(chan_node), error);
1971e505edaeSJeff LaBundy 			return error;
1972e505edaeSJeff LaBundy 		}
1973e505edaeSJeff LaBundy 
1974e505edaeSJeff LaBundy 		chan_setup[0] &= ~GENMASK(4 + ARRAY_SIZE(pins) - 1, 4);
1975e505edaeSJeff LaBundy 
1976e505edaeSJeff LaBundy 		for (i = 0; i < count; i++) {
1977e505edaeSJeff LaBundy 			int min_crx = chan_index < ext_chan / 2 ? 0 : 4;
1978e505edaeSJeff LaBundy 
1979e505edaeSJeff LaBundy 			if (pins[i] < min_crx || pins[i] > min_crx + 3) {
1980e505edaeSJeff LaBundy 				dev_err(&client->dev,
1981e505edaeSJeff LaBundy 					"Invalid %s CRx pin: %u\n",
1982e505edaeSJeff LaBundy 					fwnode_get_name(chan_node), pins[i]);
1983e505edaeSJeff LaBundy 				return -EINVAL;
1984e505edaeSJeff LaBundy 			}
1985e505edaeSJeff LaBundy 
1986e505edaeSJeff LaBundy 			chan_setup[0] |= BIT(pins[i] + 4 - min_crx);
1987e505edaeSJeff LaBundy 		}
1988e505edaeSJeff LaBundy 	}
1989e505edaeSJeff LaBundy 
1990e505edaeSJeff LaBundy 	for (i = 0; i < ARRAY_SIZE(iqs7222_kp_events); i++) {
1991e505edaeSJeff LaBundy 		const char *event_name = iqs7222_kp_events[i].name;
1992e505edaeSJeff LaBundy 		u16 event_enable = iqs7222_kp_events[i].enable;
1993e505edaeSJeff LaBundy 		struct fwnode_handle *event_node;
1994e505edaeSJeff LaBundy 
1995e505edaeSJeff LaBundy 		event_node = fwnode_get_named_child_node(chan_node, event_name);
1996e505edaeSJeff LaBundy 		if (!event_node)
1997e505edaeSJeff LaBundy 			continue;
1998e505edaeSJeff LaBundy 
1999404f3b48SJeff LaBundy 		error = fwnode_property_read_u32(event_node,
2000e505edaeSJeff LaBundy 						 "azoteq,timeout-press-ms",
2001404f3b48SJeff LaBundy 						 &val);
2002404f3b48SJeff LaBundy 		if (!error) {
2003e505edaeSJeff LaBundy 			/*
2004e505edaeSJeff LaBundy 			 * The IQS7222B employs a global pair of press timeout
2005e505edaeSJeff LaBundy 			 * registers as opposed to channel-specific registers.
2006e505edaeSJeff LaBundy 			 */
2007e505edaeSJeff LaBundy 			u16 *setup = dev_desc->reg_grps
2008e505edaeSJeff LaBundy 				     [IQS7222_REG_GRP_BTN].num_col > 2 ?
2009e505edaeSJeff LaBundy 				     &iqs7222->btn_setup[chan_index][2] :
2010e505edaeSJeff LaBundy 				     &sys_setup[9];
2011e505edaeSJeff LaBundy 
2012e505edaeSJeff LaBundy 			if (val > U8_MAX * 500) {
2013e505edaeSJeff LaBundy 				dev_err(&client->dev,
2014e505edaeSJeff LaBundy 					"Invalid %s press timeout: %u\n",
2015bbd16b0dSJeff LaBundy 					fwnode_get_name(event_node), val);
2016bbd16b0dSJeff LaBundy 				fwnode_handle_put(event_node);
2017e505edaeSJeff LaBundy 				return -EINVAL;
2018e505edaeSJeff LaBundy 			}
2019e505edaeSJeff LaBundy 
2020e505edaeSJeff LaBundy 			*setup &= ~(U8_MAX << i * 8);
2021e505edaeSJeff LaBundy 			*setup |= (val / 500 << i * 8);
2022404f3b48SJeff LaBundy 		} else if (error != -EINVAL) {
2023404f3b48SJeff LaBundy 			dev_err(&client->dev,
2024404f3b48SJeff LaBundy 				"Failed to read %s press timeout: %d\n",
2025404f3b48SJeff LaBundy 				fwnode_get_name(event_node), error);
2026404f3b48SJeff LaBundy 			fwnode_handle_put(event_node);
2027404f3b48SJeff LaBundy 			return error;
2028e505edaeSJeff LaBundy 		}
2029e505edaeSJeff LaBundy 
2030bbd16b0dSJeff LaBundy 		error = iqs7222_parse_event(iqs7222, event_node, chan_index,
2031bbd16b0dSJeff LaBundy 					    IQS7222_REG_GRP_BTN,
2032bbd16b0dSJeff LaBundy 					    iqs7222_kp_events[i].reg_key,
2033bbd16b0dSJeff LaBundy 					    BIT(chan_index),
2034bbd16b0dSJeff LaBundy 					    dev_desc->touch_link - (i ? 0 : 2),
2035bbd16b0dSJeff LaBundy 					    &iqs7222->kp_type[chan_index][i],
2036bbd16b0dSJeff LaBundy 					    &iqs7222->kp_code[chan_index][i]);
2037bbd16b0dSJeff LaBundy 		fwnode_handle_put(event_node);
2038bbd16b0dSJeff LaBundy 		if (error)
2039e505edaeSJeff LaBundy 			return error;
2040e505edaeSJeff LaBundy 
2041e505edaeSJeff LaBundy 		if (!dev_desc->event_offset)
2042e505edaeSJeff LaBundy 			continue;
2043e505edaeSJeff LaBundy 
2044e505edaeSJeff LaBundy 		sys_setup[dev_desc->event_offset] |= event_enable;
2045e505edaeSJeff LaBundy 	}
2046e505edaeSJeff LaBundy 
2047e505edaeSJeff LaBundy 	/*
2048e505edaeSJeff LaBundy 	 * The following call handles a special pair of properties that apply
2049e505edaeSJeff LaBundy 	 * to a channel node, but reside within the button (event) group.
2050e505edaeSJeff LaBundy 	 */
2051bbd16b0dSJeff LaBundy 	return iqs7222_parse_props(iqs7222, chan_node, chan_index,
2052e505edaeSJeff LaBundy 				   IQS7222_REG_GRP_BTN,
2053e505edaeSJeff LaBundy 				   IQS7222_REG_KEY_DEBOUNCE);
2054e505edaeSJeff LaBundy }
2055e505edaeSJeff LaBundy 
2056bbd16b0dSJeff LaBundy static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222,
2057bbd16b0dSJeff LaBundy 			      struct fwnode_handle *sldr_node, int sldr_index)
2058e505edaeSJeff LaBundy {
2059e505edaeSJeff LaBundy 	const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
2060e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
2061e505edaeSJeff LaBundy 	int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
2062e505edaeSJeff LaBundy 	int ext_chan = rounddown(num_chan, 10);
2063e505edaeSJeff LaBundy 	int count, error, reg_offset, i;
206495215d3dSJeff LaBundy 	u16 *event_mask = &iqs7222->sys_setup[dev_desc->event_offset];
2065e505edaeSJeff LaBundy 	u16 *sldr_setup = iqs7222->sldr_setup[sldr_index];
2066e505edaeSJeff LaBundy 	unsigned int chan_sel[4], val;
2067e505edaeSJeff LaBundy 
2068e505edaeSJeff LaBundy 	/*
2069e505edaeSJeff LaBundy 	 * Each slider can be spread across 3 to 4 channels. It is possible to
2070e505edaeSJeff LaBundy 	 * select only 2 channels, but doing so prevents the slider from using
2071e505edaeSJeff LaBundy 	 * the specified resolution.
2072e505edaeSJeff LaBundy 	 */
2073e505edaeSJeff LaBundy 	count = fwnode_property_count_u32(sldr_node, "azoteq,channel-select");
2074eba697b3SDan Carpenter 	if (count < 0) {
2075e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to count %s channels: %d\n",
2076e505edaeSJeff LaBundy 			fwnode_get_name(sldr_node), count);
2077e505edaeSJeff LaBundy 		return count;
2078eba697b3SDan Carpenter 	} else if (count < 3 || count > ARRAY_SIZE(chan_sel)) {
2079eba697b3SDan Carpenter 		dev_err(&client->dev, "Invalid number of %s channels\n",
2080eba697b3SDan Carpenter 			fwnode_get_name(sldr_node));
2081eba697b3SDan Carpenter 		return -EINVAL;
2082e505edaeSJeff LaBundy 	}
2083e505edaeSJeff LaBundy 
2084e505edaeSJeff LaBundy 	error = fwnode_property_read_u32_array(sldr_node,
2085e505edaeSJeff LaBundy 					       "azoteq,channel-select",
2086e505edaeSJeff LaBundy 					       chan_sel, count);
2087e505edaeSJeff LaBundy 	if (error) {
2088e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to read %s channels: %d\n",
2089e505edaeSJeff LaBundy 			fwnode_get_name(sldr_node), error);
2090e505edaeSJeff LaBundy 		return error;
2091e505edaeSJeff LaBundy 	}
2092e505edaeSJeff LaBundy 
2093e505edaeSJeff LaBundy 	/*
2094e505edaeSJeff LaBundy 	 * Resolution and top speed, if small enough, are packed into a single
2095e505edaeSJeff LaBundy 	 * register. Otherwise, each occupies its own register and the rest of
2096e505edaeSJeff LaBundy 	 * the slider-related register addresses are offset by one.
2097e505edaeSJeff LaBundy 	 */
2098e505edaeSJeff LaBundy 	reg_offset = dev_desc->sldr_res < U16_MAX ? 0 : 1;
2099e505edaeSJeff LaBundy 
2100e505edaeSJeff LaBundy 	sldr_setup[0] |= count;
210195215d3dSJeff LaBundy 	sldr_setup[3 + reg_offset] &= ~GENMASK(ext_chan - 1, 0);
2102e505edaeSJeff LaBundy 
2103e505edaeSJeff LaBundy 	for (i = 0; i < ARRAY_SIZE(chan_sel); i++) {
2104e505edaeSJeff LaBundy 		sldr_setup[5 + reg_offset + i] = 0;
2105e505edaeSJeff LaBundy 		if (i >= count)
2106e505edaeSJeff LaBundy 			continue;
2107e505edaeSJeff LaBundy 
2108e505edaeSJeff LaBundy 		if (chan_sel[i] >= ext_chan) {
2109e505edaeSJeff LaBundy 			dev_err(&client->dev, "Invalid %s channel: %u\n",
2110e505edaeSJeff LaBundy 				fwnode_get_name(sldr_node), chan_sel[i]);
2111e505edaeSJeff LaBundy 			return -EINVAL;
2112e505edaeSJeff LaBundy 		}
2113e505edaeSJeff LaBundy 
2114e505edaeSJeff LaBundy 		/*
2115e505edaeSJeff LaBundy 		 * The following fields indicate which channels participate in
2116e505edaeSJeff LaBundy 		 * the slider, as well as each channel's relative placement.
2117e505edaeSJeff LaBundy 		 */
2118e505edaeSJeff LaBundy 		sldr_setup[3 + reg_offset] |= BIT(chan_sel[i]);
2119e505edaeSJeff LaBundy 		sldr_setup[5 + reg_offset + i] = chan_sel[i] * 42 + 1080;
2120e505edaeSJeff LaBundy 	}
2121e505edaeSJeff LaBundy 
2122e505edaeSJeff LaBundy 	sldr_setup[4 + reg_offset] = dev_desc->touch_link;
2123e505edaeSJeff LaBundy 	if (fwnode_property_present(sldr_node, "azoteq,use-prox"))
2124e505edaeSJeff LaBundy 		sldr_setup[4 + reg_offset] -= 2;
2125e505edaeSJeff LaBundy 
2126404f3b48SJeff LaBundy 	error = fwnode_property_read_u32(sldr_node, "azoteq,slider-size", &val);
2127404f3b48SJeff LaBundy 	if (!error) {
21282f6fd232SJeff LaBundy 		if (val > dev_desc->sldr_res) {
2129e505edaeSJeff LaBundy 			dev_err(&client->dev, "Invalid %s size: %u\n",
2130e505edaeSJeff LaBundy 				fwnode_get_name(sldr_node), val);
2131e505edaeSJeff LaBundy 			return -EINVAL;
2132e505edaeSJeff LaBundy 		}
2133e505edaeSJeff LaBundy 
2134e505edaeSJeff LaBundy 		if (reg_offset) {
2135e505edaeSJeff LaBundy 			sldr_setup[3] = val;
2136e505edaeSJeff LaBundy 		} else {
2137e505edaeSJeff LaBundy 			sldr_setup[2] &= ~IQS7222_SLDR_SETUP_2_RES_MASK;
2138e505edaeSJeff LaBundy 			sldr_setup[2] |= (val / 16 <<
2139e505edaeSJeff LaBundy 					  IQS7222_SLDR_SETUP_2_RES_SHIFT);
2140e505edaeSJeff LaBundy 		}
2141404f3b48SJeff LaBundy 	} else if (error != -EINVAL) {
2142404f3b48SJeff LaBundy 		dev_err(&client->dev, "Failed to read %s size: %d\n",
2143404f3b48SJeff LaBundy 			fwnode_get_name(sldr_node), error);
2144404f3b48SJeff LaBundy 		return error;
2145e505edaeSJeff LaBundy 	}
2146e505edaeSJeff LaBundy 
21472f6fd232SJeff LaBundy 	if (!(reg_offset ? sldr_setup[3]
21482f6fd232SJeff LaBundy 			 : sldr_setup[2] & IQS7222_SLDR_SETUP_2_RES_MASK)) {
21492f6fd232SJeff LaBundy 		dev_err(&client->dev, "Undefined %s size\n",
21502f6fd232SJeff LaBundy 			fwnode_get_name(sldr_node));
21512f6fd232SJeff LaBundy 		return -EINVAL;
21522f6fd232SJeff LaBundy 	}
21532f6fd232SJeff LaBundy 
2154404f3b48SJeff LaBundy 	error = fwnode_property_read_u32(sldr_node, "azoteq,top-speed", &val);
2155404f3b48SJeff LaBundy 	if (!error) {
2156e505edaeSJeff LaBundy 		if (val > (reg_offset ? U16_MAX : U8_MAX * 4)) {
2157e505edaeSJeff LaBundy 			dev_err(&client->dev, "Invalid %s top speed: %u\n",
2158e505edaeSJeff LaBundy 				fwnode_get_name(sldr_node), val);
2159e505edaeSJeff LaBundy 			return -EINVAL;
2160e505edaeSJeff LaBundy 		}
2161e505edaeSJeff LaBundy 
2162e505edaeSJeff LaBundy 		if (reg_offset) {
2163e505edaeSJeff LaBundy 			sldr_setup[2] = val;
2164e505edaeSJeff LaBundy 		} else {
2165e505edaeSJeff LaBundy 			sldr_setup[2] &= ~IQS7222_SLDR_SETUP_2_TOP_SPEED_MASK;
2166e505edaeSJeff LaBundy 			sldr_setup[2] |= (val / 4);
2167e505edaeSJeff LaBundy 		}
2168404f3b48SJeff LaBundy 	} else if (error != -EINVAL) {
2169404f3b48SJeff LaBundy 		dev_err(&client->dev, "Failed to read %s top speed: %d\n",
2170404f3b48SJeff LaBundy 			fwnode_get_name(sldr_node), error);
2171404f3b48SJeff LaBundy 		return error;
2172e505edaeSJeff LaBundy 	}
2173e505edaeSJeff LaBundy 
2174404f3b48SJeff LaBundy 	error = fwnode_property_read_u32(sldr_node, "linux,axis", &val);
2175404f3b48SJeff LaBundy 	if (!error) {
2176e505edaeSJeff LaBundy 		u16 sldr_max = sldr_setup[3] - 1;
2177e505edaeSJeff LaBundy 
2178e505edaeSJeff LaBundy 		if (!reg_offset) {
2179e505edaeSJeff LaBundy 			sldr_max = sldr_setup[2];
2180e505edaeSJeff LaBundy 
2181e505edaeSJeff LaBundy 			sldr_max &= IQS7222_SLDR_SETUP_2_RES_MASK;
2182e505edaeSJeff LaBundy 			sldr_max >>= IQS7222_SLDR_SETUP_2_RES_SHIFT;
2183e505edaeSJeff LaBundy 
2184e505edaeSJeff LaBundy 			sldr_max = sldr_max * 16 - 1;
2185e505edaeSJeff LaBundy 		}
2186e505edaeSJeff LaBundy 
2187e505edaeSJeff LaBundy 		input_set_abs_params(iqs7222->keypad, val, 0, sldr_max, 0, 0);
2188e505edaeSJeff LaBundy 		iqs7222->sl_axis[sldr_index] = val;
2189404f3b48SJeff LaBundy 	} else if (error != -EINVAL) {
2190404f3b48SJeff LaBundy 		dev_err(&client->dev, "Failed to read %s axis: %d\n",
2191404f3b48SJeff LaBundy 			fwnode_get_name(sldr_node), error);
2192404f3b48SJeff LaBundy 		return error;
2193e505edaeSJeff LaBundy 	}
2194e505edaeSJeff LaBundy 
2195e505edaeSJeff LaBundy 	if (dev_desc->wheel_enable) {
2196e505edaeSJeff LaBundy 		sldr_setup[0] &= ~dev_desc->wheel_enable;
2197e505edaeSJeff LaBundy 		if (iqs7222->sl_axis[sldr_index] == ABS_WHEEL)
2198e505edaeSJeff LaBundy 			sldr_setup[0] |= dev_desc->wheel_enable;
2199e505edaeSJeff LaBundy 	}
2200e505edaeSJeff LaBundy 
220156a0c54cSJeff LaBundy 	/*
220256a0c54cSJeff LaBundy 	 * The absence of a register offset makes it safe to assume the device
220356a0c54cSJeff LaBundy 	 * supports gestures, each of which is first disabled until explicitly
220456a0c54cSJeff LaBundy 	 * enabled.
220556a0c54cSJeff LaBundy 	 */
220656a0c54cSJeff LaBundy 	if (!reg_offset)
220756a0c54cSJeff LaBundy 		for (i = 0; i < ARRAY_SIZE(iqs7222_sl_events); i++)
220856a0c54cSJeff LaBundy 			sldr_setup[9] &= ~iqs7222_sl_events[i].enable;
220956a0c54cSJeff LaBundy 
2210e505edaeSJeff LaBundy 	for (i = 0; i < ARRAY_SIZE(iqs7222_sl_events); i++) {
2211e505edaeSJeff LaBundy 		const char *event_name = iqs7222_sl_events[i].name;
2212e505edaeSJeff LaBundy 		struct fwnode_handle *event_node;
2213bbd16b0dSJeff LaBundy 		enum iqs7222_reg_key_id reg_key;
2214e505edaeSJeff LaBundy 
2215e505edaeSJeff LaBundy 		event_node = fwnode_get_named_child_node(sldr_node, event_name);
2216e505edaeSJeff LaBundy 		if (!event_node)
2217e505edaeSJeff LaBundy 			continue;
2218e505edaeSJeff LaBundy 
22198d4c313cSJeff LaBundy 		/*
22208d4c313cSJeff LaBundy 		 * Depending on the device, gestures are either offered using
22218d4c313cSJeff LaBundy 		 * one of two timing resolutions, or are not supported at all.
22228d4c313cSJeff LaBundy 		 */
2223bbd16b0dSJeff LaBundy 		if (reg_offset)
2224bbd16b0dSJeff LaBundy 			reg_key = IQS7222_REG_KEY_RESERVED;
22258d4c313cSJeff LaBundy 		else if (dev_desc->legacy_gesture &&
22268d4c313cSJeff LaBundy 			 iqs7222_sl_events[i].reg_key == IQS7222_REG_KEY_TAP)
22278d4c313cSJeff LaBundy 			reg_key = IQS7222_REG_KEY_TAP_LEGACY;
22288d4c313cSJeff LaBundy 		else if (dev_desc->legacy_gesture &&
22298d4c313cSJeff LaBundy 			 iqs7222_sl_events[i].reg_key == IQS7222_REG_KEY_AXIAL)
22308d4c313cSJeff LaBundy 			reg_key = IQS7222_REG_KEY_AXIAL_LEGACY;
2231bbd16b0dSJeff LaBundy 		else
2232bbd16b0dSJeff LaBundy 			reg_key = iqs7222_sl_events[i].reg_key;
2233e505edaeSJeff LaBundy 
223495215d3dSJeff LaBundy 		/*
223595215d3dSJeff LaBundy 		 * The press/release event does not expose a direct GPIO link,
223695215d3dSJeff LaBundy 		 * but one can be emulated by tying each of the participating
223795215d3dSJeff LaBundy 		 * channels to the same GPIO.
223895215d3dSJeff LaBundy 		 */
2239bbd16b0dSJeff LaBundy 		error = iqs7222_parse_event(iqs7222, event_node, sldr_index,
2240bbd16b0dSJeff LaBundy 					    IQS7222_REG_GRP_SLDR, reg_key,
224195215d3dSJeff LaBundy 					    i ? iqs7222_sl_events[i].enable
224295215d3dSJeff LaBundy 					      : sldr_setup[3 + reg_offset],
224395215d3dSJeff LaBundy 					    i ? 1568 + sldr_index * 30
2244bbd16b0dSJeff LaBundy 					      : sldr_setup[4 + reg_offset],
2245bbd16b0dSJeff LaBundy 					    NULL,
2246bbd16b0dSJeff LaBundy 					    &iqs7222->sl_code[sldr_index][i]);
2247bbd16b0dSJeff LaBundy 		fwnode_handle_put(event_node);
224895215d3dSJeff LaBundy 		if (error)
224995215d3dSJeff LaBundy 			return error;
225095215d3dSJeff LaBundy 
225195215d3dSJeff LaBundy 		if (!reg_offset)
225295215d3dSJeff LaBundy 			sldr_setup[9] |= iqs7222_sl_events[i].enable;
225395215d3dSJeff LaBundy 
2254e505edaeSJeff LaBundy 		if (!dev_desc->event_offset)
2255e505edaeSJeff LaBundy 			continue;
2256e505edaeSJeff LaBundy 
225795215d3dSJeff LaBundy 		/*
225895215d3dSJeff LaBundy 		 * The press/release event is determined based on whether the
225995215d3dSJeff LaBundy 		 * coordinate field reports 0xFFFF and solely relies on touch
226095215d3dSJeff LaBundy 		 * or proximity interrupts to be unmasked.
226195215d3dSJeff LaBundy 		 */
226295215d3dSJeff LaBundy 		if (i && !reg_offset)
226395215d3dSJeff LaBundy 			*event_mask |= (IQS7222_EVENT_MASK_SLDR << sldr_index);
226495215d3dSJeff LaBundy 		else if (sldr_setup[4 + reg_offset] == dev_desc->touch_link)
226595215d3dSJeff LaBundy 			*event_mask |= IQS7222_EVENT_MASK_TOUCH;
226695215d3dSJeff LaBundy 		else
226795215d3dSJeff LaBundy 			*event_mask |= IQS7222_EVENT_MASK_PROX;
2268e505edaeSJeff LaBundy 	}
2269e505edaeSJeff LaBundy 
2270e505edaeSJeff LaBundy 	/*
2271e505edaeSJeff LaBundy 	 * The following call handles a special pair of properties that shift
2272e505edaeSJeff LaBundy 	 * to make room for a wheel enable control in the case of IQS7222C.
2273e505edaeSJeff LaBundy 	 */
2274bbd16b0dSJeff LaBundy 	return iqs7222_parse_props(iqs7222, sldr_node, sldr_index,
2275e505edaeSJeff LaBundy 				   IQS7222_REG_GRP_SLDR,
2276e505edaeSJeff LaBundy 				   dev_desc->wheel_enable ?
2277e505edaeSJeff LaBundy 				   IQS7222_REG_KEY_WHEEL :
2278e505edaeSJeff LaBundy 				   IQS7222_REG_KEY_NO_WHEEL);
2279e505edaeSJeff LaBundy }
2280e505edaeSJeff LaBundy 
2281bbd16b0dSJeff LaBundy static int (*iqs7222_parse_extra[IQS7222_NUM_REG_GRPS])
2282bbd16b0dSJeff LaBundy 				(struct iqs7222_private *iqs7222,
2283bbd16b0dSJeff LaBundy 				 struct fwnode_handle *reg_grp_node,
2284bbd16b0dSJeff LaBundy 				 int reg_grp_index) = {
2285bbd16b0dSJeff LaBundy 	[IQS7222_REG_GRP_CYCLE] = iqs7222_parse_cycle,
2286bbd16b0dSJeff LaBundy 	[IQS7222_REG_GRP_CHAN] = iqs7222_parse_chan,
2287bbd16b0dSJeff LaBundy 	[IQS7222_REG_GRP_SLDR] = iqs7222_parse_sldr,
2288bbd16b0dSJeff LaBundy };
2289bbd16b0dSJeff LaBundy 
2290bbd16b0dSJeff LaBundy static int iqs7222_parse_reg_grp(struct iqs7222_private *iqs7222,
2291bbd16b0dSJeff LaBundy 				 enum iqs7222_reg_grp_id reg_grp,
2292bbd16b0dSJeff LaBundy 				 int reg_grp_index)
2293bbd16b0dSJeff LaBundy {
2294bbd16b0dSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
2295bbd16b0dSJeff LaBundy 	struct fwnode_handle *reg_grp_node;
2296bbd16b0dSJeff LaBundy 	int error;
2297bbd16b0dSJeff LaBundy 
2298bbd16b0dSJeff LaBundy 	if (iqs7222_reg_grp_names[reg_grp]) {
2299bbd16b0dSJeff LaBundy 		char reg_grp_name[16];
2300bbd16b0dSJeff LaBundy 
2301bbd16b0dSJeff LaBundy 		snprintf(reg_grp_name, sizeof(reg_grp_name), "%s-%d",
2302bbd16b0dSJeff LaBundy 			 iqs7222_reg_grp_names[reg_grp], reg_grp_index);
2303bbd16b0dSJeff LaBundy 
2304bbd16b0dSJeff LaBundy 		reg_grp_node = device_get_named_child_node(&client->dev,
2305bbd16b0dSJeff LaBundy 							   reg_grp_name);
2306bbd16b0dSJeff LaBundy 	} else {
2307bbd16b0dSJeff LaBundy 		reg_grp_node = fwnode_handle_get(dev_fwnode(&client->dev));
2308bbd16b0dSJeff LaBundy 	}
2309bbd16b0dSJeff LaBundy 
2310bbd16b0dSJeff LaBundy 	if (!reg_grp_node)
2311bbd16b0dSJeff LaBundy 		return 0;
2312bbd16b0dSJeff LaBundy 
2313bbd16b0dSJeff LaBundy 	error = iqs7222_parse_props(iqs7222, reg_grp_node, reg_grp_index,
2314bbd16b0dSJeff LaBundy 				    reg_grp, IQS7222_REG_KEY_NONE);
2315bbd16b0dSJeff LaBundy 
2316bbd16b0dSJeff LaBundy 	if (!error && iqs7222_parse_extra[reg_grp])
2317bbd16b0dSJeff LaBundy 		error = iqs7222_parse_extra[reg_grp](iqs7222, reg_grp_node,
2318bbd16b0dSJeff LaBundy 						     reg_grp_index);
2319bbd16b0dSJeff LaBundy 
2320bbd16b0dSJeff LaBundy 	fwnode_handle_put(reg_grp_node);
2321bbd16b0dSJeff LaBundy 
2322bbd16b0dSJeff LaBundy 	return error;
2323bbd16b0dSJeff LaBundy }
2324bbd16b0dSJeff LaBundy 
2325e505edaeSJeff LaBundy static int iqs7222_parse_all(struct iqs7222_private *iqs7222)
2326e505edaeSJeff LaBundy {
2327e505edaeSJeff LaBundy 	const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
2328e505edaeSJeff LaBundy 	const struct iqs7222_reg_grp_desc *reg_grps = dev_desc->reg_grps;
2329e505edaeSJeff LaBundy 	u16 *sys_setup = iqs7222->sys_setup;
2330bbd16b0dSJeff LaBundy 	int error, i, j;
2331e505edaeSJeff LaBundy 
2332d56111edSJeff LaBundy 	if (dev_desc->allow_offset)
2333d56111edSJeff LaBundy 		sys_setup[dev_desc->allow_offset] = U16_MAX;
2334d56111edSJeff LaBundy 
2335e505edaeSJeff LaBundy 	if (dev_desc->event_offset)
2336e505edaeSJeff LaBundy 		sys_setup[dev_desc->event_offset] = IQS7222_EVENT_MASK_ATI;
2337e505edaeSJeff LaBundy 
2338e505edaeSJeff LaBundy 	for (i = 0; i < reg_grps[IQS7222_REG_GRP_GPIO].num_row; i++) {
2339e505edaeSJeff LaBundy 		u16 *gpio_setup = iqs7222->gpio_setup[i];
2340e505edaeSJeff LaBundy 
2341e505edaeSJeff LaBundy 		gpio_setup[0] &= ~IQS7222_GPIO_SETUP_0_GPIO_EN;
2342e505edaeSJeff LaBundy 		gpio_setup[1] = 0;
2343e505edaeSJeff LaBundy 		gpio_setup[2] = 0;
2344e505edaeSJeff LaBundy 
2345e505edaeSJeff LaBundy 		if (reg_grps[IQS7222_REG_GRP_GPIO].num_row == 1)
2346e505edaeSJeff LaBundy 			continue;
2347e505edaeSJeff LaBundy 
2348e505edaeSJeff LaBundy 		/*
2349e505edaeSJeff LaBundy 		 * The IQS7222C exposes multiple GPIO and must be informed
2350e505edaeSJeff LaBundy 		 * as to which GPIO this group represents.
2351e505edaeSJeff LaBundy 		 */
2352e505edaeSJeff LaBundy 		for (j = 0; j < ARRAY_SIZE(iqs7222_gpio_links); j++)
2353e505edaeSJeff LaBundy 			gpio_setup[0] &= ~BIT(iqs7222_gpio_links[j]);
2354e505edaeSJeff LaBundy 
2355e505edaeSJeff LaBundy 		gpio_setup[0] |= BIT(iqs7222_gpio_links[i]);
2356e505edaeSJeff LaBundy 	}
2357e505edaeSJeff LaBundy 
2358e505edaeSJeff LaBundy 	for (i = 0; i < reg_grps[IQS7222_REG_GRP_CHAN].num_row; i++) {
2359e505edaeSJeff LaBundy 		u16 *chan_setup = iqs7222->chan_setup[i];
2360e505edaeSJeff LaBundy 
2361e505edaeSJeff LaBundy 		chan_setup[0] &= ~IQS7222_CHAN_SETUP_0_REF_MODE_MASK;
2362e505edaeSJeff LaBundy 		chan_setup[0] &= ~IQS7222_CHAN_SETUP_0_CHAN_EN;
2363e505edaeSJeff LaBundy 
2364e505edaeSJeff LaBundy 		chan_setup[5] = 0;
2365e505edaeSJeff LaBundy 	}
2366e505edaeSJeff LaBundy 
2367e505edaeSJeff LaBundy 	for (i = 0; i < reg_grps[IQS7222_REG_GRP_SLDR].num_row; i++) {
2368e505edaeSJeff LaBundy 		u16 *sldr_setup = iqs7222->sldr_setup[i];
2369e505edaeSJeff LaBundy 
2370e505edaeSJeff LaBundy 		sldr_setup[0] &= ~IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK;
2371bbd16b0dSJeff LaBundy 	}
2372e505edaeSJeff LaBundy 
2373bbd16b0dSJeff LaBundy 	for (i = 0; i < IQS7222_NUM_REG_GRPS; i++) {
2374bbd16b0dSJeff LaBundy 		for (j = 0; j < reg_grps[i].num_row; j++) {
2375bbd16b0dSJeff LaBundy 			error = iqs7222_parse_reg_grp(iqs7222, i, j);
2376e505edaeSJeff LaBundy 			if (error)
2377e505edaeSJeff LaBundy 				return error;
2378e505edaeSJeff LaBundy 		}
2379bbd16b0dSJeff LaBundy 	}
2380e505edaeSJeff LaBundy 
2381bbd16b0dSJeff LaBundy 	return 0;
2382e505edaeSJeff LaBundy }
2383e505edaeSJeff LaBundy 
2384e505edaeSJeff LaBundy static int iqs7222_report(struct iqs7222_private *iqs7222)
2385e505edaeSJeff LaBundy {
2386e505edaeSJeff LaBundy 	const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
2387e505edaeSJeff LaBundy 	struct i2c_client *client = iqs7222->client;
2388e505edaeSJeff LaBundy 	int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
2389e505edaeSJeff LaBundy 	int num_stat = dev_desc->reg_grps[IQS7222_REG_GRP_STAT].num_col;
2390e505edaeSJeff LaBundy 	int error, i, j;
2391e505edaeSJeff LaBundy 	__le16 status[IQS7222_MAX_COLS_STAT];
2392e505edaeSJeff LaBundy 
2393e505edaeSJeff LaBundy 	error = iqs7222_read_burst(iqs7222, IQS7222_SYS_STATUS, status,
2394e505edaeSJeff LaBundy 				   num_stat);
2395e505edaeSJeff LaBundy 	if (error)
2396e505edaeSJeff LaBundy 		return error;
2397e505edaeSJeff LaBundy 
2398e505edaeSJeff LaBundy 	if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_RESET) {
2399e505edaeSJeff LaBundy 		dev_err(&client->dev, "Unexpected device reset\n");
2400e505edaeSJeff LaBundy 		return iqs7222_dev_init(iqs7222, WRITE);
2401e505edaeSJeff LaBundy 	}
2402e505edaeSJeff LaBundy 
2403e505edaeSJeff LaBundy 	if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_ATI_ERROR) {
2404e505edaeSJeff LaBundy 		dev_err(&client->dev, "Unexpected ATI error\n");
2405e505edaeSJeff LaBundy 		return iqs7222_ati_trigger(iqs7222);
2406e505edaeSJeff LaBundy 	}
2407e505edaeSJeff LaBundy 
2408e505edaeSJeff LaBundy 	if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_ATI_ACTIVE)
2409e505edaeSJeff LaBundy 		return 0;
2410e505edaeSJeff LaBundy 
2411e505edaeSJeff LaBundy 	for (i = 0; i < num_chan; i++) {
2412e505edaeSJeff LaBundy 		u16 *chan_setup = iqs7222->chan_setup[i];
2413e505edaeSJeff LaBundy 
2414e505edaeSJeff LaBundy 		if (!(chan_setup[0] & IQS7222_CHAN_SETUP_0_CHAN_EN))
2415e505edaeSJeff LaBundy 			continue;
2416e505edaeSJeff LaBundy 
2417e505edaeSJeff LaBundy 		for (j = 0; j < ARRAY_SIZE(iqs7222_kp_events); j++) {
2418e505edaeSJeff LaBundy 			/*
2419e505edaeSJeff LaBundy 			 * Proximity state begins at offset 2 and spills into
2420e505edaeSJeff LaBundy 			 * offset 3 for devices with more than 16 channels.
2421e505edaeSJeff LaBundy 			 *
2422e505edaeSJeff LaBundy 			 * Touch state begins at the first offset immediately
2423e505edaeSJeff LaBundy 			 * following proximity state.
2424e505edaeSJeff LaBundy 			 */
2425e505edaeSJeff LaBundy 			int k = 2 + j * (num_chan > 16 ? 2 : 1);
2426e505edaeSJeff LaBundy 			u16 state = le16_to_cpu(status[k + i / 16]);
2427e505edaeSJeff LaBundy 
2428514c13b1SJeff LaBundy 			if (!iqs7222->kp_type[i][j])
2429514c13b1SJeff LaBundy 				continue;
2430514c13b1SJeff LaBundy 
2431e505edaeSJeff LaBundy 			input_event(iqs7222->keypad,
2432e505edaeSJeff LaBundy 				    iqs7222->kp_type[i][j],
2433e505edaeSJeff LaBundy 				    iqs7222->kp_code[i][j],
2434e505edaeSJeff LaBundy 				    !!(state & BIT(i % 16)));
2435e505edaeSJeff LaBundy 		}
2436e505edaeSJeff LaBundy 	}
2437e505edaeSJeff LaBundy 
2438e505edaeSJeff LaBundy 	for (i = 0; i < dev_desc->reg_grps[IQS7222_REG_GRP_SLDR].num_row; i++) {
2439e505edaeSJeff LaBundy 		u16 *sldr_setup = iqs7222->sldr_setup[i];
2440e505edaeSJeff LaBundy 		u16 sldr_pos = le16_to_cpu(status[4 + i]);
2441e505edaeSJeff LaBundy 		u16 state = le16_to_cpu(status[6 + i]);
2442e505edaeSJeff LaBundy 
2443e505edaeSJeff LaBundy 		if (!(sldr_setup[0] & IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK))
2444e505edaeSJeff LaBundy 			continue;
2445e505edaeSJeff LaBundy 
2446e505edaeSJeff LaBundy 		if (sldr_pos < dev_desc->sldr_res)
2447e505edaeSJeff LaBundy 			input_report_abs(iqs7222->keypad, iqs7222->sl_axis[i],
2448e505edaeSJeff LaBundy 					 sldr_pos);
2449e505edaeSJeff LaBundy 
245095215d3dSJeff LaBundy 		input_report_key(iqs7222->keypad, iqs7222->sl_code[i][0],
2451e505edaeSJeff LaBundy 				 sldr_pos < dev_desc->sldr_res);
2452e505edaeSJeff LaBundy 
2453e505edaeSJeff LaBundy 		/*
245495215d3dSJeff LaBundy 		 * A maximum resolution indicates the device does not support
245595215d3dSJeff LaBundy 		 * gestures, in which case the remaining fields are ignored.
2456e505edaeSJeff LaBundy 		 */
245795215d3dSJeff LaBundy 		if (dev_desc->sldr_res == U16_MAX)
2458e505edaeSJeff LaBundy 			continue;
2459e505edaeSJeff LaBundy 
246095215d3dSJeff LaBundy 		if (!(le16_to_cpu(status[1]) & IQS7222_EVENT_MASK_SLDR << i))
246195215d3dSJeff LaBundy 			continue;
246295215d3dSJeff LaBundy 
246395215d3dSJeff LaBundy 		/*
246495215d3dSJeff LaBundy 		 * Skip the press/release event, as it does not have separate
246595215d3dSJeff LaBundy 		 * status fields and is handled separately.
246695215d3dSJeff LaBundy 		 */
246795215d3dSJeff LaBundy 		for (j = 1; j < ARRAY_SIZE(iqs7222_sl_events); j++) {
246895215d3dSJeff LaBundy 			u16 mask = iqs7222_sl_events[j].mask;
246995215d3dSJeff LaBundy 			u16 val = iqs7222_sl_events[j].val;
247095215d3dSJeff LaBundy 
2471e505edaeSJeff LaBundy 			input_report_key(iqs7222->keypad,
2472e505edaeSJeff LaBundy 					 iqs7222->sl_code[i][j],
2473e505edaeSJeff LaBundy 					 (state & mask) == val);
2474e505edaeSJeff LaBundy 		}
247595215d3dSJeff LaBundy 
247695215d3dSJeff LaBundy 		input_sync(iqs7222->keypad);
247795215d3dSJeff LaBundy 
247895215d3dSJeff LaBundy 		for (j = 1; j < ARRAY_SIZE(iqs7222_sl_events); j++)
247995215d3dSJeff LaBundy 			input_report_key(iqs7222->keypad,
248095215d3dSJeff LaBundy 					 iqs7222->sl_code[i][j], 0);
2481e505edaeSJeff LaBundy 	}
2482e505edaeSJeff LaBundy 
2483e505edaeSJeff LaBundy 	input_sync(iqs7222->keypad);
2484e505edaeSJeff LaBundy 
2485e505edaeSJeff LaBundy 	return 0;
2486e505edaeSJeff LaBundy }
2487e505edaeSJeff LaBundy 
2488e505edaeSJeff LaBundy static irqreturn_t iqs7222_irq(int irq, void *context)
2489e505edaeSJeff LaBundy {
2490e505edaeSJeff LaBundy 	struct iqs7222_private *iqs7222 = context;
2491e505edaeSJeff LaBundy 
2492e505edaeSJeff LaBundy 	return iqs7222_report(iqs7222) ? IRQ_NONE : IRQ_HANDLED;
2493e505edaeSJeff LaBundy }
2494e505edaeSJeff LaBundy 
2495e505edaeSJeff LaBundy static int iqs7222_probe(struct i2c_client *client)
2496e505edaeSJeff LaBundy {
2497e505edaeSJeff LaBundy 	struct iqs7222_private *iqs7222;
2498e505edaeSJeff LaBundy 	unsigned long irq_flags;
2499e505edaeSJeff LaBundy 	int error, irq;
2500e505edaeSJeff LaBundy 
2501e505edaeSJeff LaBundy 	iqs7222 = devm_kzalloc(&client->dev, sizeof(*iqs7222), GFP_KERNEL);
2502e505edaeSJeff LaBundy 	if (!iqs7222)
2503e505edaeSJeff LaBundy 		return -ENOMEM;
2504e505edaeSJeff LaBundy 
2505e505edaeSJeff LaBundy 	i2c_set_clientdata(client, iqs7222);
2506e505edaeSJeff LaBundy 	iqs7222->client = client;
2507e505edaeSJeff LaBundy 
2508e505edaeSJeff LaBundy 	iqs7222->keypad = devm_input_allocate_device(&client->dev);
2509e505edaeSJeff LaBundy 	if (!iqs7222->keypad)
2510e505edaeSJeff LaBundy 		return -ENOMEM;
2511e505edaeSJeff LaBundy 
2512e505edaeSJeff LaBundy 	iqs7222->keypad->name = client->name;
2513e505edaeSJeff LaBundy 	iqs7222->keypad->id.bustype = BUS_I2C;
2514e505edaeSJeff LaBundy 
2515e505edaeSJeff LaBundy 	/*
2516e505edaeSJeff LaBundy 	 * The RDY pin behaves as an interrupt, but must also be polled ahead
2517e505edaeSJeff LaBundy 	 * of unsolicited I2C communication. As such, it is first opened as a
2518e505edaeSJeff LaBundy 	 * GPIO and then passed to gpiod_to_irq() to register the interrupt.
2519e505edaeSJeff LaBundy 	 */
2520e505edaeSJeff LaBundy 	iqs7222->irq_gpio = devm_gpiod_get(&client->dev, "irq", GPIOD_IN);
2521e505edaeSJeff LaBundy 	if (IS_ERR(iqs7222->irq_gpio)) {
2522e505edaeSJeff LaBundy 		error = PTR_ERR(iqs7222->irq_gpio);
2523e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to request IRQ GPIO: %d\n",
2524e505edaeSJeff LaBundy 			error);
2525e505edaeSJeff LaBundy 		return error;
2526e505edaeSJeff LaBundy 	}
2527e505edaeSJeff LaBundy 
2528e505edaeSJeff LaBundy 	iqs7222->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
2529e505edaeSJeff LaBundy 						      GPIOD_OUT_HIGH);
2530e505edaeSJeff LaBundy 	if (IS_ERR(iqs7222->reset_gpio)) {
2531e505edaeSJeff LaBundy 		error = PTR_ERR(iqs7222->reset_gpio);
2532e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to request reset GPIO: %d\n",
2533e505edaeSJeff LaBundy 			error);
2534e505edaeSJeff LaBundy 		return error;
2535e505edaeSJeff LaBundy 	}
2536e505edaeSJeff LaBundy 
2537e505edaeSJeff LaBundy 	error = iqs7222_hard_reset(iqs7222);
2538e505edaeSJeff LaBundy 	if (error)
2539e505edaeSJeff LaBundy 		return error;
2540e505edaeSJeff LaBundy 
2541e505edaeSJeff LaBundy 	error = iqs7222_dev_info(iqs7222);
2542e505edaeSJeff LaBundy 	if (error)
2543e505edaeSJeff LaBundy 		return error;
2544e505edaeSJeff LaBundy 
2545e505edaeSJeff LaBundy 	error = iqs7222_dev_init(iqs7222, READ);
2546e505edaeSJeff LaBundy 	if (error)
2547e505edaeSJeff LaBundy 		return error;
2548e505edaeSJeff LaBundy 
2549e505edaeSJeff LaBundy 	error = iqs7222_parse_all(iqs7222);
2550e505edaeSJeff LaBundy 	if (error)
2551e505edaeSJeff LaBundy 		return error;
2552e505edaeSJeff LaBundy 
2553e505edaeSJeff LaBundy 	error = iqs7222_dev_init(iqs7222, WRITE);
2554e505edaeSJeff LaBundy 	if (error)
2555e505edaeSJeff LaBundy 		return error;
2556e505edaeSJeff LaBundy 
2557e505edaeSJeff LaBundy 	error = iqs7222_report(iqs7222);
2558e505edaeSJeff LaBundy 	if (error)
2559e505edaeSJeff LaBundy 		return error;
2560e505edaeSJeff LaBundy 
2561e505edaeSJeff LaBundy 	error = input_register_device(iqs7222->keypad);
2562e505edaeSJeff LaBundy 	if (error) {
2563e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to register device: %d\n", error);
2564e505edaeSJeff LaBundy 		return error;
2565e505edaeSJeff LaBundy 	}
2566e505edaeSJeff LaBundy 
2567e505edaeSJeff LaBundy 	irq = gpiod_to_irq(iqs7222->irq_gpio);
2568e505edaeSJeff LaBundy 	if (irq < 0)
2569e505edaeSJeff LaBundy 		return irq;
2570e505edaeSJeff LaBundy 
2571e505edaeSJeff LaBundy 	irq_flags = gpiod_is_active_low(iqs7222->irq_gpio) ? IRQF_TRIGGER_LOW
2572e505edaeSJeff LaBundy 							   : IRQF_TRIGGER_HIGH;
2573e505edaeSJeff LaBundy 	irq_flags |= IRQF_ONESHOT;
2574e505edaeSJeff LaBundy 
2575e505edaeSJeff LaBundy 	error = devm_request_threaded_irq(&client->dev, irq, NULL, iqs7222_irq,
2576e505edaeSJeff LaBundy 					  irq_flags, client->name, iqs7222);
2577e505edaeSJeff LaBundy 	if (error)
2578e505edaeSJeff LaBundy 		dev_err(&client->dev, "Failed to request IRQ: %d\n", error);
2579e505edaeSJeff LaBundy 
2580e505edaeSJeff LaBundy 	return error;
2581e505edaeSJeff LaBundy }
2582e505edaeSJeff LaBundy 
2583e505edaeSJeff LaBundy static const struct of_device_id iqs7222_of_match[] = {
2584e505edaeSJeff LaBundy 	{ .compatible = "azoteq,iqs7222a" },
2585e505edaeSJeff LaBundy 	{ .compatible = "azoteq,iqs7222b" },
2586e505edaeSJeff LaBundy 	{ .compatible = "azoteq,iqs7222c" },
2587e505edaeSJeff LaBundy 	{ }
2588e505edaeSJeff LaBundy };
2589e505edaeSJeff LaBundy MODULE_DEVICE_TABLE(of, iqs7222_of_match);
2590e505edaeSJeff LaBundy 
2591e505edaeSJeff LaBundy static struct i2c_driver iqs7222_i2c_driver = {
2592e505edaeSJeff LaBundy 	.driver = {
2593e505edaeSJeff LaBundy 		.name = "iqs7222",
2594e505edaeSJeff LaBundy 		.of_match_table = iqs7222_of_match,
2595e505edaeSJeff LaBundy 	},
2596d8bde56dSUwe Kleine-König 	.probe = iqs7222_probe,
2597e505edaeSJeff LaBundy };
2598e505edaeSJeff LaBundy module_i2c_driver(iqs7222_i2c_driver);
2599e505edaeSJeff LaBundy 
2600e505edaeSJeff LaBundy MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
2601e505edaeSJeff LaBundy MODULE_DESCRIPTION("Azoteq IQS7222A/B/C Capacitive Touch Controller");
2602e505edaeSJeff LaBundy MODULE_LICENSE("GPL");
2603