xref: /openbmc/linux/drivers/input/touchscreen/iqs7211.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1f2ba47e6SJeff LaBundy // SPDX-License-Identifier: GPL-2.0-or-later
2f2ba47e6SJeff LaBundy /*
3f2ba47e6SJeff LaBundy  * Azoteq IQS7210A/7211A/E Trackpad/Touchscreen Controller
4f2ba47e6SJeff LaBundy  *
5f2ba47e6SJeff LaBundy  * Copyright (C) 2023 Jeff LaBundy <jeff@labundy.com>
6f2ba47e6SJeff LaBundy  */
7f2ba47e6SJeff LaBundy 
8f2ba47e6SJeff LaBundy #include <linux/bits.h>
9f2ba47e6SJeff LaBundy #include <linux/delay.h>
10f2ba47e6SJeff LaBundy #include <linux/device.h>
11f2ba47e6SJeff LaBundy #include <linux/err.h>
12f2ba47e6SJeff LaBundy #include <linux/gpio/consumer.h>
13f2ba47e6SJeff LaBundy #include <linux/i2c.h>
14f2ba47e6SJeff LaBundy #include <linux/input.h>
15f2ba47e6SJeff LaBundy #include <linux/input/mt.h>
16f2ba47e6SJeff LaBundy #include <linux/input/touchscreen.h>
17f2ba47e6SJeff LaBundy #include <linux/interrupt.h>
18f2ba47e6SJeff LaBundy #include <linux/iopoll.h>
19f2ba47e6SJeff LaBundy #include <linux/kernel.h>
20f2ba47e6SJeff LaBundy #include <linux/list.h>
21f2ba47e6SJeff LaBundy #include <linux/module.h>
22f2ba47e6SJeff LaBundy #include <linux/of_device.h>
23f2ba47e6SJeff LaBundy #include <linux/property.h>
24f2ba47e6SJeff LaBundy #include <linux/slab.h>
25f2ba47e6SJeff LaBundy #include <asm/unaligned.h>
26f2ba47e6SJeff LaBundy 
27f2ba47e6SJeff LaBundy #define IQS7211_PROD_NUM			0x00
28f2ba47e6SJeff LaBundy 
29f2ba47e6SJeff LaBundy #define IQS7211_EVENT_MASK_ALL			GENMASK(14, 8)
30f2ba47e6SJeff LaBundy #define IQS7211_EVENT_MASK_ALP			BIT(13)
31f2ba47e6SJeff LaBundy #define IQS7211_EVENT_MASK_BTN			BIT(12)
32f2ba47e6SJeff LaBundy #define IQS7211_EVENT_MASK_ATI			BIT(11)
33f2ba47e6SJeff LaBundy #define IQS7211_EVENT_MASK_MOVE			BIT(10)
34f2ba47e6SJeff LaBundy #define IQS7211_EVENT_MASK_GSTR			BIT(9)
35f2ba47e6SJeff LaBundy #define IQS7211_EVENT_MODE			BIT(8)
36f2ba47e6SJeff LaBundy 
37f2ba47e6SJeff LaBundy #define IQS7211_COMMS_ERROR			0xEEEE
38f2ba47e6SJeff LaBundy #define IQS7211_COMMS_RETRY_MS			50
39f2ba47e6SJeff LaBundy #define IQS7211_COMMS_SLEEP_US			100
40f2ba47e6SJeff LaBundy #define IQS7211_COMMS_TIMEOUT_US		(100 * USEC_PER_MSEC)
41f2ba47e6SJeff LaBundy #define IQS7211_RESET_TIMEOUT_MS		150
42f2ba47e6SJeff LaBundy #define IQS7211_START_TIMEOUT_US		(1 * USEC_PER_SEC)
43f2ba47e6SJeff LaBundy 
44f2ba47e6SJeff LaBundy #define IQS7211_NUM_RETRIES			5
45f2ba47e6SJeff LaBundy #define IQS7211_NUM_CRX				8
46f2ba47e6SJeff LaBundy #define IQS7211_MAX_CTX				13
47f2ba47e6SJeff LaBundy 
48f2ba47e6SJeff LaBundy #define IQS7211_MAX_CONTACTS			2
49f2ba47e6SJeff LaBundy #define IQS7211_MAX_CYCLES			21
50f2ba47e6SJeff LaBundy 
51f2ba47e6SJeff LaBundy /*
52f2ba47e6SJeff LaBundy  * The following delay is used during instances that must wait for the open-
53f2ba47e6SJeff LaBundy  * drain RDY pin to settle. Its value is calculated as 5*R*C, where R and C
54f2ba47e6SJeff LaBundy  * represent typical datasheet values of 4.7k and 100 nF, respectively.
55f2ba47e6SJeff LaBundy  */
56f2ba47e6SJeff LaBundy #define iqs7211_irq_wait()			usleep_range(2500, 2600)
57f2ba47e6SJeff LaBundy 
58f2ba47e6SJeff LaBundy enum iqs7211_dev_id {
59f2ba47e6SJeff LaBundy 	IQS7210A,
60f2ba47e6SJeff LaBundy 	IQS7211A,
61f2ba47e6SJeff LaBundy 	IQS7211E,
62f2ba47e6SJeff LaBundy };
63f2ba47e6SJeff LaBundy 
64f2ba47e6SJeff LaBundy enum iqs7211_comms_mode {
65f2ba47e6SJeff LaBundy 	IQS7211_COMMS_MODE_WAIT,
66f2ba47e6SJeff LaBundy 	IQS7211_COMMS_MODE_FREE,
67f2ba47e6SJeff LaBundy 	IQS7211_COMMS_MODE_FORCE,
68f2ba47e6SJeff LaBundy };
69f2ba47e6SJeff LaBundy 
70f2ba47e6SJeff LaBundy struct iqs7211_reg_field_desc {
71f2ba47e6SJeff LaBundy 	struct list_head list;
72f2ba47e6SJeff LaBundy 	u8 addr;
73f2ba47e6SJeff LaBundy 	u16 mask;
74f2ba47e6SJeff LaBundy 	u16 val;
75f2ba47e6SJeff LaBundy };
76f2ba47e6SJeff LaBundy 
77f2ba47e6SJeff LaBundy enum iqs7211_reg_key_id {
78f2ba47e6SJeff LaBundy 	IQS7211_REG_KEY_NONE,
79f2ba47e6SJeff LaBundy 	IQS7211_REG_KEY_PROX,
80f2ba47e6SJeff LaBundy 	IQS7211_REG_KEY_TOUCH,
81f2ba47e6SJeff LaBundy 	IQS7211_REG_KEY_TAP,
82f2ba47e6SJeff LaBundy 	IQS7211_REG_KEY_HOLD,
83f2ba47e6SJeff LaBundy 	IQS7211_REG_KEY_PALM,
84f2ba47e6SJeff LaBundy 	IQS7211_REG_KEY_AXIAL_X,
85f2ba47e6SJeff LaBundy 	IQS7211_REG_KEY_AXIAL_Y,
86f2ba47e6SJeff LaBundy 	IQS7211_REG_KEY_RESERVED
87f2ba47e6SJeff LaBundy };
88f2ba47e6SJeff LaBundy 
89f2ba47e6SJeff LaBundy enum iqs7211_reg_grp_id {
90f2ba47e6SJeff LaBundy 	IQS7211_REG_GRP_TP,
91f2ba47e6SJeff LaBundy 	IQS7211_REG_GRP_BTN,
92f2ba47e6SJeff LaBundy 	IQS7211_REG_GRP_ALP,
93f2ba47e6SJeff LaBundy 	IQS7211_REG_GRP_SYS,
94f2ba47e6SJeff LaBundy 	IQS7211_NUM_REG_GRPS
95f2ba47e6SJeff LaBundy };
96f2ba47e6SJeff LaBundy 
97f2ba47e6SJeff LaBundy static const char * const iqs7211_reg_grp_names[IQS7211_NUM_REG_GRPS] = {
98f2ba47e6SJeff LaBundy 	[IQS7211_REG_GRP_TP] = "trackpad",
99f2ba47e6SJeff LaBundy 	[IQS7211_REG_GRP_BTN] = "button",
100f2ba47e6SJeff LaBundy 	[IQS7211_REG_GRP_ALP] = "alp",
101f2ba47e6SJeff LaBundy };
102f2ba47e6SJeff LaBundy 
103f2ba47e6SJeff LaBundy static const u16 iqs7211_reg_grp_masks[IQS7211_NUM_REG_GRPS] = {
104f2ba47e6SJeff LaBundy 	[IQS7211_REG_GRP_TP] = IQS7211_EVENT_MASK_GSTR,
105f2ba47e6SJeff LaBundy 	[IQS7211_REG_GRP_BTN] = IQS7211_EVENT_MASK_BTN,
106f2ba47e6SJeff LaBundy 	[IQS7211_REG_GRP_ALP] = IQS7211_EVENT_MASK_ALP,
107f2ba47e6SJeff LaBundy };
108f2ba47e6SJeff LaBundy 
109f2ba47e6SJeff LaBundy struct iqs7211_event_desc {
110f2ba47e6SJeff LaBundy 	const char *name;
111f2ba47e6SJeff LaBundy 	u16 mask;
112f2ba47e6SJeff LaBundy 	u16 enable;
113f2ba47e6SJeff LaBundy 	enum iqs7211_reg_grp_id reg_grp;
114f2ba47e6SJeff LaBundy 	enum iqs7211_reg_key_id reg_key;
115f2ba47e6SJeff LaBundy };
116f2ba47e6SJeff LaBundy 
117f2ba47e6SJeff LaBundy static const struct iqs7211_event_desc iqs7210a_kp_events[] = {
118f2ba47e6SJeff LaBundy 	{
119f2ba47e6SJeff LaBundy 		.mask = BIT(10),
120f2ba47e6SJeff LaBundy 		.enable = BIT(13) | BIT(12),
121f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_ALP,
122f2ba47e6SJeff LaBundy 	},
123f2ba47e6SJeff LaBundy 	{
124f2ba47e6SJeff LaBundy 		.name = "event-prox",
125f2ba47e6SJeff LaBundy 		.mask = BIT(2),
126f2ba47e6SJeff LaBundy 		.enable = BIT(5) | BIT(4),
127f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_BTN,
128f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_PROX,
129f2ba47e6SJeff LaBundy 	},
130f2ba47e6SJeff LaBundy 	{
131f2ba47e6SJeff LaBundy 		.name = "event-touch",
132f2ba47e6SJeff LaBundy 		.mask = BIT(3),
133f2ba47e6SJeff LaBundy 		.enable = BIT(5) | BIT(4),
134f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_BTN,
135f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_TOUCH,
136f2ba47e6SJeff LaBundy 	},
137f2ba47e6SJeff LaBundy 	{
138f2ba47e6SJeff LaBundy 		.name = "event-tap",
139f2ba47e6SJeff LaBundy 		.mask = BIT(0),
140f2ba47e6SJeff LaBundy 		.enable = BIT(0),
141f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
142f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_TAP,
143f2ba47e6SJeff LaBundy 	},
144f2ba47e6SJeff LaBundy 	{
145f2ba47e6SJeff LaBundy 		.name = "event-hold",
146f2ba47e6SJeff LaBundy 		.mask = BIT(1),
147f2ba47e6SJeff LaBundy 		.enable = BIT(1),
148f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
149f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_HOLD,
150f2ba47e6SJeff LaBundy 	},
151f2ba47e6SJeff LaBundy 	{
152f2ba47e6SJeff LaBundy 		.name = "event-swipe-x-neg",
153f2ba47e6SJeff LaBundy 		.mask = BIT(2),
154f2ba47e6SJeff LaBundy 		.enable = BIT(2),
155f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
156f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_AXIAL_X,
157f2ba47e6SJeff LaBundy 	},
158f2ba47e6SJeff LaBundy 	{
159f2ba47e6SJeff LaBundy 		.name = "event-swipe-x-pos",
160f2ba47e6SJeff LaBundy 		.mask = BIT(3),
161f2ba47e6SJeff LaBundy 		.enable = BIT(3),
162f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
163f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_AXIAL_X,
164f2ba47e6SJeff LaBundy 	},
165f2ba47e6SJeff LaBundy 	{
166f2ba47e6SJeff LaBundy 		.name = "event-swipe-y-pos",
167f2ba47e6SJeff LaBundy 		.mask = BIT(4),
168f2ba47e6SJeff LaBundy 		.enable = BIT(4),
169f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
170f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_AXIAL_Y,
171f2ba47e6SJeff LaBundy 	},
172f2ba47e6SJeff LaBundy 	{
173f2ba47e6SJeff LaBundy 		.name = "event-swipe-y-neg",
174f2ba47e6SJeff LaBundy 		.mask = BIT(5),
175f2ba47e6SJeff LaBundy 		.enable = BIT(5),
176f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
177f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_AXIAL_Y,
178f2ba47e6SJeff LaBundy 	},
179f2ba47e6SJeff LaBundy };
180f2ba47e6SJeff LaBundy 
181f2ba47e6SJeff LaBundy static const struct iqs7211_event_desc iqs7211a_kp_events[] = {
182f2ba47e6SJeff LaBundy 	{
183f2ba47e6SJeff LaBundy 		.mask = BIT(14),
184f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_ALP,
185f2ba47e6SJeff LaBundy 	},
186f2ba47e6SJeff LaBundy 	{
187f2ba47e6SJeff LaBundy 		.name = "event-tap",
188f2ba47e6SJeff LaBundy 		.mask = BIT(0),
189f2ba47e6SJeff LaBundy 		.enable = BIT(0),
190f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
191f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_TAP,
192f2ba47e6SJeff LaBundy 	},
193f2ba47e6SJeff LaBundy 	{
194f2ba47e6SJeff LaBundy 		.name = "event-hold",
195f2ba47e6SJeff LaBundy 		.mask = BIT(1),
196f2ba47e6SJeff LaBundy 		.enable = BIT(1),
197f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
198f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_HOLD,
199f2ba47e6SJeff LaBundy 	},
200f2ba47e6SJeff LaBundy 	{
201f2ba47e6SJeff LaBundy 		.name = "event-swipe-x-neg",
202f2ba47e6SJeff LaBundy 		.mask = BIT(2),
203f2ba47e6SJeff LaBundy 		.enable = BIT(2),
204f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
205f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_AXIAL_X,
206f2ba47e6SJeff LaBundy 	},
207f2ba47e6SJeff LaBundy 	{
208f2ba47e6SJeff LaBundy 		.name = "event-swipe-x-pos",
209f2ba47e6SJeff LaBundy 		.mask = BIT(3),
210f2ba47e6SJeff LaBundy 		.enable = BIT(3),
211f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
212f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_AXIAL_X,
213f2ba47e6SJeff LaBundy 	},
214f2ba47e6SJeff LaBundy 	{
215f2ba47e6SJeff LaBundy 		.name = "event-swipe-y-pos",
216f2ba47e6SJeff LaBundy 		.mask = BIT(4),
217f2ba47e6SJeff LaBundy 		.enable = BIT(4),
218f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
219f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_AXIAL_Y,
220f2ba47e6SJeff LaBundy 	},
221f2ba47e6SJeff LaBundy 	{
222f2ba47e6SJeff LaBundy 		.name = "event-swipe-y-neg",
223f2ba47e6SJeff LaBundy 		.mask = BIT(5),
224f2ba47e6SJeff LaBundy 		.enable = BIT(5),
225f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
226f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_AXIAL_Y,
227f2ba47e6SJeff LaBundy 	},
228f2ba47e6SJeff LaBundy };
229f2ba47e6SJeff LaBundy 
230f2ba47e6SJeff LaBundy static const struct iqs7211_event_desc iqs7211e_kp_events[] = {
231f2ba47e6SJeff LaBundy 	{
232f2ba47e6SJeff LaBundy 		.mask = BIT(14),
233f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_ALP,
234f2ba47e6SJeff LaBundy 	},
235f2ba47e6SJeff LaBundy 	{
236f2ba47e6SJeff LaBundy 		.name = "event-tap",
237f2ba47e6SJeff LaBundy 		.mask = BIT(0),
238f2ba47e6SJeff LaBundy 		.enable = BIT(0),
239f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
240f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_TAP,
241f2ba47e6SJeff LaBundy 	},
242f2ba47e6SJeff LaBundy 	{
243f2ba47e6SJeff LaBundy 		.name = "event-tap-double",
244f2ba47e6SJeff LaBundy 		.mask = BIT(1),
245f2ba47e6SJeff LaBundy 		.enable = BIT(1),
246f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
247f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_TAP,
248f2ba47e6SJeff LaBundy 	},
249f2ba47e6SJeff LaBundy 	{
250f2ba47e6SJeff LaBundy 		.name = "event-tap-triple",
251f2ba47e6SJeff LaBundy 		.mask = BIT(2),
252f2ba47e6SJeff LaBundy 		.enable = BIT(2),
253f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
254f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_TAP,
255f2ba47e6SJeff LaBundy 	},
256f2ba47e6SJeff LaBundy 	{
257f2ba47e6SJeff LaBundy 		.name = "event-hold",
258f2ba47e6SJeff LaBundy 		.mask = BIT(3),
259f2ba47e6SJeff LaBundy 		.enable = BIT(3),
260f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
261f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_HOLD,
262f2ba47e6SJeff LaBundy 	},
263f2ba47e6SJeff LaBundy 	{
264f2ba47e6SJeff LaBundy 		.name = "event-palm",
265f2ba47e6SJeff LaBundy 		.mask = BIT(4),
266f2ba47e6SJeff LaBundy 		.enable = BIT(4),
267f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
268f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_PALM,
269f2ba47e6SJeff LaBundy 	},
270f2ba47e6SJeff LaBundy 	{
271f2ba47e6SJeff LaBundy 		.name = "event-swipe-x-pos",
272f2ba47e6SJeff LaBundy 		.mask = BIT(8),
273f2ba47e6SJeff LaBundy 		.enable = BIT(8),
274f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
275f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_AXIAL_X,
276f2ba47e6SJeff LaBundy 	},
277f2ba47e6SJeff LaBundy 	{
278f2ba47e6SJeff LaBundy 		.name = "event-swipe-x-neg",
279f2ba47e6SJeff LaBundy 		.mask = BIT(9),
280f2ba47e6SJeff LaBundy 		.enable = BIT(9),
281f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
282f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_AXIAL_X,
283f2ba47e6SJeff LaBundy 	},
284f2ba47e6SJeff LaBundy 	{
285f2ba47e6SJeff LaBundy 		.name = "event-swipe-y-pos",
286f2ba47e6SJeff LaBundy 		.mask = BIT(10),
287f2ba47e6SJeff LaBundy 		.enable = BIT(10),
288f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
289f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_AXIAL_Y,
290f2ba47e6SJeff LaBundy 	},
291f2ba47e6SJeff LaBundy 	{
292f2ba47e6SJeff LaBundy 		.name = "event-swipe-y-neg",
293f2ba47e6SJeff LaBundy 		.mask = BIT(11),
294f2ba47e6SJeff LaBundy 		.enable = BIT(11),
295f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
296f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_AXIAL_Y,
297f2ba47e6SJeff LaBundy 	},
298f2ba47e6SJeff LaBundy 	{
299f2ba47e6SJeff LaBundy 		.name = "event-swipe-x-pos-hold",
300f2ba47e6SJeff LaBundy 		.mask = BIT(12),
301f2ba47e6SJeff LaBundy 		.enable = BIT(12),
302f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
303f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_HOLD,
304f2ba47e6SJeff LaBundy 	},
305f2ba47e6SJeff LaBundy 	{
306f2ba47e6SJeff LaBundy 		.name = "event-swipe-x-neg-hold",
307f2ba47e6SJeff LaBundy 		.mask = BIT(13),
308f2ba47e6SJeff LaBundy 		.enable = BIT(13),
309f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
310f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_HOLD,
311f2ba47e6SJeff LaBundy 	},
312f2ba47e6SJeff LaBundy 	{
313f2ba47e6SJeff LaBundy 		.name = "event-swipe-y-pos-hold",
314f2ba47e6SJeff LaBundy 		.mask = BIT(14),
315f2ba47e6SJeff LaBundy 		.enable = BIT(14),
316f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
317f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_HOLD,
318f2ba47e6SJeff LaBundy 	},
319f2ba47e6SJeff LaBundy 	{
320f2ba47e6SJeff LaBundy 		.name = "event-swipe-y-neg-hold",
321f2ba47e6SJeff LaBundy 		.mask = BIT(15),
322f2ba47e6SJeff LaBundy 		.enable = BIT(15),
323f2ba47e6SJeff LaBundy 		.reg_grp = IQS7211_REG_GRP_TP,
324f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_HOLD,
325f2ba47e6SJeff LaBundy 	},
326f2ba47e6SJeff LaBundy };
327f2ba47e6SJeff LaBundy 
328f2ba47e6SJeff LaBundy struct iqs7211_dev_desc {
329f2ba47e6SJeff LaBundy 	const char *tp_name;
330f2ba47e6SJeff LaBundy 	const char *kp_name;
331f2ba47e6SJeff LaBundy 	u16 prod_num;
332f2ba47e6SJeff LaBundy 	u16 show_reset;
333f2ba47e6SJeff LaBundy 	u16 ati_error[IQS7211_NUM_REG_GRPS];
334f2ba47e6SJeff LaBundy 	u16 ati_start[IQS7211_NUM_REG_GRPS];
335f2ba47e6SJeff LaBundy 	u16 suspend;
336f2ba47e6SJeff LaBundy 	u16 ack_reset;
337f2ba47e6SJeff LaBundy 	u16 comms_end;
338f2ba47e6SJeff LaBundy 	u16 comms_req;
339f2ba47e6SJeff LaBundy 	int charge_shift;
340f2ba47e6SJeff LaBundy 	int info_offs;
341f2ba47e6SJeff LaBundy 	int gesture_offs;
342f2ba47e6SJeff LaBundy 	int contact_offs;
343f2ba47e6SJeff LaBundy 	u8 sys_stat;
344f2ba47e6SJeff LaBundy 	u8 sys_ctrl;
345f2ba47e6SJeff LaBundy 	u8 alp_config;
346f2ba47e6SJeff LaBundy 	u8 tp_config;
347f2ba47e6SJeff LaBundy 	u8 exp_file;
348f2ba47e6SJeff LaBundy 	u8 kp_enable[IQS7211_NUM_REG_GRPS];
349f2ba47e6SJeff LaBundy 	u8 gesture_angle;
350f2ba47e6SJeff LaBundy 	u8 rx_tx_map;
351f2ba47e6SJeff LaBundy 	u8 cycle_alloc[2];
352f2ba47e6SJeff LaBundy 	u8 cycle_limit[2];
353f2ba47e6SJeff LaBundy 	const struct iqs7211_event_desc *kp_events;
354f2ba47e6SJeff LaBundy 	int num_kp_events;
355f2ba47e6SJeff LaBundy 	int min_crx_alp;
356f2ba47e6SJeff LaBundy 	int num_ctx;
357f2ba47e6SJeff LaBundy };
358f2ba47e6SJeff LaBundy 
359f2ba47e6SJeff LaBundy static const struct iqs7211_dev_desc iqs7211_devs[] = {
360f2ba47e6SJeff LaBundy 	[IQS7210A] = {
361f2ba47e6SJeff LaBundy 		.tp_name = "iqs7210a_trackpad",
362f2ba47e6SJeff LaBundy 		.kp_name = "iqs7210a_keys",
363f2ba47e6SJeff LaBundy 		.prod_num = 944,
364f2ba47e6SJeff LaBundy 		.show_reset = BIT(15),
365f2ba47e6SJeff LaBundy 		.ati_error = {
366f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_TP] = BIT(12),
367f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_BTN] = BIT(0),
368f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_ALP] = BIT(8),
369f2ba47e6SJeff LaBundy 		},
370f2ba47e6SJeff LaBundy 		.ati_start = {
371f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_TP] = BIT(13),
372f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_BTN] = BIT(1),
373f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_ALP] = BIT(9),
374f2ba47e6SJeff LaBundy 		},
375f2ba47e6SJeff LaBundy 		.suspend = BIT(11),
376f2ba47e6SJeff LaBundy 		.ack_reset = BIT(7),
377f2ba47e6SJeff LaBundy 		.comms_end = BIT(2),
378f2ba47e6SJeff LaBundy 		.comms_req = BIT(1),
379f2ba47e6SJeff LaBundy 		.charge_shift = 4,
380f2ba47e6SJeff LaBundy 		.info_offs = 0,
381f2ba47e6SJeff LaBundy 		.gesture_offs = 1,
382f2ba47e6SJeff LaBundy 		.contact_offs = 4,
383f2ba47e6SJeff LaBundy 		.sys_stat = 0x0A,
384f2ba47e6SJeff LaBundy 		.sys_ctrl = 0x35,
385f2ba47e6SJeff LaBundy 		.alp_config = 0x39,
386f2ba47e6SJeff LaBundy 		.tp_config = 0x4E,
387f2ba47e6SJeff LaBundy 		.exp_file = 0x57,
388f2ba47e6SJeff LaBundy 		.kp_enable = {
389f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_TP] = 0x58,
390f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_BTN] = 0x37,
391f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_ALP] = 0x37,
392f2ba47e6SJeff LaBundy 		},
393f2ba47e6SJeff LaBundy 		.gesture_angle = 0x5F,
394f2ba47e6SJeff LaBundy 		.rx_tx_map = 0x60,
395f2ba47e6SJeff LaBundy 		.cycle_alloc = { 0x66, 0x75, },
396f2ba47e6SJeff LaBundy 		.cycle_limit = { 10, 6, },
397f2ba47e6SJeff LaBundy 		.kp_events = iqs7210a_kp_events,
398f2ba47e6SJeff LaBundy 		.num_kp_events = ARRAY_SIZE(iqs7210a_kp_events),
399f2ba47e6SJeff LaBundy 		.min_crx_alp = 4,
400f2ba47e6SJeff LaBundy 		.num_ctx = IQS7211_MAX_CTX - 1,
401f2ba47e6SJeff LaBundy 	},
402f2ba47e6SJeff LaBundy 	[IQS7211A] = {
403f2ba47e6SJeff LaBundy 		.tp_name = "iqs7211a_trackpad",
404f2ba47e6SJeff LaBundy 		.kp_name = "iqs7211a_keys",
405f2ba47e6SJeff LaBundy 		.prod_num = 763,
406f2ba47e6SJeff LaBundy 		.show_reset = BIT(7),
407f2ba47e6SJeff LaBundy 		.ati_error = {
408f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_TP] = BIT(3),
409f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_ALP] = BIT(5),
410f2ba47e6SJeff LaBundy 		},
411f2ba47e6SJeff LaBundy 		.ati_start = {
412f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_TP] = BIT(5),
413f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_ALP] = BIT(6),
414f2ba47e6SJeff LaBundy 		},
415f2ba47e6SJeff LaBundy 		.ack_reset = BIT(7),
416f2ba47e6SJeff LaBundy 		.comms_req = BIT(4),
417f2ba47e6SJeff LaBundy 		.charge_shift = 0,
418f2ba47e6SJeff LaBundy 		.info_offs = 0,
419f2ba47e6SJeff LaBundy 		.gesture_offs = 1,
420f2ba47e6SJeff LaBundy 		.contact_offs = 4,
421f2ba47e6SJeff LaBundy 		.sys_stat = 0x10,
422f2ba47e6SJeff LaBundy 		.sys_ctrl = 0x50,
423f2ba47e6SJeff LaBundy 		.tp_config = 0x60,
424f2ba47e6SJeff LaBundy 		.alp_config = 0x72,
425f2ba47e6SJeff LaBundy 		.exp_file = 0x74,
426f2ba47e6SJeff LaBundy 		.kp_enable = {
427f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_TP] = 0x80,
428f2ba47e6SJeff LaBundy 		},
429f2ba47e6SJeff LaBundy 		.gesture_angle = 0x87,
430f2ba47e6SJeff LaBundy 		.rx_tx_map = 0x90,
431f2ba47e6SJeff LaBundy 		.cycle_alloc = { 0xA0, 0xB0, },
432f2ba47e6SJeff LaBundy 		.cycle_limit = { 10, 8, },
433f2ba47e6SJeff LaBundy 		.kp_events = iqs7211a_kp_events,
434f2ba47e6SJeff LaBundy 		.num_kp_events = ARRAY_SIZE(iqs7211a_kp_events),
435f2ba47e6SJeff LaBundy 		.num_ctx = IQS7211_MAX_CTX - 1,
436f2ba47e6SJeff LaBundy 	},
437f2ba47e6SJeff LaBundy 	[IQS7211E] = {
438f2ba47e6SJeff LaBundy 		.tp_name = "iqs7211e_trackpad",
439f2ba47e6SJeff LaBundy 		.kp_name = "iqs7211e_keys",
440f2ba47e6SJeff LaBundy 		.prod_num = 1112,
441f2ba47e6SJeff LaBundy 		.show_reset = BIT(7),
442f2ba47e6SJeff LaBundy 		.ati_error = {
443f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_TP] = BIT(3),
444f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_ALP] = BIT(5),
445f2ba47e6SJeff LaBundy 		},
446f2ba47e6SJeff LaBundy 		.ati_start = {
447f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_TP] = BIT(5),
448f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_ALP] = BIT(6),
449f2ba47e6SJeff LaBundy 		},
450f2ba47e6SJeff LaBundy 		.suspend = BIT(11),
451f2ba47e6SJeff LaBundy 		.ack_reset = BIT(7),
452f2ba47e6SJeff LaBundy 		.comms_end = BIT(6),
453f2ba47e6SJeff LaBundy 		.comms_req = BIT(4),
454f2ba47e6SJeff LaBundy 		.charge_shift = 0,
455f2ba47e6SJeff LaBundy 		.info_offs = 1,
456f2ba47e6SJeff LaBundy 		.gesture_offs = 0,
457f2ba47e6SJeff LaBundy 		.contact_offs = 2,
458f2ba47e6SJeff LaBundy 		.sys_stat = 0x0E,
459f2ba47e6SJeff LaBundy 		.sys_ctrl = 0x33,
460f2ba47e6SJeff LaBundy 		.tp_config = 0x41,
461f2ba47e6SJeff LaBundy 		.alp_config = 0x36,
462f2ba47e6SJeff LaBundy 		.exp_file = 0x4A,
463f2ba47e6SJeff LaBundy 		.kp_enable = {
464f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_TP] = 0x4B,
465f2ba47e6SJeff LaBundy 		},
466f2ba47e6SJeff LaBundy 		.gesture_angle = 0x55,
467f2ba47e6SJeff LaBundy 		.rx_tx_map = 0x56,
468f2ba47e6SJeff LaBundy 		.cycle_alloc = { 0x5D, 0x6C, },
469f2ba47e6SJeff LaBundy 		.cycle_limit = { 10, 11, },
470f2ba47e6SJeff LaBundy 		.kp_events = iqs7211e_kp_events,
471f2ba47e6SJeff LaBundy 		.num_kp_events = ARRAY_SIZE(iqs7211e_kp_events),
472f2ba47e6SJeff LaBundy 		.num_ctx = IQS7211_MAX_CTX,
473f2ba47e6SJeff LaBundy 	},
474f2ba47e6SJeff LaBundy };
475f2ba47e6SJeff LaBundy 
476f2ba47e6SJeff LaBundy struct iqs7211_prop_desc {
477f2ba47e6SJeff LaBundy 	const char *name;
478f2ba47e6SJeff LaBundy 	enum iqs7211_reg_key_id reg_key;
479f2ba47e6SJeff LaBundy 	u8 reg_addr[IQS7211_NUM_REG_GRPS][ARRAY_SIZE(iqs7211_devs)];
480f2ba47e6SJeff LaBundy 	int reg_shift;
481f2ba47e6SJeff LaBundy 	int reg_width;
482f2ba47e6SJeff LaBundy 	int val_pitch;
483f2ba47e6SJeff LaBundy 	int val_min;
484f2ba47e6SJeff LaBundy 	int val_max;
485f2ba47e6SJeff LaBundy 	const char *label;
486f2ba47e6SJeff LaBundy };
487f2ba47e6SJeff LaBundy 
488f2ba47e6SJeff LaBundy static const struct iqs7211_prop_desc iqs7211_props[] = {
489f2ba47e6SJeff LaBundy 	{
490f2ba47e6SJeff LaBundy 		.name = "azoteq,ati-frac-div-fine",
491f2ba47e6SJeff LaBundy 		.reg_addr = {
492f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_TP] = {
493f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x1E,
494f2ba47e6SJeff LaBundy 				[IQS7211A] = 0x30,
495f2ba47e6SJeff LaBundy 				[IQS7211E] = 0x21,
496f2ba47e6SJeff LaBundy 			},
497f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_BTN] = {
498f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x22,
499f2ba47e6SJeff LaBundy 			},
500f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_ALP] = {
501f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x23,
502f2ba47e6SJeff LaBundy 				[IQS7211A] = 0x36,
503f2ba47e6SJeff LaBundy 				[IQS7211E] = 0x25,
504f2ba47e6SJeff LaBundy 			},
505f2ba47e6SJeff LaBundy 		},
506f2ba47e6SJeff LaBundy 		.reg_shift = 9,
507f2ba47e6SJeff LaBundy 		.reg_width = 5,
508f2ba47e6SJeff LaBundy 		.label = "ATI fine fractional divider",
509f2ba47e6SJeff LaBundy 	},
510f2ba47e6SJeff LaBundy 	{
511f2ba47e6SJeff LaBundy 		.name = "azoteq,ati-frac-mult-coarse",
512f2ba47e6SJeff LaBundy 		.reg_addr = {
513f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_TP] = {
514f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x1E,
515f2ba47e6SJeff LaBundy 				[IQS7211A] = 0x30,
516f2ba47e6SJeff LaBundy 				[IQS7211E] = 0x21,
517f2ba47e6SJeff LaBundy 			},
518f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_BTN] = {
519f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x22,
520f2ba47e6SJeff LaBundy 			},
521f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_ALP] = {
522f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x23,
523f2ba47e6SJeff LaBundy 				[IQS7211A] = 0x36,
524f2ba47e6SJeff LaBundy 				[IQS7211E] = 0x25,
525f2ba47e6SJeff LaBundy 			},
526f2ba47e6SJeff LaBundy 		},
527f2ba47e6SJeff LaBundy 		.reg_shift = 5,
528f2ba47e6SJeff LaBundy 		.reg_width = 4,
529f2ba47e6SJeff LaBundy 		.label = "ATI coarse fractional multiplier",
530f2ba47e6SJeff LaBundy 	},
531f2ba47e6SJeff LaBundy 	{
532f2ba47e6SJeff LaBundy 		.name = "azoteq,ati-frac-div-coarse",
533f2ba47e6SJeff LaBundy 		.reg_addr = {
534f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_TP] = {
535f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x1E,
536f2ba47e6SJeff LaBundy 				[IQS7211A] = 0x30,
537f2ba47e6SJeff LaBundy 				[IQS7211E] = 0x21,
538f2ba47e6SJeff LaBundy 			},
539f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_BTN] = {
540f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x22,
541f2ba47e6SJeff LaBundy 			},
542f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_ALP] = {
543f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x23,
544f2ba47e6SJeff LaBundy 				[IQS7211A] = 0x36,
545f2ba47e6SJeff LaBundy 				[IQS7211E] = 0x25,
546f2ba47e6SJeff LaBundy 			},
547f2ba47e6SJeff LaBundy 		},
548f2ba47e6SJeff LaBundy 		.reg_shift = 0,
549f2ba47e6SJeff LaBundy 		.reg_width = 5,
550f2ba47e6SJeff LaBundy 		.label = "ATI coarse fractional divider",
551f2ba47e6SJeff LaBundy 	},
552f2ba47e6SJeff LaBundy 	{
553f2ba47e6SJeff LaBundy 		.name = "azoteq,ati-comp-div",
554f2ba47e6SJeff LaBundy 		.reg_addr = {
555f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_TP] = {
556f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x1F,
557f2ba47e6SJeff LaBundy 				[IQS7211E] = 0x22,
558f2ba47e6SJeff LaBundy 			},
559f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_BTN] = {
560f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x24,
561f2ba47e6SJeff LaBundy 			},
562f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_ALP] = {
563f2ba47e6SJeff LaBundy 				[IQS7211E] = 0x26,
564f2ba47e6SJeff LaBundy 			},
565f2ba47e6SJeff LaBundy 		},
566f2ba47e6SJeff LaBundy 		.reg_shift = 0,
567f2ba47e6SJeff LaBundy 		.reg_width = 8,
568f2ba47e6SJeff LaBundy 		.val_max = 31,
569f2ba47e6SJeff LaBundy 		.label = "ATI compensation divider",
570f2ba47e6SJeff LaBundy 	},
571f2ba47e6SJeff LaBundy 	{
572f2ba47e6SJeff LaBundy 		.name = "azoteq,ati-comp-div",
573f2ba47e6SJeff LaBundy 		.reg_addr = {
574f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_ALP] = {
575f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x24,
576f2ba47e6SJeff LaBundy 			},
577f2ba47e6SJeff LaBundy 		},
578f2ba47e6SJeff LaBundy 		.reg_shift = 8,
579f2ba47e6SJeff LaBundy 		.reg_width = 8,
580f2ba47e6SJeff LaBundy 		.val_max = 31,
581f2ba47e6SJeff LaBundy 		.label = "ATI compensation divider",
582f2ba47e6SJeff LaBundy 	},
583f2ba47e6SJeff LaBundy 	{
584f2ba47e6SJeff LaBundy 		.name = "azoteq,ati-comp-div",
585f2ba47e6SJeff LaBundy 		.reg_addr = {
586f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_TP] = {
587f2ba47e6SJeff LaBundy 				[IQS7211A] = 0x31,
588f2ba47e6SJeff LaBundy 			},
589f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_ALP] = {
590f2ba47e6SJeff LaBundy 				[IQS7211A] = 0x37,
591f2ba47e6SJeff LaBundy 			},
592f2ba47e6SJeff LaBundy 		},
593f2ba47e6SJeff LaBundy 		.val_max = 31,
594f2ba47e6SJeff LaBundy 		.label = "ATI compensation divider",
595f2ba47e6SJeff LaBundy 	},
596f2ba47e6SJeff LaBundy 	{
597f2ba47e6SJeff LaBundy 		.name = "azoteq,ati-target",
598f2ba47e6SJeff LaBundy 		.reg_addr = {
599f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_TP] = {
600f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x20,
601f2ba47e6SJeff LaBundy 				[IQS7211A] = 0x32,
602f2ba47e6SJeff LaBundy 				[IQS7211E] = 0x23,
603f2ba47e6SJeff LaBundy 			},
604f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_BTN] = {
605f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x27,
606f2ba47e6SJeff LaBundy 			},
607f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_ALP] = {
608f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x28,
609f2ba47e6SJeff LaBundy 				[IQS7211A] = 0x38,
610f2ba47e6SJeff LaBundy 				[IQS7211E] = 0x27,
611f2ba47e6SJeff LaBundy 			},
612f2ba47e6SJeff LaBundy 		},
613f2ba47e6SJeff LaBundy 		.label = "ATI target",
614f2ba47e6SJeff LaBundy 	},
615f2ba47e6SJeff LaBundy 	{
616f2ba47e6SJeff LaBundy 		.name = "azoteq,ati-base",
617f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_ALP] = {
618f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x26,
619f2ba47e6SJeff LaBundy 		},
620f2ba47e6SJeff LaBundy 		.reg_shift = 8,
621f2ba47e6SJeff LaBundy 		.reg_width = 8,
622f2ba47e6SJeff LaBundy 		.val_pitch = 8,
623f2ba47e6SJeff LaBundy 		.label = "ATI base",
624f2ba47e6SJeff LaBundy 	},
625f2ba47e6SJeff LaBundy 	{
626f2ba47e6SJeff LaBundy 		.name = "azoteq,ati-base",
627f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_BTN] = {
628f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x26,
629f2ba47e6SJeff LaBundy 		},
630f2ba47e6SJeff LaBundy 		.reg_shift = 0,
631f2ba47e6SJeff LaBundy 		.reg_width = 8,
632f2ba47e6SJeff LaBundy 		.val_pitch = 8,
633f2ba47e6SJeff LaBundy 		.label = "ATI base",
634f2ba47e6SJeff LaBundy 	},
635f2ba47e6SJeff LaBundy 	{
636f2ba47e6SJeff LaBundy 		.name = "azoteq,rate-active-ms",
637f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
638f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x29,
639f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x40,
640f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x28,
641f2ba47e6SJeff LaBundy 		},
642f2ba47e6SJeff LaBundy 		.label = "active mode report rate",
643f2ba47e6SJeff LaBundy 	},
644f2ba47e6SJeff LaBundy 	{
645f2ba47e6SJeff LaBundy 		.name = "azoteq,rate-touch-ms",
646f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
647f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x2A,
648f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x41,
649f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x29,
650f2ba47e6SJeff LaBundy 		},
651f2ba47e6SJeff LaBundy 		.label = "idle-touch mode report rate",
652f2ba47e6SJeff LaBundy 	},
653f2ba47e6SJeff LaBundy 	{
654f2ba47e6SJeff LaBundy 		.name = "azoteq,rate-idle-ms",
655f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
656f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x2B,
657f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x42,
658f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x2A,
659f2ba47e6SJeff LaBundy 		},
660f2ba47e6SJeff LaBundy 		.label = "idle mode report rate",
661f2ba47e6SJeff LaBundy 	},
662f2ba47e6SJeff LaBundy 	{
663f2ba47e6SJeff LaBundy 		.name = "azoteq,rate-lp1-ms",
664f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
665f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x2C,
666f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x43,
667f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x2B,
668f2ba47e6SJeff LaBundy 		},
669f2ba47e6SJeff LaBundy 		.label = "low-power mode 1 report rate",
670f2ba47e6SJeff LaBundy 	},
671f2ba47e6SJeff LaBundy 	{
672f2ba47e6SJeff LaBundy 		.name = "azoteq,rate-lp2-ms",
673f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
674f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x2D,
675f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x44,
676f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x2C,
677f2ba47e6SJeff LaBundy 		},
678f2ba47e6SJeff LaBundy 		.label = "low-power mode 2 report rate",
679f2ba47e6SJeff LaBundy 	},
680f2ba47e6SJeff LaBundy 	{
681f2ba47e6SJeff LaBundy 		.name = "azoteq,timeout-active-ms",
682f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
683f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x2E,
684f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x45,
685f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x2D,
686f2ba47e6SJeff LaBundy 		},
687f2ba47e6SJeff LaBundy 		.val_pitch = 1000,
688f2ba47e6SJeff LaBundy 		.label = "active mode timeout",
689f2ba47e6SJeff LaBundy 	},
690f2ba47e6SJeff LaBundy 	{
691f2ba47e6SJeff LaBundy 		.name = "azoteq,timeout-touch-ms",
692f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
693f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x2F,
694f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x46,
695f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x2E,
696f2ba47e6SJeff LaBundy 		},
697f2ba47e6SJeff LaBundy 		.val_pitch = 1000,
698f2ba47e6SJeff LaBundy 		.label = "idle-touch mode timeout",
699f2ba47e6SJeff LaBundy 	},
700f2ba47e6SJeff LaBundy 	{
701f2ba47e6SJeff LaBundy 		.name = "azoteq,timeout-idle-ms",
702f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
703f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x30,
704f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x47,
705f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x2F,
706f2ba47e6SJeff LaBundy 		},
707f2ba47e6SJeff LaBundy 		.val_pitch = 1000,
708f2ba47e6SJeff LaBundy 		.label = "idle mode timeout",
709f2ba47e6SJeff LaBundy 	},
710f2ba47e6SJeff LaBundy 	{
711f2ba47e6SJeff LaBundy 		.name = "azoteq,timeout-lp1-ms",
712f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
713f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x31,
714f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x48,
715f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x30,
716f2ba47e6SJeff LaBundy 		},
717f2ba47e6SJeff LaBundy 		.val_pitch = 1000,
718f2ba47e6SJeff LaBundy 		.label = "low-power mode 1 timeout",
719f2ba47e6SJeff LaBundy 	},
720f2ba47e6SJeff LaBundy 	{
721f2ba47e6SJeff LaBundy 		.name = "azoteq,timeout-lp2-ms",
722f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
723f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x32,
724f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x31,
725f2ba47e6SJeff LaBundy 		},
726f2ba47e6SJeff LaBundy 		.reg_shift = 8,
727f2ba47e6SJeff LaBundy 		.reg_width = 8,
728f2ba47e6SJeff LaBundy 		.val_pitch = 1000,
729f2ba47e6SJeff LaBundy 		.val_max = 60000,
730f2ba47e6SJeff LaBundy 		.label = "trackpad reference value update rate",
731f2ba47e6SJeff LaBundy 	},
732f2ba47e6SJeff LaBundy 	{
733f2ba47e6SJeff LaBundy 		.name = "azoteq,timeout-lp2-ms",
734f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
735f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x49,
736f2ba47e6SJeff LaBundy 		},
737f2ba47e6SJeff LaBundy 		.val_pitch = 1000,
738f2ba47e6SJeff LaBundy 		.val_max = 60000,
739f2ba47e6SJeff LaBundy 		.label = "trackpad reference value update rate",
740f2ba47e6SJeff LaBundy 	},
741f2ba47e6SJeff LaBundy 	{
742f2ba47e6SJeff LaBundy 		.name = "azoteq,timeout-ati-ms",
743f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
744f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x32,
745f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x31,
746f2ba47e6SJeff LaBundy 		},
747f2ba47e6SJeff LaBundy 		.reg_width = 8,
748f2ba47e6SJeff LaBundy 		.val_pitch = 1000,
749f2ba47e6SJeff LaBundy 		.val_max = 60000,
750f2ba47e6SJeff LaBundy 		.label = "ATI error timeout",
751f2ba47e6SJeff LaBundy 	},
752f2ba47e6SJeff LaBundy 	{
753f2ba47e6SJeff LaBundy 		.name = "azoteq,timeout-ati-ms",
754f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
755f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x35,
756f2ba47e6SJeff LaBundy 		},
757f2ba47e6SJeff LaBundy 		.val_pitch = 1000,
758f2ba47e6SJeff LaBundy 		.val_max = 60000,
759f2ba47e6SJeff LaBundy 		.label = "ATI error timeout",
760f2ba47e6SJeff LaBundy 	},
761f2ba47e6SJeff LaBundy 	{
762f2ba47e6SJeff LaBundy 		.name = "azoteq,timeout-comms-ms",
763f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
764f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x33,
765f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x4A,
766f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x32,
767f2ba47e6SJeff LaBundy 		},
768f2ba47e6SJeff LaBundy 		.label = "communication timeout",
769f2ba47e6SJeff LaBundy 	},
770f2ba47e6SJeff LaBundy 	{
771f2ba47e6SJeff LaBundy 		.name = "azoteq,timeout-press-ms",
772f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
773f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x34,
774f2ba47e6SJeff LaBundy 		},
775f2ba47e6SJeff LaBundy 		.reg_width = 8,
776f2ba47e6SJeff LaBundy 		.val_pitch = 1000,
777f2ba47e6SJeff LaBundy 		.val_max = 60000,
778f2ba47e6SJeff LaBundy 		.label = "press timeout",
779f2ba47e6SJeff LaBundy 	},
780f2ba47e6SJeff LaBundy 	{
781f2ba47e6SJeff LaBundy 		.name = "azoteq,ati-mode",
782f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_ALP] = {
783f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x37,
784f2ba47e6SJeff LaBundy 		},
785f2ba47e6SJeff LaBundy 		.reg_shift = 15,
786f2ba47e6SJeff LaBundy 		.reg_width = 1,
787f2ba47e6SJeff LaBundy 		.label = "ATI mode",
788f2ba47e6SJeff LaBundy 	},
789f2ba47e6SJeff LaBundy 	{
790f2ba47e6SJeff LaBundy 		.name = "azoteq,ati-mode",
791f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_BTN] = {
792f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x37,
793f2ba47e6SJeff LaBundy 		},
794f2ba47e6SJeff LaBundy 		.reg_shift = 7,
795f2ba47e6SJeff LaBundy 		.reg_width = 1,
796f2ba47e6SJeff LaBundy 		.label = "ATI mode",
797f2ba47e6SJeff LaBundy 	},
798f2ba47e6SJeff LaBundy 	{
799f2ba47e6SJeff LaBundy 		.name = "azoteq,sense-mode",
800f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_ALP] = {
801f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x37,
802f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x72,
803f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x36,
804f2ba47e6SJeff LaBundy 		},
805f2ba47e6SJeff LaBundy 		.reg_shift = 8,
806f2ba47e6SJeff LaBundy 		.reg_width = 1,
807f2ba47e6SJeff LaBundy 		.label = "sensing mode",
808f2ba47e6SJeff LaBundy 	},
809f2ba47e6SJeff LaBundy 	{
810f2ba47e6SJeff LaBundy 		.name = "azoteq,sense-mode",
811f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_BTN] = {
812f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x37,
813f2ba47e6SJeff LaBundy 		},
814f2ba47e6SJeff LaBundy 		.reg_shift = 0,
815f2ba47e6SJeff LaBundy 		.reg_width = 2,
816f2ba47e6SJeff LaBundy 		.val_max = 2,
817f2ba47e6SJeff LaBundy 		.label = "sensing mode",
818f2ba47e6SJeff LaBundy 	},
819f2ba47e6SJeff LaBundy 	{
820f2ba47e6SJeff LaBundy 		.name = "azoteq,fosc-freq",
821f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
822f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x38,
823f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x52,
824f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x35,
825f2ba47e6SJeff LaBundy 		},
826f2ba47e6SJeff LaBundy 		.reg_shift = 4,
827f2ba47e6SJeff LaBundy 		.reg_width = 1,
828f2ba47e6SJeff LaBundy 		.label = "core clock frequency selection",
829f2ba47e6SJeff LaBundy 	},
830f2ba47e6SJeff LaBundy 	{
831f2ba47e6SJeff LaBundy 		.name = "azoteq,fosc-trim",
832f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
833f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x38,
834f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x52,
835f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x35,
836f2ba47e6SJeff LaBundy 		},
837f2ba47e6SJeff LaBundy 		.reg_shift = 0,
838f2ba47e6SJeff LaBundy 		.reg_width = 4,
839f2ba47e6SJeff LaBundy 		.label = "core clock frequency trim",
840f2ba47e6SJeff LaBundy 	},
841f2ba47e6SJeff LaBundy 	{
842f2ba47e6SJeff LaBundy 		.name = "azoteq,touch-exit",
843f2ba47e6SJeff LaBundy 		.reg_addr = {
844f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_TP] = {
845f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x3B,
846f2ba47e6SJeff LaBundy 				[IQS7211A] = 0x53,
847f2ba47e6SJeff LaBundy 				[IQS7211E] = 0x38,
848f2ba47e6SJeff LaBundy 			},
849f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_BTN] = {
850f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x3E,
851f2ba47e6SJeff LaBundy 			},
852f2ba47e6SJeff LaBundy 		},
853f2ba47e6SJeff LaBundy 		.reg_shift = 8,
854f2ba47e6SJeff LaBundy 		.reg_width = 8,
855f2ba47e6SJeff LaBundy 		.label = "touch exit factor",
856f2ba47e6SJeff LaBundy 	},
857f2ba47e6SJeff LaBundy 	{
858f2ba47e6SJeff LaBundy 		.name = "azoteq,touch-enter",
859f2ba47e6SJeff LaBundy 		.reg_addr = {
860f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_TP] = {
861f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x3B,
862f2ba47e6SJeff LaBundy 				[IQS7211A] = 0x53,
863f2ba47e6SJeff LaBundy 				[IQS7211E] = 0x38,
864f2ba47e6SJeff LaBundy 			},
865f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_BTN] = {
866f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x3E,
867f2ba47e6SJeff LaBundy 			},
868f2ba47e6SJeff LaBundy 		},
869f2ba47e6SJeff LaBundy 		.reg_shift = 0,
870f2ba47e6SJeff LaBundy 		.reg_width = 8,
871f2ba47e6SJeff LaBundy 		.label = "touch entrance factor",
872f2ba47e6SJeff LaBundy 	},
873f2ba47e6SJeff LaBundy 	{
874f2ba47e6SJeff LaBundy 		.name = "azoteq,thresh",
875f2ba47e6SJeff LaBundy 		.reg_addr = {
876f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_BTN] = {
877f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x3C,
878f2ba47e6SJeff LaBundy 			},
879f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_ALP] = {
880f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x3D,
881f2ba47e6SJeff LaBundy 				[IQS7211A] = 0x54,
882f2ba47e6SJeff LaBundy 				[IQS7211E] = 0x39,
883f2ba47e6SJeff LaBundy 			},
884f2ba47e6SJeff LaBundy 		},
885f2ba47e6SJeff LaBundy 		.label = "threshold",
886f2ba47e6SJeff LaBundy 	},
887f2ba47e6SJeff LaBundy 	{
888f2ba47e6SJeff LaBundy 		.name = "azoteq,debounce-exit",
889f2ba47e6SJeff LaBundy 		.reg_addr = {
890f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_BTN] = {
891f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x3F,
892f2ba47e6SJeff LaBundy 			},
893f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_ALP] = {
894f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x40,
895f2ba47e6SJeff LaBundy 				[IQS7211A] = 0x56,
896f2ba47e6SJeff LaBundy 				[IQS7211E] = 0x3A,
897f2ba47e6SJeff LaBundy 			},
898f2ba47e6SJeff LaBundy 		},
899f2ba47e6SJeff LaBundy 		.reg_shift = 8,
900f2ba47e6SJeff LaBundy 		.reg_width = 8,
901f2ba47e6SJeff LaBundy 		.label = "debounce exit factor",
902f2ba47e6SJeff LaBundy 	},
903f2ba47e6SJeff LaBundy 	{
904f2ba47e6SJeff LaBundy 		.name = "azoteq,debounce-enter",
905f2ba47e6SJeff LaBundy 		.reg_addr = {
906f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_BTN] = {
907f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x3F,
908f2ba47e6SJeff LaBundy 			},
909f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_ALP] = {
910f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x40,
911f2ba47e6SJeff LaBundy 				[IQS7211A] = 0x56,
912f2ba47e6SJeff LaBundy 				[IQS7211E] = 0x3A,
913f2ba47e6SJeff LaBundy 			},
914f2ba47e6SJeff LaBundy 		},
915f2ba47e6SJeff LaBundy 		.reg_shift = 0,
916f2ba47e6SJeff LaBundy 		.reg_width = 8,
917f2ba47e6SJeff LaBundy 		.label = "debounce entrance factor",
918f2ba47e6SJeff LaBundy 	},
919f2ba47e6SJeff LaBundy 	{
920f2ba47e6SJeff LaBundy 		.name = "azoteq,conv-frac",
921f2ba47e6SJeff LaBundy 		.reg_addr = {
922f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_TP] = {
923f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x48,
924f2ba47e6SJeff LaBundy 				[IQS7211A] = 0x58,
925f2ba47e6SJeff LaBundy 				[IQS7211E] = 0x3D,
926f2ba47e6SJeff LaBundy 			},
927f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_BTN] = {
928f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x49,
929f2ba47e6SJeff LaBundy 			},
930f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_ALP] = {
931f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x4A,
932f2ba47e6SJeff LaBundy 				[IQS7211A] = 0x59,
933f2ba47e6SJeff LaBundy 				[IQS7211E] = 0x3E,
934f2ba47e6SJeff LaBundy 			},
935f2ba47e6SJeff LaBundy 		},
936f2ba47e6SJeff LaBundy 		.reg_shift = 8,
937f2ba47e6SJeff LaBundy 		.reg_width = 8,
938f2ba47e6SJeff LaBundy 		.label = "conversion frequency fractional divider",
939f2ba47e6SJeff LaBundy 	},
940f2ba47e6SJeff LaBundy 	{
941f2ba47e6SJeff LaBundy 		.name = "azoteq,conv-period",
942f2ba47e6SJeff LaBundy 		.reg_addr = {
943f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_TP] = {
944f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x48,
945f2ba47e6SJeff LaBundy 				[IQS7211A] = 0x58,
946f2ba47e6SJeff LaBundy 				[IQS7211E] = 0x3D,
947f2ba47e6SJeff LaBundy 			},
948f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_BTN] = {
949f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x49,
950f2ba47e6SJeff LaBundy 			},
951f2ba47e6SJeff LaBundy 			[IQS7211_REG_GRP_ALP] = {
952f2ba47e6SJeff LaBundy 				[IQS7210A] = 0x4A,
953f2ba47e6SJeff LaBundy 				[IQS7211A] = 0x59,
954f2ba47e6SJeff LaBundy 				[IQS7211E] = 0x3E,
955f2ba47e6SJeff LaBundy 			},
956f2ba47e6SJeff LaBundy 		},
957f2ba47e6SJeff LaBundy 		.reg_shift = 0,
958f2ba47e6SJeff LaBundy 		.reg_width = 8,
959f2ba47e6SJeff LaBundy 		.label = "conversion period",
960f2ba47e6SJeff LaBundy 	},
961f2ba47e6SJeff LaBundy 	{
962f2ba47e6SJeff LaBundy 		.name = "azoteq,thresh",
963f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_TP] = {
964f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x55,
965f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x67,
966f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x48,
967f2ba47e6SJeff LaBundy 		},
968f2ba47e6SJeff LaBundy 		.reg_shift = 0,
969f2ba47e6SJeff LaBundy 		.reg_width = 8,
970f2ba47e6SJeff LaBundy 		.label = "threshold",
971f2ba47e6SJeff LaBundy 	},
972f2ba47e6SJeff LaBundy 	{
973f2ba47e6SJeff LaBundy 		.name = "azoteq,contact-split",
974f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
975f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x55,
976f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x67,
977f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x48,
978f2ba47e6SJeff LaBundy 		},
979f2ba47e6SJeff LaBundy 		.reg_shift = 8,
980f2ba47e6SJeff LaBundy 		.reg_width = 8,
981f2ba47e6SJeff LaBundy 		.label = "contact split factor",
982f2ba47e6SJeff LaBundy 	},
983f2ba47e6SJeff LaBundy 	{
984f2ba47e6SJeff LaBundy 		.name = "azoteq,trim-x",
985f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
986f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x56,
987f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x49,
988f2ba47e6SJeff LaBundy 		},
989f2ba47e6SJeff LaBundy 		.reg_shift = 0,
990f2ba47e6SJeff LaBundy 		.reg_width = 8,
991f2ba47e6SJeff LaBundy 		.label = "horizontal trim width",
992f2ba47e6SJeff LaBundy 	},
993f2ba47e6SJeff LaBundy 	{
994f2ba47e6SJeff LaBundy 		.name = "azoteq,trim-x",
995f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
996f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x68,
997f2ba47e6SJeff LaBundy 		},
998f2ba47e6SJeff LaBundy 		.label = "horizontal trim width",
999f2ba47e6SJeff LaBundy 	},
1000f2ba47e6SJeff LaBundy 	{
1001f2ba47e6SJeff LaBundy 		.name = "azoteq,trim-y",
1002f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
1003f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x56,
1004f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x49,
1005f2ba47e6SJeff LaBundy 		},
1006f2ba47e6SJeff LaBundy 		.reg_shift = 8,
1007f2ba47e6SJeff LaBundy 		.reg_width = 8,
1008f2ba47e6SJeff LaBundy 		.label = "vertical trim height",
1009f2ba47e6SJeff LaBundy 	},
1010f2ba47e6SJeff LaBundy 	{
1011f2ba47e6SJeff LaBundy 		.name = "azoteq,trim-y",
1012f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_SYS] = {
1013f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x69,
1014f2ba47e6SJeff LaBundy 		},
1015f2ba47e6SJeff LaBundy 		.label = "vertical trim height",
1016f2ba47e6SJeff LaBundy 	},
1017f2ba47e6SJeff LaBundy 	{
1018f2ba47e6SJeff LaBundy 		.name = "azoteq,gesture-max-ms",
1019f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_TAP,
1020f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_TP] = {
1021f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x59,
1022f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x81,
1023f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x4C,
1024f2ba47e6SJeff LaBundy 		},
1025f2ba47e6SJeff LaBundy 		.label = "maximum gesture time",
1026f2ba47e6SJeff LaBundy 	},
1027f2ba47e6SJeff LaBundy 	{
1028f2ba47e6SJeff LaBundy 		.name = "azoteq,gesture-mid-ms",
1029f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_TAP,
1030f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_TP] = {
1031f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x4D,
1032f2ba47e6SJeff LaBundy 		},
1033f2ba47e6SJeff LaBundy 		.label = "repeated gesture time",
1034f2ba47e6SJeff LaBundy 	},
1035f2ba47e6SJeff LaBundy 	{
1036f2ba47e6SJeff LaBundy 		.name = "azoteq,gesture-dist",
1037f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_TAP,
1038f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_TP] = {
1039f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x5A,
1040f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x82,
1041f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x4E,
1042f2ba47e6SJeff LaBundy 		},
1043f2ba47e6SJeff LaBundy 		.label = "gesture distance",
1044f2ba47e6SJeff LaBundy 	},
1045f2ba47e6SJeff LaBundy 	{
1046f2ba47e6SJeff LaBundy 		.name = "azoteq,gesture-dist",
1047f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_HOLD,
1048f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_TP] = {
1049f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x5A,
1050f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x82,
1051f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x4E,
1052f2ba47e6SJeff LaBundy 		},
1053f2ba47e6SJeff LaBundy 		.label = "gesture distance",
1054f2ba47e6SJeff LaBundy 	},
1055f2ba47e6SJeff LaBundy 	{
1056f2ba47e6SJeff LaBundy 		.name = "azoteq,gesture-min-ms",
1057f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_HOLD,
1058f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_TP] = {
1059f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x5B,
1060f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x83,
1061f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x4F,
1062f2ba47e6SJeff LaBundy 		},
1063f2ba47e6SJeff LaBundy 		.label = "minimum gesture time",
1064f2ba47e6SJeff LaBundy 	},
1065f2ba47e6SJeff LaBundy 	{
1066f2ba47e6SJeff LaBundy 		.name = "azoteq,gesture-max-ms",
1067f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_AXIAL_X,
1068f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_TP] = {
1069f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x5C,
1070f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x84,
1071f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x50,
1072f2ba47e6SJeff LaBundy 		},
1073f2ba47e6SJeff LaBundy 		.label = "maximum gesture time",
1074f2ba47e6SJeff LaBundy 	},
1075f2ba47e6SJeff LaBundy 	{
1076f2ba47e6SJeff LaBundy 		.name = "azoteq,gesture-max-ms",
1077f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_AXIAL_Y,
1078f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_TP] = {
1079f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x5C,
1080f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x84,
1081f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x50,
1082f2ba47e6SJeff LaBundy 		},
1083f2ba47e6SJeff LaBundy 		.label = "maximum gesture time",
1084f2ba47e6SJeff LaBundy 	},
1085f2ba47e6SJeff LaBundy 	{
1086f2ba47e6SJeff LaBundy 		.name = "azoteq,gesture-dist",
1087f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_AXIAL_X,
1088f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_TP] = {
1089f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x5D,
1090f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x85,
1091f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x51,
1092f2ba47e6SJeff LaBundy 		},
1093f2ba47e6SJeff LaBundy 		.label = "gesture distance",
1094f2ba47e6SJeff LaBundy 	},
1095f2ba47e6SJeff LaBundy 	{
1096f2ba47e6SJeff LaBundy 		.name = "azoteq,gesture-dist",
1097f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_AXIAL_Y,
1098f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_TP] = {
1099f2ba47e6SJeff LaBundy 			[IQS7210A] = 0x5E,
1100f2ba47e6SJeff LaBundy 			[IQS7211A] = 0x86,
1101f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x52,
1102f2ba47e6SJeff LaBundy 		},
1103f2ba47e6SJeff LaBundy 		.label = "gesture distance",
1104f2ba47e6SJeff LaBundy 	},
1105f2ba47e6SJeff LaBundy 	{
1106f2ba47e6SJeff LaBundy 		.name = "azoteq,gesture-dist-rep",
1107f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_AXIAL_X,
1108f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_TP] = {
1109f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x53,
1110f2ba47e6SJeff LaBundy 		},
1111f2ba47e6SJeff LaBundy 		.label = "repeated gesture distance",
1112f2ba47e6SJeff LaBundy 	},
1113f2ba47e6SJeff LaBundy 	{
1114f2ba47e6SJeff LaBundy 		.name = "azoteq,gesture-dist-rep",
1115f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_AXIAL_Y,
1116f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_TP] = {
1117f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x54,
1118f2ba47e6SJeff LaBundy 		},
1119f2ba47e6SJeff LaBundy 		.label = "repeated gesture distance",
1120f2ba47e6SJeff LaBundy 	},
1121f2ba47e6SJeff LaBundy 	{
1122f2ba47e6SJeff LaBundy 		.name = "azoteq,thresh",
1123f2ba47e6SJeff LaBundy 		.reg_key = IQS7211_REG_KEY_PALM,
1124f2ba47e6SJeff LaBundy 		.reg_addr[IQS7211_REG_GRP_TP] = {
1125f2ba47e6SJeff LaBundy 			[IQS7211E] = 0x55,
1126f2ba47e6SJeff LaBundy 		},
1127f2ba47e6SJeff LaBundy 		.reg_shift = 8,
1128f2ba47e6SJeff LaBundy 		.reg_width = 8,
1129f2ba47e6SJeff LaBundy 		.val_max = 42,
1130f2ba47e6SJeff LaBundy 		.label = "threshold",
1131f2ba47e6SJeff LaBundy 	},
1132f2ba47e6SJeff LaBundy };
1133f2ba47e6SJeff LaBundy 
1134f2ba47e6SJeff LaBundy static const u8 iqs7211_gesture_angle[] = {
1135f2ba47e6SJeff LaBundy 	0x00, 0x01, 0x02, 0x03,
1136f2ba47e6SJeff LaBundy 	0x04, 0x06, 0x07, 0x08,
1137f2ba47e6SJeff LaBundy 	0x09, 0x0A, 0x0B, 0x0C,
1138f2ba47e6SJeff LaBundy 	0x0E, 0x0F, 0x10, 0x11,
1139f2ba47e6SJeff LaBundy 	0x12, 0x14, 0x15, 0x16,
1140f2ba47e6SJeff LaBundy 	0x17, 0x19, 0x1A, 0x1B,
1141f2ba47e6SJeff LaBundy 	0x1C, 0x1E, 0x1F, 0x21,
1142f2ba47e6SJeff LaBundy 	0x22, 0x23, 0x25, 0x26,
1143f2ba47e6SJeff LaBundy 	0x28, 0x2A, 0x2B, 0x2D,
1144f2ba47e6SJeff LaBundy 	0x2E, 0x30, 0x32, 0x34,
1145f2ba47e6SJeff LaBundy 	0x36, 0x38, 0x3A, 0x3C,
1146f2ba47e6SJeff LaBundy 	0x3E, 0x40, 0x42, 0x45,
1147f2ba47e6SJeff LaBundy 	0x47, 0x4A, 0x4C, 0x4F,
1148f2ba47e6SJeff LaBundy 	0x52, 0x55, 0x58, 0x5B,
1149f2ba47e6SJeff LaBundy 	0x5F, 0x63, 0x66, 0x6B,
1150f2ba47e6SJeff LaBundy 	0x6F, 0x73, 0x78, 0x7E,
1151f2ba47e6SJeff LaBundy 	0x83, 0x89, 0x90, 0x97,
1152f2ba47e6SJeff LaBundy 	0x9E, 0xA7, 0xB0, 0xBA,
1153f2ba47e6SJeff LaBundy 	0xC5, 0xD1, 0xDF, 0xEF,
1154f2ba47e6SJeff LaBundy };
1155f2ba47e6SJeff LaBundy 
1156f2ba47e6SJeff LaBundy struct iqs7211_ver_info {
1157f2ba47e6SJeff LaBundy 	__le16 prod_num;
1158f2ba47e6SJeff LaBundy 	__le16 major;
1159f2ba47e6SJeff LaBundy 	__le16 minor;
1160f2ba47e6SJeff LaBundy 	__le32 patch;
1161f2ba47e6SJeff LaBundy } __packed;
1162f2ba47e6SJeff LaBundy 
1163f2ba47e6SJeff LaBundy struct iqs7211_touch_data {
1164f2ba47e6SJeff LaBundy 	__le16 abs_x;
1165f2ba47e6SJeff LaBundy 	__le16 abs_y;
1166f2ba47e6SJeff LaBundy 	__le16 pressure;
1167f2ba47e6SJeff LaBundy 	__le16 area;
1168f2ba47e6SJeff LaBundy } __packed;
1169f2ba47e6SJeff LaBundy 
1170f2ba47e6SJeff LaBundy struct iqs7211_tp_config {
1171f2ba47e6SJeff LaBundy 	u8 tp_settings;
1172f2ba47e6SJeff LaBundy 	u8 total_rx;
1173f2ba47e6SJeff LaBundy 	u8 total_tx;
1174f2ba47e6SJeff LaBundy 	u8 num_contacts;
1175f2ba47e6SJeff LaBundy 	__le16 max_x;
1176f2ba47e6SJeff LaBundy 	__le16 max_y;
1177f2ba47e6SJeff LaBundy } __packed;
1178f2ba47e6SJeff LaBundy 
1179f2ba47e6SJeff LaBundy struct iqs7211_private {
1180f2ba47e6SJeff LaBundy 	const struct iqs7211_dev_desc *dev_desc;
1181f2ba47e6SJeff LaBundy 	struct gpio_desc *reset_gpio;
1182f2ba47e6SJeff LaBundy 	struct gpio_desc *irq_gpio;
1183f2ba47e6SJeff LaBundy 	struct i2c_client *client;
1184f2ba47e6SJeff LaBundy 	struct input_dev *tp_idev;
1185f2ba47e6SJeff LaBundy 	struct input_dev *kp_idev;
1186f2ba47e6SJeff LaBundy 	struct iqs7211_ver_info ver_info;
1187f2ba47e6SJeff LaBundy 	struct iqs7211_tp_config tp_config;
1188f2ba47e6SJeff LaBundy 	struct touchscreen_properties prop;
1189f2ba47e6SJeff LaBundy 	struct list_head reg_field_head;
1190f2ba47e6SJeff LaBundy 	enum iqs7211_comms_mode comms_init;
1191f2ba47e6SJeff LaBundy 	enum iqs7211_comms_mode comms_mode;
1192f2ba47e6SJeff LaBundy 	unsigned int num_contacts;
1193f2ba47e6SJeff LaBundy 	unsigned int kp_code[ARRAY_SIZE(iqs7211e_kp_events)];
1194f2ba47e6SJeff LaBundy 	u8 rx_tx_map[IQS7211_MAX_CTX + 1];
1195f2ba47e6SJeff LaBundy 	u8 cycle_alloc[2][33];
1196f2ba47e6SJeff LaBundy 	u8 exp_file[2];
1197f2ba47e6SJeff LaBundy 	u16 event_mask;
1198f2ba47e6SJeff LaBundy 	u16 ati_start;
1199f2ba47e6SJeff LaBundy 	u16 gesture_cache;
1200f2ba47e6SJeff LaBundy };
1201f2ba47e6SJeff LaBundy 
iqs7211_irq_poll(struct iqs7211_private * iqs7211,u64 timeout_us)1202f2ba47e6SJeff LaBundy static int iqs7211_irq_poll(struct iqs7211_private *iqs7211, u64 timeout_us)
1203f2ba47e6SJeff LaBundy {
1204f2ba47e6SJeff LaBundy 	int error, val;
1205f2ba47e6SJeff LaBundy 
1206f2ba47e6SJeff LaBundy 	error = readx_poll_timeout(gpiod_get_value_cansleep, iqs7211->irq_gpio,
1207f2ba47e6SJeff LaBundy 				   val, val, IQS7211_COMMS_SLEEP_US, timeout_us);
1208f2ba47e6SJeff LaBundy 
1209f2ba47e6SJeff LaBundy 	return val < 0 ? val : error;
1210f2ba47e6SJeff LaBundy }
1211f2ba47e6SJeff LaBundy 
iqs7211_hard_reset(struct iqs7211_private * iqs7211)1212f2ba47e6SJeff LaBundy static int iqs7211_hard_reset(struct iqs7211_private *iqs7211)
1213f2ba47e6SJeff LaBundy {
1214f2ba47e6SJeff LaBundy 	if (!iqs7211->reset_gpio)
1215f2ba47e6SJeff LaBundy 		return 0;
1216f2ba47e6SJeff LaBundy 
1217f2ba47e6SJeff LaBundy 	gpiod_set_value_cansleep(iqs7211->reset_gpio, 1);
1218f2ba47e6SJeff LaBundy 
1219f2ba47e6SJeff LaBundy 	/*
1220f2ba47e6SJeff LaBundy 	 * The following delay ensures the shared RDY/MCLR pin is sampled in
1221f2ba47e6SJeff LaBundy 	 * between periodic assertions by the device and assumes the default
1222f2ba47e6SJeff LaBundy 	 * communication timeout has not been overwritten in OTP memory.
1223f2ba47e6SJeff LaBundy 	 */
1224f2ba47e6SJeff LaBundy 	if (iqs7211->reset_gpio == iqs7211->irq_gpio)
1225f2ba47e6SJeff LaBundy 		msleep(IQS7211_RESET_TIMEOUT_MS);
1226f2ba47e6SJeff LaBundy 	else
1227f2ba47e6SJeff LaBundy 		usleep_range(1000, 1100);
1228f2ba47e6SJeff LaBundy 
1229f2ba47e6SJeff LaBundy 	gpiod_set_value_cansleep(iqs7211->reset_gpio, 0);
1230f2ba47e6SJeff LaBundy 	if (iqs7211->reset_gpio == iqs7211->irq_gpio)
1231f2ba47e6SJeff LaBundy 		iqs7211_irq_wait();
1232f2ba47e6SJeff LaBundy 
1233f2ba47e6SJeff LaBundy 	return iqs7211_irq_poll(iqs7211, IQS7211_START_TIMEOUT_US);
1234f2ba47e6SJeff LaBundy }
1235f2ba47e6SJeff LaBundy 
iqs7211_force_comms(struct iqs7211_private * iqs7211)1236f2ba47e6SJeff LaBundy static int iqs7211_force_comms(struct iqs7211_private *iqs7211)
1237f2ba47e6SJeff LaBundy {
1238f2ba47e6SJeff LaBundy 	u8 msg_buf[] = { 0xFF, };
1239f2ba47e6SJeff LaBundy 	int ret;
1240f2ba47e6SJeff LaBundy 
1241f2ba47e6SJeff LaBundy 	switch (iqs7211->comms_mode) {
1242f2ba47e6SJeff LaBundy 	case IQS7211_COMMS_MODE_WAIT:
1243f2ba47e6SJeff LaBundy 		return iqs7211_irq_poll(iqs7211, IQS7211_START_TIMEOUT_US);
1244f2ba47e6SJeff LaBundy 
1245f2ba47e6SJeff LaBundy 	case IQS7211_COMMS_MODE_FREE:
1246f2ba47e6SJeff LaBundy 		return 0;
1247f2ba47e6SJeff LaBundy 
1248f2ba47e6SJeff LaBundy 	case IQS7211_COMMS_MODE_FORCE:
1249f2ba47e6SJeff LaBundy 		break;
1250f2ba47e6SJeff LaBundy 
1251f2ba47e6SJeff LaBundy 	default:
1252f2ba47e6SJeff LaBundy 		return -EINVAL;
1253f2ba47e6SJeff LaBundy 	}
1254f2ba47e6SJeff LaBundy 
1255f2ba47e6SJeff LaBundy 	/*
1256f2ba47e6SJeff LaBundy 	 * The device cannot communicate until it asserts its interrupt (RDY)
1257f2ba47e6SJeff LaBundy 	 * pin. Attempts to do so while RDY is deasserted return an ACK; how-
1258f2ba47e6SJeff LaBundy 	 * ever all write data is ignored, and all read data returns 0xEE.
1259f2ba47e6SJeff LaBundy 	 *
1260f2ba47e6SJeff LaBundy 	 * Unsolicited communication must be preceded by a special force com-
1261f2ba47e6SJeff LaBundy 	 * munication command, after which the device eventually asserts its
1262f2ba47e6SJeff LaBundy 	 * RDY pin and agrees to communicate.
1263f2ba47e6SJeff LaBundy 	 *
1264f2ba47e6SJeff LaBundy 	 * Regardless of whether communication is forced or the result of an
1265f2ba47e6SJeff LaBundy 	 * interrupt, the device automatically deasserts its RDY pin once it
1266f2ba47e6SJeff LaBundy 	 * detects an I2C stop condition, or a timeout expires.
1267f2ba47e6SJeff LaBundy 	 */
1268f2ba47e6SJeff LaBundy 	ret = gpiod_get_value_cansleep(iqs7211->irq_gpio);
1269f2ba47e6SJeff LaBundy 	if (ret < 0)
1270f2ba47e6SJeff LaBundy 		return ret;
1271f2ba47e6SJeff LaBundy 	else if (ret > 0)
1272f2ba47e6SJeff LaBundy 		return 0;
1273f2ba47e6SJeff LaBundy 
1274f2ba47e6SJeff LaBundy 	ret = i2c_master_send(iqs7211->client, msg_buf, sizeof(msg_buf));
1275f2ba47e6SJeff LaBundy 	if (ret < (int)sizeof(msg_buf)) {
1276f2ba47e6SJeff LaBundy 		if (ret >= 0)
1277f2ba47e6SJeff LaBundy 			ret = -EIO;
1278f2ba47e6SJeff LaBundy 
1279f2ba47e6SJeff LaBundy 		msleep(IQS7211_COMMS_RETRY_MS);
1280f2ba47e6SJeff LaBundy 		return ret;
1281f2ba47e6SJeff LaBundy 	}
1282f2ba47e6SJeff LaBundy 
1283f2ba47e6SJeff LaBundy 	iqs7211_irq_wait();
1284f2ba47e6SJeff LaBundy 
1285f2ba47e6SJeff LaBundy 	return iqs7211_irq_poll(iqs7211, IQS7211_COMMS_TIMEOUT_US);
1286f2ba47e6SJeff LaBundy }
1287f2ba47e6SJeff LaBundy 
iqs7211_read_burst(struct iqs7211_private * iqs7211,u8 reg,void * val,u16 val_len)1288f2ba47e6SJeff LaBundy static int iqs7211_read_burst(struct iqs7211_private *iqs7211,
1289f2ba47e6SJeff LaBundy 			      u8 reg, void *val, u16 val_len)
1290f2ba47e6SJeff LaBundy {
1291f2ba47e6SJeff LaBundy 	int ret, i;
1292f2ba47e6SJeff LaBundy 	struct i2c_client *client = iqs7211->client;
1293f2ba47e6SJeff LaBundy 	struct i2c_msg msg[] = {
1294f2ba47e6SJeff LaBundy 		{
1295f2ba47e6SJeff LaBundy 			.addr = client->addr,
1296f2ba47e6SJeff LaBundy 			.flags = 0,
1297f2ba47e6SJeff LaBundy 			.len = sizeof(reg),
1298f2ba47e6SJeff LaBundy 			.buf = &reg,
1299f2ba47e6SJeff LaBundy 		},
1300f2ba47e6SJeff LaBundy 		{
1301f2ba47e6SJeff LaBundy 			.addr = client->addr,
1302f2ba47e6SJeff LaBundy 			.flags = I2C_M_RD,
1303f2ba47e6SJeff LaBundy 			.len = val_len,
1304f2ba47e6SJeff LaBundy 			.buf = (u8 *)val,
1305f2ba47e6SJeff LaBundy 		},
1306f2ba47e6SJeff LaBundy 	};
1307f2ba47e6SJeff LaBundy 
1308f2ba47e6SJeff LaBundy 	/*
1309f2ba47e6SJeff LaBundy 	 * The following loop protects against an edge case in which the RDY
1310f2ba47e6SJeff LaBundy 	 * pin is automatically deasserted just as the read is initiated. In
1311f2ba47e6SJeff LaBundy 	 * that case, the read must be retried using forced communication.
1312f2ba47e6SJeff LaBundy 	 */
1313f2ba47e6SJeff LaBundy 	for (i = 0; i < IQS7211_NUM_RETRIES; i++) {
1314f2ba47e6SJeff LaBundy 		ret = iqs7211_force_comms(iqs7211);
1315f2ba47e6SJeff LaBundy 		if (ret < 0)
1316f2ba47e6SJeff LaBundy 			continue;
1317f2ba47e6SJeff LaBundy 
1318f2ba47e6SJeff LaBundy 		ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
1319f2ba47e6SJeff LaBundy 		if (ret < (int)ARRAY_SIZE(msg)) {
1320f2ba47e6SJeff LaBundy 			if (ret >= 0)
1321f2ba47e6SJeff LaBundy 				ret = -EIO;
1322f2ba47e6SJeff LaBundy 
1323f2ba47e6SJeff LaBundy 			msleep(IQS7211_COMMS_RETRY_MS);
1324f2ba47e6SJeff LaBundy 			continue;
1325f2ba47e6SJeff LaBundy 		}
1326f2ba47e6SJeff LaBundy 
1327f2ba47e6SJeff LaBundy 		if (get_unaligned_le16(msg[1].buf) == IQS7211_COMMS_ERROR) {
1328f2ba47e6SJeff LaBundy 			ret = -ENODATA;
1329f2ba47e6SJeff LaBundy 			continue;
1330f2ba47e6SJeff LaBundy 		}
1331f2ba47e6SJeff LaBundy 
1332f2ba47e6SJeff LaBundy 		ret = 0;
1333f2ba47e6SJeff LaBundy 		break;
1334f2ba47e6SJeff LaBundy 	}
1335f2ba47e6SJeff LaBundy 
1336f2ba47e6SJeff LaBundy 	iqs7211_irq_wait();
1337f2ba47e6SJeff LaBundy 
1338f2ba47e6SJeff LaBundy 	if (ret < 0)
1339f2ba47e6SJeff LaBundy 		dev_err(&client->dev,
1340f2ba47e6SJeff LaBundy 			"Failed to read from address 0x%02X: %d\n", reg, ret);
1341f2ba47e6SJeff LaBundy 
1342f2ba47e6SJeff LaBundy 	return ret;
1343f2ba47e6SJeff LaBundy }
1344f2ba47e6SJeff LaBundy 
iqs7211_read_word(struct iqs7211_private * iqs7211,u8 reg,u16 * val)1345f2ba47e6SJeff LaBundy static int iqs7211_read_word(struct iqs7211_private *iqs7211, u8 reg, u16 *val)
1346f2ba47e6SJeff LaBundy {
1347f2ba47e6SJeff LaBundy 	__le16 val_buf;
1348f2ba47e6SJeff LaBundy 	int error;
1349f2ba47e6SJeff LaBundy 
1350f2ba47e6SJeff LaBundy 	error = iqs7211_read_burst(iqs7211, reg, &val_buf, sizeof(val_buf));
1351f2ba47e6SJeff LaBundy 	if (error)
1352f2ba47e6SJeff LaBundy 		return error;
1353f2ba47e6SJeff LaBundy 
1354f2ba47e6SJeff LaBundy 	*val = le16_to_cpu(val_buf);
1355f2ba47e6SJeff LaBundy 
1356f2ba47e6SJeff LaBundy 	return 0;
1357f2ba47e6SJeff LaBundy }
1358f2ba47e6SJeff LaBundy 
iqs7211_write_burst(struct iqs7211_private * iqs7211,u8 reg,const void * val,u16 val_len)1359f2ba47e6SJeff LaBundy static int iqs7211_write_burst(struct iqs7211_private *iqs7211,
1360f2ba47e6SJeff LaBundy 			       u8 reg, const void *val, u16 val_len)
1361f2ba47e6SJeff LaBundy {
1362f2ba47e6SJeff LaBundy 	int msg_len = sizeof(reg) + val_len;
1363f2ba47e6SJeff LaBundy 	int ret, i;
1364f2ba47e6SJeff LaBundy 	struct i2c_client *client = iqs7211->client;
1365f2ba47e6SJeff LaBundy 	u8 *msg_buf;
1366f2ba47e6SJeff LaBundy 
1367f2ba47e6SJeff LaBundy 	msg_buf = kzalloc(msg_len, GFP_KERNEL);
1368f2ba47e6SJeff LaBundy 	if (!msg_buf)
1369f2ba47e6SJeff LaBundy 		return -ENOMEM;
1370f2ba47e6SJeff LaBundy 
1371f2ba47e6SJeff LaBundy 	*msg_buf = reg;
1372f2ba47e6SJeff LaBundy 	memcpy(msg_buf + sizeof(reg), val, val_len);
1373f2ba47e6SJeff LaBundy 
1374f2ba47e6SJeff LaBundy 	/*
1375f2ba47e6SJeff LaBundy 	 * The following loop protects against an edge case in which the RDY
1376f2ba47e6SJeff LaBundy 	 * pin is automatically asserted just before the force communication
1377f2ba47e6SJeff LaBundy 	 * command is sent.
1378f2ba47e6SJeff LaBundy 	 *
1379f2ba47e6SJeff LaBundy 	 * In that case, the subsequent I2C stop condition tricks the device
1380f2ba47e6SJeff LaBundy 	 * into preemptively deasserting the RDY pin and the command must be
1381f2ba47e6SJeff LaBundy 	 * sent again.
1382f2ba47e6SJeff LaBundy 	 */
1383f2ba47e6SJeff LaBundy 	for (i = 0; i < IQS7211_NUM_RETRIES; i++) {
1384f2ba47e6SJeff LaBundy 		ret = iqs7211_force_comms(iqs7211);
1385f2ba47e6SJeff LaBundy 		if (ret < 0)
1386f2ba47e6SJeff LaBundy 			continue;
1387f2ba47e6SJeff LaBundy 
1388f2ba47e6SJeff LaBundy 		ret = i2c_master_send(client, msg_buf, msg_len);
1389f2ba47e6SJeff LaBundy 		if (ret < msg_len) {
1390f2ba47e6SJeff LaBundy 			if (ret >= 0)
1391f2ba47e6SJeff LaBundy 				ret = -EIO;
1392f2ba47e6SJeff LaBundy 
1393f2ba47e6SJeff LaBundy 			msleep(IQS7211_COMMS_RETRY_MS);
1394f2ba47e6SJeff LaBundy 			continue;
1395f2ba47e6SJeff LaBundy 		}
1396f2ba47e6SJeff LaBundy 
1397f2ba47e6SJeff LaBundy 		ret = 0;
1398f2ba47e6SJeff LaBundy 		break;
1399f2ba47e6SJeff LaBundy 	}
1400f2ba47e6SJeff LaBundy 
1401f2ba47e6SJeff LaBundy 	kfree(msg_buf);
1402f2ba47e6SJeff LaBundy 
1403f2ba47e6SJeff LaBundy 	iqs7211_irq_wait();
1404f2ba47e6SJeff LaBundy 
1405f2ba47e6SJeff LaBundy 	if (ret < 0)
1406f2ba47e6SJeff LaBundy 		dev_err(&client->dev,
1407f2ba47e6SJeff LaBundy 			"Failed to write to address 0x%02X: %d\n", reg, ret);
1408f2ba47e6SJeff LaBundy 
1409f2ba47e6SJeff LaBundy 	return ret;
1410f2ba47e6SJeff LaBundy }
1411f2ba47e6SJeff LaBundy 
iqs7211_write_word(struct iqs7211_private * iqs7211,u8 reg,u16 val)1412f2ba47e6SJeff LaBundy static int iqs7211_write_word(struct iqs7211_private *iqs7211, u8 reg, u16 val)
1413f2ba47e6SJeff LaBundy {
1414f2ba47e6SJeff LaBundy 	__le16 val_buf = cpu_to_le16(val);
1415f2ba47e6SJeff LaBundy 
1416f2ba47e6SJeff LaBundy 	return iqs7211_write_burst(iqs7211, reg, &val_buf, sizeof(val_buf));
1417f2ba47e6SJeff LaBundy }
1418f2ba47e6SJeff LaBundy 
iqs7211_start_comms(struct iqs7211_private * iqs7211)1419f2ba47e6SJeff LaBundy static int iqs7211_start_comms(struct iqs7211_private *iqs7211)
1420f2ba47e6SJeff LaBundy {
1421f2ba47e6SJeff LaBundy 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
1422f2ba47e6SJeff LaBundy 	struct i2c_client *client = iqs7211->client;
1423f2ba47e6SJeff LaBundy 	bool forced_comms;
1424f2ba47e6SJeff LaBundy 	unsigned int val;
1425f2ba47e6SJeff LaBundy 	u16 comms_setup;
1426f2ba47e6SJeff LaBundy 	int error;
1427f2ba47e6SJeff LaBundy 
1428f2ba47e6SJeff LaBundy 	/*
1429f2ba47e6SJeff LaBundy 	 * Until forced communication can be enabled, the host must wait for a
1430f2ba47e6SJeff LaBundy 	 * communication window each time it intends to elicit a response from
1431f2ba47e6SJeff LaBundy 	 * the device.
1432f2ba47e6SJeff LaBundy 	 *
1433f2ba47e6SJeff LaBundy 	 * Forced communication is not necessary, however, if the host adapter
1434f2ba47e6SJeff LaBundy 	 * can support clock stretching. In that case, the device freely clock
1435f2ba47e6SJeff LaBundy 	 * stretches until all pending conversions are complete.
1436f2ba47e6SJeff LaBundy 	 */
1437f2ba47e6SJeff LaBundy 	forced_comms = device_property_present(&client->dev,
1438f2ba47e6SJeff LaBundy 					       "azoteq,forced-comms");
1439f2ba47e6SJeff LaBundy 
1440f2ba47e6SJeff LaBundy 	error = device_property_read_u32(&client->dev,
1441f2ba47e6SJeff LaBundy 					 "azoteq,forced-comms-default", &val);
1442f2ba47e6SJeff LaBundy 	if (error == -EINVAL) {
1443f2ba47e6SJeff LaBundy 		iqs7211->comms_init = IQS7211_COMMS_MODE_WAIT;
1444f2ba47e6SJeff LaBundy 	} else if (error) {
1445f2ba47e6SJeff LaBundy 		dev_err(&client->dev,
1446f2ba47e6SJeff LaBundy 			"Failed to read default communication mode: %d\n",
1447f2ba47e6SJeff LaBundy 			error);
1448f2ba47e6SJeff LaBundy 		return error;
1449f2ba47e6SJeff LaBundy 	} else if (val) {
1450f2ba47e6SJeff LaBundy 		iqs7211->comms_init = forced_comms ? IQS7211_COMMS_MODE_FORCE
1451f2ba47e6SJeff LaBundy 						   : IQS7211_COMMS_MODE_WAIT;
1452f2ba47e6SJeff LaBundy 	} else {
1453f2ba47e6SJeff LaBundy 		iqs7211->comms_init = forced_comms ? IQS7211_COMMS_MODE_WAIT
1454f2ba47e6SJeff LaBundy 						   : IQS7211_COMMS_MODE_FREE;
1455f2ba47e6SJeff LaBundy 	}
1456f2ba47e6SJeff LaBundy 
1457f2ba47e6SJeff LaBundy 	iqs7211->comms_mode = iqs7211->comms_init;
1458f2ba47e6SJeff LaBundy 
1459f2ba47e6SJeff LaBundy 	error = iqs7211_hard_reset(iqs7211);
1460f2ba47e6SJeff LaBundy 	if (error) {
1461f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Failed to reset device: %d\n", error);
1462f2ba47e6SJeff LaBundy 		return error;
1463f2ba47e6SJeff LaBundy 	}
1464f2ba47e6SJeff LaBundy 
1465f2ba47e6SJeff LaBundy 	error = iqs7211_read_burst(iqs7211, IQS7211_PROD_NUM,
1466f2ba47e6SJeff LaBundy 				   &iqs7211->ver_info,
1467f2ba47e6SJeff LaBundy 				   sizeof(iqs7211->ver_info));
1468f2ba47e6SJeff LaBundy 	if (error)
1469f2ba47e6SJeff LaBundy 		return error;
1470f2ba47e6SJeff LaBundy 
1471f2ba47e6SJeff LaBundy 	if (le16_to_cpu(iqs7211->ver_info.prod_num) != dev_desc->prod_num) {
1472f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Invalid product number: %u\n",
1473f2ba47e6SJeff LaBundy 			le16_to_cpu(iqs7211->ver_info.prod_num));
1474f2ba47e6SJeff LaBundy 		return -EINVAL;
1475f2ba47e6SJeff LaBundy 	}
1476f2ba47e6SJeff LaBundy 
1477f2ba47e6SJeff LaBundy 	error = iqs7211_read_word(iqs7211, dev_desc->sys_ctrl + 1,
1478f2ba47e6SJeff LaBundy 				  &comms_setup);
1479f2ba47e6SJeff LaBundy 	if (error)
1480f2ba47e6SJeff LaBundy 		return error;
1481f2ba47e6SJeff LaBundy 
1482f2ba47e6SJeff LaBundy 	if (forced_comms)
1483f2ba47e6SJeff LaBundy 		comms_setup |= dev_desc->comms_req;
1484f2ba47e6SJeff LaBundy 	else
1485f2ba47e6SJeff LaBundy 		comms_setup &= ~dev_desc->comms_req;
1486f2ba47e6SJeff LaBundy 
1487f2ba47e6SJeff LaBundy 	error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl + 1,
1488f2ba47e6SJeff LaBundy 				   comms_setup | dev_desc->comms_end);
1489f2ba47e6SJeff LaBundy 	if (error)
1490f2ba47e6SJeff LaBundy 		return error;
1491f2ba47e6SJeff LaBundy 
1492f2ba47e6SJeff LaBundy 	if (forced_comms)
1493f2ba47e6SJeff LaBundy 		iqs7211->comms_mode = IQS7211_COMMS_MODE_FORCE;
1494f2ba47e6SJeff LaBundy 	else
1495f2ba47e6SJeff LaBundy 		iqs7211->comms_mode = IQS7211_COMMS_MODE_FREE;
1496f2ba47e6SJeff LaBundy 
1497f2ba47e6SJeff LaBundy 	error = iqs7211_read_burst(iqs7211, dev_desc->exp_file,
1498f2ba47e6SJeff LaBundy 				   iqs7211->exp_file,
1499f2ba47e6SJeff LaBundy 				   sizeof(iqs7211->exp_file));
1500f2ba47e6SJeff LaBundy 	if (error)
1501f2ba47e6SJeff LaBundy 		return error;
1502f2ba47e6SJeff LaBundy 
1503f2ba47e6SJeff LaBundy 	error = iqs7211_read_burst(iqs7211, dev_desc->tp_config,
1504f2ba47e6SJeff LaBundy 				   &iqs7211->tp_config,
1505f2ba47e6SJeff LaBundy 				   sizeof(iqs7211->tp_config));
1506f2ba47e6SJeff LaBundy 	if (error)
1507f2ba47e6SJeff LaBundy 		return error;
1508f2ba47e6SJeff LaBundy 
1509f2ba47e6SJeff LaBundy 	error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl + 1,
1510f2ba47e6SJeff LaBundy 				   comms_setup);
1511f2ba47e6SJeff LaBundy 	if (error)
1512f2ba47e6SJeff LaBundy 		return error;
1513f2ba47e6SJeff LaBundy 
1514f2ba47e6SJeff LaBundy 	iqs7211->event_mask = comms_setup & ~IQS7211_EVENT_MASK_ALL;
1515f2ba47e6SJeff LaBundy 	iqs7211->event_mask |= (IQS7211_EVENT_MASK_ATI | IQS7211_EVENT_MODE);
1516f2ba47e6SJeff LaBundy 
1517f2ba47e6SJeff LaBundy 	return 0;
1518f2ba47e6SJeff LaBundy }
1519f2ba47e6SJeff LaBundy 
iqs7211_init_device(struct iqs7211_private * iqs7211)1520f2ba47e6SJeff LaBundy static int iqs7211_init_device(struct iqs7211_private *iqs7211)
1521f2ba47e6SJeff LaBundy {
1522f2ba47e6SJeff LaBundy 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
1523f2ba47e6SJeff LaBundy 	struct iqs7211_reg_field_desc *reg_field;
1524f2ba47e6SJeff LaBundy 	__le16 sys_ctrl[] = {
1525f2ba47e6SJeff LaBundy 		cpu_to_le16(dev_desc->ack_reset),
1526f2ba47e6SJeff LaBundy 		cpu_to_le16(iqs7211->event_mask),
1527f2ba47e6SJeff LaBundy 	};
1528f2ba47e6SJeff LaBundy 	int error, i;
1529f2ba47e6SJeff LaBundy 
1530f2ba47e6SJeff LaBundy 	/*
1531f2ba47e6SJeff LaBundy 	 * Acknowledge reset before writing any registers in case the device
1532f2ba47e6SJeff LaBundy 	 * suffers a spurious reset during initialization. The communication
1533f2ba47e6SJeff LaBundy 	 * mode is configured at this time as well.
1534f2ba47e6SJeff LaBundy 	 */
1535f2ba47e6SJeff LaBundy 	error = iqs7211_write_burst(iqs7211, dev_desc->sys_ctrl, sys_ctrl,
1536f2ba47e6SJeff LaBundy 				    sizeof(sys_ctrl));
1537f2ba47e6SJeff LaBundy 	if (error)
1538f2ba47e6SJeff LaBundy 		return error;
1539f2ba47e6SJeff LaBundy 
1540f2ba47e6SJeff LaBundy 	if (iqs7211->event_mask & dev_desc->comms_req)
1541f2ba47e6SJeff LaBundy 		iqs7211->comms_mode = IQS7211_COMMS_MODE_FORCE;
1542f2ba47e6SJeff LaBundy 	else
1543f2ba47e6SJeff LaBundy 		iqs7211->comms_mode = IQS7211_COMMS_MODE_FREE;
1544f2ba47e6SJeff LaBundy 
1545f2ba47e6SJeff LaBundy 	/*
1546f2ba47e6SJeff LaBundy 	 * Take advantage of the stop-bit disable function, if available, to
1547f2ba47e6SJeff LaBundy 	 * save the trouble of having to reopen a communication window after
1548f2ba47e6SJeff LaBundy 	 * each read or write.
1549f2ba47e6SJeff LaBundy 	 */
1550f2ba47e6SJeff LaBundy 	error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl + 1,
1551f2ba47e6SJeff LaBundy 				   iqs7211->event_mask | dev_desc->comms_end);
1552f2ba47e6SJeff LaBundy 	if (error)
1553f2ba47e6SJeff LaBundy 		return error;
1554f2ba47e6SJeff LaBundy 
1555f2ba47e6SJeff LaBundy 	list_for_each_entry(reg_field, &iqs7211->reg_field_head, list) {
1556f2ba47e6SJeff LaBundy 		u16 new_val = reg_field->val;
1557f2ba47e6SJeff LaBundy 
1558f2ba47e6SJeff LaBundy 		if (reg_field->mask < U16_MAX) {
1559f2ba47e6SJeff LaBundy 			u16 old_val;
1560f2ba47e6SJeff LaBundy 
1561f2ba47e6SJeff LaBundy 			error = iqs7211_read_word(iqs7211, reg_field->addr,
1562f2ba47e6SJeff LaBundy 						  &old_val);
1563f2ba47e6SJeff LaBundy 			if (error)
1564f2ba47e6SJeff LaBundy 				return error;
1565f2ba47e6SJeff LaBundy 
1566f2ba47e6SJeff LaBundy 			new_val = old_val & ~reg_field->mask;
1567f2ba47e6SJeff LaBundy 			new_val |= reg_field->val;
1568f2ba47e6SJeff LaBundy 
1569f2ba47e6SJeff LaBundy 			if (new_val == old_val)
1570f2ba47e6SJeff LaBundy 				continue;
1571f2ba47e6SJeff LaBundy 		}
1572f2ba47e6SJeff LaBundy 
1573f2ba47e6SJeff LaBundy 		error = iqs7211_write_word(iqs7211, reg_field->addr, new_val);
1574f2ba47e6SJeff LaBundy 		if (error)
1575f2ba47e6SJeff LaBundy 			return error;
1576f2ba47e6SJeff LaBundy 	}
1577f2ba47e6SJeff LaBundy 
1578f2ba47e6SJeff LaBundy 	error = iqs7211_write_burst(iqs7211, dev_desc->tp_config,
1579f2ba47e6SJeff LaBundy 				    &iqs7211->tp_config,
1580f2ba47e6SJeff LaBundy 				    sizeof(iqs7211->tp_config));
1581f2ba47e6SJeff LaBundy 	if (error)
1582f2ba47e6SJeff LaBundy 		return error;
1583f2ba47e6SJeff LaBundy 
1584f2ba47e6SJeff LaBundy 	if (**iqs7211->cycle_alloc) {
1585f2ba47e6SJeff LaBundy 		error = iqs7211_write_burst(iqs7211, dev_desc->rx_tx_map,
1586f2ba47e6SJeff LaBundy 					    &iqs7211->rx_tx_map,
1587f2ba47e6SJeff LaBundy 					    dev_desc->num_ctx);
1588f2ba47e6SJeff LaBundy 		if (error)
1589f2ba47e6SJeff LaBundy 			return error;
1590f2ba47e6SJeff LaBundy 
1591f2ba47e6SJeff LaBundy 		for (i = 0; i < sizeof(dev_desc->cycle_limit); i++) {
1592f2ba47e6SJeff LaBundy 			error = iqs7211_write_burst(iqs7211,
1593f2ba47e6SJeff LaBundy 						    dev_desc->cycle_alloc[i],
1594f2ba47e6SJeff LaBundy 						    iqs7211->cycle_alloc[i],
1595f2ba47e6SJeff LaBundy 						    dev_desc->cycle_limit[i] * 3);
1596f2ba47e6SJeff LaBundy 			if (error)
1597f2ba47e6SJeff LaBundy 				return error;
1598f2ba47e6SJeff LaBundy 		}
1599f2ba47e6SJeff LaBundy 	}
1600f2ba47e6SJeff LaBundy 
1601f2ba47e6SJeff LaBundy 	*sys_ctrl = cpu_to_le16(iqs7211->ati_start);
1602f2ba47e6SJeff LaBundy 
1603f2ba47e6SJeff LaBundy 	return iqs7211_write_burst(iqs7211, dev_desc->sys_ctrl, sys_ctrl,
1604f2ba47e6SJeff LaBundy 				   sizeof(sys_ctrl));
1605f2ba47e6SJeff LaBundy }
1606f2ba47e6SJeff LaBundy 
iqs7211_add_field(struct iqs7211_private * iqs7211,struct iqs7211_reg_field_desc new_field)1607f2ba47e6SJeff LaBundy static int iqs7211_add_field(struct iqs7211_private *iqs7211,
1608f2ba47e6SJeff LaBundy 			     struct iqs7211_reg_field_desc new_field)
1609f2ba47e6SJeff LaBundy {
1610f2ba47e6SJeff LaBundy 	struct i2c_client *client = iqs7211->client;
1611f2ba47e6SJeff LaBundy 	struct iqs7211_reg_field_desc *reg_field;
1612f2ba47e6SJeff LaBundy 
1613f2ba47e6SJeff LaBundy 	if (!new_field.addr)
1614f2ba47e6SJeff LaBundy 		return 0;
1615f2ba47e6SJeff LaBundy 
1616f2ba47e6SJeff LaBundy 	list_for_each_entry(reg_field, &iqs7211->reg_field_head, list) {
1617f2ba47e6SJeff LaBundy 		if (reg_field->addr != new_field.addr)
1618f2ba47e6SJeff LaBundy 			continue;
1619f2ba47e6SJeff LaBundy 
1620f2ba47e6SJeff LaBundy 		reg_field->mask |= new_field.mask;
1621f2ba47e6SJeff LaBundy 		reg_field->val |= new_field.val;
1622f2ba47e6SJeff LaBundy 		return 0;
1623f2ba47e6SJeff LaBundy 	}
1624f2ba47e6SJeff LaBundy 
1625f2ba47e6SJeff LaBundy 	reg_field = devm_kzalloc(&client->dev, sizeof(*reg_field), GFP_KERNEL);
1626f2ba47e6SJeff LaBundy 	if (!reg_field)
1627f2ba47e6SJeff LaBundy 		return -ENOMEM;
1628f2ba47e6SJeff LaBundy 
1629f2ba47e6SJeff LaBundy 	reg_field->addr = new_field.addr;
1630f2ba47e6SJeff LaBundy 	reg_field->mask = new_field.mask;
1631f2ba47e6SJeff LaBundy 	reg_field->val = new_field.val;
1632f2ba47e6SJeff LaBundy 
1633f2ba47e6SJeff LaBundy 	list_add(&reg_field->list, &iqs7211->reg_field_head);
1634f2ba47e6SJeff LaBundy 
1635f2ba47e6SJeff LaBundy 	return 0;
1636f2ba47e6SJeff LaBundy }
1637f2ba47e6SJeff LaBundy 
iqs7211_parse_props(struct iqs7211_private * iqs7211,struct fwnode_handle * reg_grp_node,enum iqs7211_reg_grp_id reg_grp,enum iqs7211_reg_key_id reg_key)1638f2ba47e6SJeff LaBundy static int iqs7211_parse_props(struct iqs7211_private *iqs7211,
1639f2ba47e6SJeff LaBundy 			       struct fwnode_handle *reg_grp_node,
1640f2ba47e6SJeff LaBundy 			       enum iqs7211_reg_grp_id reg_grp,
1641f2ba47e6SJeff LaBundy 			       enum iqs7211_reg_key_id reg_key)
1642f2ba47e6SJeff LaBundy {
1643f2ba47e6SJeff LaBundy 	struct i2c_client *client = iqs7211->client;
1644f2ba47e6SJeff LaBundy 	int i;
1645f2ba47e6SJeff LaBundy 
1646f2ba47e6SJeff LaBundy 	for (i = 0; i < ARRAY_SIZE(iqs7211_props); i++) {
1647f2ba47e6SJeff LaBundy 		const char *name = iqs7211_props[i].name;
1648f2ba47e6SJeff LaBundy 		u8 reg_addr = iqs7211_props[i].reg_addr[reg_grp]
1649f2ba47e6SJeff LaBundy 						       [iqs7211->dev_desc -
1650f2ba47e6SJeff LaBundy 							iqs7211_devs];
1651f2ba47e6SJeff LaBundy 		int reg_shift = iqs7211_props[i].reg_shift;
1652f2ba47e6SJeff LaBundy 		int reg_width = iqs7211_props[i].reg_width ? : 16;
1653f2ba47e6SJeff LaBundy 		int val_pitch = iqs7211_props[i].val_pitch ? : 1;
1654f2ba47e6SJeff LaBundy 		int val_min = iqs7211_props[i].val_min;
1655f2ba47e6SJeff LaBundy 		int val_max = iqs7211_props[i].val_max;
1656f2ba47e6SJeff LaBundy 		const char *label = iqs7211_props[i].label ? : name;
1657f2ba47e6SJeff LaBundy 		struct iqs7211_reg_field_desc reg_field;
1658f2ba47e6SJeff LaBundy 		unsigned int val;
1659f2ba47e6SJeff LaBundy 		int error;
1660f2ba47e6SJeff LaBundy 
1661f2ba47e6SJeff LaBundy 		if (iqs7211_props[i].reg_key != reg_key)
1662f2ba47e6SJeff LaBundy 			continue;
1663f2ba47e6SJeff LaBundy 
1664f2ba47e6SJeff LaBundy 		if (!reg_addr)
1665f2ba47e6SJeff LaBundy 			continue;
1666f2ba47e6SJeff LaBundy 
1667f2ba47e6SJeff LaBundy 		error = fwnode_property_read_u32(reg_grp_node, name, &val);
1668f2ba47e6SJeff LaBundy 		if (error == -EINVAL) {
1669f2ba47e6SJeff LaBundy 			continue;
1670f2ba47e6SJeff LaBundy 		} else if (error) {
1671f2ba47e6SJeff LaBundy 			dev_err(&client->dev, "Failed to read %s %s: %d\n",
1672f2ba47e6SJeff LaBundy 				fwnode_get_name(reg_grp_node), label, error);
1673f2ba47e6SJeff LaBundy 			return error;
1674f2ba47e6SJeff LaBundy 		}
1675f2ba47e6SJeff LaBundy 
1676f2ba47e6SJeff LaBundy 		if (!val_max)
1677f2ba47e6SJeff LaBundy 			val_max = GENMASK(reg_width - 1, 0) * val_pitch;
1678f2ba47e6SJeff LaBundy 
1679f2ba47e6SJeff LaBundy 		if (val < val_min || val > val_max) {
1680f2ba47e6SJeff LaBundy 			dev_err(&client->dev, "Invalid %s: %u\n", label, val);
1681f2ba47e6SJeff LaBundy 			return -EINVAL;
1682f2ba47e6SJeff LaBundy 		}
1683f2ba47e6SJeff LaBundy 
1684f2ba47e6SJeff LaBundy 		reg_field.addr = reg_addr;
1685f2ba47e6SJeff LaBundy 		reg_field.mask = GENMASK(reg_shift + reg_width - 1, reg_shift);
1686f2ba47e6SJeff LaBundy 		reg_field.val = val / val_pitch << reg_shift;
1687f2ba47e6SJeff LaBundy 
1688f2ba47e6SJeff LaBundy 		error = iqs7211_add_field(iqs7211, reg_field);
1689f2ba47e6SJeff LaBundy 		if (error)
1690f2ba47e6SJeff LaBundy 			return error;
1691f2ba47e6SJeff LaBundy 	}
1692f2ba47e6SJeff LaBundy 
1693f2ba47e6SJeff LaBundy 	return 0;
1694f2ba47e6SJeff LaBundy }
1695f2ba47e6SJeff LaBundy 
iqs7211_parse_event(struct iqs7211_private * iqs7211,struct fwnode_handle * event_node,enum iqs7211_reg_grp_id reg_grp,enum iqs7211_reg_key_id reg_key,unsigned int * event_code)1696f2ba47e6SJeff LaBundy static int iqs7211_parse_event(struct iqs7211_private *iqs7211,
1697f2ba47e6SJeff LaBundy 			       struct fwnode_handle *event_node,
1698f2ba47e6SJeff LaBundy 			       enum iqs7211_reg_grp_id reg_grp,
1699f2ba47e6SJeff LaBundy 			       enum iqs7211_reg_key_id reg_key,
1700f2ba47e6SJeff LaBundy 			       unsigned int *event_code)
1701f2ba47e6SJeff LaBundy {
1702f2ba47e6SJeff LaBundy 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
1703f2ba47e6SJeff LaBundy 	struct i2c_client *client = iqs7211->client;
1704f2ba47e6SJeff LaBundy 	struct iqs7211_reg_field_desc reg_field;
1705f2ba47e6SJeff LaBundy 	unsigned int val;
1706f2ba47e6SJeff LaBundy 	int error;
1707f2ba47e6SJeff LaBundy 
1708f2ba47e6SJeff LaBundy 	error = iqs7211_parse_props(iqs7211, event_node, reg_grp, reg_key);
1709f2ba47e6SJeff LaBundy 	if (error)
1710f2ba47e6SJeff LaBundy 		return error;
1711f2ba47e6SJeff LaBundy 
1712f2ba47e6SJeff LaBundy 	if (reg_key == IQS7211_REG_KEY_AXIAL_X ||
1713f2ba47e6SJeff LaBundy 	    reg_key == IQS7211_REG_KEY_AXIAL_Y) {
1714f2ba47e6SJeff LaBundy 		error = fwnode_property_read_u32(event_node,
1715f2ba47e6SJeff LaBundy 						 "azoteq,gesture-angle", &val);
1716f2ba47e6SJeff LaBundy 		if (!error) {
1717f2ba47e6SJeff LaBundy 			if (val >= ARRAY_SIZE(iqs7211_gesture_angle)) {
1718f2ba47e6SJeff LaBundy 				dev_err(&client->dev,
1719f2ba47e6SJeff LaBundy 					"Invalid %s gesture angle: %u\n",
1720f2ba47e6SJeff LaBundy 					fwnode_get_name(event_node), val);
1721f2ba47e6SJeff LaBundy 				return -EINVAL;
1722f2ba47e6SJeff LaBundy 			}
1723f2ba47e6SJeff LaBundy 
1724f2ba47e6SJeff LaBundy 			reg_field.addr = dev_desc->gesture_angle;
1725f2ba47e6SJeff LaBundy 			reg_field.mask = U8_MAX;
1726f2ba47e6SJeff LaBundy 			reg_field.val = iqs7211_gesture_angle[val];
1727f2ba47e6SJeff LaBundy 
1728f2ba47e6SJeff LaBundy 			error = iqs7211_add_field(iqs7211, reg_field);
1729f2ba47e6SJeff LaBundy 			if (error)
1730f2ba47e6SJeff LaBundy 				return error;
1731f2ba47e6SJeff LaBundy 		} else if (error != -EINVAL) {
1732f2ba47e6SJeff LaBundy 			dev_err(&client->dev,
1733f2ba47e6SJeff LaBundy 				"Failed to read %s gesture angle: %d\n",
1734f2ba47e6SJeff LaBundy 				fwnode_get_name(event_node), error);
1735f2ba47e6SJeff LaBundy 			return error;
1736f2ba47e6SJeff LaBundy 		}
1737f2ba47e6SJeff LaBundy 	}
1738f2ba47e6SJeff LaBundy 
1739f2ba47e6SJeff LaBundy 	error = fwnode_property_read_u32(event_node, "linux,code", event_code);
1740f2ba47e6SJeff LaBundy 	if (error == -EINVAL)
1741f2ba47e6SJeff LaBundy 		error = 0;
1742f2ba47e6SJeff LaBundy 	else if (error)
1743f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Failed to read %s code: %d\n",
1744f2ba47e6SJeff LaBundy 			fwnode_get_name(event_node), error);
1745f2ba47e6SJeff LaBundy 
1746f2ba47e6SJeff LaBundy 	return error;
1747f2ba47e6SJeff LaBundy }
1748f2ba47e6SJeff LaBundy 
iqs7211_parse_cycles(struct iqs7211_private * iqs7211,struct fwnode_handle * tp_node)1749f2ba47e6SJeff LaBundy static int iqs7211_parse_cycles(struct iqs7211_private *iqs7211,
1750f2ba47e6SJeff LaBundy 				struct fwnode_handle *tp_node)
1751f2ba47e6SJeff LaBundy {
1752f2ba47e6SJeff LaBundy 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
1753f2ba47e6SJeff LaBundy 	struct i2c_client *client = iqs7211->client;
1754f2ba47e6SJeff LaBundy 	int num_cycles = dev_desc->cycle_limit[0] + dev_desc->cycle_limit[1];
1755f2ba47e6SJeff LaBundy 	int error, count, i, j, k, cycle_start;
1756f2ba47e6SJeff LaBundy 	unsigned int cycle_alloc[IQS7211_MAX_CYCLES][2];
1757f2ba47e6SJeff LaBundy 	u8 total_rx = iqs7211->tp_config.total_rx;
1758f2ba47e6SJeff LaBundy 	u8 total_tx = iqs7211->tp_config.total_tx;
1759f2ba47e6SJeff LaBundy 
1760f2ba47e6SJeff LaBundy 	for (i = 0; i < IQS7211_MAX_CYCLES * 2; i++)
1761f2ba47e6SJeff LaBundy 		*(cycle_alloc[0] + i) = U8_MAX;
1762f2ba47e6SJeff LaBundy 
1763f2ba47e6SJeff LaBundy 	count = fwnode_property_count_u32(tp_node, "azoteq,channel-select");
1764f2ba47e6SJeff LaBundy 	if (count == -EINVAL) {
1765f2ba47e6SJeff LaBundy 		/*
1766f2ba47e6SJeff LaBundy 		 * Assign each sensing cycle's slots (0 and 1) to a channel,
1767f2ba47e6SJeff LaBundy 		 * defined as the intersection between two CRx and CTx pins.
1768f2ba47e6SJeff LaBundy 		 * A channel assignment of 255 means the slot is unused.
1769f2ba47e6SJeff LaBundy 		 */
1770f2ba47e6SJeff LaBundy 		for (i = 0, cycle_start = 0; i < total_tx; i++) {
1771f2ba47e6SJeff LaBundy 			int cycle_stop = 0;
1772f2ba47e6SJeff LaBundy 
1773f2ba47e6SJeff LaBundy 			for (j = 0; j < total_rx; j++) {
1774f2ba47e6SJeff LaBundy 				/*
1775f2ba47e6SJeff LaBundy 				 * Channels formed by CRx0-3 and CRx4-7 are
1776f2ba47e6SJeff LaBundy 				 * bound to slots 0 and 1, respectively.
1777f2ba47e6SJeff LaBundy 				 */
1778f2ba47e6SJeff LaBundy 				int slot = iqs7211->rx_tx_map[j] < 4 ? 0 : 1;
1779f2ba47e6SJeff LaBundy 				int chan = i * total_rx + j;
1780f2ba47e6SJeff LaBundy 
1781f2ba47e6SJeff LaBundy 				for (k = cycle_start; k < num_cycles; k++) {
1782f2ba47e6SJeff LaBundy 					if (cycle_alloc[k][slot] < U8_MAX)
1783f2ba47e6SJeff LaBundy 						continue;
1784f2ba47e6SJeff LaBundy 
1785f2ba47e6SJeff LaBundy 					cycle_alloc[k][slot] = chan;
1786f2ba47e6SJeff LaBundy 					break;
1787f2ba47e6SJeff LaBundy 				}
1788f2ba47e6SJeff LaBundy 
1789f2ba47e6SJeff LaBundy 				if (k < num_cycles) {
1790f2ba47e6SJeff LaBundy 					cycle_stop = max(k, cycle_stop);
1791f2ba47e6SJeff LaBundy 					continue;
1792f2ba47e6SJeff LaBundy 				}
1793f2ba47e6SJeff LaBundy 
1794f2ba47e6SJeff LaBundy 				dev_err(&client->dev,
1795f2ba47e6SJeff LaBundy 					"Insufficient number of cycles\n");
1796f2ba47e6SJeff LaBundy 				return -EINVAL;
1797f2ba47e6SJeff LaBundy 			}
1798f2ba47e6SJeff LaBundy 
1799f2ba47e6SJeff LaBundy 			/*
1800f2ba47e6SJeff LaBundy 			 * Sensing cycles cannot straddle more than one CTx
1801f2ba47e6SJeff LaBundy 			 * pin. As such, the next row's starting cycle must
1802f2ba47e6SJeff LaBundy 			 * be greater than the previous row's highest cycle.
1803f2ba47e6SJeff LaBundy 			 */
1804f2ba47e6SJeff LaBundy 			cycle_start = cycle_stop + 1;
1805f2ba47e6SJeff LaBundy 		}
1806f2ba47e6SJeff LaBundy 	} else if (count < 0) {
1807f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Failed to count channels: %d\n", count);
1808f2ba47e6SJeff LaBundy 		return count;
1809f2ba47e6SJeff LaBundy 	} else if (count > num_cycles * 2) {
1810f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Insufficient number of cycles\n");
1811f2ba47e6SJeff LaBundy 		return -EINVAL;
1812f2ba47e6SJeff LaBundy 	} else if (count > 0) {
1813f2ba47e6SJeff LaBundy 		error = fwnode_property_read_u32_array(tp_node,
1814f2ba47e6SJeff LaBundy 						       "azoteq,channel-select",
1815f2ba47e6SJeff LaBundy 						       cycle_alloc[0], count);
1816f2ba47e6SJeff LaBundy 		if (error) {
1817f2ba47e6SJeff LaBundy 			dev_err(&client->dev, "Failed to read channels: %d\n",
1818f2ba47e6SJeff LaBundy 				error);
1819f2ba47e6SJeff LaBundy 			return error;
1820f2ba47e6SJeff LaBundy 		}
1821f2ba47e6SJeff LaBundy 
1822f2ba47e6SJeff LaBundy 		for (i = 0; i < count; i++) {
1823f2ba47e6SJeff LaBundy 			int chan = *(cycle_alloc[0] + i);
1824f2ba47e6SJeff LaBundy 
1825f2ba47e6SJeff LaBundy 			if (chan == U8_MAX)
1826f2ba47e6SJeff LaBundy 				continue;
1827f2ba47e6SJeff LaBundy 
1828f2ba47e6SJeff LaBundy 			if (chan >= total_rx * total_tx) {
1829f2ba47e6SJeff LaBundy 				dev_err(&client->dev, "Invalid channel: %d\n",
1830f2ba47e6SJeff LaBundy 					chan);
1831f2ba47e6SJeff LaBundy 				return -EINVAL;
1832f2ba47e6SJeff LaBundy 			}
1833f2ba47e6SJeff LaBundy 
1834f2ba47e6SJeff LaBundy 			for (j = 0; j < count; j++) {
1835f2ba47e6SJeff LaBundy 				if (j == i || *(cycle_alloc[0] + j) != chan)
1836f2ba47e6SJeff LaBundy 					continue;
1837f2ba47e6SJeff LaBundy 
1838f2ba47e6SJeff LaBundy 				dev_err(&client->dev, "Duplicate channel: %d\n",
1839f2ba47e6SJeff LaBundy 					chan);
1840f2ba47e6SJeff LaBundy 				return -EINVAL;
1841f2ba47e6SJeff LaBundy 			}
1842f2ba47e6SJeff LaBundy 		}
1843f2ba47e6SJeff LaBundy 	}
1844f2ba47e6SJeff LaBundy 
1845f2ba47e6SJeff LaBundy 	/*
1846f2ba47e6SJeff LaBundy 	 * Once the raw channel assignments have been derived, they must be
1847f2ba47e6SJeff LaBundy 	 * packed according to the device's register map.
1848f2ba47e6SJeff LaBundy 	 */
1849f2ba47e6SJeff LaBundy 	for (i = 0, cycle_start = 0; i < sizeof(dev_desc->cycle_limit); i++) {
1850f2ba47e6SJeff LaBundy 		int offs = 0;
1851f2ba47e6SJeff LaBundy 
1852f2ba47e6SJeff LaBundy 		for (j = cycle_start;
1853f2ba47e6SJeff LaBundy 		     j < cycle_start + dev_desc->cycle_limit[i]; j++) {
1854f2ba47e6SJeff LaBundy 			iqs7211->cycle_alloc[i][offs++] = 0x05;
1855f2ba47e6SJeff LaBundy 			iqs7211->cycle_alloc[i][offs++] = cycle_alloc[j][0];
1856f2ba47e6SJeff LaBundy 			iqs7211->cycle_alloc[i][offs++] = cycle_alloc[j][1];
1857f2ba47e6SJeff LaBundy 		}
1858f2ba47e6SJeff LaBundy 
1859f2ba47e6SJeff LaBundy 		cycle_start += dev_desc->cycle_limit[i];
1860f2ba47e6SJeff LaBundy 	}
1861f2ba47e6SJeff LaBundy 
1862f2ba47e6SJeff LaBundy 	return 0;
1863f2ba47e6SJeff LaBundy }
1864f2ba47e6SJeff LaBundy 
iqs7211_parse_tp(struct iqs7211_private * iqs7211,struct fwnode_handle * tp_node)1865f2ba47e6SJeff LaBundy static int iqs7211_parse_tp(struct iqs7211_private *iqs7211,
1866f2ba47e6SJeff LaBundy 			    struct fwnode_handle *tp_node)
1867f2ba47e6SJeff LaBundy {
1868f2ba47e6SJeff LaBundy 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
1869f2ba47e6SJeff LaBundy 	struct i2c_client *client = iqs7211->client;
1870f2ba47e6SJeff LaBundy 	unsigned int pins[IQS7211_MAX_CTX];
1871f2ba47e6SJeff LaBundy 	int error, count, i, j;
1872f2ba47e6SJeff LaBundy 
1873f2ba47e6SJeff LaBundy 	count = fwnode_property_count_u32(tp_node, "azoteq,rx-enable");
1874f2ba47e6SJeff LaBundy 	if (count == -EINVAL) {
1875f2ba47e6SJeff LaBundy 		return 0;
1876f2ba47e6SJeff LaBundy 	} else if (count < 0) {
1877f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Failed to count CRx pins: %d\n", count);
1878f2ba47e6SJeff LaBundy 		return count;
1879f2ba47e6SJeff LaBundy 	} else if (count > IQS7211_NUM_CRX) {
1880f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Invalid number of CRx pins\n");
1881f2ba47e6SJeff LaBundy 		return -EINVAL;
1882f2ba47e6SJeff LaBundy 	}
1883f2ba47e6SJeff LaBundy 
1884f2ba47e6SJeff LaBundy 	error = fwnode_property_read_u32_array(tp_node, "azoteq,rx-enable",
1885f2ba47e6SJeff LaBundy 					       pins, count);
1886f2ba47e6SJeff LaBundy 	if (error) {
1887f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Failed to read CRx pins: %d\n", error);
1888f2ba47e6SJeff LaBundy 		return error;
1889f2ba47e6SJeff LaBundy 	}
1890f2ba47e6SJeff LaBundy 
1891f2ba47e6SJeff LaBundy 	for (i = 0; i < count; i++) {
1892f2ba47e6SJeff LaBundy 		if (pins[i] >= IQS7211_NUM_CRX) {
1893f2ba47e6SJeff LaBundy 			dev_err(&client->dev, "Invalid CRx pin: %u\n", pins[i]);
1894f2ba47e6SJeff LaBundy 			return -EINVAL;
1895f2ba47e6SJeff LaBundy 		}
1896f2ba47e6SJeff LaBundy 
1897f2ba47e6SJeff LaBundy 		iqs7211->rx_tx_map[i] = pins[i];
1898f2ba47e6SJeff LaBundy 	}
1899f2ba47e6SJeff LaBundy 
1900f2ba47e6SJeff LaBundy 	iqs7211->tp_config.total_rx = count;
1901f2ba47e6SJeff LaBundy 
1902f2ba47e6SJeff LaBundy 	count = fwnode_property_count_u32(tp_node, "azoteq,tx-enable");
1903f2ba47e6SJeff LaBundy 	if (count < 0) {
1904f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Failed to count CTx pins: %d\n", count);
1905f2ba47e6SJeff LaBundy 		return count;
1906f2ba47e6SJeff LaBundy 	} else if (count > dev_desc->num_ctx) {
1907f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Invalid number of CTx pins\n");
1908f2ba47e6SJeff LaBundy 		return -EINVAL;
1909f2ba47e6SJeff LaBundy 	}
1910f2ba47e6SJeff LaBundy 
1911f2ba47e6SJeff LaBundy 	error = fwnode_property_read_u32_array(tp_node, "azoteq,tx-enable",
1912f2ba47e6SJeff LaBundy 					       pins, count);
1913f2ba47e6SJeff LaBundy 	if (error) {
1914f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Failed to read CTx pins: %d\n", error);
1915f2ba47e6SJeff LaBundy 		return error;
1916f2ba47e6SJeff LaBundy 	}
1917f2ba47e6SJeff LaBundy 
1918f2ba47e6SJeff LaBundy 	for (i = 0; i < count; i++) {
1919f2ba47e6SJeff LaBundy 		if (pins[i] >= dev_desc->num_ctx) {
1920f2ba47e6SJeff LaBundy 			dev_err(&client->dev, "Invalid CTx pin: %u\n", pins[i]);
1921f2ba47e6SJeff LaBundy 			return -EINVAL;
1922f2ba47e6SJeff LaBundy 		}
1923f2ba47e6SJeff LaBundy 
1924f2ba47e6SJeff LaBundy 		for (j = 0; j < iqs7211->tp_config.total_rx; j++) {
1925f2ba47e6SJeff LaBundy 			if (iqs7211->rx_tx_map[j] != pins[i])
1926f2ba47e6SJeff LaBundy 				continue;
1927f2ba47e6SJeff LaBundy 
1928f2ba47e6SJeff LaBundy 			dev_err(&client->dev, "Conflicting CTx pin: %u\n",
1929f2ba47e6SJeff LaBundy 				pins[i]);
1930f2ba47e6SJeff LaBundy 			return -EINVAL;
1931f2ba47e6SJeff LaBundy 		}
1932f2ba47e6SJeff LaBundy 
1933f2ba47e6SJeff LaBundy 		iqs7211->rx_tx_map[iqs7211->tp_config.total_rx + i] = pins[i];
1934f2ba47e6SJeff LaBundy 	}
1935f2ba47e6SJeff LaBundy 
1936f2ba47e6SJeff LaBundy 	iqs7211->tp_config.total_tx = count;
1937f2ba47e6SJeff LaBundy 
1938f2ba47e6SJeff LaBundy 	return iqs7211_parse_cycles(iqs7211, tp_node);
1939f2ba47e6SJeff LaBundy }
1940f2ba47e6SJeff LaBundy 
iqs7211_parse_alp(struct iqs7211_private * iqs7211,struct fwnode_handle * alp_node)1941f2ba47e6SJeff LaBundy static int iqs7211_parse_alp(struct iqs7211_private *iqs7211,
1942f2ba47e6SJeff LaBundy 			     struct fwnode_handle *alp_node)
1943f2ba47e6SJeff LaBundy {
1944f2ba47e6SJeff LaBundy 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
1945f2ba47e6SJeff LaBundy 	struct i2c_client *client = iqs7211->client;
1946f2ba47e6SJeff LaBundy 	struct iqs7211_reg_field_desc reg_field;
1947f2ba47e6SJeff LaBundy 	int error, count, i;
1948f2ba47e6SJeff LaBundy 
1949f2ba47e6SJeff LaBundy 	count = fwnode_property_count_u32(alp_node, "azoteq,rx-enable");
1950f2ba47e6SJeff LaBundy 	if (count < 0 && count != -EINVAL) {
1951f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Failed to count CRx pins: %d\n", count);
1952f2ba47e6SJeff LaBundy 		return count;
1953f2ba47e6SJeff LaBundy 	} else if (count > IQS7211_NUM_CRX) {
1954f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Invalid number of CRx pins\n");
1955f2ba47e6SJeff LaBundy 		return -EINVAL;
1956f2ba47e6SJeff LaBundy 	} else if (count >= 0) {
1957f2ba47e6SJeff LaBundy 		unsigned int pins[IQS7211_NUM_CRX];
1958f2ba47e6SJeff LaBundy 
1959f2ba47e6SJeff LaBundy 		error = fwnode_property_read_u32_array(alp_node,
1960f2ba47e6SJeff LaBundy 						       "azoteq,rx-enable",
1961f2ba47e6SJeff LaBundy 						       pins, count);
1962f2ba47e6SJeff LaBundy 		if (error) {
1963f2ba47e6SJeff LaBundy 			dev_err(&client->dev, "Failed to read CRx pins: %d\n",
1964f2ba47e6SJeff LaBundy 				error);
1965f2ba47e6SJeff LaBundy 			return error;
1966f2ba47e6SJeff LaBundy 		}
1967f2ba47e6SJeff LaBundy 
1968f2ba47e6SJeff LaBundy 		reg_field.addr = dev_desc->alp_config;
1969f2ba47e6SJeff LaBundy 		reg_field.mask = GENMASK(IQS7211_NUM_CRX - 1, 0);
1970f2ba47e6SJeff LaBundy 		reg_field.val = 0;
1971f2ba47e6SJeff LaBundy 
1972f2ba47e6SJeff LaBundy 		for (i = 0; i < count; i++) {
1973f2ba47e6SJeff LaBundy 			if (pins[i] < dev_desc->min_crx_alp ||
1974f2ba47e6SJeff LaBundy 			    pins[i] >= IQS7211_NUM_CRX) {
1975f2ba47e6SJeff LaBundy 				dev_err(&client->dev, "Invalid CRx pin: %u\n",
1976f2ba47e6SJeff LaBundy 					pins[i]);
1977f2ba47e6SJeff LaBundy 				return -EINVAL;
1978f2ba47e6SJeff LaBundy 			}
1979f2ba47e6SJeff LaBundy 
1980f2ba47e6SJeff LaBundy 			reg_field.val |= BIT(pins[i]);
1981f2ba47e6SJeff LaBundy 		}
1982f2ba47e6SJeff LaBundy 
1983f2ba47e6SJeff LaBundy 		error = iqs7211_add_field(iqs7211, reg_field);
1984f2ba47e6SJeff LaBundy 		if (error)
1985f2ba47e6SJeff LaBundy 			return error;
1986f2ba47e6SJeff LaBundy 	}
1987f2ba47e6SJeff LaBundy 
1988f2ba47e6SJeff LaBundy 	count = fwnode_property_count_u32(alp_node, "azoteq,tx-enable");
1989f2ba47e6SJeff LaBundy 	if (count < 0 && count != -EINVAL) {
1990f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Failed to count CTx pins: %d\n", count);
1991f2ba47e6SJeff LaBundy 		return count;
1992f2ba47e6SJeff LaBundy 	} else if (count > dev_desc->num_ctx) {
1993f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Invalid number of CTx pins\n");
1994f2ba47e6SJeff LaBundy 		return -EINVAL;
1995f2ba47e6SJeff LaBundy 	} else if (count >= 0) {
1996f2ba47e6SJeff LaBundy 		unsigned int pins[IQS7211_MAX_CTX];
1997f2ba47e6SJeff LaBundy 
1998f2ba47e6SJeff LaBundy 		error = fwnode_property_read_u32_array(alp_node,
1999f2ba47e6SJeff LaBundy 						       "azoteq,tx-enable",
2000f2ba47e6SJeff LaBundy 						       pins, count);
2001f2ba47e6SJeff LaBundy 		if (error) {
2002f2ba47e6SJeff LaBundy 			dev_err(&client->dev, "Failed to read CTx pins: %d\n",
2003f2ba47e6SJeff LaBundy 				error);
2004f2ba47e6SJeff LaBundy 			return error;
2005f2ba47e6SJeff LaBundy 		}
2006f2ba47e6SJeff LaBundy 
2007f2ba47e6SJeff LaBundy 		reg_field.addr = dev_desc->alp_config + 1;
2008f2ba47e6SJeff LaBundy 		reg_field.mask = GENMASK(dev_desc->num_ctx - 1, 0);
2009f2ba47e6SJeff LaBundy 		reg_field.val = 0;
2010f2ba47e6SJeff LaBundy 
2011f2ba47e6SJeff LaBundy 		for (i = 0; i < count; i++) {
2012f2ba47e6SJeff LaBundy 			if (pins[i] >= dev_desc->num_ctx) {
2013f2ba47e6SJeff LaBundy 				dev_err(&client->dev, "Invalid CTx pin: %u\n",
2014f2ba47e6SJeff LaBundy 					pins[i]);
2015f2ba47e6SJeff LaBundy 				return -EINVAL;
2016f2ba47e6SJeff LaBundy 			}
2017f2ba47e6SJeff LaBundy 
2018f2ba47e6SJeff LaBundy 			reg_field.val |= BIT(pins[i]);
2019f2ba47e6SJeff LaBundy 		}
2020f2ba47e6SJeff LaBundy 
2021f2ba47e6SJeff LaBundy 		error = iqs7211_add_field(iqs7211, reg_field);
2022f2ba47e6SJeff LaBundy 		if (error)
2023f2ba47e6SJeff LaBundy 			return error;
2024f2ba47e6SJeff LaBundy 	}
2025f2ba47e6SJeff LaBundy 
2026f2ba47e6SJeff LaBundy 	return 0;
2027f2ba47e6SJeff LaBundy }
2028f2ba47e6SJeff LaBundy 
2029f2ba47e6SJeff LaBundy static int (*iqs7211_parse_extra[IQS7211_NUM_REG_GRPS])
2030f2ba47e6SJeff LaBundy 				(struct iqs7211_private *iqs7211,
2031f2ba47e6SJeff LaBundy 				 struct fwnode_handle *reg_grp_node) = {
2032f2ba47e6SJeff LaBundy 	[IQS7211_REG_GRP_TP] = iqs7211_parse_tp,
2033f2ba47e6SJeff LaBundy 	[IQS7211_REG_GRP_ALP] = iqs7211_parse_alp,
2034f2ba47e6SJeff LaBundy };
2035f2ba47e6SJeff LaBundy 
iqs7211_parse_reg_grp(struct iqs7211_private * iqs7211,struct fwnode_handle * reg_grp_node,enum iqs7211_reg_grp_id reg_grp)2036f2ba47e6SJeff LaBundy static int iqs7211_parse_reg_grp(struct iqs7211_private *iqs7211,
2037f2ba47e6SJeff LaBundy 				 struct fwnode_handle *reg_grp_node,
2038f2ba47e6SJeff LaBundy 				 enum iqs7211_reg_grp_id reg_grp)
2039f2ba47e6SJeff LaBundy {
2040f2ba47e6SJeff LaBundy 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
2041f2ba47e6SJeff LaBundy 	struct iqs7211_reg_field_desc reg_field;
2042f2ba47e6SJeff LaBundy 	int error, i;
2043f2ba47e6SJeff LaBundy 
2044f2ba47e6SJeff LaBundy 	error = iqs7211_parse_props(iqs7211, reg_grp_node, reg_grp,
2045f2ba47e6SJeff LaBundy 				    IQS7211_REG_KEY_NONE);
2046f2ba47e6SJeff LaBundy 	if (error)
2047f2ba47e6SJeff LaBundy 		return error;
2048f2ba47e6SJeff LaBundy 
2049f2ba47e6SJeff LaBundy 	if (iqs7211_parse_extra[reg_grp]) {
2050f2ba47e6SJeff LaBundy 		error = iqs7211_parse_extra[reg_grp](iqs7211, reg_grp_node);
2051f2ba47e6SJeff LaBundy 		if (error)
2052f2ba47e6SJeff LaBundy 			return error;
2053f2ba47e6SJeff LaBundy 	}
2054f2ba47e6SJeff LaBundy 
2055f2ba47e6SJeff LaBundy 	iqs7211->ati_start |= dev_desc->ati_start[reg_grp];
2056f2ba47e6SJeff LaBundy 
2057f2ba47e6SJeff LaBundy 	reg_field.addr = dev_desc->kp_enable[reg_grp];
2058f2ba47e6SJeff LaBundy 	reg_field.mask = 0;
2059f2ba47e6SJeff LaBundy 	reg_field.val = 0;
2060f2ba47e6SJeff LaBundy 
2061f2ba47e6SJeff LaBundy 	for (i = 0; i < dev_desc->num_kp_events; i++) {
2062f2ba47e6SJeff LaBundy 		const char *event_name = dev_desc->kp_events[i].name;
2063f2ba47e6SJeff LaBundy 		struct fwnode_handle *event_node;
2064f2ba47e6SJeff LaBundy 
2065f2ba47e6SJeff LaBundy 		if (dev_desc->kp_events[i].reg_grp != reg_grp)
2066f2ba47e6SJeff LaBundy 			continue;
2067f2ba47e6SJeff LaBundy 
2068f2ba47e6SJeff LaBundy 		reg_field.mask |= dev_desc->kp_events[i].enable;
2069f2ba47e6SJeff LaBundy 
2070f2ba47e6SJeff LaBundy 		if (event_name)
2071f2ba47e6SJeff LaBundy 			event_node = fwnode_get_named_child_node(reg_grp_node,
2072f2ba47e6SJeff LaBundy 								 event_name);
2073f2ba47e6SJeff LaBundy 		else
2074f2ba47e6SJeff LaBundy 			event_node = fwnode_handle_get(reg_grp_node);
2075f2ba47e6SJeff LaBundy 
2076f2ba47e6SJeff LaBundy 		if (!event_node)
2077f2ba47e6SJeff LaBundy 			continue;
2078f2ba47e6SJeff LaBundy 
2079f2ba47e6SJeff LaBundy 		error = iqs7211_parse_event(iqs7211, event_node,
2080f2ba47e6SJeff LaBundy 					    dev_desc->kp_events[i].reg_grp,
2081f2ba47e6SJeff LaBundy 					    dev_desc->kp_events[i].reg_key,
2082f2ba47e6SJeff LaBundy 					    &iqs7211->kp_code[i]);
2083f2ba47e6SJeff LaBundy 		fwnode_handle_put(event_node);
2084f2ba47e6SJeff LaBundy 		if (error)
2085f2ba47e6SJeff LaBundy 			return error;
2086f2ba47e6SJeff LaBundy 
2087f2ba47e6SJeff LaBundy 		reg_field.val |= dev_desc->kp_events[i].enable;
2088f2ba47e6SJeff LaBundy 
2089f2ba47e6SJeff LaBundy 		iqs7211->event_mask |= iqs7211_reg_grp_masks[reg_grp];
2090f2ba47e6SJeff LaBundy 	}
2091f2ba47e6SJeff LaBundy 
2092f2ba47e6SJeff LaBundy 	return iqs7211_add_field(iqs7211, reg_field);
2093f2ba47e6SJeff LaBundy }
2094f2ba47e6SJeff LaBundy 
iqs7211_register_kp(struct iqs7211_private * iqs7211)2095f2ba47e6SJeff LaBundy static int iqs7211_register_kp(struct iqs7211_private *iqs7211)
2096f2ba47e6SJeff LaBundy {
2097f2ba47e6SJeff LaBundy 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
2098f2ba47e6SJeff LaBundy 	struct input_dev *kp_idev = iqs7211->kp_idev;
2099f2ba47e6SJeff LaBundy 	struct i2c_client *client = iqs7211->client;
2100f2ba47e6SJeff LaBundy 	int error, i;
2101f2ba47e6SJeff LaBundy 
2102f2ba47e6SJeff LaBundy 	for (i = 0; i < dev_desc->num_kp_events; i++)
2103f2ba47e6SJeff LaBundy 		if (iqs7211->kp_code[i])
2104f2ba47e6SJeff LaBundy 			break;
2105f2ba47e6SJeff LaBundy 
2106f2ba47e6SJeff LaBundy 	if (i == dev_desc->num_kp_events)
2107f2ba47e6SJeff LaBundy 		return 0;
2108f2ba47e6SJeff LaBundy 
2109f2ba47e6SJeff LaBundy 	kp_idev = devm_input_allocate_device(&client->dev);
2110f2ba47e6SJeff LaBundy 	if (!kp_idev)
2111f2ba47e6SJeff LaBundy 		return -ENOMEM;
2112f2ba47e6SJeff LaBundy 
2113f2ba47e6SJeff LaBundy 	iqs7211->kp_idev = kp_idev;
2114f2ba47e6SJeff LaBundy 
2115f2ba47e6SJeff LaBundy 	kp_idev->name = dev_desc->kp_name;
2116f2ba47e6SJeff LaBundy 	kp_idev->id.bustype = BUS_I2C;
2117f2ba47e6SJeff LaBundy 
2118f2ba47e6SJeff LaBundy 	for (i = 0; i < dev_desc->num_kp_events; i++)
2119f2ba47e6SJeff LaBundy 		if (iqs7211->kp_code[i])
2120f2ba47e6SJeff LaBundy 			input_set_capability(iqs7211->kp_idev, EV_KEY,
2121f2ba47e6SJeff LaBundy 					     iqs7211->kp_code[i]);
2122f2ba47e6SJeff LaBundy 
2123f2ba47e6SJeff LaBundy 	error = input_register_device(kp_idev);
2124f2ba47e6SJeff LaBundy 	if (error)
2125f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Failed to register %s: %d\n",
2126f2ba47e6SJeff LaBundy 			kp_idev->name, error);
2127f2ba47e6SJeff LaBundy 
2128f2ba47e6SJeff LaBundy 	return error;
2129f2ba47e6SJeff LaBundy }
2130f2ba47e6SJeff LaBundy 
iqs7211_register_tp(struct iqs7211_private * iqs7211)2131f2ba47e6SJeff LaBundy static int iqs7211_register_tp(struct iqs7211_private *iqs7211)
2132f2ba47e6SJeff LaBundy {
2133f2ba47e6SJeff LaBundy 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
2134f2ba47e6SJeff LaBundy 	struct touchscreen_properties *prop = &iqs7211->prop;
2135f2ba47e6SJeff LaBundy 	struct input_dev *tp_idev = iqs7211->tp_idev;
2136f2ba47e6SJeff LaBundy 	struct i2c_client *client = iqs7211->client;
2137f2ba47e6SJeff LaBundy 	int error;
2138f2ba47e6SJeff LaBundy 
2139f2ba47e6SJeff LaBundy 	error = device_property_read_u32(&client->dev, "azoteq,num-contacts",
2140f2ba47e6SJeff LaBundy 					 &iqs7211->num_contacts);
2141f2ba47e6SJeff LaBundy 	if (error == -EINVAL) {
2142f2ba47e6SJeff LaBundy 		return 0;
2143f2ba47e6SJeff LaBundy 	} else if (error) {
2144f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Failed to read number of contacts: %d\n",
2145f2ba47e6SJeff LaBundy 			error);
2146f2ba47e6SJeff LaBundy 		return error;
2147f2ba47e6SJeff LaBundy 	} else if (iqs7211->num_contacts > IQS7211_MAX_CONTACTS) {
2148f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Invalid number of contacts: %u\n",
2149f2ba47e6SJeff LaBundy 			iqs7211->num_contacts);
2150f2ba47e6SJeff LaBundy 		return -EINVAL;
2151f2ba47e6SJeff LaBundy 	}
2152f2ba47e6SJeff LaBundy 
2153f2ba47e6SJeff LaBundy 	iqs7211->tp_config.num_contacts = iqs7211->num_contacts ? : 1;
2154f2ba47e6SJeff LaBundy 
2155f2ba47e6SJeff LaBundy 	if (!iqs7211->num_contacts)
2156f2ba47e6SJeff LaBundy 		return 0;
2157f2ba47e6SJeff LaBundy 
2158f2ba47e6SJeff LaBundy 	iqs7211->event_mask |= IQS7211_EVENT_MASK_MOVE;
2159f2ba47e6SJeff LaBundy 
2160f2ba47e6SJeff LaBundy 	tp_idev = devm_input_allocate_device(&client->dev);
2161f2ba47e6SJeff LaBundy 	if (!tp_idev)
2162f2ba47e6SJeff LaBundy 		return -ENOMEM;
2163f2ba47e6SJeff LaBundy 
2164f2ba47e6SJeff LaBundy 	iqs7211->tp_idev = tp_idev;
2165f2ba47e6SJeff LaBundy 
2166f2ba47e6SJeff LaBundy 	tp_idev->name = dev_desc->tp_name;
2167f2ba47e6SJeff LaBundy 	tp_idev->id.bustype = BUS_I2C;
2168f2ba47e6SJeff LaBundy 
2169f2ba47e6SJeff LaBundy 	input_set_abs_params(tp_idev, ABS_MT_POSITION_X,
2170f2ba47e6SJeff LaBundy 			     0, le16_to_cpu(iqs7211->tp_config.max_x), 0, 0);
2171f2ba47e6SJeff LaBundy 
2172f2ba47e6SJeff LaBundy 	input_set_abs_params(tp_idev, ABS_MT_POSITION_Y,
2173f2ba47e6SJeff LaBundy 			     0, le16_to_cpu(iqs7211->tp_config.max_y), 0, 0);
2174f2ba47e6SJeff LaBundy 
2175f2ba47e6SJeff LaBundy 	input_set_abs_params(tp_idev, ABS_MT_PRESSURE, 0, U16_MAX, 0, 0);
2176f2ba47e6SJeff LaBundy 
2177f2ba47e6SJeff LaBundy 	touchscreen_parse_properties(tp_idev, true, prop);
2178f2ba47e6SJeff LaBundy 
2179f2ba47e6SJeff LaBundy 	/*
2180f2ba47e6SJeff LaBundy 	 * The device reserves 0xFFFF for coordinates that correspond to slots
2181f2ba47e6SJeff LaBundy 	 * which are not in a state of touch.
2182f2ba47e6SJeff LaBundy 	 */
2183f2ba47e6SJeff LaBundy 	if (prop->max_x >= U16_MAX || prop->max_y >= U16_MAX) {
2184f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Invalid trackpad size: %u*%u\n",
2185f2ba47e6SJeff LaBundy 			prop->max_x, prop->max_y);
2186f2ba47e6SJeff LaBundy 		return -EINVAL;
2187f2ba47e6SJeff LaBundy 	}
2188f2ba47e6SJeff LaBundy 
2189f2ba47e6SJeff LaBundy 	iqs7211->tp_config.max_x = cpu_to_le16(prop->max_x);
2190f2ba47e6SJeff LaBundy 	iqs7211->tp_config.max_y = cpu_to_le16(prop->max_y);
2191f2ba47e6SJeff LaBundy 
2192f2ba47e6SJeff LaBundy 	error = input_mt_init_slots(tp_idev, iqs7211->num_contacts,
2193f2ba47e6SJeff LaBundy 				    INPUT_MT_DIRECT);
2194f2ba47e6SJeff LaBundy 	if (error) {
2195f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Failed to initialize slots: %d\n",
2196f2ba47e6SJeff LaBundy 			error);
2197f2ba47e6SJeff LaBundy 		return error;
2198f2ba47e6SJeff LaBundy 	}
2199f2ba47e6SJeff LaBundy 
2200f2ba47e6SJeff LaBundy 	error = input_register_device(tp_idev);
2201f2ba47e6SJeff LaBundy 	if (error)
2202f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Failed to register %s: %d\n",
2203f2ba47e6SJeff LaBundy 			tp_idev->name, error);
2204f2ba47e6SJeff LaBundy 
2205f2ba47e6SJeff LaBundy 	return error;
2206f2ba47e6SJeff LaBundy }
2207f2ba47e6SJeff LaBundy 
iqs7211_report(struct iqs7211_private * iqs7211)2208f2ba47e6SJeff LaBundy static int iqs7211_report(struct iqs7211_private *iqs7211)
2209f2ba47e6SJeff LaBundy {
2210f2ba47e6SJeff LaBundy 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
2211f2ba47e6SJeff LaBundy 	struct i2c_client *client = iqs7211->client;
2212f2ba47e6SJeff LaBundy 	struct iqs7211_touch_data *touch_data;
2213f2ba47e6SJeff LaBundy 	u16 info_flags, charge_mode, gesture_flags;
2214f2ba47e6SJeff LaBundy 	__le16 status[12];
2215f2ba47e6SJeff LaBundy 	int error, i;
2216f2ba47e6SJeff LaBundy 
2217f2ba47e6SJeff LaBundy 	error = iqs7211_read_burst(iqs7211, dev_desc->sys_stat, status,
2218f2ba47e6SJeff LaBundy 				   dev_desc->contact_offs * sizeof(__le16) +
2219f2ba47e6SJeff LaBundy 				   iqs7211->num_contacts * sizeof(*touch_data));
2220f2ba47e6SJeff LaBundy 	if (error)
2221f2ba47e6SJeff LaBundy 		return error;
2222f2ba47e6SJeff LaBundy 
2223f2ba47e6SJeff LaBundy 	info_flags = le16_to_cpu(status[dev_desc->info_offs]);
2224f2ba47e6SJeff LaBundy 
2225f2ba47e6SJeff LaBundy 	if (info_flags & dev_desc->show_reset) {
2226f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Unexpected device reset\n");
2227f2ba47e6SJeff LaBundy 
2228f2ba47e6SJeff LaBundy 		/*
2229f2ba47e6SJeff LaBundy 		 * The device may or may not expect forced communication after
2230f2ba47e6SJeff LaBundy 		 * it exits hardware reset, so the corresponding state machine
2231f2ba47e6SJeff LaBundy 		 * must be reset as well.
2232f2ba47e6SJeff LaBundy 		 */
2233f2ba47e6SJeff LaBundy 		iqs7211->comms_mode = iqs7211->comms_init;
2234f2ba47e6SJeff LaBundy 
2235f2ba47e6SJeff LaBundy 		return iqs7211_init_device(iqs7211);
2236f2ba47e6SJeff LaBundy 	}
2237f2ba47e6SJeff LaBundy 
2238f2ba47e6SJeff LaBundy 	for (i = 0; i < ARRAY_SIZE(dev_desc->ati_error); i++) {
2239f2ba47e6SJeff LaBundy 		if (!(info_flags & dev_desc->ati_error[i]))
2240f2ba47e6SJeff LaBundy 			continue;
2241f2ba47e6SJeff LaBundy 
2242f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Unexpected %s ATI error\n",
2243f2ba47e6SJeff LaBundy 			iqs7211_reg_grp_names[i]);
2244f2ba47e6SJeff LaBundy 		return 0;
2245f2ba47e6SJeff LaBundy 	}
2246f2ba47e6SJeff LaBundy 
2247f2ba47e6SJeff LaBundy 	for (i = 0; i < iqs7211->num_contacts; i++) {
2248f2ba47e6SJeff LaBundy 		u16 pressure;
2249f2ba47e6SJeff LaBundy 
2250f2ba47e6SJeff LaBundy 		touch_data = (struct iqs7211_touch_data *)
2251f2ba47e6SJeff LaBundy 			     &status[dev_desc->contact_offs] + i;
2252f2ba47e6SJeff LaBundy 		pressure = le16_to_cpu(touch_data->pressure);
2253f2ba47e6SJeff LaBundy 
2254f2ba47e6SJeff LaBundy 		input_mt_slot(iqs7211->tp_idev, i);
2255f2ba47e6SJeff LaBundy 		if (input_mt_report_slot_state(iqs7211->tp_idev, MT_TOOL_FINGER,
2256f2ba47e6SJeff LaBundy 					       pressure != 0)) {
2257f2ba47e6SJeff LaBundy 			touchscreen_report_pos(iqs7211->tp_idev, &iqs7211->prop,
2258f2ba47e6SJeff LaBundy 					       le16_to_cpu(touch_data->abs_x),
2259f2ba47e6SJeff LaBundy 					       le16_to_cpu(touch_data->abs_y),
2260f2ba47e6SJeff LaBundy 					       true);
2261f2ba47e6SJeff LaBundy 			input_report_abs(iqs7211->tp_idev, ABS_MT_PRESSURE,
2262f2ba47e6SJeff LaBundy 					 pressure);
2263f2ba47e6SJeff LaBundy 		}
2264f2ba47e6SJeff LaBundy 	}
2265f2ba47e6SJeff LaBundy 
2266f2ba47e6SJeff LaBundy 	if (iqs7211->num_contacts) {
2267f2ba47e6SJeff LaBundy 		input_mt_sync_frame(iqs7211->tp_idev);
2268f2ba47e6SJeff LaBundy 		input_sync(iqs7211->tp_idev);
2269f2ba47e6SJeff LaBundy 	}
2270f2ba47e6SJeff LaBundy 
2271f2ba47e6SJeff LaBundy 	if (!iqs7211->kp_idev)
2272f2ba47e6SJeff LaBundy 		return 0;
2273f2ba47e6SJeff LaBundy 
2274f2ba47e6SJeff LaBundy 	charge_mode = info_flags & GENMASK(dev_desc->charge_shift + 2,
2275f2ba47e6SJeff LaBundy 					   dev_desc->charge_shift);
2276f2ba47e6SJeff LaBundy 	charge_mode >>= dev_desc->charge_shift;
2277f2ba47e6SJeff LaBundy 
2278f2ba47e6SJeff LaBundy 	/*
2279f2ba47e6SJeff LaBundy 	 * A charging mode higher than 2 (idle mode) indicates the device last
2280f2ba47e6SJeff LaBundy 	 * operated in low-power mode and intends to express an ALP event.
2281f2ba47e6SJeff LaBundy 	 */
2282f2ba47e6SJeff LaBundy 	if (info_flags & dev_desc->kp_events->mask && charge_mode > 2) {
2283f2ba47e6SJeff LaBundy 		input_report_key(iqs7211->kp_idev, *iqs7211->kp_code, 1);
2284f2ba47e6SJeff LaBundy 		input_sync(iqs7211->kp_idev);
2285f2ba47e6SJeff LaBundy 
2286f2ba47e6SJeff LaBundy 		input_report_key(iqs7211->kp_idev, *iqs7211->kp_code, 0);
2287f2ba47e6SJeff LaBundy 	}
2288f2ba47e6SJeff LaBundy 
2289f2ba47e6SJeff LaBundy 	for (i = 0; i < dev_desc->num_kp_events; i++) {
2290f2ba47e6SJeff LaBundy 		if (dev_desc->kp_events[i].reg_grp != IQS7211_REG_GRP_BTN)
2291f2ba47e6SJeff LaBundy 			continue;
2292f2ba47e6SJeff LaBundy 
2293f2ba47e6SJeff LaBundy 		input_report_key(iqs7211->kp_idev, iqs7211->kp_code[i],
2294f2ba47e6SJeff LaBundy 				 info_flags & dev_desc->kp_events[i].mask);
2295f2ba47e6SJeff LaBundy 	}
2296f2ba47e6SJeff LaBundy 
2297f2ba47e6SJeff LaBundy 	gesture_flags = le16_to_cpu(status[dev_desc->gesture_offs]);
2298f2ba47e6SJeff LaBundy 
2299f2ba47e6SJeff LaBundy 	for (i = 0; i < dev_desc->num_kp_events; i++) {
2300f2ba47e6SJeff LaBundy 		enum iqs7211_reg_key_id reg_key = dev_desc->kp_events[i].reg_key;
2301f2ba47e6SJeff LaBundy 		u16 mask = dev_desc->kp_events[i].mask;
2302f2ba47e6SJeff LaBundy 
2303f2ba47e6SJeff LaBundy 		if (dev_desc->kp_events[i].reg_grp != IQS7211_REG_GRP_TP)
2304f2ba47e6SJeff LaBundy 			continue;
2305f2ba47e6SJeff LaBundy 
2306f2ba47e6SJeff LaBundy 		if ((gesture_flags ^ iqs7211->gesture_cache) & mask)
2307f2ba47e6SJeff LaBundy 			input_report_key(iqs7211->kp_idev, iqs7211->kp_code[i],
2308f2ba47e6SJeff LaBundy 					 gesture_flags & mask);
2309f2ba47e6SJeff LaBundy 
2310f2ba47e6SJeff LaBundy 		iqs7211->gesture_cache &= ~mask;
2311f2ba47e6SJeff LaBundy 
2312f2ba47e6SJeff LaBundy 		/*
2313f2ba47e6SJeff LaBundy 		 * Hold and palm gestures persist while the contact remains in
2314f2ba47e6SJeff LaBundy 		 * place; all others are momentary and hence are followed by a
2315f2ba47e6SJeff LaBundy 		 * complementary release event.
2316f2ba47e6SJeff LaBundy 		 */
2317f2ba47e6SJeff LaBundy 		if (reg_key == IQS7211_REG_KEY_HOLD ||
2318f2ba47e6SJeff LaBundy 		    reg_key == IQS7211_REG_KEY_PALM) {
2319f2ba47e6SJeff LaBundy 			iqs7211->gesture_cache |= gesture_flags & mask;
2320f2ba47e6SJeff LaBundy 			gesture_flags &= ~mask;
2321f2ba47e6SJeff LaBundy 		}
2322f2ba47e6SJeff LaBundy 	}
2323f2ba47e6SJeff LaBundy 
2324f2ba47e6SJeff LaBundy 	if (gesture_flags) {
2325f2ba47e6SJeff LaBundy 		input_sync(iqs7211->kp_idev);
2326f2ba47e6SJeff LaBundy 
2327f2ba47e6SJeff LaBundy 		for (i = 0; i < dev_desc->num_kp_events; i++)
2328f2ba47e6SJeff LaBundy 			if (dev_desc->kp_events[i].reg_grp == IQS7211_REG_GRP_TP &&
2329f2ba47e6SJeff LaBundy 			    gesture_flags & dev_desc->kp_events[i].mask)
2330f2ba47e6SJeff LaBundy 				input_report_key(iqs7211->kp_idev,
2331f2ba47e6SJeff LaBundy 						 iqs7211->kp_code[i], 0);
2332f2ba47e6SJeff LaBundy 	}
2333f2ba47e6SJeff LaBundy 
2334f2ba47e6SJeff LaBundy 	input_sync(iqs7211->kp_idev);
2335f2ba47e6SJeff LaBundy 
2336f2ba47e6SJeff LaBundy 	return 0;
2337f2ba47e6SJeff LaBundy }
2338f2ba47e6SJeff LaBundy 
iqs7211_irq(int irq,void * context)2339f2ba47e6SJeff LaBundy static irqreturn_t iqs7211_irq(int irq, void *context)
2340f2ba47e6SJeff LaBundy {
2341f2ba47e6SJeff LaBundy 	struct iqs7211_private *iqs7211 = context;
2342f2ba47e6SJeff LaBundy 
2343f2ba47e6SJeff LaBundy 	return iqs7211_report(iqs7211) ? IRQ_NONE : IRQ_HANDLED;
2344f2ba47e6SJeff LaBundy }
2345f2ba47e6SJeff LaBundy 
iqs7211_suspend(struct device * dev)2346f2ba47e6SJeff LaBundy static int iqs7211_suspend(struct device *dev)
2347f2ba47e6SJeff LaBundy {
2348f2ba47e6SJeff LaBundy 	struct iqs7211_private *iqs7211 = dev_get_drvdata(dev);
2349f2ba47e6SJeff LaBundy 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
2350f2ba47e6SJeff LaBundy 	int error;
2351f2ba47e6SJeff LaBundy 
2352f2ba47e6SJeff LaBundy 	if (!dev_desc->suspend || device_may_wakeup(dev))
2353f2ba47e6SJeff LaBundy 		return 0;
2354f2ba47e6SJeff LaBundy 
2355f2ba47e6SJeff LaBundy 	/*
2356f2ba47e6SJeff LaBundy 	 * I2C communication prompts the device to assert its RDY pin if it is
2357f2ba47e6SJeff LaBundy 	 * not already asserted. As such, the interrupt must be disabled so as
2358f2ba47e6SJeff LaBundy 	 * to prevent reentrant interrupts.
2359f2ba47e6SJeff LaBundy 	 */
2360f2ba47e6SJeff LaBundy 	disable_irq(gpiod_to_irq(iqs7211->irq_gpio));
2361f2ba47e6SJeff LaBundy 
2362f2ba47e6SJeff LaBundy 	error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl,
2363f2ba47e6SJeff LaBundy 				   dev_desc->suspend);
2364f2ba47e6SJeff LaBundy 
2365f2ba47e6SJeff LaBundy 	enable_irq(gpiod_to_irq(iqs7211->irq_gpio));
2366f2ba47e6SJeff LaBundy 
2367f2ba47e6SJeff LaBundy 	return error;
2368f2ba47e6SJeff LaBundy }
2369f2ba47e6SJeff LaBundy 
iqs7211_resume(struct device * dev)2370f2ba47e6SJeff LaBundy static int iqs7211_resume(struct device *dev)
2371f2ba47e6SJeff LaBundy {
2372f2ba47e6SJeff LaBundy 	struct iqs7211_private *iqs7211 = dev_get_drvdata(dev);
2373f2ba47e6SJeff LaBundy 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
2374f2ba47e6SJeff LaBundy 	__le16 sys_ctrl[] = {
2375f2ba47e6SJeff LaBundy 		0,
2376f2ba47e6SJeff LaBundy 		cpu_to_le16(iqs7211->event_mask),
2377f2ba47e6SJeff LaBundy 	};
2378f2ba47e6SJeff LaBundy 	int error;
2379f2ba47e6SJeff LaBundy 
2380f2ba47e6SJeff LaBundy 	if (!dev_desc->suspend || device_may_wakeup(dev))
2381f2ba47e6SJeff LaBundy 		return 0;
2382f2ba47e6SJeff LaBundy 
2383f2ba47e6SJeff LaBundy 	disable_irq(gpiod_to_irq(iqs7211->irq_gpio));
2384f2ba47e6SJeff LaBundy 
2385f2ba47e6SJeff LaBundy 	/*
2386f2ba47e6SJeff LaBundy 	 * Forced communication, if in use, must be explicitly enabled as part
2387f2ba47e6SJeff LaBundy 	 * of the wake-up command.
2388f2ba47e6SJeff LaBundy 	 */
2389f2ba47e6SJeff LaBundy 	error = iqs7211_write_burst(iqs7211, dev_desc->sys_ctrl, sys_ctrl,
2390f2ba47e6SJeff LaBundy 				    sizeof(sys_ctrl));
2391f2ba47e6SJeff LaBundy 
2392f2ba47e6SJeff LaBundy 	enable_irq(gpiod_to_irq(iqs7211->irq_gpio));
2393f2ba47e6SJeff LaBundy 
2394f2ba47e6SJeff LaBundy 	return error;
2395f2ba47e6SJeff LaBundy }
2396f2ba47e6SJeff LaBundy 
2397f2ba47e6SJeff LaBundy static DEFINE_SIMPLE_DEV_PM_OPS(iqs7211_pm, iqs7211_suspend, iqs7211_resume);
2398f2ba47e6SJeff LaBundy 
fw_info_show(struct device * dev,struct device_attribute * attr,char * buf)2399f2ba47e6SJeff LaBundy static ssize_t fw_info_show(struct device *dev,
2400f2ba47e6SJeff LaBundy 			    struct device_attribute *attr, char *buf)
2401f2ba47e6SJeff LaBundy {
2402f2ba47e6SJeff LaBundy 	struct iqs7211_private *iqs7211 = dev_get_drvdata(dev);
2403f2ba47e6SJeff LaBundy 
2404f2ba47e6SJeff LaBundy 	return scnprintf(buf, PAGE_SIZE, "%u.%u.%u.%u:%u.%u\n",
2405f2ba47e6SJeff LaBundy 			 le16_to_cpu(iqs7211->ver_info.prod_num),
2406f2ba47e6SJeff LaBundy 			 le32_to_cpu(iqs7211->ver_info.patch),
2407f2ba47e6SJeff LaBundy 			 le16_to_cpu(iqs7211->ver_info.major),
2408f2ba47e6SJeff LaBundy 			 le16_to_cpu(iqs7211->ver_info.minor),
2409f2ba47e6SJeff LaBundy 			 iqs7211->exp_file[1], iqs7211->exp_file[0]);
2410f2ba47e6SJeff LaBundy }
2411f2ba47e6SJeff LaBundy 
2412f2ba47e6SJeff LaBundy static DEVICE_ATTR_RO(fw_info);
2413f2ba47e6SJeff LaBundy 
2414f2ba47e6SJeff LaBundy static struct attribute *iqs7211_attrs[] = {
2415f2ba47e6SJeff LaBundy 	&dev_attr_fw_info.attr,
2416f2ba47e6SJeff LaBundy 	NULL
2417f2ba47e6SJeff LaBundy };
2418f2ba47e6SJeff LaBundy ATTRIBUTE_GROUPS(iqs7211);
2419f2ba47e6SJeff LaBundy 
2420f2ba47e6SJeff LaBundy static const struct of_device_id iqs7211_of_match[] = {
2421f2ba47e6SJeff LaBundy 	{
2422f2ba47e6SJeff LaBundy 		.compatible = "azoteq,iqs7210a",
2423*677232f8SJeff LaBundy 		.data = &iqs7211_devs[IQS7210A],
2424f2ba47e6SJeff LaBundy 	},
2425f2ba47e6SJeff LaBundy 	{
2426f2ba47e6SJeff LaBundy 		.compatible = "azoteq,iqs7211a",
2427*677232f8SJeff LaBundy 		.data = &iqs7211_devs[IQS7211A],
2428f2ba47e6SJeff LaBundy 	},
2429f2ba47e6SJeff LaBundy 	{
2430f2ba47e6SJeff LaBundy 		.compatible = "azoteq,iqs7211e",
2431*677232f8SJeff LaBundy 		.data = &iqs7211_devs[IQS7211E],
2432f2ba47e6SJeff LaBundy 	},
2433f2ba47e6SJeff LaBundy 	{ }
2434f2ba47e6SJeff LaBundy };
2435f2ba47e6SJeff LaBundy MODULE_DEVICE_TABLE(of, iqs7211_of_match);
2436f2ba47e6SJeff LaBundy 
iqs7211_probe(struct i2c_client * client)2437f2ba47e6SJeff LaBundy static int iqs7211_probe(struct i2c_client *client)
2438f2ba47e6SJeff LaBundy {
2439f2ba47e6SJeff LaBundy 	struct iqs7211_private *iqs7211;
2440f2ba47e6SJeff LaBundy 	enum iqs7211_reg_grp_id reg_grp;
2441f2ba47e6SJeff LaBundy 	unsigned long irq_flags;
2442f2ba47e6SJeff LaBundy 	bool shared_irq;
2443f2ba47e6SJeff LaBundy 	int error, irq;
2444f2ba47e6SJeff LaBundy 
2445f2ba47e6SJeff LaBundy 	iqs7211 = devm_kzalloc(&client->dev, sizeof(*iqs7211), GFP_KERNEL);
2446f2ba47e6SJeff LaBundy 	if (!iqs7211)
2447f2ba47e6SJeff LaBundy 		return -ENOMEM;
2448f2ba47e6SJeff LaBundy 
2449f2ba47e6SJeff LaBundy 	i2c_set_clientdata(client, iqs7211);
2450f2ba47e6SJeff LaBundy 	iqs7211->client = client;
2451f2ba47e6SJeff LaBundy 
2452f2ba47e6SJeff LaBundy 	INIT_LIST_HEAD(&iqs7211->reg_field_head);
2453f2ba47e6SJeff LaBundy 
2454*677232f8SJeff LaBundy 	iqs7211->dev_desc = device_get_match_data(&client->dev);
2455*677232f8SJeff LaBundy 	if (!iqs7211->dev_desc)
2456*677232f8SJeff LaBundy 		return -ENODEV;
2457f2ba47e6SJeff LaBundy 
2458*677232f8SJeff LaBundy 	shared_irq = iqs7211->dev_desc->num_ctx == IQS7211_MAX_CTX;
2459f2ba47e6SJeff LaBundy 
2460f2ba47e6SJeff LaBundy 	/*
2461f2ba47e6SJeff LaBundy 	 * The RDY pin behaves as an interrupt, but must also be polled ahead
2462f2ba47e6SJeff LaBundy 	 * of unsolicited I2C communication. As such, it is first opened as a
2463f2ba47e6SJeff LaBundy 	 * GPIO and then passed to gpiod_to_irq() to register the interrupt.
2464f2ba47e6SJeff LaBundy 	 *
2465f2ba47e6SJeff LaBundy 	 * If an extra CTx pin is present, the RDY and MCLR pins are combined
2466f2ba47e6SJeff LaBundy 	 * into a single bidirectional pin. In that case, the platform's GPIO
2467f2ba47e6SJeff LaBundy 	 * must be configured as an open-drain output.
2468f2ba47e6SJeff LaBundy 	 */
2469f2ba47e6SJeff LaBundy 	iqs7211->irq_gpio = devm_gpiod_get(&client->dev, "irq",
2470f2ba47e6SJeff LaBundy 					   shared_irq ? GPIOD_OUT_LOW
2471f2ba47e6SJeff LaBundy 						      : GPIOD_IN);
2472f2ba47e6SJeff LaBundy 	if (IS_ERR(iqs7211->irq_gpio)) {
2473f2ba47e6SJeff LaBundy 		error = PTR_ERR(iqs7211->irq_gpio);
2474f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Failed to request IRQ GPIO: %d\n",
2475f2ba47e6SJeff LaBundy 			error);
2476f2ba47e6SJeff LaBundy 		return error;
2477f2ba47e6SJeff LaBundy 	}
2478f2ba47e6SJeff LaBundy 
2479f2ba47e6SJeff LaBundy 	if (shared_irq) {
2480f2ba47e6SJeff LaBundy 		iqs7211->reset_gpio = iqs7211->irq_gpio;
2481f2ba47e6SJeff LaBundy 	} else {
2482f2ba47e6SJeff LaBundy 		iqs7211->reset_gpio = devm_gpiod_get_optional(&client->dev,
2483f2ba47e6SJeff LaBundy 							      "reset",
2484f2ba47e6SJeff LaBundy 							      GPIOD_OUT_HIGH);
2485f2ba47e6SJeff LaBundy 		if (IS_ERR(iqs7211->reset_gpio)) {
2486f2ba47e6SJeff LaBundy 			error = PTR_ERR(iqs7211->reset_gpio);
2487f2ba47e6SJeff LaBundy 			dev_err(&client->dev,
2488f2ba47e6SJeff LaBundy 				"Failed to request reset GPIO: %d\n", error);
2489f2ba47e6SJeff LaBundy 			return error;
2490f2ba47e6SJeff LaBundy 		}
2491f2ba47e6SJeff LaBundy 	}
2492f2ba47e6SJeff LaBundy 
2493f2ba47e6SJeff LaBundy 	error = iqs7211_start_comms(iqs7211);
2494f2ba47e6SJeff LaBundy 	if (error)
2495f2ba47e6SJeff LaBundy 		return error;
2496f2ba47e6SJeff LaBundy 
2497f2ba47e6SJeff LaBundy 	for (reg_grp = 0; reg_grp < IQS7211_NUM_REG_GRPS; reg_grp++) {
2498f2ba47e6SJeff LaBundy 		const char *reg_grp_name = iqs7211_reg_grp_names[reg_grp];
2499f2ba47e6SJeff LaBundy 		struct fwnode_handle *reg_grp_node;
2500f2ba47e6SJeff LaBundy 
2501f2ba47e6SJeff LaBundy 		if (reg_grp_name)
2502f2ba47e6SJeff LaBundy 			reg_grp_node = device_get_named_child_node(&client->dev,
2503f2ba47e6SJeff LaBundy 								   reg_grp_name);
2504f2ba47e6SJeff LaBundy 		else
2505f2ba47e6SJeff LaBundy 			reg_grp_node = fwnode_handle_get(dev_fwnode(&client->dev));
2506f2ba47e6SJeff LaBundy 
2507f2ba47e6SJeff LaBundy 		if (!reg_grp_node)
2508f2ba47e6SJeff LaBundy 			continue;
2509f2ba47e6SJeff LaBundy 
2510f2ba47e6SJeff LaBundy 		error = iqs7211_parse_reg_grp(iqs7211, reg_grp_node, reg_grp);
2511f2ba47e6SJeff LaBundy 		fwnode_handle_put(reg_grp_node);
2512f2ba47e6SJeff LaBundy 		if (error)
2513f2ba47e6SJeff LaBundy 			return error;
2514f2ba47e6SJeff LaBundy 	}
2515f2ba47e6SJeff LaBundy 
2516f2ba47e6SJeff LaBundy 	error = iqs7211_register_kp(iqs7211);
2517f2ba47e6SJeff LaBundy 	if (error)
2518f2ba47e6SJeff LaBundy 		return error;
2519f2ba47e6SJeff LaBundy 
2520f2ba47e6SJeff LaBundy 	error = iqs7211_register_tp(iqs7211);
2521f2ba47e6SJeff LaBundy 	if (error)
2522f2ba47e6SJeff LaBundy 		return error;
2523f2ba47e6SJeff LaBundy 
2524f2ba47e6SJeff LaBundy 	error = iqs7211_init_device(iqs7211);
2525f2ba47e6SJeff LaBundy 	if (error)
2526f2ba47e6SJeff LaBundy 		return error;
2527f2ba47e6SJeff LaBundy 
2528f2ba47e6SJeff LaBundy 	irq = gpiod_to_irq(iqs7211->irq_gpio);
2529f2ba47e6SJeff LaBundy 	if (irq < 0)
2530f2ba47e6SJeff LaBundy 		return irq;
2531f2ba47e6SJeff LaBundy 
2532f2ba47e6SJeff LaBundy 	irq_flags = gpiod_is_active_low(iqs7211->irq_gpio) ? IRQF_TRIGGER_LOW
2533f2ba47e6SJeff LaBundy 							   : IRQF_TRIGGER_HIGH;
2534f2ba47e6SJeff LaBundy 	irq_flags |= IRQF_ONESHOT;
2535f2ba47e6SJeff LaBundy 
2536f2ba47e6SJeff LaBundy 	error = devm_request_threaded_irq(&client->dev, irq, NULL, iqs7211_irq,
2537f2ba47e6SJeff LaBundy 					  irq_flags, client->name, iqs7211);
2538f2ba47e6SJeff LaBundy 	if (error)
2539f2ba47e6SJeff LaBundy 		dev_err(&client->dev, "Failed to request IRQ: %d\n", error);
2540f2ba47e6SJeff LaBundy 
2541f2ba47e6SJeff LaBundy 	return error;
2542f2ba47e6SJeff LaBundy }
2543f2ba47e6SJeff LaBundy 
2544f2ba47e6SJeff LaBundy static struct i2c_driver iqs7211_i2c_driver = {
2545f2ba47e6SJeff LaBundy 	.probe = iqs7211_probe,
2546f2ba47e6SJeff LaBundy 	.driver = {
2547f2ba47e6SJeff LaBundy 		.name = "iqs7211",
2548f2ba47e6SJeff LaBundy 		.of_match_table = iqs7211_of_match,
2549f2ba47e6SJeff LaBundy 		.dev_groups = iqs7211_groups,
2550f2ba47e6SJeff LaBundy 		.pm = pm_sleep_ptr(&iqs7211_pm),
2551f2ba47e6SJeff LaBundy 	},
2552f2ba47e6SJeff LaBundy };
2553f2ba47e6SJeff LaBundy module_i2c_driver(iqs7211_i2c_driver);
2554f2ba47e6SJeff LaBundy 
2555f2ba47e6SJeff LaBundy MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
2556f2ba47e6SJeff LaBundy MODULE_DESCRIPTION("Azoteq IQS7210A/7211A/E Trackpad/Touchscreen Controller");
2557f2ba47e6SJeff LaBundy MODULE_LICENSE("GPL");
2558