xref: /linux/drivers/input/touchscreen/atmel_mxt_ts.c (revision 17bb415fefedb74d2ff02656cf59e4e3ab92ee20)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
24cf51c38SJoonyoung Shim /*
37686b108SIiro Valkonen  * Atmel maXTouch Touchscreen driver
44cf51c38SJoonyoung Shim  *
54cf51c38SJoonyoung Shim  * Copyright (C) 2010 Samsung Electronics Co.Ltd
650a77c65SNick Dyer  * Copyright (C) 2011-2014 Atmel Corporation
71e0c0c5bSDaniel Kurtz  * Copyright (C) 2012 Google, Inc.
8f3c4a8f8SNick Dyer  * Copyright (C) 2016 Zodiac Inflight Innovations
91e0c0c5bSDaniel Kurtz  *
104cf51c38SJoonyoung Shim  * Author: Joonyoung Shim <jy0922.shim@samsung.com>
114cf51c38SJoonyoung Shim  */
124cf51c38SJoonyoung Shim 
134f8d8088SDmitry Torokhov #include <linux/acpi.h>
144f8d8088SDmitry Torokhov #include <linux/dmi.h>
154cf51c38SJoonyoung Shim #include <linux/module.h>
16d79e7e47SBenson Leung #include <linux/init.h>
17d79e7e47SBenson Leung #include <linux/completion.h>
184cf51c38SJoonyoung Shim #include <linux/delay.h>
194cf51c38SJoonyoung Shim #include <linux/firmware.h>
204cf51c38SJoonyoung Shim #include <linux/i2c.h>
218b86c1c2SJoonyoung Shim #include <linux/input/mt.h>
224cf51c38SJoonyoung Shim #include <linux/interrupt.h>
2374d905d2SNick Dyer #include <linux/irq.h>
2478188be3SStephen Warren #include <linux/of.h>
2596a938aaSDmitry Torokhov #include <linux/property.h>
264cf51c38SJoonyoung Shim #include <linux/slab.h>
27f657b00dSSebastian Reichel #include <linux/gpio/consumer.h>
28b23157dcSNick Dyer #include <asm/unaligned.h>
29ecfdd7e2SNick Dyer #include <media/v4l2-device.h>
30ecfdd7e2SNick Dyer #include <media/v4l2-ioctl.h>
31ecfdd7e2SNick Dyer #include <media/videobuf2-v4l2.h>
32ecfdd7e2SNick Dyer #include <media/videobuf2-vmalloc.h>
334cf51c38SJoonyoung Shim 
3450a77c65SNick Dyer /* Firmware files */
357686b108SIiro Valkonen #define MXT_FW_NAME		"maxtouch.fw"
3650a77c65SNick Dyer #define MXT_CFG_NAME		"maxtouch.cfg"
3750a77c65SNick Dyer #define MXT_CFG_MAGIC		"OBP_RAW V1"
384cf51c38SJoonyoung Shim 
394cf51c38SJoonyoung Shim /* Registers */
407686b108SIiro Valkonen #define MXT_OBJECT_START	0x07
417686b108SIiro Valkonen #define MXT_OBJECT_SIZE		6
424ce6fa01SNick Dyer #define MXT_INFO_CHECKSUM_SIZE	3
434ce6fa01SNick Dyer #define MXT_MAX_BLOCK_WRITE	256
444cf51c38SJoonyoung Shim 
454cf51c38SJoonyoung Shim /* Object types */
4681c88a71SIiro Valkonen #define MXT_DEBUG_DIAGNOSTIC_T37	37
4781c88a71SIiro Valkonen #define MXT_GEN_MESSAGE_T5		5
4881c88a71SIiro Valkonen #define MXT_GEN_COMMAND_T6		6
4981c88a71SIiro Valkonen #define MXT_GEN_POWER_T7		7
5081c88a71SIiro Valkonen #define MXT_GEN_ACQUIRE_T8		8
5181c88a71SIiro Valkonen #define MXT_GEN_DATASOURCE_T53		53
5281c88a71SIiro Valkonen #define MXT_TOUCH_MULTI_T9		9
5381c88a71SIiro Valkonen #define MXT_TOUCH_KEYARRAY_T15		15
5481c88a71SIiro Valkonen #define MXT_TOUCH_PROXIMITY_T23		23
5581c88a71SIiro Valkonen #define MXT_TOUCH_PROXKEY_T52		52
5681c88a71SIiro Valkonen #define MXT_PROCI_GRIPFACE_T20		20
5781c88a71SIiro Valkonen #define MXT_PROCG_NOISE_T22		22
5881c88a71SIiro Valkonen #define MXT_PROCI_ONETOUCH_T24		24
5981c88a71SIiro Valkonen #define MXT_PROCI_TWOTOUCH_T27		27
6081c88a71SIiro Valkonen #define MXT_PROCI_GRIP_T40		40
6181c88a71SIiro Valkonen #define MXT_PROCI_PALM_T41		41
6281c88a71SIiro Valkonen #define MXT_PROCI_TOUCHSUPPRESSION_T42	42
6381c88a71SIiro Valkonen #define MXT_PROCI_STYLUS_T47		47
6481c88a71SIiro Valkonen #define MXT_PROCG_NOISESUPPRESSION_T48	48
6581c88a71SIiro Valkonen #define MXT_SPT_COMMSCONFIG_T18		18
6681c88a71SIiro Valkonen #define MXT_SPT_GPIOPWM_T19		19
6781c88a71SIiro Valkonen #define MXT_SPT_SELFTEST_T25		25
6881c88a71SIiro Valkonen #define MXT_SPT_CTECONFIG_T28		28
6981c88a71SIiro Valkonen #define MXT_SPT_USERDATA_T38		38
7081c88a71SIiro Valkonen #define MXT_SPT_DIGITIZER_T43		43
7181c88a71SIiro Valkonen #define MXT_SPT_MESSAGECOUNT_T44	44
7281c88a71SIiro Valkonen #define MXT_SPT_CTECONFIG_T46		46
7315082bdbSNick Dyer #define MXT_SPT_DYNAMICCONFIGURATIONCONTAINER_T71 71
74b23157dcSNick Dyer #define MXT_TOUCH_MULTITOUCHSCREEN_T100 100
754cf51c38SJoonyoung Shim 
765f3f9bc2SNick Dyer /* MXT_GEN_MESSAGE_T5 object */
775f3f9bc2SNick Dyer #define MXT_RPTID_NOMSG		0xff
785f3f9bc2SNick Dyer 
7981c88a71SIiro Valkonen /* MXT_GEN_COMMAND_T6 field */
807686b108SIiro Valkonen #define MXT_COMMAND_RESET	0
817686b108SIiro Valkonen #define MXT_COMMAND_BACKUPNV	1
827686b108SIiro Valkonen #define MXT_COMMAND_CALIBRATE	2
837686b108SIiro Valkonen #define MXT_COMMAND_REPORTALL	3
847686b108SIiro Valkonen #define MXT_COMMAND_DIAGNOSTIC	5
854cf51c38SJoonyoung Shim 
86a4a2ef46SIiro Valkonen /* Define for T6 status byte */
87204b4eaeSNick Dyer #define MXT_T6_STATUS_RESET	BIT(7)
88204b4eaeSNick Dyer #define MXT_T6_STATUS_OFL	BIT(6)
89204b4eaeSNick Dyer #define MXT_T6_STATUS_SIGERR	BIT(5)
90204b4eaeSNick Dyer #define MXT_T6_STATUS_CAL	BIT(4)
91204b4eaeSNick Dyer #define MXT_T6_STATUS_CFGERR	BIT(3)
92204b4eaeSNick Dyer #define MXT_T6_STATUS_COMSERR	BIT(2)
93a4a2ef46SIiro Valkonen 
9481c88a71SIiro Valkonen /* MXT_GEN_POWER_T7 field */
957f3884f7SNick Dyer struct t7_config {
967f3884f7SNick Dyer 	u8 idle;
977f3884f7SNick Dyer 	u8 active;
987f3884f7SNick Dyer } __packed;
997f3884f7SNick Dyer 
1007f3884f7SNick Dyer #define MXT_POWER_CFG_RUN		0
1017f3884f7SNick Dyer #define MXT_POWER_CFG_DEEPSLEEP		1
1024cf51c38SJoonyoung Shim 
10381c88a71SIiro Valkonen /* MXT_TOUCH_MULTI_T9 field */
1047f3884f7SNick Dyer #define MXT_T9_CTRL		0
1052786489fSNick Dyer #define MXT_T9_XSIZE		3
1062786489fSNick Dyer #define MXT_T9_YSIZE		4
10761dc1abaSNick Dyer #define MXT_T9_ORIENT		9
10861dc1abaSNick Dyer #define MXT_T9_RANGE		18
10961dc1abaSNick Dyer 
110f3889ed1SNick Dyer /* MXT_TOUCH_MULTI_T9 status */
111204b4eaeSNick Dyer #define MXT_T9_UNGRIP		BIT(0)
112204b4eaeSNick Dyer #define MXT_T9_SUPPRESS		BIT(1)
113204b4eaeSNick Dyer #define MXT_T9_AMP		BIT(2)
114204b4eaeSNick Dyer #define MXT_T9_VECTOR		BIT(3)
115204b4eaeSNick Dyer #define MXT_T9_MOVE		BIT(4)
116204b4eaeSNick Dyer #define MXT_T9_RELEASE		BIT(5)
117204b4eaeSNick Dyer #define MXT_T9_PRESS		BIT(6)
118204b4eaeSNick Dyer #define MXT_T9_DETECT		BIT(7)
119f3889ed1SNick Dyer 
12061dc1abaSNick Dyer struct t9_range {
1211c0276d5SNick Dyer 	__le16 x;
1221c0276d5SNick Dyer 	__le16 y;
12361dc1abaSNick Dyer } __packed;
12461dc1abaSNick Dyer 
125f3889ed1SNick Dyer /* MXT_TOUCH_MULTI_T9 orient */
126204b4eaeSNick Dyer #define MXT_T9_ORIENT_SWITCH	BIT(0)
127204b4eaeSNick Dyer #define MXT_T9_ORIENT_INVERTX	BIT(1)
128204b4eaeSNick Dyer #define MXT_T9_ORIENT_INVERTY	BIT(2)
1294cf51c38SJoonyoung Shim 
13081c88a71SIiro Valkonen /* MXT_SPT_COMMSCONFIG_T18 */
1317686b108SIiro Valkonen #define MXT_COMMS_CTRL		0
1327686b108SIiro Valkonen #define MXT_COMMS_CMD		1
13374d905d2SNick Dyer #define MXT_COMMS_RETRIGEN	BIT(6)
1344cf51c38SJoonyoung Shim 
135d6a39404SNick Dyer /* MXT_DEBUG_DIAGNOSTIC_T37 */
136d6a39404SNick Dyer #define MXT_DIAGNOSTIC_PAGEUP	0x01
137d6a39404SNick Dyer #define MXT_DIAGNOSTIC_DELTAS	0x10
13806b3d3f3SNick Dyer #define MXT_DIAGNOSTIC_REFS	0x11
139d6a39404SNick Dyer #define MXT_DIAGNOSTIC_SIZE	128
140d6a39404SNick Dyer 
141566d533aSNick Dyer #define MXT_FAMILY_1386			160
142566d533aSNick Dyer #define MXT1386_COLUMNS			3
143566d533aSNick Dyer #define MXT1386_PAGES_PER_COLUMN	8
144566d533aSNick Dyer 
145d6a39404SNick Dyer struct t37_debug {
146d6a39404SNick Dyer #ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37
147d6a39404SNick Dyer 	u8 mode;
148d6a39404SNick Dyer 	u8 page;
149d6a39404SNick Dyer 	u8 data[MXT_DIAGNOSTIC_SIZE];
150d6a39404SNick Dyer #endif
151d6a39404SNick Dyer };
152d6a39404SNick Dyer 
15381c88a71SIiro Valkonen /* Define for MXT_GEN_COMMAND_T6 */
1547686b108SIiro Valkonen #define MXT_BOOT_VALUE		0xa5
155a4a2ef46SIiro Valkonen #define MXT_RESET_VALUE		0x01
1567686b108SIiro Valkonen #define MXT_BACKUP_VALUE	0x55
157a4a2ef46SIiro Valkonen 
158b23157dcSNick Dyer /* T100 Multiple Touch Touchscreen */
159b23157dcSNick Dyer #define MXT_T100_CTRL		0
160b23157dcSNick Dyer #define MXT_T100_CFG1		1
161b23157dcSNick Dyer #define MXT_T100_TCHAUX		3
1622786489fSNick Dyer #define MXT_T100_XSIZE		9
163b23157dcSNick Dyer #define MXT_T100_XRANGE		13
1642786489fSNick Dyer #define MXT_T100_YSIZE		20
165b23157dcSNick Dyer #define MXT_T100_YRANGE		24
166b23157dcSNick Dyer 
167b23157dcSNick Dyer #define MXT_T100_CFG_SWITCHXY	BIT(5)
168de601f71SNick Dyer #define MXT_T100_CFG_INVERTY	BIT(6)
169de601f71SNick Dyer #define MXT_T100_CFG_INVERTX	BIT(7)
170b23157dcSNick Dyer 
171b23157dcSNick Dyer #define MXT_T100_TCHAUX_VECT	BIT(0)
172b23157dcSNick Dyer #define MXT_T100_TCHAUX_AMPL	BIT(1)
173b23157dcSNick Dyer #define MXT_T100_TCHAUX_AREA	BIT(2)
174b23157dcSNick Dyer 
175b23157dcSNick Dyer #define MXT_T100_DETECT		BIT(7)
176b23157dcSNick Dyer #define MXT_T100_TYPE_MASK	0x70
177b23157dcSNick Dyer 
178b23157dcSNick Dyer enum t100_type {
179b23157dcSNick Dyer 	MXT_T100_TYPE_FINGER		= 1,
180b23157dcSNick Dyer 	MXT_T100_TYPE_PASSIVE_STYLUS	= 2,
181b23157dcSNick Dyer 	MXT_T100_TYPE_HOVERING_FINGER	= 4,
182b23157dcSNick Dyer 	MXT_T100_TYPE_GLOVE		= 5,
183b23157dcSNick Dyer 	MXT_T100_TYPE_LARGE_TOUCH	= 6,
184b23157dcSNick Dyer };
185b23157dcSNick Dyer 
186b23157dcSNick Dyer #define MXT_DISTANCE_ACTIVE_TOUCH	0
187b23157dcSNick Dyer #define MXT_DISTANCE_HOVERING		1
188b23157dcSNick Dyer 
189b23157dcSNick Dyer #define MXT_TOUCH_MAJOR_DEFAULT		1
190b23157dcSNick Dyer #define MXT_PRESSURE_DEFAULT		1
191b23157dcSNick Dyer 
192a4a2ef46SIiro Valkonen /* Delay times */
1938343bce1SLinus Torvalds #define MXT_BACKUP_TIME		50	/* msec */
194ca1cd36cSSebastian Reichel #define MXT_RESET_GPIO_TIME	20	/* msec */
195ca1cd36cSSebastian Reichel #define MXT_RESET_INVALID_CHG	100	/* msec */
1968343bce1SLinus Torvalds #define MXT_RESET_TIME		200	/* msec */
197a4a2ef46SIiro Valkonen #define MXT_RESET_TIMEOUT	3000	/* msec */
198c3f78043SNick Dyer #define MXT_CRC_TIMEOUT		1000	/* msec */
199a0434b75SBenson Leung #define MXT_FW_RESET_TIME	3000	/* msec */
200a0434b75SBenson Leung #define MXT_FW_CHG_TIMEOUT	300	/* msec */
2014cf51c38SJoonyoung Shim 
2024cf51c38SJoonyoung Shim /* Command to unlock bootloader */
2037686b108SIiro Valkonen #define MXT_UNLOCK_CMD_MSB	0xaa
2047686b108SIiro Valkonen #define MXT_UNLOCK_CMD_LSB	0xdc
2054cf51c38SJoonyoung Shim 
2064cf51c38SJoonyoung Shim /* Bootloader mode status */
2077686b108SIiro Valkonen #define MXT_WAITING_BOOTLOAD_CMD	0xc0	/* valid 7 6 bit only */
2087686b108SIiro Valkonen #define MXT_WAITING_FRAME_DATA	0x80	/* valid 7 6 bit only */
2097686b108SIiro Valkonen #define MXT_FRAME_CRC_CHECK	0x02
2107686b108SIiro Valkonen #define MXT_FRAME_CRC_FAIL	0x03
2117686b108SIiro Valkonen #define MXT_FRAME_CRC_PASS	0x04
2127686b108SIiro Valkonen #define MXT_APP_CRC_FAIL	0x40	/* valid 7 8 bit only */
2137686b108SIiro Valkonen #define MXT_BOOT_STATUS_MASK	0x3f
214204b4eaeSNick Dyer #define MXT_BOOT_EXTENDED_ID	BIT(5)
215e57a66aaSNick Dyer #define MXT_BOOT_ID_MASK	0x1f
2164cf51c38SJoonyoung Shim 
2174cf51c38SJoonyoung Shim /* Touchscreen absolute values */
2187686b108SIiro Valkonen #define MXT_MAX_AREA		0xff
2194cf51c38SJoonyoung Shim 
22022dfab7fSDaniel Kurtz #define MXT_PIXELS_PER_MM	20
22122dfab7fSDaniel Kurtz 
2227686b108SIiro Valkonen struct mxt_info {
2234cf51c38SJoonyoung Shim 	u8 family_id;
2244cf51c38SJoonyoung Shim 	u8 variant_id;
2254cf51c38SJoonyoung Shim 	u8 version;
2264cf51c38SJoonyoung Shim 	u8 build;
2274cf51c38SJoonyoung Shim 	u8 matrix_xsize;
2284cf51c38SJoonyoung Shim 	u8 matrix_ysize;
2294cf51c38SJoonyoung Shim 	u8 object_num;
2304cf51c38SJoonyoung Shim };
2314cf51c38SJoonyoung Shim 
2327686b108SIiro Valkonen struct mxt_object {
2334cf51c38SJoonyoung Shim 	u8 type;
2344cf51c38SJoonyoung Shim 	u16 start_address;
2351e0c0c5bSDaniel Kurtz 	u8 size_minus_one;
2361e0c0c5bSDaniel Kurtz 	u8 instances_minus_one;
2374cf51c38SJoonyoung Shim 	u8 num_report_ids;
238333e5a9aSDaniel Kurtz } __packed;
2394cf51c38SJoonyoung Shim 
240d6a39404SNick Dyer struct mxt_dbg {
241d6a39404SNick Dyer 	u16 t37_address;
242d6a39404SNick Dyer 	u16 diag_cmd_address;
243d6a39404SNick Dyer 	struct t37_debug *t37_buf;
244d6a39404SNick Dyer 	unsigned int t37_pages;
245d6a39404SNick Dyer 	unsigned int t37_nodes;
246ecfdd7e2SNick Dyer 
247ecfdd7e2SNick Dyer 	struct v4l2_device v4l2;
248ecfdd7e2SNick Dyer 	struct v4l2_pix_format format;
249ecfdd7e2SNick Dyer 	struct video_device vdev;
250ecfdd7e2SNick Dyer 	struct vb2_queue queue;
251ecfdd7e2SNick Dyer 	struct mutex lock;
252ecfdd7e2SNick Dyer 	int input;
253ecfdd7e2SNick Dyer };
254ecfdd7e2SNick Dyer 
25506b3d3f3SNick Dyer enum v4l_dbg_inputs {
25606b3d3f3SNick Dyer 	MXT_V4L_INPUT_DELTAS,
25706b3d3f3SNick Dyer 	MXT_V4L_INPUT_REFS,
25806b3d3f3SNick Dyer 	MXT_V4L_INPUT_MAX,
25906b3d3f3SNick Dyer };
26006b3d3f3SNick Dyer 
26196a938aaSDmitry Torokhov enum mxt_suspend_mode {
26296a938aaSDmitry Torokhov 	MXT_SUSPEND_DEEP_SLEEP	= 0,
26396a938aaSDmitry Torokhov 	MXT_SUSPEND_T9_CTRL	= 1,
26496a938aaSDmitry Torokhov };
26596a938aaSDmitry Torokhov 
266f865df73SNick Dyer /* Config update context */
267f865df73SNick Dyer struct mxt_cfg {
268a4891f10SNick Dyer 	u8 *raw;
269f865df73SNick Dyer 	size_t raw_size;
270f865df73SNick Dyer 	off_t raw_pos;
271f865df73SNick Dyer 
272f865df73SNick Dyer 	u8 *mem;
273f865df73SNick Dyer 	size_t mem_size;
274f865df73SNick Dyer 	int start_ofs;
275f865df73SNick Dyer 
276f865df73SNick Dyer 	struct mxt_info info;
277f865df73SNick Dyer };
278f865df73SNick Dyer 
2794cf51c38SJoonyoung Shim /* Each client has this additional data */
2807686b108SIiro Valkonen struct mxt_data {
2814cf51c38SJoonyoung Shim 	struct i2c_client *client;
2824cf51c38SJoonyoung Shim 	struct input_dev *input_dev;
283ec02ac2bSDaniel Kurtz 	char phys[64];		/* device physical location */
2847686b108SIiro Valkonen 	struct mxt_object *object_table;
285068bdb67SNick Dyer 	struct mxt_info *info;
286068bdb67SNick Dyer 	void *raw_info_block;
2874cf51c38SJoonyoung Shim 	unsigned int irq;
288910d8051SJoonyoung Shim 	unsigned int max_x;
289910d8051SJoonyoung Shim 	unsigned int max_y;
290de601f71SNick Dyer 	bool invertx;
291de601f71SNick Dyer 	bool inverty;
2921c0276d5SNick Dyer 	bool xy_switch;
2932786489fSNick Dyer 	u8 xsize;
2942786489fSNick Dyer 	u8 ysize;
295d79e7e47SBenson Leung 	bool in_bootloader;
2964ce6fa01SNick Dyer 	u16 mem_size;
297b23157dcSNick Dyer 	u8 t100_aux_ampl;
298b23157dcSNick Dyer 	u8 t100_aux_area;
299b23157dcSNick Dyer 	u8 t100_aux_vect;
3009d8dc3e5SNick Dyer 	u8 max_reportid;
301c3f78043SNick Dyer 	u32 config_crc;
3024ce6fa01SNick Dyer 	u32 info_crc;
303f28a842dSNick Dyer 	u8 bootloader_addr;
3045f3f9bc2SNick Dyer 	u8 *msg_buf;
305497767d1SNick Dyer 	u8 t6_status;
306b9b05a89SNick Dyer 	bool update_input;
3079d8dc3e5SNick Dyer 	u8 last_message_count;
3089d8dc3e5SNick Dyer 	u8 num_touchids;
309b23157dcSNick Dyer 	u8 multitouch;
3107f3884f7SNick Dyer 	struct t7_config t7_cfg;
311d6a39404SNick Dyer 	struct mxt_dbg dbg;
312f657b00dSSebastian Reichel 	struct gpio_desc *reset_gpio;
31374d905d2SNick Dyer 	bool use_retrigen_workaround;
314333e5a9aSDaniel Kurtz 
315333e5a9aSDaniel Kurtz 	/* Cached parameters from object table */
316b9b05a89SNick Dyer 	u16 T5_address;
3175f3f9bc2SNick Dyer 	u8 T5_msg_size;
318fdf80421SDaniel Kurtz 	u8 T6_reportid;
319a4a2ef46SIiro Valkonen 	u16 T6_address;
3204ce6fa01SNick Dyer 	u16 T7_address;
32115082bdbSNick Dyer 	u16 T71_address;
322333e5a9aSDaniel Kurtz 	u8 T9_reportid_min;
323333e5a9aSDaniel Kurtz 	u8 T9_reportid_max;
32474d905d2SNick Dyer 	u16 T18_address;
32522dfab7fSDaniel Kurtz 	u8 T19_reportid;
3269d8dc3e5SNick Dyer 	u16 T44_address;
327b23157dcSNick Dyer 	u8 T100_reportid_min;
328b23157dcSNick Dyer 	u8 T100_reportid_max;
329d79e7e47SBenson Leung 
330d79e7e47SBenson Leung 	/* for fw update in bootloader */
331d79e7e47SBenson Leung 	struct completion bl_completion;
332a4a2ef46SIiro Valkonen 
333a4a2ef46SIiro Valkonen 	/* for reset handling */
334a4a2ef46SIiro Valkonen 	struct completion reset_completion;
335c3f78043SNick Dyer 
336c3f78043SNick Dyer 	/* for config update handling */
337c3f78043SNick Dyer 	struct completion crc_completion;
338d80808e1SDmitry Torokhov 
33996a938aaSDmitry Torokhov 	u32 *t19_keymap;
34096a938aaSDmitry Torokhov 	unsigned int t19_num_keys;
34196a938aaSDmitry Torokhov 
342d80808e1SDmitry Torokhov 	enum mxt_suspend_mode suspend_mode;
3434cf51c38SJoonyoung Shim };
3444cf51c38SJoonyoung Shim 
345ecfdd7e2SNick Dyer struct mxt_vb2_buffer {
346ecfdd7e2SNick Dyer 	struct vb2_buffer	vb;
347ecfdd7e2SNick Dyer 	struct list_head	list;
348ecfdd7e2SNick Dyer };
349ecfdd7e2SNick Dyer 
3501e0c0c5bSDaniel Kurtz static size_t mxt_obj_size(const struct mxt_object *obj)
3511e0c0c5bSDaniel Kurtz {
3521e0c0c5bSDaniel Kurtz 	return obj->size_minus_one + 1;
3531e0c0c5bSDaniel Kurtz }
3541e0c0c5bSDaniel Kurtz 
3551e0c0c5bSDaniel Kurtz static size_t mxt_obj_instances(const struct mxt_object *obj)
3561e0c0c5bSDaniel Kurtz {
3571e0c0c5bSDaniel Kurtz 	return obj->instances_minus_one + 1;
3581e0c0c5bSDaniel Kurtz }
3591e0c0c5bSDaniel Kurtz 
3607686b108SIiro Valkonen static bool mxt_object_readable(unsigned int type)
3614cf51c38SJoonyoung Shim {
3624cf51c38SJoonyoung Shim 	switch (type) {
36381c88a71SIiro Valkonen 	case MXT_GEN_COMMAND_T6:
36481c88a71SIiro Valkonen 	case MXT_GEN_POWER_T7:
36581c88a71SIiro Valkonen 	case MXT_GEN_ACQUIRE_T8:
36681c88a71SIiro Valkonen 	case MXT_GEN_DATASOURCE_T53:
36781c88a71SIiro Valkonen 	case MXT_TOUCH_MULTI_T9:
36881c88a71SIiro Valkonen 	case MXT_TOUCH_KEYARRAY_T15:
36981c88a71SIiro Valkonen 	case MXT_TOUCH_PROXIMITY_T23:
37081c88a71SIiro Valkonen 	case MXT_TOUCH_PROXKEY_T52:
371089b50d9SMaxime Roussin-Bélanger 	case MXT_TOUCH_MULTITOUCHSCREEN_T100:
37281c88a71SIiro Valkonen 	case MXT_PROCI_GRIPFACE_T20:
37381c88a71SIiro Valkonen 	case MXT_PROCG_NOISE_T22:
37481c88a71SIiro Valkonen 	case MXT_PROCI_ONETOUCH_T24:
37581c88a71SIiro Valkonen 	case MXT_PROCI_TWOTOUCH_T27:
37681c88a71SIiro Valkonen 	case MXT_PROCI_GRIP_T40:
37781c88a71SIiro Valkonen 	case MXT_PROCI_PALM_T41:
37881c88a71SIiro Valkonen 	case MXT_PROCI_TOUCHSUPPRESSION_T42:
37981c88a71SIiro Valkonen 	case MXT_PROCI_STYLUS_T47:
38081c88a71SIiro Valkonen 	case MXT_PROCG_NOISESUPPRESSION_T48:
38181c88a71SIiro Valkonen 	case MXT_SPT_COMMSCONFIG_T18:
38281c88a71SIiro Valkonen 	case MXT_SPT_GPIOPWM_T19:
38381c88a71SIiro Valkonen 	case MXT_SPT_SELFTEST_T25:
38481c88a71SIiro Valkonen 	case MXT_SPT_CTECONFIG_T28:
38581c88a71SIiro Valkonen 	case MXT_SPT_USERDATA_T38:
38681c88a71SIiro Valkonen 	case MXT_SPT_DIGITIZER_T43:
38781c88a71SIiro Valkonen 	case MXT_SPT_CTECONFIG_T46:
38815082bdbSNick Dyer 	case MXT_SPT_DYNAMICCONFIGURATIONCONTAINER_T71:
3894cf51c38SJoonyoung Shim 		return true;
3904cf51c38SJoonyoung Shim 	default:
3914cf51c38SJoonyoung Shim 		return false;
3924cf51c38SJoonyoung Shim 	}
3934cf51c38SJoonyoung Shim }
3944cf51c38SJoonyoung Shim 
3955f3f9bc2SNick Dyer static void mxt_dump_message(struct mxt_data *data, u8 *message)
3964cf51c38SJoonyoung Shim {
3975f3f9bc2SNick Dyer 	dev_dbg(&data->client->dev, "message: %*ph\n",
3985f3f9bc2SNick Dyer 		data->T5_msg_size, message);
3994cf51c38SJoonyoung Shim }
4004cf51c38SJoonyoung Shim 
401a4a2ef46SIiro Valkonen static int mxt_wait_for_completion(struct mxt_data *data,
402a4a2ef46SIiro Valkonen 				   struct completion *comp,
403a4a2ef46SIiro Valkonen 				   unsigned int timeout_ms)
4044cf51c38SJoonyoung Shim {
405d79e7e47SBenson Leung 	struct device *dev = &data->client->dev;
406d79e7e47SBenson Leung 	unsigned long timeout = msecs_to_jiffies(timeout_ms);
407d79e7e47SBenson Leung 	long ret;
408d79e7e47SBenson Leung 
409d79e7e47SBenson Leung 	ret = wait_for_completion_interruptible_timeout(comp, timeout);
410d79e7e47SBenson Leung 	if (ret < 0) {
411d79e7e47SBenson Leung 		return ret;
412d79e7e47SBenson Leung 	} else if (ret == 0) {
413d79e7e47SBenson Leung 		dev_err(dev, "Wait for completion timed out.\n");
414d79e7e47SBenson Leung 		return -ETIMEDOUT;
415d79e7e47SBenson Leung 	}
416d79e7e47SBenson Leung 	return 0;
417d79e7e47SBenson Leung }
418d79e7e47SBenson Leung 
419f28a842dSNick Dyer static int mxt_bootloader_read(struct mxt_data *data,
420f28a842dSNick Dyer 			       u8 *val, unsigned int count)
421f28a842dSNick Dyer {
422f28a842dSNick Dyer 	int ret;
423f28a842dSNick Dyer 	struct i2c_msg msg;
424f28a842dSNick Dyer 
425f28a842dSNick Dyer 	msg.addr = data->bootloader_addr;
426f28a842dSNick Dyer 	msg.flags = data->client->flags & I2C_M_TEN;
427f28a842dSNick Dyer 	msg.flags |= I2C_M_RD;
428f28a842dSNick Dyer 	msg.len = count;
429f28a842dSNick Dyer 	msg.buf = val;
430f28a842dSNick Dyer 
431f28a842dSNick Dyer 	ret = i2c_transfer(data->client->adapter, &msg, 1);
432f28a842dSNick Dyer 	if (ret == 1) {
433f28a842dSNick Dyer 		ret = 0;
434f28a842dSNick Dyer 	} else {
435f28a842dSNick Dyer 		ret = ret < 0 ? ret : -EIO;
436f28a842dSNick Dyer 		dev_err(&data->client->dev, "%s: i2c recv failed (%d)\n",
437f28a842dSNick Dyer 			__func__, ret);
438f28a842dSNick Dyer 	}
439f28a842dSNick Dyer 
440f28a842dSNick Dyer 	return ret;
441f28a842dSNick Dyer }
442f28a842dSNick Dyer 
443f28a842dSNick Dyer static int mxt_bootloader_write(struct mxt_data *data,
444f28a842dSNick Dyer 				const u8 * const val, unsigned int count)
445f28a842dSNick Dyer {
446f28a842dSNick Dyer 	int ret;
447f28a842dSNick Dyer 	struct i2c_msg msg;
448f28a842dSNick Dyer 
449f28a842dSNick Dyer 	msg.addr = data->bootloader_addr;
450f28a842dSNick Dyer 	msg.flags = data->client->flags & I2C_M_TEN;
451f28a842dSNick Dyer 	msg.len = count;
452f28a842dSNick Dyer 	msg.buf = (u8 *)val;
453f28a842dSNick Dyer 
454f28a842dSNick Dyer 	ret = i2c_transfer(data->client->adapter, &msg, 1);
455f28a842dSNick Dyer 	if (ret == 1) {
456f28a842dSNick Dyer 		ret = 0;
457f28a842dSNick Dyer 	} else {
458f28a842dSNick Dyer 		ret = ret < 0 ? ret : -EIO;
459f28a842dSNick Dyer 		dev_err(&data->client->dev, "%s: i2c send failed (%d)\n",
460f28a842dSNick Dyer 			__func__, ret);
461f28a842dSNick Dyer 	}
462f28a842dSNick Dyer 
463f28a842dSNick Dyer 	return ret;
464f28a842dSNick Dyer }
465f28a842dSNick Dyer 
4668efaa5e5SNick Dyer static int mxt_lookup_bootloader_address(struct mxt_data *data, bool retry)
467f28a842dSNick Dyer {
468f28a842dSNick Dyer 	u8 appmode = data->client->addr;
469f28a842dSNick Dyer 	u8 bootloader;
470068bdb67SNick Dyer 	u8 family_id = data->info ? data->info->family_id : 0;
471f28a842dSNick Dyer 
472f28a842dSNick Dyer 	switch (appmode) {
473f28a842dSNick Dyer 	case 0x4a:
474f28a842dSNick Dyer 	case 0x4b:
47544a0bab2SNick Dyer 		/* Chips after 1664S use different scheme */
476068bdb67SNick Dyer 		if (retry || family_id >= 0xa2) {
47744a0bab2SNick Dyer 			bootloader = appmode - 0x24;
47844a0bab2SNick Dyer 			break;
47944a0bab2SNick Dyer 		}
480*df561f66SGustavo A. R. Silva 		fallthrough;	/* for normal case */
481f28a842dSNick Dyer 	case 0x4c:
482f28a842dSNick Dyer 	case 0x4d:
483f28a842dSNick Dyer 	case 0x5a:
484f28a842dSNick Dyer 	case 0x5b:
485f28a842dSNick Dyer 		bootloader = appmode - 0x26;
486f28a842dSNick Dyer 		break;
4876cd1ab0fSDmitry Torokhov 
488f28a842dSNick Dyer 	default:
489f28a842dSNick Dyer 		dev_err(&data->client->dev,
490f28a842dSNick Dyer 			"Appmode i2c address 0x%02x not found\n",
491f28a842dSNick Dyer 			appmode);
492f28a842dSNick Dyer 		return -EINVAL;
493f28a842dSNick Dyer 	}
494f28a842dSNick Dyer 
495f28a842dSNick Dyer 	data->bootloader_addr = bootloader;
496f28a842dSNick Dyer 	return 0;
497f28a842dSNick Dyer }
498f28a842dSNick Dyer 
4996cd1ab0fSDmitry Torokhov static int mxt_probe_bootloader(struct mxt_data *data, bool alt_address)
500a9fdd1e6SNick Dyer {
501a9fdd1e6SNick Dyer 	struct device *dev = &data->client->dev;
5026cd1ab0fSDmitry Torokhov 	int error;
503a9fdd1e6SNick Dyer 	u8 val;
504a9fdd1e6SNick Dyer 	bool crc_failure;
505a9fdd1e6SNick Dyer 
5066cd1ab0fSDmitry Torokhov 	error = mxt_lookup_bootloader_address(data, alt_address);
5076cd1ab0fSDmitry Torokhov 	if (error)
5086cd1ab0fSDmitry Torokhov 		return error;
509a9fdd1e6SNick Dyer 
5106cd1ab0fSDmitry Torokhov 	error = mxt_bootloader_read(data, &val, 1);
5116cd1ab0fSDmitry Torokhov 	if (error)
5126cd1ab0fSDmitry Torokhov 		return error;
513a9fdd1e6SNick Dyer 
514a9fdd1e6SNick Dyer 	/* Check app crc fail mode */
515a9fdd1e6SNick Dyer 	crc_failure = (val & ~MXT_BOOT_STATUS_MASK) == MXT_APP_CRC_FAIL;
516a9fdd1e6SNick Dyer 
517a9fdd1e6SNick Dyer 	dev_err(dev, "Detected bootloader, status:%02X%s\n",
518a9fdd1e6SNick Dyer 			val, crc_failure ? ", APP_CRC_FAIL" : "");
519a9fdd1e6SNick Dyer 
520a9fdd1e6SNick Dyer 	return 0;
521a9fdd1e6SNick Dyer }
522a9fdd1e6SNick Dyer 
523e57a66aaSNick Dyer static u8 mxt_get_bootloader_version(struct mxt_data *data, u8 val)
524e57a66aaSNick Dyer {
525e57a66aaSNick Dyer 	struct device *dev = &data->client->dev;
526e57a66aaSNick Dyer 	u8 buf[3];
527e57a66aaSNick Dyer 
528e57a66aaSNick Dyer 	if (val & MXT_BOOT_EXTENDED_ID) {
529e57a66aaSNick Dyer 		if (mxt_bootloader_read(data, &buf[0], 3) != 0) {
530e57a66aaSNick Dyer 			dev_err(dev, "%s: i2c failure\n", __func__);
53168807a0cSNick Dyer 			return val;
532e57a66aaSNick Dyer 		}
533e57a66aaSNick Dyer 
534e57a66aaSNick Dyer 		dev_dbg(dev, "Bootloader ID:%d Version:%d\n", buf[1], buf[2]);
535e57a66aaSNick Dyer 
536e57a66aaSNick Dyer 		return buf[0];
537e57a66aaSNick Dyer 	} else {
538e57a66aaSNick Dyer 		dev_dbg(dev, "Bootloader ID:%d\n", val & MXT_BOOT_ID_MASK);
539e57a66aaSNick Dyer 
540e57a66aaSNick Dyer 		return val;
541e57a66aaSNick Dyer 	}
542e57a66aaSNick Dyer }
543e57a66aaSNick Dyer 
544385deb96SNick Dyer static int mxt_check_bootloader(struct mxt_data *data, unsigned int state,
545385deb96SNick Dyer 				bool wait)
546d79e7e47SBenson Leung {
547f28a842dSNick Dyer 	struct device *dev = &data->client->dev;
5484cf51c38SJoonyoung Shim 	u8 val;
549d79e7e47SBenson Leung 	int ret;
5504cf51c38SJoonyoung Shim 
5514cf51c38SJoonyoung Shim recheck:
552385deb96SNick Dyer 	if (wait) {
553d79e7e47SBenson Leung 		/*
554d79e7e47SBenson Leung 		 * In application update mode, the interrupt
555d79e7e47SBenson Leung 		 * line signals state transitions. We must wait for the
556d79e7e47SBenson Leung 		 * CHG assertion before reading the status byte.
557d79e7e47SBenson Leung 		 * Once the status byte has been read, the line is deasserted.
558d79e7e47SBenson Leung 		 */
559a4a2ef46SIiro Valkonen 		ret = mxt_wait_for_completion(data, &data->bl_completion,
560a4a2ef46SIiro Valkonen 					      MXT_FW_CHG_TIMEOUT);
561d79e7e47SBenson Leung 		if (ret) {
562d79e7e47SBenson Leung 			/*
563d79e7e47SBenson Leung 			 * TODO: handle -ERESTARTSYS better by terminating
564d79e7e47SBenson Leung 			 * fw update process before returning to userspace
565d79e7e47SBenson Leung 			 * by writing length 0x000 to device (iff we are in
566d79e7e47SBenson Leung 			 * WAITING_FRAME_DATA state).
567d79e7e47SBenson Leung 			 */
568f28a842dSNick Dyer 			dev_err(dev, "Update wait error %d\n", ret);
569d79e7e47SBenson Leung 			return ret;
570d79e7e47SBenson Leung 		}
571d79e7e47SBenson Leung 	}
572d79e7e47SBenson Leung 
573f28a842dSNick Dyer 	ret = mxt_bootloader_read(data, &val, 1);
574f28a842dSNick Dyer 	if (ret)
575f28a842dSNick Dyer 		return ret;
5764cf51c38SJoonyoung Shim 
577e57a66aaSNick Dyer 	if (state == MXT_WAITING_BOOTLOAD_CMD)
578e57a66aaSNick Dyer 		val = mxt_get_bootloader_version(data, val);
579e57a66aaSNick Dyer 
5804cf51c38SJoonyoung Shim 	switch (state) {
5817686b108SIiro Valkonen 	case MXT_WAITING_BOOTLOAD_CMD:
5827686b108SIiro Valkonen 	case MXT_WAITING_FRAME_DATA:
583a9fdd1e6SNick Dyer 	case MXT_APP_CRC_FAIL:
5847686b108SIiro Valkonen 		val &= ~MXT_BOOT_STATUS_MASK;
5854cf51c38SJoonyoung Shim 		break;
5867686b108SIiro Valkonen 	case MXT_FRAME_CRC_PASS:
587f943c74aSNick Dyer 		if (val == MXT_FRAME_CRC_CHECK) {
5884cf51c38SJoonyoung Shim 			goto recheck;
589f943c74aSNick Dyer 		} else if (val == MXT_FRAME_CRC_FAIL) {
590f943c74aSNick Dyer 			dev_err(dev, "Bootloader CRC fail\n");
591f943c74aSNick Dyer 			return -EINVAL;
592f943c74aSNick Dyer 		}
5934cf51c38SJoonyoung Shim 		break;
5944cf51c38SJoonyoung Shim 	default:
5954cf51c38SJoonyoung Shim 		return -EINVAL;
5964cf51c38SJoonyoung Shim 	}
5974cf51c38SJoonyoung Shim 
5984cf51c38SJoonyoung Shim 	if (val != state) {
599f28a842dSNick Dyer 		dev_err(dev, "Invalid bootloader state %02X != %02X\n",
6007bed6805SNick Dyer 			val, state);
6014cf51c38SJoonyoung Shim 		return -EINVAL;
6024cf51c38SJoonyoung Shim 	}
6034cf51c38SJoonyoung Shim 
6044cf51c38SJoonyoung Shim 	return 0;
6054cf51c38SJoonyoung Shim }
6064cf51c38SJoonyoung Shim 
6078efaa5e5SNick Dyer static int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock)
6084cf51c38SJoonyoung Shim {
609f28a842dSNick Dyer 	int ret;
6104cf51c38SJoonyoung Shim 	u8 buf[2];
6114cf51c38SJoonyoung Shim 
6128efaa5e5SNick Dyer 	if (unlock) {
6137686b108SIiro Valkonen 		buf[0] = MXT_UNLOCK_CMD_LSB;
6147686b108SIiro Valkonen 		buf[1] = MXT_UNLOCK_CMD_MSB;
6158efaa5e5SNick Dyer 	} else {
6168efaa5e5SNick Dyer 		buf[0] = 0x01;
6178efaa5e5SNick Dyer 		buf[1] = 0x01;
6188efaa5e5SNick Dyer 	}
6194cf51c38SJoonyoung Shim 
620f28a842dSNick Dyer 	ret = mxt_bootloader_write(data, buf, 2);
621f28a842dSNick Dyer 	if (ret)
622f28a842dSNick Dyer 		return ret;
6234cf51c38SJoonyoung Shim 
6244cf51c38SJoonyoung Shim 	return 0;
6254cf51c38SJoonyoung Shim }
6264cf51c38SJoonyoung Shim 
6277686b108SIiro Valkonen static int __mxt_read_reg(struct i2c_client *client,
6284cf51c38SJoonyoung Shim 			       u16 reg, u16 len, void *val)
6294cf51c38SJoonyoung Shim {
6304cf51c38SJoonyoung Shim 	struct i2c_msg xfer[2];
6314cf51c38SJoonyoung Shim 	u8 buf[2];
632771733e3SDaniel Kurtz 	int ret;
6334cf51c38SJoonyoung Shim 
6344cf51c38SJoonyoung Shim 	buf[0] = reg & 0xff;
6354cf51c38SJoonyoung Shim 	buf[1] = (reg >> 8) & 0xff;
6364cf51c38SJoonyoung Shim 
6374cf51c38SJoonyoung Shim 	/* Write register */
6384cf51c38SJoonyoung Shim 	xfer[0].addr = client->addr;
6394cf51c38SJoonyoung Shim 	xfer[0].flags = 0;
6404cf51c38SJoonyoung Shim 	xfer[0].len = 2;
6414cf51c38SJoonyoung Shim 	xfer[0].buf = buf;
6424cf51c38SJoonyoung Shim 
6434cf51c38SJoonyoung Shim 	/* Read data */
6444cf51c38SJoonyoung Shim 	xfer[1].addr = client->addr;
6454cf51c38SJoonyoung Shim 	xfer[1].flags = I2C_M_RD;
6464cf51c38SJoonyoung Shim 	xfer[1].len = len;
6474cf51c38SJoonyoung Shim 	xfer[1].buf = val;
6484cf51c38SJoonyoung Shim 
649771733e3SDaniel Kurtz 	ret = i2c_transfer(client->adapter, xfer, 2);
650771733e3SDaniel Kurtz 	if (ret == 2) {
651771733e3SDaniel Kurtz 		ret = 0;
652771733e3SDaniel Kurtz 	} else {
653771733e3SDaniel Kurtz 		if (ret >= 0)
654771733e3SDaniel Kurtz 			ret = -EIO;
655771733e3SDaniel Kurtz 		dev_err(&client->dev, "%s: i2c transfer failed (%d)\n",
656771733e3SDaniel Kurtz 			__func__, ret);
6574cf51c38SJoonyoung Shim 	}
6584cf51c38SJoonyoung Shim 
659771733e3SDaniel Kurtz 	return ret;
6604cf51c38SJoonyoung Shim }
6614cf51c38SJoonyoung Shim 
6629638ab7cSDaniel Kurtz static int __mxt_write_reg(struct i2c_client *client, u16 reg, u16 len,
6639638ab7cSDaniel Kurtz 			   const void *val)
6644cf51c38SJoonyoung Shim {
6659638ab7cSDaniel Kurtz 	u8 *buf;
6669638ab7cSDaniel Kurtz 	size_t count;
667771733e3SDaniel Kurtz 	int ret;
6684cf51c38SJoonyoung Shim 
6699638ab7cSDaniel Kurtz 	count = len + 2;
6709638ab7cSDaniel Kurtz 	buf = kmalloc(count, GFP_KERNEL);
6719638ab7cSDaniel Kurtz 	if (!buf)
6729638ab7cSDaniel Kurtz 		return -ENOMEM;
6734cf51c38SJoonyoung Shim 
6744cf51c38SJoonyoung Shim 	buf[0] = reg & 0xff;
6754cf51c38SJoonyoung Shim 	buf[1] = (reg >> 8) & 0xff;
6769638ab7cSDaniel Kurtz 	memcpy(&buf[2], val, len);
6774cf51c38SJoonyoung Shim 
6789638ab7cSDaniel Kurtz 	ret = i2c_master_send(client, buf, count);
6799638ab7cSDaniel Kurtz 	if (ret == count) {
680771733e3SDaniel Kurtz 		ret = 0;
681771733e3SDaniel Kurtz 	} else {
682771733e3SDaniel Kurtz 		if (ret >= 0)
683771733e3SDaniel Kurtz 			ret = -EIO;
684771733e3SDaniel Kurtz 		dev_err(&client->dev, "%s: i2c send failed (%d)\n",
685771733e3SDaniel Kurtz 			__func__, ret);
6864cf51c38SJoonyoung Shim 	}
6874cf51c38SJoonyoung Shim 
6889638ab7cSDaniel Kurtz 	kfree(buf);
689771733e3SDaniel Kurtz 	return ret;
6904cf51c38SJoonyoung Shim }
6914cf51c38SJoonyoung Shim 
6929638ab7cSDaniel Kurtz static int mxt_write_reg(struct i2c_client *client, u16 reg, u8 val)
6934cf51c38SJoonyoung Shim {
6949638ab7cSDaniel Kurtz 	return __mxt_write_reg(client, reg, 1, &val);
6954cf51c38SJoonyoung Shim }
6964cf51c38SJoonyoung Shim 
6977686b108SIiro Valkonen static struct mxt_object *
6987686b108SIiro Valkonen mxt_get_object(struct mxt_data *data, u8 type)
6994cf51c38SJoonyoung Shim {
7007686b108SIiro Valkonen 	struct mxt_object *object;
7014cf51c38SJoonyoung Shim 	int i;
7024cf51c38SJoonyoung Shim 
703068bdb67SNick Dyer 	for (i = 0; i < data->info->object_num; i++) {
7044cf51c38SJoonyoung Shim 		object = data->object_table + i;
7054cf51c38SJoonyoung Shim 		if (object->type == type)
7064cf51c38SJoonyoung Shim 			return object;
7074cf51c38SJoonyoung Shim 	}
7084cf51c38SJoonyoung Shim 
70950a77c65SNick Dyer 	dev_warn(&data->client->dev, "Invalid object type T%u\n", type);
7104cf51c38SJoonyoung Shim 	return NULL;
7114cf51c38SJoonyoung Shim }
7124cf51c38SJoonyoung Shim 
713497767d1SNick Dyer static void mxt_proc_t6_messages(struct mxt_data *data, u8 *msg)
714497767d1SNick Dyer {
715497767d1SNick Dyer 	struct device *dev = &data->client->dev;
716497767d1SNick Dyer 	u8 status = msg[1];
717497767d1SNick Dyer 	u32 crc = msg[2] | (msg[3] << 8) | (msg[4] << 16);
718497767d1SNick Dyer 
719497767d1SNick Dyer 	if (crc != data->config_crc) {
720497767d1SNick Dyer 		data->config_crc = crc;
721497767d1SNick Dyer 		dev_dbg(dev, "T6 Config Checksum: 0x%06X\n", crc);
722497767d1SNick Dyer 	}
723497767d1SNick Dyer 
72419a7121eSNick Dyer 	complete(&data->crc_completion);
72519a7121eSNick Dyer 
726497767d1SNick Dyer 	/* Detect reset */
727497767d1SNick Dyer 	if (status & MXT_T6_STATUS_RESET)
728497767d1SNick Dyer 		complete(&data->reset_completion);
729497767d1SNick Dyer 
730497767d1SNick Dyer 	/* Output debug if status has changed */
731497767d1SNick Dyer 	if (status != data->t6_status)
732497767d1SNick Dyer 		dev_dbg(dev, "T6 Status 0x%02X%s%s%s%s%s%s%s\n",
733497767d1SNick Dyer 			status,
734497767d1SNick Dyer 			status == 0 ? " OK" : "",
735497767d1SNick Dyer 			status & MXT_T6_STATUS_RESET ? " RESET" : "",
736497767d1SNick Dyer 			status & MXT_T6_STATUS_OFL ? " OFL" : "",
737497767d1SNick Dyer 			status & MXT_T6_STATUS_SIGERR ? " SIGERR" : "",
738497767d1SNick Dyer 			status & MXT_T6_STATUS_CAL ? " CAL" : "",
739497767d1SNick Dyer 			status & MXT_T6_STATUS_CFGERR ? " CFGERR" : "",
740497767d1SNick Dyer 			status & MXT_T6_STATUS_COMSERR ? " COMSERR" : "");
741497767d1SNick Dyer 
742497767d1SNick Dyer 	/* Save current status */
743497767d1SNick Dyer 	data->t6_status = status;
744497767d1SNick Dyer }
745497767d1SNick Dyer 
7467f405483SLinus Torvalds static int mxt_write_object(struct mxt_data *data,
7477f405483SLinus Torvalds 				 u8 type, u8 offset, u8 val)
7487f405483SLinus Torvalds {
7497f405483SLinus Torvalds 	struct mxt_object *object;
7507f405483SLinus Torvalds 	u16 reg;
7517f405483SLinus Torvalds 
7527f405483SLinus Torvalds 	object = mxt_get_object(data, type);
7537f405483SLinus Torvalds 	if (!object || offset >= mxt_obj_size(object))
7547f405483SLinus Torvalds 		return -EINVAL;
7557f405483SLinus Torvalds 
7567f405483SLinus Torvalds 	reg = object->start_address;
7577f405483SLinus Torvalds 	return mxt_write_reg(data->client, reg + offset, val);
7587f405483SLinus Torvalds }
7597f405483SLinus Torvalds 
7605f3f9bc2SNick Dyer static void mxt_input_button(struct mxt_data *data, u8 *message)
76122dfab7fSDaniel Kurtz {
76222dfab7fSDaniel Kurtz 	struct input_dev *input = data->input_dev;
76322dfab7fSDaniel Kurtz 	int i;
76422dfab7fSDaniel Kurtz 
76596a938aaSDmitry Torokhov 	for (i = 0; i < data->t19_num_keys; i++) {
76696a938aaSDmitry Torokhov 		if (data->t19_keymap[i] == KEY_RESERVED)
76722dfab7fSDaniel Kurtz 			continue;
768c37f6d38SDmitry Torokhov 
769c37f6d38SDmitry Torokhov 		/* Active-low switch */
77096a938aaSDmitry Torokhov 		input_report_key(input, data->t19_keymap[i],
771c37f6d38SDmitry Torokhov 				 !(message[1] & BIT(i)));
77222dfab7fSDaniel Kurtz 	}
77322dfab7fSDaniel Kurtz }
77422dfab7fSDaniel Kurtz 
775b735fbe0SBenson Leung static void mxt_input_sync(struct mxt_data *data)
776eef820dcSNick Dyer {
777b735fbe0SBenson Leung 	input_mt_report_pointer_emulation(data->input_dev,
77896a938aaSDmitry Torokhov 					  data->t19_num_keys);
779b735fbe0SBenson Leung 	input_sync(data->input_dev);
780eef820dcSNick Dyer }
781eef820dcSNick Dyer 
782b9b05a89SNick Dyer static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
7834cf51c38SJoonyoung Shim {
7844cf51c38SJoonyoung Shim 	struct device *dev = &data->client->dev;
785fba5bc31SDaniel Kurtz 	struct input_dev *input_dev = data->input_dev;
7865f3f9bc2SNick Dyer 	int id;
7875f3f9bc2SNick Dyer 	u8 status;
7884cf51c38SJoonyoung Shim 	int x;
7894cf51c38SJoonyoung Shim 	int y;
7904cf51c38SJoonyoung Shim 	int area;
791fea9e467SNick Dyer 	int amplitude;
7924cf51c38SJoonyoung Shim 
7935f3f9bc2SNick Dyer 	id = message[0] - data->T9_reportid_min;
7945f3f9bc2SNick Dyer 	status = message[1];
7955f3f9bc2SNick Dyer 	x = (message[2] << 4) | ((message[4] >> 4) & 0xf);
7965f3f9bc2SNick Dyer 	y = (message[3] << 4) | ((message[4] & 0xf));
797eef820dcSNick Dyer 
798eef820dcSNick Dyer 	/* Handle 10/12 bit switching */
799910d8051SJoonyoung Shim 	if (data->max_x < 1024)
800eef820dcSNick Dyer 		x >>= 2;
801910d8051SJoonyoung Shim 	if (data->max_y < 1024)
802eef820dcSNick Dyer 		y >>= 2;
803910d8051SJoonyoung Shim 
8045f3f9bc2SNick Dyer 	area = message[5];
8055f3f9bc2SNick Dyer 	amplitude = message[6];
8064cf51c38SJoonyoung Shim 
807b2e459b8SDaniel Kurtz 	dev_dbg(dev,
808b2e459b8SDaniel Kurtz 		"[%u] %c%c%c%c%c%c%c%c x: %5u y: %5u area: %3u amp: %3u\n",
809b2e459b8SDaniel Kurtz 		id,
810f3889ed1SNick Dyer 		(status & MXT_T9_DETECT) ? 'D' : '.',
811f3889ed1SNick Dyer 		(status & MXT_T9_PRESS) ? 'P' : '.',
812f3889ed1SNick Dyer 		(status & MXT_T9_RELEASE) ? 'R' : '.',
813f3889ed1SNick Dyer 		(status & MXT_T9_MOVE) ? 'M' : '.',
814f3889ed1SNick Dyer 		(status & MXT_T9_VECTOR) ? 'V' : '.',
815f3889ed1SNick Dyer 		(status & MXT_T9_AMP) ? 'A' : '.',
816f3889ed1SNick Dyer 		(status & MXT_T9_SUPPRESS) ? 'S' : '.',
817f3889ed1SNick Dyer 		(status & MXT_T9_UNGRIP) ? 'U' : '.',
818fea9e467SNick Dyer 		x, y, area, amplitude);
8194cf51c38SJoonyoung Shim 
820fba5bc31SDaniel Kurtz 	input_mt_slot(input_dev, id);
8214cf51c38SJoonyoung Shim 
822f3889ed1SNick Dyer 	if (status & MXT_T9_DETECT) {
823eef820dcSNick Dyer 		/*
824eef820dcSNick Dyer 		 * Multiple bits may be set if the host is slow to read
825eef820dcSNick Dyer 		 * the status messages, indicating all the events that
826eef820dcSNick Dyer 		 * have happened.
827eef820dcSNick Dyer 		 */
828eef820dcSNick Dyer 		if (status & MXT_T9_RELEASE) {
8295fc70e35SJiada Wang 			input_mt_report_slot_inactive(input_dev);
830b735fbe0SBenson Leung 			mxt_input_sync(data);
831eef820dcSNick Dyer 		}
832eef820dcSNick Dyer 
8332ca3ba0aSNick Dyer 		/* if active, pressure must be non-zero */
8342ca3ba0aSNick Dyer 		if (!amplitude)
8352ca3ba0aSNick Dyer 			amplitude = MXT_PRESSURE_DEFAULT;
8362ca3ba0aSNick Dyer 
837eef820dcSNick Dyer 		/* Touch active */
838eef820dcSNick Dyer 		input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1);
839fba5bc31SDaniel Kurtz 		input_report_abs(input_dev, ABS_MT_POSITION_X, x);
840fba5bc31SDaniel Kurtz 		input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
841fea9e467SNick Dyer 		input_report_abs(input_dev, ABS_MT_PRESSURE, amplitude);
842fba5bc31SDaniel Kurtz 		input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area);
843eef820dcSNick Dyer 	} else {
844eef820dcSNick Dyer 		/* Touch no longer active, close out slot */
8455fc70e35SJiada Wang 		input_mt_report_slot_inactive(input_dev);
846fba5bc31SDaniel Kurtz 	}
847b9b05a89SNick Dyer 
848b9b05a89SNick Dyer 	data->update_input = true;
8494cf51c38SJoonyoung Shim }
8504cf51c38SJoonyoung Shim 
851b23157dcSNick Dyer static void mxt_proc_t100_message(struct mxt_data *data, u8 *message)
852b23157dcSNick Dyer {
853b23157dcSNick Dyer 	struct device *dev = &data->client->dev;
854b23157dcSNick Dyer 	struct input_dev *input_dev = data->input_dev;
855b23157dcSNick Dyer 	int id;
856b23157dcSNick Dyer 	u8 status;
857b23157dcSNick Dyer 	u8 type = 0;
858b23157dcSNick Dyer 	u16 x;
859b23157dcSNick Dyer 	u16 y;
860b23157dcSNick Dyer 	int distance = 0;
861b23157dcSNick Dyer 	int tool = 0;
862b23157dcSNick Dyer 	u8 major = 0;
863b23157dcSNick Dyer 	u8 pressure = 0;
864b23157dcSNick Dyer 	u8 orientation = 0;
865b23157dcSNick Dyer 
866b23157dcSNick Dyer 	id = message[0] - data->T100_reportid_min - 2;
867b23157dcSNick Dyer 
868b23157dcSNick Dyer 	/* ignore SCRSTATUS events */
869b23157dcSNick Dyer 	if (id < 0)
870b23157dcSNick Dyer 		return;
871b23157dcSNick Dyer 
872b23157dcSNick Dyer 	status = message[1];
873b23157dcSNick Dyer 	x = get_unaligned_le16(&message[2]);
874b23157dcSNick Dyer 	y = get_unaligned_le16(&message[4]);
875b23157dcSNick Dyer 
876b23157dcSNick Dyer 	if (status & MXT_T100_DETECT) {
877b23157dcSNick Dyer 		type = (status & MXT_T100_TYPE_MASK) >> 4;
878b23157dcSNick Dyer 
879b23157dcSNick Dyer 		switch (type) {
880b23157dcSNick Dyer 		case MXT_T100_TYPE_HOVERING_FINGER:
881b23157dcSNick Dyer 			tool = MT_TOOL_FINGER;
882b23157dcSNick Dyer 			distance = MXT_DISTANCE_HOVERING;
883b23157dcSNick Dyer 
884b23157dcSNick Dyer 			if (data->t100_aux_vect)
885b23157dcSNick Dyer 				orientation = message[data->t100_aux_vect];
886b23157dcSNick Dyer 
887b23157dcSNick Dyer 			break;
888b23157dcSNick Dyer 
889b23157dcSNick Dyer 		case MXT_T100_TYPE_FINGER:
890b23157dcSNick Dyer 		case MXT_T100_TYPE_GLOVE:
891b23157dcSNick Dyer 			tool = MT_TOOL_FINGER;
892b23157dcSNick Dyer 			distance = MXT_DISTANCE_ACTIVE_TOUCH;
893b23157dcSNick Dyer 
894b23157dcSNick Dyer 			if (data->t100_aux_area)
895b23157dcSNick Dyer 				major = message[data->t100_aux_area];
896b23157dcSNick Dyer 
897b23157dcSNick Dyer 			if (data->t100_aux_ampl)
898b23157dcSNick Dyer 				pressure = message[data->t100_aux_ampl];
899b23157dcSNick Dyer 
900b23157dcSNick Dyer 			if (data->t100_aux_vect)
901b23157dcSNick Dyer 				orientation = message[data->t100_aux_vect];
902b23157dcSNick Dyer 
903b23157dcSNick Dyer 			break;
904b23157dcSNick Dyer 
905b23157dcSNick Dyer 		case MXT_T100_TYPE_PASSIVE_STYLUS:
906b23157dcSNick Dyer 			tool = MT_TOOL_PEN;
907b23157dcSNick Dyer 
908b23157dcSNick Dyer 			/*
909b23157dcSNick Dyer 			 * Passive stylus is reported with size zero so
910b23157dcSNick Dyer 			 * hardcode.
911b23157dcSNick Dyer 			 */
912b23157dcSNick Dyer 			major = MXT_TOUCH_MAJOR_DEFAULT;
913b23157dcSNick Dyer 
914b23157dcSNick Dyer 			if (data->t100_aux_ampl)
915b23157dcSNick Dyer 				pressure = message[data->t100_aux_ampl];
916b23157dcSNick Dyer 
917b23157dcSNick Dyer 			break;
918b23157dcSNick Dyer 
919b23157dcSNick Dyer 		case MXT_T100_TYPE_LARGE_TOUCH:
920b23157dcSNick Dyer 			/* Ignore suppressed touch */
921b23157dcSNick Dyer 			break;
922b23157dcSNick Dyer 
923b23157dcSNick Dyer 		default:
924b23157dcSNick Dyer 			dev_dbg(dev, "Unexpected T100 type\n");
925b23157dcSNick Dyer 			return;
926b23157dcSNick Dyer 		}
927b23157dcSNick Dyer 	}
928b23157dcSNick Dyer 
929b23157dcSNick Dyer 	/*
930b23157dcSNick Dyer 	 * Values reported should be non-zero if tool is touching the
931b23157dcSNick Dyer 	 * device
932b23157dcSNick Dyer 	 */
933b23157dcSNick Dyer 	if (!pressure && type != MXT_T100_TYPE_HOVERING_FINGER)
934b23157dcSNick Dyer 		pressure = MXT_PRESSURE_DEFAULT;
935b23157dcSNick Dyer 
936b23157dcSNick Dyer 	input_mt_slot(input_dev, id);
937b23157dcSNick Dyer 
938b23157dcSNick Dyer 	if (status & MXT_T100_DETECT) {
939b23157dcSNick Dyer 		dev_dbg(dev, "[%u] type:%u x:%u y:%u a:%02X p:%02X v:%02X\n",
940b23157dcSNick Dyer 			id, type, x, y, major, pressure, orientation);
941b23157dcSNick Dyer 
942b23157dcSNick Dyer 		input_mt_report_slot_state(input_dev, tool, 1);
943b23157dcSNick Dyer 		input_report_abs(input_dev, ABS_MT_POSITION_X, x);
944b23157dcSNick Dyer 		input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
945b23157dcSNick Dyer 		input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, major);
946b23157dcSNick Dyer 		input_report_abs(input_dev, ABS_MT_PRESSURE, pressure);
947b23157dcSNick Dyer 		input_report_abs(input_dev, ABS_MT_DISTANCE, distance);
948b23157dcSNick Dyer 		input_report_abs(input_dev, ABS_MT_ORIENTATION, orientation);
949b23157dcSNick Dyer 	} else {
950b23157dcSNick Dyer 		dev_dbg(dev, "[%u] release\n", id);
951b23157dcSNick Dyer 
952b23157dcSNick Dyer 		/* close out slot */
9535fc70e35SJiada Wang 		input_mt_report_slot_inactive(input_dev);
954b23157dcSNick Dyer 	}
955b23157dcSNick Dyer 
956b23157dcSNick Dyer 	data->update_input = true;
957b23157dcSNick Dyer }
958b23157dcSNick Dyer 
959b9b05a89SNick Dyer static int mxt_proc_message(struct mxt_data *data, u8 *message)
96004a79181SDaniel Kurtz {
961b9b05a89SNick Dyer 	u8 report_id = message[0];
962b9b05a89SNick Dyer 
963b9b05a89SNick Dyer 	if (report_id == MXT_RPTID_NOMSG)
964b9b05a89SNick Dyer 		return 0;
965b9b05a89SNick Dyer 
966b9b05a89SNick Dyer 	if (report_id == data->T6_reportid) {
967b9b05a89SNick Dyer 		mxt_proc_t6_messages(data, message);
968b9b05a89SNick Dyer 	} else if (!data->input_dev) {
969b9b05a89SNick Dyer 		/*
970b9b05a89SNick Dyer 		 * Do not report events if input device
971b9b05a89SNick Dyer 		 * is not yet registered.
972b9b05a89SNick Dyer 		 */
973b9b05a89SNick Dyer 		mxt_dump_message(data, message);
974b23157dcSNick Dyer 	} else if (report_id >= data->T9_reportid_min &&
975b23157dcSNick Dyer 		   report_id <= data->T9_reportid_max) {
976b9b05a89SNick Dyer 		mxt_proc_t9_message(data, message);
977b23157dcSNick Dyer 	} else if (report_id >= data->T100_reportid_min &&
978b23157dcSNick Dyer 		   report_id <= data->T100_reportid_max) {
979b23157dcSNick Dyer 		mxt_proc_t100_message(data, message);
980b9b05a89SNick Dyer 	} else if (report_id == data->T19_reportid) {
981b9b05a89SNick Dyer 		mxt_input_button(data, message);
982b9b05a89SNick Dyer 		data->update_input = true;
983b9b05a89SNick Dyer 	} else {
984b9b05a89SNick Dyer 		mxt_dump_message(data, message);
985b9b05a89SNick Dyer 	}
986b9b05a89SNick Dyer 
987b9b05a89SNick Dyer 	return 1;
988b9b05a89SNick Dyer }
989b9b05a89SNick Dyer 
9909d8dc3e5SNick Dyer static int mxt_read_and_process_messages(struct mxt_data *data, u8 count)
991b9b05a89SNick Dyer {
992b9b05a89SNick Dyer 	struct device *dev = &data->client->dev;
993b9b05a89SNick Dyer 	int ret;
9949d8dc3e5SNick Dyer 	int i;
9959d8dc3e5SNick Dyer 	u8 num_valid = 0;
996b9b05a89SNick Dyer 
9979d8dc3e5SNick Dyer 	/* Safety check for msg_buf */
9989d8dc3e5SNick Dyer 	if (count > data->max_reportid)
9999d8dc3e5SNick Dyer 		return -EINVAL;
10009d8dc3e5SNick Dyer 
10019d8dc3e5SNick Dyer 	/* Process remaining messages if necessary */
1002b9b05a89SNick Dyer 	ret = __mxt_read_reg(data->client, data->T5_address,
10039d8dc3e5SNick Dyer 				data->T5_msg_size * count, data->msg_buf);
1004b9b05a89SNick Dyer 	if (ret) {
10059d8dc3e5SNick Dyer 		dev_err(dev, "Failed to read %u messages (%d)\n", count, ret);
1006b9b05a89SNick Dyer 		return ret;
1007b9b05a89SNick Dyer 	}
1008b9b05a89SNick Dyer 
10099d8dc3e5SNick Dyer 	for (i = 0;  i < count; i++) {
10109d8dc3e5SNick Dyer 		ret = mxt_proc_message(data,
10119d8dc3e5SNick Dyer 			data->msg_buf + data->T5_msg_size * i);
10129d8dc3e5SNick Dyer 
10139d8dc3e5SNick Dyer 		if (ret == 1)
10149d8dc3e5SNick Dyer 			num_valid++;
10154cf51c38SJoonyoung Shim 	}
10164cf51c38SJoonyoung Shim 
10179d8dc3e5SNick Dyer 	/* return number of messages read */
10189d8dc3e5SNick Dyer 	return num_valid;
10199d8dc3e5SNick Dyer }
10204cf51c38SJoonyoung Shim 
10219d8dc3e5SNick Dyer static irqreturn_t mxt_process_messages_t44(struct mxt_data *data)
10229d8dc3e5SNick Dyer {
10239d8dc3e5SNick Dyer 	struct device *dev = &data->client->dev;
10249d8dc3e5SNick Dyer 	int ret;
10259d8dc3e5SNick Dyer 	u8 count, num_left;
10269d8dc3e5SNick Dyer 
10279d8dc3e5SNick Dyer 	/* Read T44 and T5 together */
10289d8dc3e5SNick Dyer 	ret = __mxt_read_reg(data->client, data->T44_address,
10299d8dc3e5SNick Dyer 		data->T5_msg_size + 1, data->msg_buf);
10309d8dc3e5SNick Dyer 	if (ret) {
10319d8dc3e5SNick Dyer 		dev_err(dev, "Failed to read T44 and T5 (%d)\n", ret);
10328d4e1639SNick Dyer 		return IRQ_NONE;
10339d8dc3e5SNick Dyer 	}
10349d8dc3e5SNick Dyer 
10359d8dc3e5SNick Dyer 	count = data->msg_buf[0];
10369d8dc3e5SNick Dyer 
1037651b4608SNick Dyer 	/*
1038507584e2SNick Dyer 	 * This condition may be caused by the CHG line being configured in
1039507584e2SNick Dyer 	 * Mode 0. It results in unnecessary I2C operations but it is benign.
1040651b4608SNick Dyer 	 */
1041507584e2SNick Dyer 	if (count == 0)
10429d8dc3e5SNick Dyer 		return IRQ_NONE;
1043507584e2SNick Dyer 
1044507584e2SNick Dyer 	if (count > data->max_reportid) {
1045507584e2SNick Dyer 		dev_warn(dev, "T44 count %d exceeded max report id\n", count);
10469d8dc3e5SNick Dyer 		count = data->max_reportid;
10479d8dc3e5SNick Dyer 	}
10489d8dc3e5SNick Dyer 
10499d8dc3e5SNick Dyer 	/* Process first message */
10509d8dc3e5SNick Dyer 	ret = mxt_proc_message(data, data->msg_buf + 1);
10519d8dc3e5SNick Dyer 	if (ret < 0) {
10529d8dc3e5SNick Dyer 		dev_warn(dev, "Unexpected invalid message\n");
10539d8dc3e5SNick Dyer 		return IRQ_NONE;
10549d8dc3e5SNick Dyer 	}
10559d8dc3e5SNick Dyer 
10569d8dc3e5SNick Dyer 	num_left = count - 1;
10579d8dc3e5SNick Dyer 
10589d8dc3e5SNick Dyer 	/* Process remaining messages if necessary */
10599d8dc3e5SNick Dyer 	if (num_left) {
10609d8dc3e5SNick Dyer 		ret = mxt_read_and_process_messages(data, num_left);
10619d8dc3e5SNick Dyer 		if (ret < 0)
10629d8dc3e5SNick Dyer 			goto end;
10639d8dc3e5SNick Dyer 		else if (ret != num_left)
10649d8dc3e5SNick Dyer 			dev_warn(dev, "Unexpected invalid message\n");
10659d8dc3e5SNick Dyer 	}
10669d8dc3e5SNick Dyer 
10679d8dc3e5SNick Dyer end:
10689d8dc3e5SNick Dyer 	if (data->update_input) {
10699d8dc3e5SNick Dyer 		mxt_input_sync(data);
10709d8dc3e5SNick Dyer 		data->update_input = false;
10719d8dc3e5SNick Dyer 	}
10729d8dc3e5SNick Dyer 
10739d8dc3e5SNick Dyer 	return IRQ_HANDLED;
10749d8dc3e5SNick Dyer }
10759d8dc3e5SNick Dyer 
10769d8dc3e5SNick Dyer static int mxt_process_messages_until_invalid(struct mxt_data *data)
10779d8dc3e5SNick Dyer {
10789d8dc3e5SNick Dyer 	struct device *dev = &data->client->dev;
10799d8dc3e5SNick Dyer 	int count, read;
10809d8dc3e5SNick Dyer 	u8 tries = 2;
10819d8dc3e5SNick Dyer 
10829d8dc3e5SNick Dyer 	count = data->max_reportid;
10839d8dc3e5SNick Dyer 
10849d8dc3e5SNick Dyer 	/* Read messages until we force an invalid */
10859d8dc3e5SNick Dyer 	do {
10869d8dc3e5SNick Dyer 		read = mxt_read_and_process_messages(data, count);
10879d8dc3e5SNick Dyer 		if (read < count)
10889d8dc3e5SNick Dyer 			return 0;
10899d8dc3e5SNick Dyer 	} while (--tries);
10909d8dc3e5SNick Dyer 
10919d8dc3e5SNick Dyer 	if (data->update_input) {
10929d8dc3e5SNick Dyer 		mxt_input_sync(data);
10939d8dc3e5SNick Dyer 		data->update_input = false;
10949d8dc3e5SNick Dyer 	}
10959d8dc3e5SNick Dyer 
10969d8dc3e5SNick Dyer 	dev_err(dev, "CHG pin isn't cleared\n");
10979d8dc3e5SNick Dyer 	return -EBUSY;
10989d8dc3e5SNick Dyer }
10999d8dc3e5SNick Dyer 
11009d8dc3e5SNick Dyer static irqreturn_t mxt_process_messages(struct mxt_data *data)
11019d8dc3e5SNick Dyer {
11029d8dc3e5SNick Dyer 	int total_handled, num_handled;
11039d8dc3e5SNick Dyer 	u8 count = data->last_message_count;
11049d8dc3e5SNick Dyer 
11059d8dc3e5SNick Dyer 	if (count < 1 || count > data->max_reportid)
11069d8dc3e5SNick Dyer 		count = 1;
11079d8dc3e5SNick Dyer 
11089d8dc3e5SNick Dyer 	/* include final invalid message */
11099d8dc3e5SNick Dyer 	total_handled = mxt_read_and_process_messages(data, count + 1);
11109d8dc3e5SNick Dyer 	if (total_handled < 0)
11119d8dc3e5SNick Dyer 		return IRQ_NONE;
11129d8dc3e5SNick Dyer 	/* if there were invalid messages, then we are done */
11139d8dc3e5SNick Dyer 	else if (total_handled <= count)
11149d8dc3e5SNick Dyer 		goto update_count;
11159d8dc3e5SNick Dyer 
11169d8dc3e5SNick Dyer 	/* keep reading two msgs until one is invalid or reportid limit */
11179d8dc3e5SNick Dyer 	do {
11189d8dc3e5SNick Dyer 		num_handled = mxt_read_and_process_messages(data, 2);
11199d8dc3e5SNick Dyer 		if (num_handled < 0)
11209d8dc3e5SNick Dyer 			return IRQ_NONE;
11219d8dc3e5SNick Dyer 
11229d8dc3e5SNick Dyer 		total_handled += num_handled;
11239d8dc3e5SNick Dyer 
11249d8dc3e5SNick Dyer 		if (num_handled < 2)
11259d8dc3e5SNick Dyer 			break;
11269d8dc3e5SNick Dyer 	} while (total_handled < data->num_touchids);
11279d8dc3e5SNick Dyer 
11289d8dc3e5SNick Dyer update_count:
11299d8dc3e5SNick Dyer 	data->last_message_count = total_handled;
11304cf51c38SJoonyoung Shim 
1131b9b05a89SNick Dyer 	if (data->update_input) {
1132b735fbe0SBenson Leung 		mxt_input_sync(data);
1133b9b05a89SNick Dyer 		data->update_input = false;
1134b9b05a89SNick Dyer 	}
113564464ae8SDaniel Kurtz 
11364cf51c38SJoonyoung Shim 	return IRQ_HANDLED;
11374cf51c38SJoonyoung Shim }
11384cf51c38SJoonyoung Shim 
1139d79e7e47SBenson Leung static irqreturn_t mxt_interrupt(int irq, void *dev_id)
1140d79e7e47SBenson Leung {
1141d79e7e47SBenson Leung 	struct mxt_data *data = dev_id;
1142d79e7e47SBenson Leung 
1143d79e7e47SBenson Leung 	if (data->in_bootloader) {
1144d79e7e47SBenson Leung 		/* bootloader state transition completion */
1145d79e7e47SBenson Leung 		complete(&data->bl_completion);
1146d79e7e47SBenson Leung 		return IRQ_HANDLED;
1147d79e7e47SBenson Leung 	}
1148d79e7e47SBenson Leung 
1149dd24dcf5SNick Dyer 	if (!data->object_table)
1150dd24dcf5SNick Dyer 		return IRQ_HANDLED;
1151dd24dcf5SNick Dyer 
11529d8dc3e5SNick Dyer 	if (data->T44_address) {
11539d8dc3e5SNick Dyer 		return mxt_process_messages_t44(data);
11549d8dc3e5SNick Dyer 	} else {
11559d8dc3e5SNick Dyer 		return mxt_process_messages(data);
11569d8dc3e5SNick Dyer 	}
1157d79e7e47SBenson Leung }
1158d79e7e47SBenson Leung 
1159a4a2ef46SIiro Valkonen static int mxt_t6_command(struct mxt_data *data, u16 cmd_offset,
1160a4a2ef46SIiro Valkonen 			  u8 value, bool wait)
1161a4a2ef46SIiro Valkonen {
1162a4a2ef46SIiro Valkonen 	u16 reg;
1163a4a2ef46SIiro Valkonen 	u8 command_register;
1164a4a2ef46SIiro Valkonen 	int timeout_counter = 0;
1165a4a2ef46SIiro Valkonen 	int ret;
1166a4a2ef46SIiro Valkonen 
1167a4a2ef46SIiro Valkonen 	reg = data->T6_address + cmd_offset;
1168a4a2ef46SIiro Valkonen 
1169a4a2ef46SIiro Valkonen 	ret = mxt_write_reg(data->client, reg, value);
1170a4a2ef46SIiro Valkonen 	if (ret)
1171a4a2ef46SIiro Valkonen 		return ret;
1172a4a2ef46SIiro Valkonen 
1173a4a2ef46SIiro Valkonen 	if (!wait)
1174a4a2ef46SIiro Valkonen 		return 0;
1175a4a2ef46SIiro Valkonen 
1176a4a2ef46SIiro Valkonen 	do {
1177a4a2ef46SIiro Valkonen 		msleep(20);
1178a4a2ef46SIiro Valkonen 		ret = __mxt_read_reg(data->client, reg, 1, &command_register);
1179a4a2ef46SIiro Valkonen 		if (ret)
1180a4a2ef46SIiro Valkonen 			return ret;
1181a4a2ef46SIiro Valkonen 	} while (command_register != 0 && timeout_counter++ <= 100);
1182a4a2ef46SIiro Valkonen 
1183a4a2ef46SIiro Valkonen 	if (timeout_counter > 100) {
1184a4a2ef46SIiro Valkonen 		dev_err(&data->client->dev, "Command failed!\n");
1185a4a2ef46SIiro Valkonen 		return -EIO;
1186a4a2ef46SIiro Valkonen 	}
1187a4a2ef46SIiro Valkonen 
1188a4a2ef46SIiro Valkonen 	return 0;
1189a4a2ef46SIiro Valkonen }
1190a4a2ef46SIiro Valkonen 
1191eb43335cSNick Dyer static int mxt_acquire_irq(struct mxt_data *data)
1192eb43335cSNick Dyer {
1193eb43335cSNick Dyer 	int error;
1194eb43335cSNick Dyer 
1195eb43335cSNick Dyer 	enable_irq(data->irq);
1196eb43335cSNick Dyer 
119774d905d2SNick Dyer 	if (data->use_retrigen_workaround) {
1198eb43335cSNick Dyer 		error = mxt_process_messages_until_invalid(data);
1199eb43335cSNick Dyer 		if (error)
1200eb43335cSNick Dyer 			return error;
120174d905d2SNick Dyer 	}
1202eb43335cSNick Dyer 
1203eb43335cSNick Dyer 	return 0;
1204eb43335cSNick Dyer }
1205eb43335cSNick Dyer 
1206a4a2ef46SIiro Valkonen static int mxt_soft_reset(struct mxt_data *data)
1207a4a2ef46SIiro Valkonen {
1208a4a2ef46SIiro Valkonen 	struct device *dev = &data->client->dev;
1209a4a2ef46SIiro Valkonen 	int ret = 0;
1210a4a2ef46SIiro Valkonen 
1211885f3fb9SNick Dyer 	dev_info(dev, "Resetting device\n");
1212885f3fb9SNick Dyer 
1213885f3fb9SNick Dyer 	disable_irq(data->irq);
1214a4a2ef46SIiro Valkonen 
1215a4a2ef46SIiro Valkonen 	reinit_completion(&data->reset_completion);
1216a4a2ef46SIiro Valkonen 
1217a4a2ef46SIiro Valkonen 	ret = mxt_t6_command(data, MXT_COMMAND_RESET, MXT_RESET_VALUE, false);
1218a4a2ef46SIiro Valkonen 	if (ret)
1219a4a2ef46SIiro Valkonen 		return ret;
1220a4a2ef46SIiro Valkonen 
1221885f3fb9SNick Dyer 	/* Ignore CHG line for 100ms after reset */
1222ca1cd36cSSebastian Reichel 	msleep(MXT_RESET_INVALID_CHG);
1223885f3fb9SNick Dyer 
1224eb43335cSNick Dyer 	mxt_acquire_irq(data);
1225885f3fb9SNick Dyer 
1226a4a2ef46SIiro Valkonen 	ret = mxt_wait_for_completion(data, &data->reset_completion,
1227a4a2ef46SIiro Valkonen 				      MXT_RESET_TIMEOUT);
1228a4a2ef46SIiro Valkonen 	if (ret)
1229a4a2ef46SIiro Valkonen 		return ret;
1230a4a2ef46SIiro Valkonen 
1231a4a2ef46SIiro Valkonen 	return 0;
1232a4a2ef46SIiro Valkonen }
1233a4a2ef46SIiro Valkonen 
1234c3f78043SNick Dyer static void mxt_update_crc(struct mxt_data *data, u8 cmd, u8 value)
1235c3f78043SNick Dyer {
1236c3f78043SNick Dyer 	/*
1237c3f78043SNick Dyer 	 * On failure, CRC is set to 0 and config will always be
1238c3f78043SNick Dyer 	 * downloaded.
1239c3f78043SNick Dyer 	 */
1240c3f78043SNick Dyer 	data->config_crc = 0;
1241c3f78043SNick Dyer 	reinit_completion(&data->crc_completion);
1242c3f78043SNick Dyer 
1243c3f78043SNick Dyer 	mxt_t6_command(data, cmd, value, true);
1244c3f78043SNick Dyer 
1245c3f78043SNick Dyer 	/*
1246c3f78043SNick Dyer 	 * Wait for crc message. On failure, CRC is set to 0 and config will
1247c3f78043SNick Dyer 	 * always be downloaded.
1248c3f78043SNick Dyer 	 */
1249c3f78043SNick Dyer 	mxt_wait_for_completion(data, &data->crc_completion, MXT_CRC_TIMEOUT);
1250c3f78043SNick Dyer }
1251c3f78043SNick Dyer 
12524ce6fa01SNick Dyer static void mxt_calc_crc24(u32 *crc, u8 firstbyte, u8 secondbyte)
12534ce6fa01SNick Dyer {
12544ce6fa01SNick Dyer 	static const unsigned int crcpoly = 0x80001B;
12554ce6fa01SNick Dyer 	u32 result;
12564ce6fa01SNick Dyer 	u32 data_word;
12574ce6fa01SNick Dyer 
12584ce6fa01SNick Dyer 	data_word = (secondbyte << 8) | firstbyte;
12594ce6fa01SNick Dyer 	result = ((*crc << 1) ^ data_word);
12604ce6fa01SNick Dyer 
12614ce6fa01SNick Dyer 	if (result & 0x1000000)
12624ce6fa01SNick Dyer 		result ^= crcpoly;
12634ce6fa01SNick Dyer 
12644ce6fa01SNick Dyer 	*crc = result;
12654ce6fa01SNick Dyer }
12664ce6fa01SNick Dyer 
12674ce6fa01SNick Dyer static u32 mxt_calculate_crc(u8 *base, off_t start_off, off_t end_off)
12684ce6fa01SNick Dyer {
12694ce6fa01SNick Dyer 	u32 crc = 0;
12704ce6fa01SNick Dyer 	u8 *ptr = base + start_off;
12714ce6fa01SNick Dyer 	u8 *last_val = base + end_off - 1;
12724ce6fa01SNick Dyer 
12734ce6fa01SNick Dyer 	if (end_off < start_off)
12744ce6fa01SNick Dyer 		return -EINVAL;
12754ce6fa01SNick Dyer 
12764ce6fa01SNick Dyer 	while (ptr < last_val) {
12774ce6fa01SNick Dyer 		mxt_calc_crc24(&crc, *ptr, *(ptr + 1));
12784ce6fa01SNick Dyer 		ptr += 2;
12794ce6fa01SNick Dyer 	}
12804ce6fa01SNick Dyer 
12814ce6fa01SNick Dyer 	/* if len is odd, fill the last byte with 0 */
12824ce6fa01SNick Dyer 	if (ptr == last_val)
12834ce6fa01SNick Dyer 		mxt_calc_crc24(&crc, *ptr, 0);
12844ce6fa01SNick Dyer 
12854ce6fa01SNick Dyer 	/* Mask to 24-bit */
12864ce6fa01SNick Dyer 	crc &= 0x00FFFFFF;
12874ce6fa01SNick Dyer 
12884ce6fa01SNick Dyer 	return crc;
12894ce6fa01SNick Dyer }
12904ce6fa01SNick Dyer 
129174d905d2SNick Dyer static int mxt_check_retrigen(struct mxt_data *data)
129274d905d2SNick Dyer {
129374d905d2SNick Dyer 	struct i2c_client *client = data->client;
129474d905d2SNick Dyer 	int error;
129574d905d2SNick Dyer 	int val;
129674d905d2SNick Dyer 	struct irq_data *irqd;
129774d905d2SNick Dyer 
129874d905d2SNick Dyer 	data->use_retrigen_workaround = false;
129974d905d2SNick Dyer 
130074d905d2SNick Dyer 	irqd = irq_get_irq_data(data->irq);
130174d905d2SNick Dyer 	if (!irqd)
130274d905d2SNick Dyer 		return -EINVAL;
130374d905d2SNick Dyer 
130474d905d2SNick Dyer 	if (irqd_is_level_type(irqd))
130574d905d2SNick Dyer 		return 0;
130674d905d2SNick Dyer 
130774d905d2SNick Dyer 	if (data->T18_address) {
130874d905d2SNick Dyer 		error = __mxt_read_reg(client,
130974d905d2SNick Dyer 				       data->T18_address + MXT_COMMS_CTRL,
131074d905d2SNick Dyer 				       1, &val);
131174d905d2SNick Dyer 		if (error)
131274d905d2SNick Dyer 			return error;
131374d905d2SNick Dyer 
131474d905d2SNick Dyer 		if (val & MXT_COMMS_RETRIGEN)
131574d905d2SNick Dyer 			return 0;
131674d905d2SNick Dyer 	}
131774d905d2SNick Dyer 
131874d905d2SNick Dyer 	dev_warn(&client->dev, "Enabling RETRIGEN workaround\n");
131974d905d2SNick Dyer 	data->use_retrigen_workaround = true;
132074d905d2SNick Dyer 	return 0;
132174d905d2SNick Dyer }
132274d905d2SNick Dyer 
1323f865df73SNick Dyer static int mxt_prepare_cfg_mem(struct mxt_data *data, struct mxt_cfg *cfg)
13244cf51c38SJoonyoung Shim {
13254cf51c38SJoonyoung Shim 	struct device *dev = &data->client->dev;
132650a77c65SNick Dyer 	struct mxt_object *object;
1327efdbd7aeSDmitry Torokhov 	unsigned int type, instance, size, byte_offset;
132850a77c65SNick Dyer 	int offset;
1329efdbd7aeSDmitry Torokhov 	int ret;
133050a77c65SNick Dyer 	int i;
133150a77c65SNick Dyer 	u16 reg;
1332efdbd7aeSDmitry Torokhov 	u8 val;
133350a77c65SNick Dyer 
1334f865df73SNick Dyer 	while (cfg->raw_pos < cfg->raw_size) {
133550a77c65SNick Dyer 		/* Read type, instance, length */
1336f865df73SNick Dyer 		ret = sscanf(cfg->raw + cfg->raw_pos, "%x %x %x%n",
133750a77c65SNick Dyer 			     &type, &instance, &size, &offset);
133850a77c65SNick Dyer 		if (ret == 0) {
133950a77c65SNick Dyer 			/* EOF */
13404ce6fa01SNick Dyer 			break;
134150a77c65SNick Dyer 		} else if (ret != 3) {
134250a77c65SNick Dyer 			dev_err(dev, "Bad format: failed to parse object\n");
1343efdbd7aeSDmitry Torokhov 			return -EINVAL;
134450a77c65SNick Dyer 		}
1345f865df73SNick Dyer 		cfg->raw_pos += offset;
134650a77c65SNick Dyer 
134750a77c65SNick Dyer 		object = mxt_get_object(data, type);
134850a77c65SNick Dyer 		if (!object) {
134950a77c65SNick Dyer 			/* Skip object */
135050a77c65SNick Dyer 			for (i = 0; i < size; i++) {
1351f865df73SNick Dyer 				ret = sscanf(cfg->raw + cfg->raw_pos, "%hhx%n",
1352041fa159SDmitry Torokhov 					     &val, &offset);
1353041fa159SDmitry Torokhov 				if (ret != 1) {
1354041fa159SDmitry Torokhov 					dev_err(dev, "Bad format in T%d at %d\n",
1355041fa159SDmitry Torokhov 						type, i);
1356041fa159SDmitry Torokhov 					return -EINVAL;
1357041fa159SDmitry Torokhov 				}
1358f865df73SNick Dyer 				cfg->raw_pos += offset;
135950a77c65SNick Dyer 			}
136050a77c65SNick Dyer 			continue;
136150a77c65SNick Dyer 		}
136250a77c65SNick Dyer 
136350a77c65SNick Dyer 		if (size > mxt_obj_size(object)) {
13644ce6fa01SNick Dyer 			/*
13654ce6fa01SNick Dyer 			 * Either we are in fallback mode due to wrong
13664ce6fa01SNick Dyer 			 * config or config from a later fw version,
13674ce6fa01SNick Dyer 			 * or the file is corrupt or hand-edited.
13684ce6fa01SNick Dyer 			 */
13694ce6fa01SNick Dyer 			dev_warn(dev, "Discarding %zu byte(s) in T%u\n",
137050a77c65SNick Dyer 				 size - mxt_obj_size(object), type);
13714ce6fa01SNick Dyer 		} else if (mxt_obj_size(object) > size) {
13724ce6fa01SNick Dyer 			/*
13734ce6fa01SNick Dyer 			 * If firmware is upgraded, new bytes may be added to
13744ce6fa01SNick Dyer 			 * end of objects. It is generally forward compatible
13754ce6fa01SNick Dyer 			 * to zero these bytes - previous behaviour will be
13764ce6fa01SNick Dyer 			 * retained. However this does invalidate the CRC and
13774ce6fa01SNick Dyer 			 * will force fallback mode until the configuration is
13784ce6fa01SNick Dyer 			 * updated. We warn here but do nothing else - the
13794ce6fa01SNick Dyer 			 * malloc has zeroed the entire configuration.
13804ce6fa01SNick Dyer 			 */
13814ce6fa01SNick Dyer 			dev_warn(dev, "Zeroing %zu byte(s) in T%d\n",
13824ce6fa01SNick Dyer 				 mxt_obj_size(object) - size, type);
138350a77c65SNick Dyer 		}
138450a77c65SNick Dyer 
138550a77c65SNick Dyer 		if (instance >= mxt_obj_instances(object)) {
138650a77c65SNick Dyer 			dev_err(dev, "Object instances exceeded!\n");
1387efdbd7aeSDmitry Torokhov 			return -EINVAL;
138850a77c65SNick Dyer 		}
138950a77c65SNick Dyer 
139050a77c65SNick Dyer 		reg = object->start_address + mxt_obj_size(object) * instance;
139150a77c65SNick Dyer 
139250a77c65SNick Dyer 		for (i = 0; i < size; i++) {
1393f865df73SNick Dyer 			ret = sscanf(cfg->raw + cfg->raw_pos, "%hhx%n",
139450a77c65SNick Dyer 				     &val,
139550a77c65SNick Dyer 				     &offset);
139650a77c65SNick Dyer 			if (ret != 1) {
1397041fa159SDmitry Torokhov 				dev_err(dev, "Bad format in T%d at %d\n",
1398041fa159SDmitry Torokhov 					type, i);
1399efdbd7aeSDmitry Torokhov 				return -EINVAL;
140050a77c65SNick Dyer 			}
1401f865df73SNick Dyer 			cfg->raw_pos += offset;
140250a77c65SNick Dyer 
140350a77c65SNick Dyer 			if (i > mxt_obj_size(object))
14044cf51c38SJoonyoung Shim 				continue;
14054cf51c38SJoonyoung Shim 
1406f865df73SNick Dyer 			byte_offset = reg + i - cfg->start_ofs;
140750a77c65SNick Dyer 
1408f865df73SNick Dyer 			if (byte_offset >= 0 && byte_offset < cfg->mem_size) {
1409f865df73SNick Dyer 				*(cfg->mem + byte_offset) = val;
14104ce6fa01SNick Dyer 			} else {
14114ce6fa01SNick Dyer 				dev_err(dev, "Bad object: reg:%d, T%d, ofs=%d\n",
14124ce6fa01SNick Dyer 					reg, object->type, byte_offset);
1413efdbd7aeSDmitry Torokhov 				return -EINVAL;
1414efdbd7aeSDmitry Torokhov 			}
1415efdbd7aeSDmitry Torokhov 		}
1416efdbd7aeSDmitry Torokhov 	}
1417efdbd7aeSDmitry Torokhov 
1418efdbd7aeSDmitry Torokhov 	return 0;
1419efdbd7aeSDmitry Torokhov }
1420efdbd7aeSDmitry Torokhov 
1421f865df73SNick Dyer static int mxt_upload_cfg_mem(struct mxt_data *data, struct mxt_cfg *cfg)
1422efdbd7aeSDmitry Torokhov {
1423efdbd7aeSDmitry Torokhov 	unsigned int byte_offset = 0;
1424efdbd7aeSDmitry Torokhov 	int error;
1425efdbd7aeSDmitry Torokhov 
1426efdbd7aeSDmitry Torokhov 	/* Write configuration as blocks */
1427f865df73SNick Dyer 	while (byte_offset < cfg->mem_size) {
1428f865df73SNick Dyer 		unsigned int size = cfg->mem_size - byte_offset;
1429efdbd7aeSDmitry Torokhov 
1430efdbd7aeSDmitry Torokhov 		if (size > MXT_MAX_BLOCK_WRITE)
1431efdbd7aeSDmitry Torokhov 			size = MXT_MAX_BLOCK_WRITE;
1432efdbd7aeSDmitry Torokhov 
1433efdbd7aeSDmitry Torokhov 		error = __mxt_write_reg(data->client,
1434f865df73SNick Dyer 					cfg->start_ofs + byte_offset,
1435f865df73SNick Dyer 					size, cfg->mem + byte_offset);
1436efdbd7aeSDmitry Torokhov 		if (error) {
1437efdbd7aeSDmitry Torokhov 			dev_err(&data->client->dev,
1438efdbd7aeSDmitry Torokhov 				"Config write error, ret=%d\n", error);
1439efdbd7aeSDmitry Torokhov 			return error;
1440efdbd7aeSDmitry Torokhov 		}
1441efdbd7aeSDmitry Torokhov 
1442efdbd7aeSDmitry Torokhov 		byte_offset += size;
1443efdbd7aeSDmitry Torokhov 	}
1444efdbd7aeSDmitry Torokhov 
1445efdbd7aeSDmitry Torokhov 	return 0;
1446efdbd7aeSDmitry Torokhov }
1447efdbd7aeSDmitry Torokhov 
14487f3884f7SNick Dyer static int mxt_init_t7_power_cfg(struct mxt_data *data);
14497f3884f7SNick Dyer 
1450efdbd7aeSDmitry Torokhov /*
1451efdbd7aeSDmitry Torokhov  * mxt_update_cfg - download configuration to chip
1452efdbd7aeSDmitry Torokhov  *
1453efdbd7aeSDmitry Torokhov  * Atmel Raw Config File Format
1454efdbd7aeSDmitry Torokhov  *
1455efdbd7aeSDmitry Torokhov  * The first four lines of the raw config file contain:
1456efdbd7aeSDmitry Torokhov  *  1) Version
1457efdbd7aeSDmitry Torokhov  *  2) Chip ID Information (first 7 bytes of device memory)
1458efdbd7aeSDmitry Torokhov  *  3) Chip Information Block 24-bit CRC Checksum
1459efdbd7aeSDmitry Torokhov  *  4) Chip Configuration 24-bit CRC Checksum
1460efdbd7aeSDmitry Torokhov  *
1461efdbd7aeSDmitry Torokhov  * The rest of the file consists of one line per object instance:
1462efdbd7aeSDmitry Torokhov  *   <TYPE> <INSTANCE> <SIZE> <CONTENTS>
1463efdbd7aeSDmitry Torokhov  *
1464efdbd7aeSDmitry Torokhov  *   <TYPE> - 2-byte object type as hex
1465efdbd7aeSDmitry Torokhov  *   <INSTANCE> - 2-byte object instance number as hex
1466efdbd7aeSDmitry Torokhov  *   <SIZE> - 2-byte object size as hex
1467efdbd7aeSDmitry Torokhov  *   <CONTENTS> - array of <SIZE> 1-byte hex values
1468efdbd7aeSDmitry Torokhov  */
1469f865df73SNick Dyer static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw)
1470efdbd7aeSDmitry Torokhov {
1471efdbd7aeSDmitry Torokhov 	struct device *dev = &data->client->dev;
1472f865df73SNick Dyer 	struct mxt_cfg cfg;
1473efdbd7aeSDmitry Torokhov 	int ret;
1474efdbd7aeSDmitry Torokhov 	int offset;
1475efdbd7aeSDmitry Torokhov 	int i;
1476efdbd7aeSDmitry Torokhov 	u32 info_crc, config_crc, calculated_crc;
147715082bdbSNick Dyer 	u16 crc_start = 0;
1478efdbd7aeSDmitry Torokhov 
1479a4891f10SNick Dyer 	/* Make zero terminated copy of the OBP_RAW file */
1480a4891f10SNick Dyer 	cfg.raw = kmemdup_nul(fw->data, fw->size, GFP_KERNEL);
1481a4891f10SNick Dyer 	if (!cfg.raw)
1482a4891f10SNick Dyer 		return -ENOMEM;
1483a4891f10SNick Dyer 
1484f865df73SNick Dyer 	cfg.raw_size = fw->size;
1485f865df73SNick Dyer 
1486efdbd7aeSDmitry Torokhov 	mxt_update_crc(data, MXT_COMMAND_REPORTALL, 1);
1487efdbd7aeSDmitry Torokhov 
1488f865df73SNick Dyer 	if (strncmp(cfg.raw, MXT_CFG_MAGIC, strlen(MXT_CFG_MAGIC))) {
1489efdbd7aeSDmitry Torokhov 		dev_err(dev, "Unrecognised config file\n");
1490a4891f10SNick Dyer 		ret = -EINVAL;
1491a4891f10SNick Dyer 		goto release_raw;
1492efdbd7aeSDmitry Torokhov 	}
1493efdbd7aeSDmitry Torokhov 
1494f865df73SNick Dyer 	cfg.raw_pos = strlen(MXT_CFG_MAGIC);
1495efdbd7aeSDmitry Torokhov 
1496efdbd7aeSDmitry Torokhov 	/* Load information block and check */
1497efdbd7aeSDmitry Torokhov 	for (i = 0; i < sizeof(struct mxt_info); i++) {
1498f865df73SNick Dyer 		ret = sscanf(cfg.raw + cfg.raw_pos, "%hhx%n",
1499f865df73SNick Dyer 			     (unsigned char *)&cfg.info + i,
1500efdbd7aeSDmitry Torokhov 			     &offset);
1501efdbd7aeSDmitry Torokhov 		if (ret != 1) {
1502efdbd7aeSDmitry Torokhov 			dev_err(dev, "Bad format\n");
1503a4891f10SNick Dyer 			ret = -EINVAL;
1504a4891f10SNick Dyer 			goto release_raw;
1505efdbd7aeSDmitry Torokhov 		}
1506efdbd7aeSDmitry Torokhov 
1507f865df73SNick Dyer 		cfg.raw_pos += offset;
1508efdbd7aeSDmitry Torokhov 	}
1509efdbd7aeSDmitry Torokhov 
1510f865df73SNick Dyer 	if (cfg.info.family_id != data->info->family_id) {
1511efdbd7aeSDmitry Torokhov 		dev_err(dev, "Family ID mismatch!\n");
1512a4891f10SNick Dyer 		ret = -EINVAL;
1513a4891f10SNick Dyer 		goto release_raw;
1514efdbd7aeSDmitry Torokhov 	}
1515efdbd7aeSDmitry Torokhov 
1516f865df73SNick Dyer 	if (cfg.info.variant_id != data->info->variant_id) {
1517efdbd7aeSDmitry Torokhov 		dev_err(dev, "Variant ID mismatch!\n");
1518a4891f10SNick Dyer 		ret = -EINVAL;
1519a4891f10SNick Dyer 		goto release_raw;
1520efdbd7aeSDmitry Torokhov 	}
1521efdbd7aeSDmitry Torokhov 
1522efdbd7aeSDmitry Torokhov 	/* Read CRCs */
1523f865df73SNick Dyer 	ret = sscanf(cfg.raw + cfg.raw_pos, "%x%n", &info_crc, &offset);
1524efdbd7aeSDmitry Torokhov 	if (ret != 1) {
1525efdbd7aeSDmitry Torokhov 		dev_err(dev, "Bad format: failed to parse Info CRC\n");
1526a4891f10SNick Dyer 		ret = -EINVAL;
1527a4891f10SNick Dyer 		goto release_raw;
1528efdbd7aeSDmitry Torokhov 	}
1529f865df73SNick Dyer 	cfg.raw_pos += offset;
1530efdbd7aeSDmitry Torokhov 
1531f865df73SNick Dyer 	ret = sscanf(cfg.raw + cfg.raw_pos, "%x%n", &config_crc, &offset);
1532efdbd7aeSDmitry Torokhov 	if (ret != 1) {
1533efdbd7aeSDmitry Torokhov 		dev_err(dev, "Bad format: failed to parse Config CRC\n");
1534a4891f10SNick Dyer 		ret = -EINVAL;
1535a4891f10SNick Dyer 		goto release_raw;
1536efdbd7aeSDmitry Torokhov 	}
1537f865df73SNick Dyer 	cfg.raw_pos += offset;
1538efdbd7aeSDmitry Torokhov 
1539efdbd7aeSDmitry Torokhov 	/*
1540efdbd7aeSDmitry Torokhov 	 * The Info Block CRC is calculated over mxt_info and the object
1541efdbd7aeSDmitry Torokhov 	 * table. If it does not match then we are trying to load the
1542efdbd7aeSDmitry Torokhov 	 * configuration from a different chip or firmware version, so
1543efdbd7aeSDmitry Torokhov 	 * the configuration CRC is invalid anyway.
1544efdbd7aeSDmitry Torokhov 	 */
1545efdbd7aeSDmitry Torokhov 	if (info_crc == data->info_crc) {
1546efdbd7aeSDmitry Torokhov 		if (config_crc == 0 || data->config_crc == 0) {
1547efdbd7aeSDmitry Torokhov 			dev_info(dev, "CRC zero, attempting to apply config\n");
1548efdbd7aeSDmitry Torokhov 		} else if (config_crc == data->config_crc) {
1549efdbd7aeSDmitry Torokhov 			dev_dbg(dev, "Config CRC 0x%06X: OK\n",
1550efdbd7aeSDmitry Torokhov 				 data->config_crc);
1551f0dd6878SIan Ray 			ret = 0;
1552f0dd6878SIan Ray 			goto release_raw;
1553efdbd7aeSDmitry Torokhov 		} else {
1554efdbd7aeSDmitry Torokhov 			dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n",
1555efdbd7aeSDmitry Torokhov 				 data->config_crc, config_crc);
1556efdbd7aeSDmitry Torokhov 		}
1557efdbd7aeSDmitry Torokhov 	} else {
1558efdbd7aeSDmitry Torokhov 		dev_warn(dev,
1559efdbd7aeSDmitry Torokhov 			 "Warning: Info CRC error - device=0x%06X file=0x%06X\n",
1560efdbd7aeSDmitry Torokhov 			 data->info_crc, info_crc);
1561efdbd7aeSDmitry Torokhov 	}
1562efdbd7aeSDmitry Torokhov 
1563efdbd7aeSDmitry Torokhov 	/* Malloc memory to store configuration */
1564f865df73SNick Dyer 	cfg.start_ofs = MXT_OBJECT_START +
1565068bdb67SNick Dyer 			data->info->object_num * sizeof(struct mxt_object) +
1566efdbd7aeSDmitry Torokhov 			MXT_INFO_CHECKSUM_SIZE;
1567f865df73SNick Dyer 	cfg.mem_size = data->mem_size - cfg.start_ofs;
1568f865df73SNick Dyer 	cfg.mem = kzalloc(cfg.mem_size, GFP_KERNEL);
1569a4891f10SNick Dyer 	if (!cfg.mem) {
1570a4891f10SNick Dyer 		ret = -ENOMEM;
1571a4891f10SNick Dyer 		goto release_raw;
1572a4891f10SNick Dyer 	}
1573efdbd7aeSDmitry Torokhov 
1574f865df73SNick Dyer 	ret = mxt_prepare_cfg_mem(data, &cfg);
1575efdbd7aeSDmitry Torokhov 	if (ret)
15764ce6fa01SNick Dyer 		goto release_mem;
15774cf51c38SJoonyoung Shim 
15784ce6fa01SNick Dyer 	/* Calculate crc of the received configs (not the raw config file) */
157915082bdbSNick Dyer 	if (data->T71_address)
158015082bdbSNick Dyer 		crc_start = data->T71_address;
158115082bdbSNick Dyer 	else if (data->T7_address)
158215082bdbSNick Dyer 		crc_start = data->T7_address;
158315082bdbSNick Dyer 	else
158415082bdbSNick Dyer 		dev_warn(dev, "Could not find CRC start\n");
15854ce6fa01SNick Dyer 
1586f865df73SNick Dyer 	if (crc_start > cfg.start_ofs) {
1587f865df73SNick Dyer 		calculated_crc = mxt_calculate_crc(cfg.mem,
1588f865df73SNick Dyer 						   crc_start - cfg.start_ofs,
1589f865df73SNick Dyer 						   cfg.mem_size);
15904ce6fa01SNick Dyer 
1591efdbd7aeSDmitry Torokhov 		if (config_crc > 0 && config_crc != calculated_crc)
159215082bdbSNick Dyer 			dev_warn(dev, "Config CRC in file inconsistent, calculated=%06X, file=%06X\n",
15934ce6fa01SNick Dyer 				 calculated_crc, config_crc);
159415082bdbSNick Dyer 	}
15954ce6fa01SNick Dyer 
1596f865df73SNick Dyer 	ret = mxt_upload_cfg_mem(data, &cfg);
1597efdbd7aeSDmitry Torokhov 	if (ret)
15984ce6fa01SNick Dyer 		goto release_mem;
15994ce6fa01SNick Dyer 
1600c3f78043SNick Dyer 	mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE);
1601c3f78043SNick Dyer 
160274d905d2SNick Dyer 	ret = mxt_check_retrigen(data);
160374d905d2SNick Dyer 	if (ret)
160474d905d2SNick Dyer 		goto release_mem;
160574d905d2SNick Dyer 
1606c3f78043SNick Dyer 	ret = mxt_soft_reset(data);
1607c3f78043SNick Dyer 	if (ret)
16084ce6fa01SNick Dyer 		goto release_mem;
1609c3f78043SNick Dyer 
1610c3f78043SNick Dyer 	dev_info(dev, "Config successfully updated\n");
1611c3f78043SNick Dyer 
16127f3884f7SNick Dyer 	/* T7 config may have changed */
16137f3884f7SNick Dyer 	mxt_init_t7_power_cfg(data);
16147f3884f7SNick Dyer 
16154ce6fa01SNick Dyer release_mem:
1616f865df73SNick Dyer 	kfree(cfg.mem);
16171e3c336aSSanjeev Chugh release_raw:
16181e3c336aSSanjeev Chugh 	kfree(cfg.raw);
161950a77c65SNick Dyer 	return ret;
16204cf51c38SJoonyoung Shim }
16214cf51c38SJoonyoung Shim 
162258e4aeeeSStephen Warren static void mxt_free_input_device(struct mxt_data *data)
16235f3f9bc2SNick Dyer {
162458e4aeeeSStephen Warren 	if (data->input_dev) {
16255f3f9bc2SNick Dyer 		input_unregister_device(data->input_dev);
16265f3f9bc2SNick Dyer 		data->input_dev = NULL;
162758e4aeeeSStephen Warren 	}
162858e4aeeeSStephen Warren }
16295f3f9bc2SNick Dyer 
163058e4aeeeSStephen Warren static void mxt_free_object_table(struct mxt_data *data)
163158e4aeeeSStephen Warren {
1632ecfdd7e2SNick Dyer #ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37
1633ecfdd7e2SNick Dyer 	video_unregister_device(&data->dbg.vdev);
1634ecfdd7e2SNick Dyer 	v4l2_device_unregister(&data->dbg.v4l2);
1635ecfdd7e2SNick Dyer #endif
16365f3f9bc2SNick Dyer 	data->object_table = NULL;
1637068bdb67SNick Dyer 	data->info = NULL;
1638068bdb67SNick Dyer 	kfree(data->raw_info_block);
1639068bdb67SNick Dyer 	data->raw_info_block = NULL;
16405f3f9bc2SNick Dyer 	kfree(data->msg_buf);
16415f3f9bc2SNick Dyer 	data->msg_buf = NULL;
1642b9b05a89SNick Dyer 	data->T5_address = 0;
16435f3f9bc2SNick Dyer 	data->T5_msg_size = 0;
16445f3f9bc2SNick Dyer 	data->T6_reportid = 0;
16455f3f9bc2SNick Dyer 	data->T7_address = 0;
164615082bdbSNick Dyer 	data->T71_address = 0;
16475f3f9bc2SNick Dyer 	data->T9_reportid_min = 0;
16485f3f9bc2SNick Dyer 	data->T9_reportid_max = 0;
164974d905d2SNick Dyer 	data->T18_address = 0;
16505f3f9bc2SNick Dyer 	data->T19_reportid = 0;
16519d8dc3e5SNick Dyer 	data->T44_address = 0;
1652b23157dcSNick Dyer 	data->T100_reportid_min = 0;
1653b23157dcSNick Dyer 	data->T100_reportid_max = 0;
16549d8dc3e5SNick Dyer 	data->max_reportid = 0;
16555f3f9bc2SNick Dyer }
16565f3f9bc2SNick Dyer 
1657068bdb67SNick Dyer static int mxt_parse_object_table(struct mxt_data *data,
1658068bdb67SNick Dyer 				  struct mxt_object *object_table)
16594cf51c38SJoonyoung Shim {
1660333e5a9aSDaniel Kurtz 	struct i2c_client *client = data->client;
16614cf51c38SJoonyoung Shim 	int i;
1662333e5a9aSDaniel Kurtz 	u8 reportid;
16634ce6fa01SNick Dyer 	u16 end_address;
16644cf51c38SJoonyoung Shim 
1665333e5a9aSDaniel Kurtz 	/* Valid Report IDs start counting from 1 */
1666333e5a9aSDaniel Kurtz 	reportid = 1;
16674ce6fa01SNick Dyer 	data->mem_size = 0;
1668068bdb67SNick Dyer 	for (i = 0; i < data->info->object_num; i++) {
1669dd24dcf5SNick Dyer 		struct mxt_object *object = object_table + i;
1670333e5a9aSDaniel Kurtz 		u8 min_id, max_id;
1671333e5a9aSDaniel Kurtz 
1672333e5a9aSDaniel Kurtz 		le16_to_cpus(&object->start_address);
16734cf51c38SJoonyoung Shim 
16744cf51c38SJoonyoung Shim 		if (object->num_report_ids) {
1675333e5a9aSDaniel Kurtz 			min_id = reportid;
16764cf51c38SJoonyoung Shim 			reportid += object->num_report_ids *
16771e0c0c5bSDaniel Kurtz 					mxt_obj_instances(object);
1678333e5a9aSDaniel Kurtz 			max_id = reportid - 1;
1679333e5a9aSDaniel Kurtz 		} else {
1680333e5a9aSDaniel Kurtz 			min_id = 0;
1681333e5a9aSDaniel Kurtz 			max_id = 0;
1682333e5a9aSDaniel Kurtz 		}
1683333e5a9aSDaniel Kurtz 
1684333e5a9aSDaniel Kurtz 		dev_dbg(&data->client->dev,
16857bed6805SNick Dyer 			"T%u Start:%u Size:%zu Instances:%zu Report IDs:%u-%u\n",
16861e0c0c5bSDaniel Kurtz 			object->type, object->start_address,
16871e0c0c5bSDaniel Kurtz 			mxt_obj_size(object), mxt_obj_instances(object),
16881e0c0c5bSDaniel Kurtz 			min_id, max_id);
1689333e5a9aSDaniel Kurtz 
1690333e5a9aSDaniel Kurtz 		switch (object->type) {
16915f3f9bc2SNick Dyer 		case MXT_GEN_MESSAGE_T5:
1692068bdb67SNick Dyer 			if (data->info->family_id == 0x80 &&
1693068bdb67SNick Dyer 			    data->info->version < 0x20) {
16949d8dc3e5SNick Dyer 				/*
1695437d4f37SNick Dyer 				 * On mXT224 firmware versions prior to V2.0
1696437d4f37SNick Dyer 				 * read and discard unused CRC byte otherwise
1697437d4f37SNick Dyer 				 * DMA reads are misaligned.
16989d8dc3e5SNick Dyer 				 */
16999d8dc3e5SNick Dyer 				data->T5_msg_size = mxt_obj_size(object);
17009d8dc3e5SNick Dyer 			} else {
17019d8dc3e5SNick Dyer 				/* CRC not enabled, so skip last byte */
17025f3f9bc2SNick Dyer 				data->T5_msg_size = mxt_obj_size(object) - 1;
17039d8dc3e5SNick Dyer 			}
1704b9b05a89SNick Dyer 			data->T5_address = object->start_address;
1705041fa159SDmitry Torokhov 			break;
1706fdf80421SDaniel Kurtz 		case MXT_GEN_COMMAND_T6:
1707fdf80421SDaniel Kurtz 			data->T6_reportid = min_id;
1708a4a2ef46SIiro Valkonen 			data->T6_address = object->start_address;
1709fdf80421SDaniel Kurtz 			break;
17104ce6fa01SNick Dyer 		case MXT_GEN_POWER_T7:
17114ce6fa01SNick Dyer 			data->T7_address = object->start_address;
17124ce6fa01SNick Dyer 			break;
171315082bdbSNick Dyer 		case MXT_SPT_DYNAMICCONFIGURATIONCONTAINER_T71:
171415082bdbSNick Dyer 			data->T71_address = object->start_address;
171515082bdbSNick Dyer 			break;
1716333e5a9aSDaniel Kurtz 		case MXT_TOUCH_MULTI_T9:
1717b23157dcSNick Dyer 			data->multitouch = MXT_TOUCH_MULTI_T9;
171836f5d9efSNick Dyer 			/* Only handle messages from first T9 instance */
1719333e5a9aSDaniel Kurtz 			data->T9_reportid_min = min_id;
172036f5d9efSNick Dyer 			data->T9_reportid_max = min_id +
172136f5d9efSNick Dyer 						object->num_report_ids - 1;
172236f5d9efSNick Dyer 			data->num_touchids = object->num_report_ids;
17239d8dc3e5SNick Dyer 			break;
172474d905d2SNick Dyer 		case MXT_SPT_COMMSCONFIG_T18:
172574d905d2SNick Dyer 			data->T18_address = object->start_address;
172674d905d2SNick Dyer 			break;
17279d8dc3e5SNick Dyer 		case MXT_SPT_MESSAGECOUNT_T44:
17289d8dc3e5SNick Dyer 			data->T44_address = object->start_address;
1729333e5a9aSDaniel Kurtz 			break;
173022dfab7fSDaniel Kurtz 		case MXT_SPT_GPIOPWM_T19:
173122dfab7fSDaniel Kurtz 			data->T19_reportid = min_id;
173222dfab7fSDaniel Kurtz 			break;
1733b23157dcSNick Dyer 		case MXT_TOUCH_MULTITOUCHSCREEN_T100:
1734b23157dcSNick Dyer 			data->multitouch = MXT_TOUCH_MULTITOUCHSCREEN_T100;
1735b23157dcSNick Dyer 			data->T100_reportid_min = min_id;
1736b23157dcSNick Dyer 			data->T100_reportid_max = max_id;
1737b23157dcSNick Dyer 			/* first two report IDs reserved */
1738b23157dcSNick Dyer 			data->num_touchids = object->num_report_ids - 2;
1739b23157dcSNick Dyer 			break;
17404cf51c38SJoonyoung Shim 		}
17414ce6fa01SNick Dyer 
17424ce6fa01SNick Dyer 		end_address = object->start_address
17434ce6fa01SNick Dyer 			+ mxt_obj_size(object) * mxt_obj_instances(object) - 1;
17444ce6fa01SNick Dyer 
17454ce6fa01SNick Dyer 		if (end_address >= data->mem_size)
17464ce6fa01SNick Dyer 			data->mem_size = end_address + 1;
17474cf51c38SJoonyoung Shim 	}
17484cf51c38SJoonyoung Shim 
17499d8dc3e5SNick Dyer 	/* Store maximum reportid */
17509d8dc3e5SNick Dyer 	data->max_reportid = reportid;
17519d8dc3e5SNick Dyer 
17529d8dc3e5SNick Dyer 	/* If T44 exists, T5 position has to be directly after */
17539d8dc3e5SNick Dyer 	if (data->T44_address && (data->T5_address != data->T44_address + 1)) {
17549d8dc3e5SNick Dyer 		dev_err(&client->dev, "Invalid T44 position\n");
1755068bdb67SNick Dyer 		return -EINVAL;
17569d8dc3e5SNick Dyer 	}
17579d8dc3e5SNick Dyer 
17589d8dc3e5SNick Dyer 	data->msg_buf = kcalloc(data->max_reportid,
17599d8dc3e5SNick Dyer 				data->T5_msg_size, GFP_KERNEL);
1760068bdb67SNick Dyer 	if (!data->msg_buf)
1761068bdb67SNick Dyer 		return -ENOMEM;
1762068bdb67SNick Dyer 
1763068bdb67SNick Dyer 	return 0;
17645f3f9bc2SNick Dyer }
17655f3f9bc2SNick Dyer 
1766068bdb67SNick Dyer static int mxt_read_info_block(struct mxt_data *data)
1767068bdb67SNick Dyer {
1768068bdb67SNick Dyer 	struct i2c_client *client = data->client;
1769068bdb67SNick Dyer 	int error;
1770068bdb67SNick Dyer 	size_t size;
1771068bdb67SNick Dyer 	void *id_buf, *buf;
1772068bdb67SNick Dyer 	uint8_t num_objects;
1773068bdb67SNick Dyer 	u32 calculated_crc;
1774068bdb67SNick Dyer 	u8 *crc_ptr;
1775068bdb67SNick Dyer 
1776068bdb67SNick Dyer 	/* If info block already allocated, free it */
1777068bdb67SNick Dyer 	if (data->raw_info_block)
1778068bdb67SNick Dyer 		mxt_free_object_table(data);
1779068bdb67SNick Dyer 
1780068bdb67SNick Dyer 	/* Read 7-byte ID information block starting at address 0 */
1781068bdb67SNick Dyer 	size = sizeof(struct mxt_info);
1782068bdb67SNick Dyer 	id_buf = kzalloc(size, GFP_KERNEL);
1783068bdb67SNick Dyer 	if (!id_buf)
1784068bdb67SNick Dyer 		return -ENOMEM;
1785068bdb67SNick Dyer 
1786068bdb67SNick Dyer 	error = __mxt_read_reg(client, 0, size, id_buf);
1787068bdb67SNick Dyer 	if (error)
1788068bdb67SNick Dyer 		goto err_free_mem;
1789068bdb67SNick Dyer 
1790068bdb67SNick Dyer 	/* Resize buffer to give space for rest of info block */
1791068bdb67SNick Dyer 	num_objects = ((struct mxt_info *)id_buf)->object_num;
1792068bdb67SNick Dyer 	size += (num_objects * sizeof(struct mxt_object))
1793068bdb67SNick Dyer 		+ MXT_INFO_CHECKSUM_SIZE;
1794068bdb67SNick Dyer 
1795068bdb67SNick Dyer 	buf = krealloc(id_buf, size, GFP_KERNEL);
1796068bdb67SNick Dyer 	if (!buf) {
1797068bdb67SNick Dyer 		error = -ENOMEM;
1798068bdb67SNick Dyer 		goto err_free_mem;
1799068bdb67SNick Dyer 	}
1800068bdb67SNick Dyer 	id_buf = buf;
1801068bdb67SNick Dyer 
1802068bdb67SNick Dyer 	/* Read rest of info block */
1803068bdb67SNick Dyer 	error = __mxt_read_reg(client, MXT_OBJECT_START,
1804068bdb67SNick Dyer 			       size - MXT_OBJECT_START,
1805068bdb67SNick Dyer 			       id_buf + MXT_OBJECT_START);
1806068bdb67SNick Dyer 	if (error)
1807068bdb67SNick Dyer 		goto err_free_mem;
1808068bdb67SNick Dyer 
1809068bdb67SNick Dyer 	/* Extract & calculate checksum */
1810068bdb67SNick Dyer 	crc_ptr = id_buf + size - MXT_INFO_CHECKSUM_SIZE;
1811068bdb67SNick Dyer 	data->info_crc = crc_ptr[0] | (crc_ptr[1] << 8) | (crc_ptr[2] << 16);
1812068bdb67SNick Dyer 
1813068bdb67SNick Dyer 	calculated_crc = mxt_calculate_crc(id_buf, 0,
1814068bdb67SNick Dyer 					   size - MXT_INFO_CHECKSUM_SIZE);
1815068bdb67SNick Dyer 
1816068bdb67SNick Dyer 	/*
1817068bdb67SNick Dyer 	 * CRC mismatch can be caused by data corruption due to I2C comms
1818068bdb67SNick Dyer 	 * issue or else device is not using Object Based Protocol (eg i2c-hid)
1819068bdb67SNick Dyer 	 */
1820068bdb67SNick Dyer 	if ((data->info_crc == 0) || (data->info_crc != calculated_crc)) {
1821068bdb67SNick Dyer 		dev_err(&client->dev,
1822068bdb67SNick Dyer 			"Info Block CRC error calculated=0x%06X read=0x%06X\n",
1823068bdb67SNick Dyer 			calculated_crc, data->info_crc);
1824068bdb67SNick Dyer 		error = -EIO;
1825068bdb67SNick Dyer 		goto err_free_mem;
1826068bdb67SNick Dyer 	}
1827068bdb67SNick Dyer 
1828068bdb67SNick Dyer 	data->raw_info_block = id_buf;
1829068bdb67SNick Dyer 	data->info = (struct mxt_info *)id_buf;
1830068bdb67SNick Dyer 
1831068bdb67SNick Dyer 	dev_info(&client->dev,
1832068bdb67SNick Dyer 		 "Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n",
1833068bdb67SNick Dyer 		 data->info->family_id, data->info->variant_id,
1834068bdb67SNick Dyer 		 data->info->version >> 4, data->info->version & 0xf,
1835068bdb67SNick Dyer 		 data->info->build, data->info->object_num);
1836068bdb67SNick Dyer 
1837068bdb67SNick Dyer 	/* Parse object table information */
1838068bdb67SNick Dyer 	error = mxt_parse_object_table(data, id_buf + MXT_OBJECT_START);
1839068bdb67SNick Dyer 	if (error) {
1840068bdb67SNick Dyer 		dev_err(&client->dev, "Error %d parsing object table\n", error);
1841068bdb67SNick Dyer 		mxt_free_object_table(data);
1842068bdb67SNick Dyer 		goto err_free_mem;
1843068bdb67SNick Dyer 	}
1844068bdb67SNick Dyer 
1845068bdb67SNick Dyer 	data->object_table = (struct mxt_object *)(id_buf + MXT_OBJECT_START);
1846dd24dcf5SNick Dyer 
18474cf51c38SJoonyoung Shim 	return 0;
18484cf51c38SJoonyoung Shim 
1849068bdb67SNick Dyer err_free_mem:
1850068bdb67SNick Dyer 	kfree(id_buf);
18515f3f9bc2SNick Dyer 	return error;
18527d4fa100SDaniel Kurtz }
18537d4fa100SDaniel Kurtz 
185461dc1abaSNick Dyer static int mxt_read_t9_resolution(struct mxt_data *data)
185561dc1abaSNick Dyer {
185661dc1abaSNick Dyer 	struct i2c_client *client = data->client;
185761dc1abaSNick Dyer 	int error;
185861dc1abaSNick Dyer 	struct t9_range range;
185961dc1abaSNick Dyer 	unsigned char orient;
186061dc1abaSNick Dyer 	struct mxt_object *object;
186161dc1abaSNick Dyer 
186261dc1abaSNick Dyer 	object = mxt_get_object(data, MXT_TOUCH_MULTI_T9);
186361dc1abaSNick Dyer 	if (!object)
186461dc1abaSNick Dyer 		return -EINVAL;
186561dc1abaSNick Dyer 
186661dc1abaSNick Dyer 	error = __mxt_read_reg(client,
18672786489fSNick Dyer 			       object->start_address + MXT_T9_XSIZE,
18682786489fSNick Dyer 			       sizeof(data->xsize), &data->xsize);
18692786489fSNick Dyer 	if (error)
18702786489fSNick Dyer 		return error;
18712786489fSNick Dyer 
18722786489fSNick Dyer 	error = __mxt_read_reg(client,
18732786489fSNick Dyer 			       object->start_address + MXT_T9_YSIZE,
18742786489fSNick Dyer 			       sizeof(data->ysize), &data->ysize);
18752786489fSNick Dyer 	if (error)
18762786489fSNick Dyer 		return error;
18772786489fSNick Dyer 
18782786489fSNick Dyer 	error = __mxt_read_reg(client,
187961dc1abaSNick Dyer 			       object->start_address + MXT_T9_RANGE,
188061dc1abaSNick Dyer 			       sizeof(range), &range);
188161dc1abaSNick Dyer 	if (error)
188261dc1abaSNick Dyer 		return error;
188361dc1abaSNick Dyer 
18841c0276d5SNick Dyer 	data->max_x = get_unaligned_le16(&range.x);
18851c0276d5SNick Dyer 	data->max_y = get_unaligned_le16(&range.y);
188661dc1abaSNick Dyer 
188761dc1abaSNick Dyer 	error =  __mxt_read_reg(client,
188861dc1abaSNick Dyer 				object->start_address + MXT_T9_ORIENT,
188961dc1abaSNick Dyer 				1, &orient);
189061dc1abaSNick Dyer 	if (error)
189161dc1abaSNick Dyer 		return error;
189261dc1abaSNick Dyer 
18931c0276d5SNick Dyer 	data->xy_switch = orient & MXT_T9_ORIENT_SWITCH;
1894de601f71SNick Dyer 	data->invertx = orient & MXT_T9_ORIENT_INVERTX;
1895de601f71SNick Dyer 	data->inverty = orient & MXT_T9_ORIENT_INVERTY;
189661dc1abaSNick Dyer 
189761dc1abaSNick Dyer 	return 0;
189861dc1abaSNick Dyer }
189961dc1abaSNick Dyer 
1900b23157dcSNick Dyer static int mxt_read_t100_config(struct mxt_data *data)
1901b23157dcSNick Dyer {
1902b23157dcSNick Dyer 	struct i2c_client *client = data->client;
1903b23157dcSNick Dyer 	int error;
1904b23157dcSNick Dyer 	struct mxt_object *object;
1905b23157dcSNick Dyer 	u16 range_x, range_y;
1906b23157dcSNick Dyer 	u8 cfg, tchaux;
1907b23157dcSNick Dyer 	u8 aux;
1908b23157dcSNick Dyer 
1909b23157dcSNick Dyer 	object = mxt_get_object(data, MXT_TOUCH_MULTITOUCHSCREEN_T100);
1910b23157dcSNick Dyer 	if (!object)
1911b23157dcSNick Dyer 		return -EINVAL;
1912b23157dcSNick Dyer 
19131c0276d5SNick Dyer 	/* read touchscreen dimensions */
1914b23157dcSNick Dyer 	error = __mxt_read_reg(client,
1915b23157dcSNick Dyer 			       object->start_address + MXT_T100_XRANGE,
1916b23157dcSNick Dyer 			       sizeof(range_x), &range_x);
1917b23157dcSNick Dyer 	if (error)
1918b23157dcSNick Dyer 		return error;
1919b23157dcSNick Dyer 
19201c0276d5SNick Dyer 	data->max_x = get_unaligned_le16(&range_x);
1921b23157dcSNick Dyer 
1922b23157dcSNick Dyer 	error = __mxt_read_reg(client,
1923b23157dcSNick Dyer 			       object->start_address + MXT_T100_YRANGE,
1924b23157dcSNick Dyer 			       sizeof(range_y), &range_y);
1925b23157dcSNick Dyer 	if (error)
1926b23157dcSNick Dyer 		return error;
1927b23157dcSNick Dyer 
19281c0276d5SNick Dyer 	data->max_y = get_unaligned_le16(&range_y);
1929b23157dcSNick Dyer 
19302786489fSNick Dyer 	error = __mxt_read_reg(client,
19312786489fSNick Dyer 			       object->start_address + MXT_T100_XSIZE,
19322786489fSNick Dyer 			       sizeof(data->xsize), &data->xsize);
19332786489fSNick Dyer 	if (error)
19342786489fSNick Dyer 		return error;
19352786489fSNick Dyer 
19362786489fSNick Dyer 	error = __mxt_read_reg(client,
19372786489fSNick Dyer 			       object->start_address + MXT_T100_YSIZE,
19382786489fSNick Dyer 			       sizeof(data->ysize), &data->ysize);
19392786489fSNick Dyer 	if (error)
19402786489fSNick Dyer 		return error;
19412786489fSNick Dyer 
19421c0276d5SNick Dyer 	/* read orientation config */
1943b23157dcSNick Dyer 	error =  __mxt_read_reg(client,
1944b23157dcSNick Dyer 				object->start_address + MXT_T100_CFG1,
1945b23157dcSNick Dyer 				1, &cfg);
1946b23157dcSNick Dyer 	if (error)
1947b23157dcSNick Dyer 		return error;
1948b23157dcSNick Dyer 
19491c0276d5SNick Dyer 	data->xy_switch = cfg & MXT_T100_CFG_SWITCHXY;
1950de601f71SNick Dyer 	data->invertx = cfg & MXT_T100_CFG_INVERTX;
1951de601f71SNick Dyer 	data->inverty = cfg & MXT_T100_CFG_INVERTY;
19521c0276d5SNick Dyer 
19531c0276d5SNick Dyer 	/* allocate aux bytes */
1954b23157dcSNick Dyer 	error =  __mxt_read_reg(client,
1955b23157dcSNick Dyer 				object->start_address + MXT_T100_TCHAUX,
1956b23157dcSNick Dyer 				1, &tchaux);
1957b23157dcSNick Dyer 	if (error)
1958b23157dcSNick Dyer 		return error;
1959b23157dcSNick Dyer 
1960b23157dcSNick Dyer 	aux = 6;
1961b23157dcSNick Dyer 
1962b23157dcSNick Dyer 	if (tchaux & MXT_T100_TCHAUX_VECT)
1963b23157dcSNick Dyer 		data->t100_aux_vect = aux++;
1964b23157dcSNick Dyer 
1965b23157dcSNick Dyer 	if (tchaux & MXT_T100_TCHAUX_AMPL)
1966b23157dcSNick Dyer 		data->t100_aux_ampl = aux++;
1967b23157dcSNick Dyer 
1968b23157dcSNick Dyer 	if (tchaux & MXT_T100_TCHAUX_AREA)
1969b23157dcSNick Dyer 		data->t100_aux_area = aux++;
1970b23157dcSNick Dyer 
1971b23157dcSNick Dyer 	dev_dbg(&client->dev,
1972b23157dcSNick Dyer 		"T100 aux mappings vect:%u ampl:%u area:%u\n",
1973b23157dcSNick Dyer 		data->t100_aux_vect, data->t100_aux_ampl, data->t100_aux_area);
1974b23157dcSNick Dyer 
1975b23157dcSNick Dyer 	return 0;
1976b23157dcSNick Dyer }
1977b23157dcSNick Dyer 
19787a53d609SNick Dyer static int mxt_input_open(struct input_dev *dev);
19797a53d609SNick Dyer static void mxt_input_close(struct input_dev *dev);
19807a53d609SNick Dyer 
1981b6d2d328SSjoerd Simons static void mxt_set_up_as_touchpad(struct input_dev *input_dev,
1982b6d2d328SSjoerd Simons 				   struct mxt_data *data)
1983b6d2d328SSjoerd Simons {
1984b6d2d328SSjoerd Simons 	int i;
1985b6d2d328SSjoerd Simons 
1986b6d2d328SSjoerd Simons 	input_dev->name = "Atmel maXTouch Touchpad";
1987b6d2d328SSjoerd Simons 
1988b6d2d328SSjoerd Simons 	__set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
1989b6d2d328SSjoerd Simons 
1990b6d2d328SSjoerd Simons 	input_abs_set_res(input_dev, ABS_X, MXT_PIXELS_PER_MM);
1991b6d2d328SSjoerd Simons 	input_abs_set_res(input_dev, ABS_Y, MXT_PIXELS_PER_MM);
1992b6d2d328SSjoerd Simons 	input_abs_set_res(input_dev, ABS_MT_POSITION_X,
1993b6d2d328SSjoerd Simons 			  MXT_PIXELS_PER_MM);
1994b6d2d328SSjoerd Simons 	input_abs_set_res(input_dev, ABS_MT_POSITION_Y,
1995b6d2d328SSjoerd Simons 			  MXT_PIXELS_PER_MM);
1996b6d2d328SSjoerd Simons 
199796a938aaSDmitry Torokhov 	for (i = 0; i < data->t19_num_keys; i++)
199896a938aaSDmitry Torokhov 		if (data->t19_keymap[i] != KEY_RESERVED)
1999b6d2d328SSjoerd Simons 			input_set_capability(input_dev, EV_KEY,
200096a938aaSDmitry Torokhov 					     data->t19_keymap[i]);
2001b6d2d328SSjoerd Simons }
2002b6d2d328SSjoerd Simons 
2003b23157dcSNick Dyer static int mxt_initialize_input_device(struct mxt_data *data)
20047a53d609SNick Dyer {
2005b6d2d328SSjoerd Simons 	struct device *dev = &data->client->dev;
20067a53d609SNick Dyer 	struct input_dev *input_dev;
20077a53d609SNick Dyer 	int error;
20087a53d609SNick Dyer 	unsigned int num_mt_slots;
20097a53d609SNick Dyer 	unsigned int mt_flags = 0;
20107a53d609SNick Dyer 
2011b23157dcSNick Dyer 	switch (data->multitouch) {
2012b23157dcSNick Dyer 	case MXT_TOUCH_MULTI_T9:
2013b23157dcSNick Dyer 		num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1;
20147a53d609SNick Dyer 		error = mxt_read_t9_resolution(data);
20157a53d609SNick Dyer 		if (error)
20167a53d609SNick Dyer 			dev_warn(dev, "Failed to initialize T9 resolution\n");
2017b23157dcSNick Dyer 		break;
2018b23157dcSNick Dyer 
2019b23157dcSNick Dyer 	case MXT_TOUCH_MULTITOUCHSCREEN_T100:
2020b23157dcSNick Dyer 		num_mt_slots = data->num_touchids;
2021b23157dcSNick Dyer 		error = mxt_read_t100_config(data);
2022b23157dcSNick Dyer 		if (error)
2023b23157dcSNick Dyer 			dev_warn(dev, "Failed to read T100 config\n");
2024b23157dcSNick Dyer 		break;
2025b23157dcSNick Dyer 
2026b23157dcSNick Dyer 	default:
2027b23157dcSNick Dyer 		dev_err(dev, "Invalid multitouch object\n");
2028b23157dcSNick Dyer 		return -EINVAL;
2029b23157dcSNick Dyer 	}
20307a53d609SNick Dyer 
20311c0276d5SNick Dyer 	/* Handle default values and orientation switch */
20321c0276d5SNick Dyer 	if (data->max_x == 0)
20331c0276d5SNick Dyer 		data->max_x = 1023;
20341c0276d5SNick Dyer 
20351c0276d5SNick Dyer 	if (data->max_y == 0)
20361c0276d5SNick Dyer 		data->max_y = 1023;
20371c0276d5SNick Dyer 
20381c0276d5SNick Dyer 	if (data->xy_switch)
20391c0276d5SNick Dyer 		swap(data->max_x, data->max_y);
20401c0276d5SNick Dyer 
20411c0276d5SNick Dyer 	dev_info(dev, "Touchscreen size X%uY%u\n", data->max_x, data->max_y);
20421c0276d5SNick Dyer 
20431c0276d5SNick Dyer 	/* Register input device */
20447a53d609SNick Dyer 	input_dev = input_allocate_device();
204501cc75f9SNick Dyer 	if (!input_dev)
20467a53d609SNick Dyer 		return -ENOMEM;
20477a53d609SNick Dyer 
20487a53d609SNick Dyer 	input_dev->name = "Atmel maXTouch Touchscreen";
20497a53d609SNick Dyer 	input_dev->phys = data->phys;
20507a53d609SNick Dyer 	input_dev->id.bustype = BUS_I2C;
20517a53d609SNick Dyer 	input_dev->dev.parent = dev;
20527a53d609SNick Dyer 	input_dev->open = mxt_input_open;
20537a53d609SNick Dyer 	input_dev->close = mxt_input_close;
20547a53d609SNick Dyer 
2055b23157dcSNick Dyer 	input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
20567a53d609SNick Dyer 
20577a53d609SNick Dyer 	/* For single touch */
2058b23157dcSNick Dyer 	input_set_abs_params(input_dev, ABS_X, 0, data->max_x, 0, 0);
2059b23157dcSNick Dyer 	input_set_abs_params(input_dev, ABS_Y, 0, data->max_y, 0, 0);
2060b23157dcSNick Dyer 
2061b23157dcSNick Dyer 	if (data->multitouch == MXT_TOUCH_MULTI_T9 ||
2062b23157dcSNick Dyer 	    (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 &&
2063b23157dcSNick Dyer 	     data->t100_aux_ampl)) {
2064b23157dcSNick Dyer 		input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0);
2065b23157dcSNick Dyer 	}
20667a53d609SNick Dyer 
2067b6d2d328SSjoerd Simons 	/* If device has buttons we assume it is a touchpad */
206896a938aaSDmitry Torokhov 	if (data->t19_num_keys) {
2069b6d2d328SSjoerd Simons 		mxt_set_up_as_touchpad(input_dev, data);
2070b6d2d328SSjoerd Simons 		mt_flags |= INPUT_MT_POINTER;
2071eafc0c87SNick Dyer 	} else {
2072eafc0c87SNick Dyer 		mt_flags |= INPUT_MT_DIRECT;
2073b6d2d328SSjoerd Simons 	}
2074b6d2d328SSjoerd Simons 
20757a53d609SNick Dyer 	/* For multi touch */
20767a53d609SNick Dyer 	error = input_mt_init_slots(input_dev, num_mt_slots, mt_flags);
20777a53d609SNick Dyer 	if (error) {
20787a53d609SNick Dyer 		dev_err(dev, "Error %d initialising slots\n", error);
20797a53d609SNick Dyer 		goto err_free_mem;
20807a53d609SNick Dyer 	}
20817a53d609SNick Dyer 
2082b23157dcSNick Dyer 	if (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100) {
2083b23157dcSNick Dyer 		input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
2084b23157dcSNick Dyer 				     0, MT_TOOL_MAX, 0, 0);
2085b23157dcSNick Dyer 		input_set_abs_params(input_dev, ABS_MT_DISTANCE,
2086b23157dcSNick Dyer 				     MXT_DISTANCE_ACTIVE_TOUCH,
2087b23157dcSNick Dyer 				     MXT_DISTANCE_HOVERING,
2088b23157dcSNick Dyer 				     0, 0);
2089b23157dcSNick Dyer 	}
2090b23157dcSNick Dyer 
20917a53d609SNick Dyer 	input_set_abs_params(input_dev, ABS_MT_POSITION_X,
20927a53d609SNick Dyer 			     0, data->max_x, 0, 0);
20937a53d609SNick Dyer 	input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
20947a53d609SNick Dyer 			     0, data->max_y, 0, 0);
2095b23157dcSNick Dyer 
2096b23157dcSNick Dyer 	if (data->multitouch == MXT_TOUCH_MULTI_T9 ||
2097b23157dcSNick Dyer 	    (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 &&
2098b23157dcSNick Dyer 	     data->t100_aux_area)) {
2099b23157dcSNick Dyer 		input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
2100b23157dcSNick Dyer 				     0, MXT_MAX_AREA, 0, 0);
2101b23157dcSNick Dyer 	}
2102b23157dcSNick Dyer 
2103b23157dcSNick Dyer 	if (data->multitouch == MXT_TOUCH_MULTI_T9 ||
2104b23157dcSNick Dyer 	    (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 &&
2105b23157dcSNick Dyer 	     data->t100_aux_ampl)) {
21067a53d609SNick Dyer 		input_set_abs_params(input_dev, ABS_MT_PRESSURE,
21077a53d609SNick Dyer 				     0, 255, 0, 0);
2108b23157dcSNick Dyer 	}
2109b23157dcSNick Dyer 
2110b23157dcSNick Dyer 	if (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 &&
2111b23157dcSNick Dyer 	    data->t100_aux_vect) {
2112b23157dcSNick Dyer 		input_set_abs_params(input_dev, ABS_MT_ORIENTATION,
2113b23157dcSNick Dyer 				     0, 255, 0, 0);
2114b23157dcSNick Dyer 	}
2115b23157dcSNick Dyer 
2116b23157dcSNick Dyer 	if (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 &&
2117b23157dcSNick Dyer 	    data->t100_aux_vect) {
2118b23157dcSNick Dyer 		input_set_abs_params(input_dev, ABS_MT_ORIENTATION,
2119b23157dcSNick Dyer 				     0, 255, 0, 0);
2120b23157dcSNick Dyer 	}
21217a53d609SNick Dyer 
21227a53d609SNick Dyer 	input_set_drvdata(input_dev, data);
21237a53d609SNick Dyer 
21247a53d609SNick Dyer 	error = input_register_device(input_dev);
21257a53d609SNick Dyer 	if (error) {
21267a53d609SNick Dyer 		dev_err(dev, "Error %d registering input device\n", error);
21277a53d609SNick Dyer 		goto err_free_mem;
21287a53d609SNick Dyer 	}
21297a53d609SNick Dyer 
21307a53d609SNick Dyer 	data->input_dev = input_dev;
21317a53d609SNick Dyer 
21327a53d609SNick Dyer 	return 0;
21337a53d609SNick Dyer 
21347a53d609SNick Dyer err_free_mem:
21357a53d609SNick Dyer 	input_free_device(input_dev);
21367a53d609SNick Dyer 	return error;
21377a53d609SNick Dyer }
21387a53d609SNick Dyer 
213950a77c65SNick Dyer static int mxt_configure_objects(struct mxt_data *data,
214050a77c65SNick Dyer 				 const struct firmware *cfg);
214150a77c65SNick Dyer 
214250a77c65SNick Dyer static void mxt_config_cb(const struct firmware *cfg, void *ctx)
214350a77c65SNick Dyer {
214450a77c65SNick Dyer 	mxt_configure_objects(ctx, cfg);
2145efdbd7aeSDmitry Torokhov 	release_firmware(cfg);
214650a77c65SNick Dyer }
214750a77c65SNick Dyer 
21487686b108SIiro Valkonen static int mxt_initialize(struct mxt_data *data)
21494cf51c38SJoonyoung Shim {
21504cf51c38SJoonyoung Shim 	struct i2c_client *client = data->client;
21516cd1ab0fSDmitry Torokhov 	int recovery_attempts = 0;
21524cf51c38SJoonyoung Shim 	int error;
21534cf51c38SJoonyoung Shim 
21546cd1ab0fSDmitry Torokhov 	while (1) {
2155068bdb67SNick Dyer 		error = mxt_read_info_block(data);
21566cd1ab0fSDmitry Torokhov 		if (!error)
21576cd1ab0fSDmitry Torokhov 			break;
21586cd1ab0fSDmitry Torokhov 
21596cd1ab0fSDmitry Torokhov 		/* Check bootloader state */
21606cd1ab0fSDmitry Torokhov 		error = mxt_probe_bootloader(data, false);
2161a9fdd1e6SNick Dyer 		if (error) {
21626cd1ab0fSDmitry Torokhov 			dev_info(&client->dev, "Trying alternate bootloader address\n");
21636cd1ab0fSDmitry Torokhov 			error = mxt_probe_bootloader(data, true);
21648efaa5e5SNick Dyer 			if (error) {
21658efaa5e5SNick Dyer 				/* Chip is not in appmode or bootloader mode */
21664cf51c38SJoonyoung Shim 				return error;
21678efaa5e5SNick Dyer 			}
21686cd1ab0fSDmitry Torokhov 		}
21694cf51c38SJoonyoung Shim 
21706cd1ab0fSDmitry Torokhov 		/* OK, we are in bootloader, see if we can recover */
21716cd1ab0fSDmitry Torokhov 		if (++recovery_attempts > 1) {
21728efaa5e5SNick Dyer 			dev_err(&client->dev, "Could not recover from bootloader mode\n");
21738efaa5e5SNick Dyer 			/*
21748efaa5e5SNick Dyer 			 * We can reflash from this state, so do not
21756cd1ab0fSDmitry Torokhov 			 * abort initialization.
21768efaa5e5SNick Dyer 			 */
2177a9fdd1e6SNick Dyer 			data->in_bootloader = true;
2178a9fdd1e6SNick Dyer 			return 0;
2179a9fdd1e6SNick Dyer 		}
2180a9fdd1e6SNick Dyer 
21818efaa5e5SNick Dyer 		/* Attempt to exit bootloader into app mode */
21828efaa5e5SNick Dyer 		mxt_send_bootloader_cmd(data, false);
21838efaa5e5SNick Dyer 		msleep(MXT_FW_RESET_TIME);
21848efaa5e5SNick Dyer 	}
21858efaa5e5SNick Dyer 
2186041fa159SDmitry Torokhov 	error = mxt_acquire_irq(data);
2187dd24dcf5SNick Dyer 	if (error)
2188068bdb67SNick Dyer 		return error;
2189dd24dcf5SNick Dyer 
219074d905d2SNick Dyer 	error = mxt_check_retrigen(data);
219174d905d2SNick Dyer 	if (error)
219274d905d2SNick Dyer 		return error;
219374d905d2SNick Dyer 
21946cd1ab0fSDmitry Torokhov 	error = request_firmware_nowait(THIS_MODULE, true, MXT_CFG_NAME,
21956cd1ab0fSDmitry Torokhov 					&client->dev, GFP_KERNEL, data,
219650a77c65SNick Dyer 					mxt_config_cb);
21976cd1ab0fSDmitry Torokhov 	if (error) {
21986cd1ab0fSDmitry Torokhov 		dev_err(&client->dev, "Failed to invoke firmware loader: %d\n",
21996cd1ab0fSDmitry Torokhov 			error);
2200068bdb67SNick Dyer 		return error;
22016cd1ab0fSDmitry Torokhov 	}
22024cf51c38SJoonyoung Shim 
22034cf51c38SJoonyoung Shim 	return 0;
22044cf51c38SJoonyoung Shim }
22054cf51c38SJoonyoung Shim 
22067f3884f7SNick Dyer static int mxt_set_t7_power_cfg(struct mxt_data *data, u8 sleep)
22077f3884f7SNick Dyer {
22087f3884f7SNick Dyer 	struct device *dev = &data->client->dev;
22097f3884f7SNick Dyer 	int error;
22107f3884f7SNick Dyer 	struct t7_config *new_config;
22117f3884f7SNick Dyer 	struct t7_config deepsleep = { .active = 0, .idle = 0 };
22127f3884f7SNick Dyer 
22137f3884f7SNick Dyer 	if (sleep == MXT_POWER_CFG_DEEPSLEEP)
22147f3884f7SNick Dyer 		new_config = &deepsleep;
22157f3884f7SNick Dyer 	else
22167f3884f7SNick Dyer 		new_config = &data->t7_cfg;
22177f3884f7SNick Dyer 
22187f3884f7SNick Dyer 	error = __mxt_write_reg(data->client, data->T7_address,
22197f3884f7SNick Dyer 				sizeof(data->t7_cfg), new_config);
22207f3884f7SNick Dyer 	if (error)
22217f3884f7SNick Dyer 		return error;
22227f3884f7SNick Dyer 
22237f3884f7SNick Dyer 	dev_dbg(dev, "Set T7 ACTV:%d IDLE:%d\n",
22247f3884f7SNick Dyer 		new_config->active, new_config->idle);
22257f3884f7SNick Dyer 
22267f3884f7SNick Dyer 	return 0;
22277f3884f7SNick Dyer }
22287f3884f7SNick Dyer 
22297f3884f7SNick Dyer static int mxt_init_t7_power_cfg(struct mxt_data *data)
22307f3884f7SNick Dyer {
22317f3884f7SNick Dyer 	struct device *dev = &data->client->dev;
22327f3884f7SNick Dyer 	int error;
22337f3884f7SNick Dyer 	bool retry = false;
22347f3884f7SNick Dyer 
22357f3884f7SNick Dyer recheck:
22367f3884f7SNick Dyer 	error = __mxt_read_reg(data->client, data->T7_address,
22377f3884f7SNick Dyer 				sizeof(data->t7_cfg), &data->t7_cfg);
22387f3884f7SNick Dyer 	if (error)
22397f3884f7SNick Dyer 		return error;
22407f3884f7SNick Dyer 
22417f3884f7SNick Dyer 	if (data->t7_cfg.active == 0 || data->t7_cfg.idle == 0) {
22427f3884f7SNick Dyer 		if (!retry) {
22437f3884f7SNick Dyer 			dev_dbg(dev, "T7 cfg zero, resetting\n");
22447f3884f7SNick Dyer 			mxt_soft_reset(data);
22457f3884f7SNick Dyer 			retry = true;
22467f3884f7SNick Dyer 			goto recheck;
22477f3884f7SNick Dyer 		} else {
22487f3884f7SNick Dyer 			dev_dbg(dev, "T7 cfg zero after reset, overriding\n");
22497f3884f7SNick Dyer 			data->t7_cfg.active = 20;
22507f3884f7SNick Dyer 			data->t7_cfg.idle = 100;
22517f3884f7SNick Dyer 			return mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN);
22527f3884f7SNick Dyer 		}
22537f3884f7SNick Dyer 	}
22547f3884f7SNick Dyer 
22557f3884f7SNick Dyer 	dev_dbg(dev, "Initialized power cfg: ACTV %d, IDLE %d\n",
22567f3884f7SNick Dyer 		data->t7_cfg.active, data->t7_cfg.idle);
22577f3884f7SNick Dyer 	return 0;
22587f3884f7SNick Dyer }
22597f3884f7SNick Dyer 
2260d6a39404SNick Dyer #ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37
22615cecc2bcSNathan Huckleberry static const struct v4l2_file_operations mxt_video_fops = {
22625cecc2bcSNathan Huckleberry 	.owner = THIS_MODULE,
22635cecc2bcSNathan Huckleberry 	.open = v4l2_fh_open,
22645cecc2bcSNathan Huckleberry 	.release = vb2_fop_release,
22655cecc2bcSNathan Huckleberry 	.unlocked_ioctl = video_ioctl2,
22665cecc2bcSNathan Huckleberry 	.read = vb2_fop_read,
22675cecc2bcSNathan Huckleberry 	.mmap = vb2_fop_mmap,
22685cecc2bcSNathan Huckleberry 	.poll = vb2_fop_poll,
22695cecc2bcSNathan Huckleberry };
22705cecc2bcSNathan Huckleberry 
2271d6a39404SNick Dyer static u16 mxt_get_debug_value(struct mxt_data *data, unsigned int x,
2272d6a39404SNick Dyer 			       unsigned int y)
2273d6a39404SNick Dyer {
2274068bdb67SNick Dyer 	struct mxt_info *info = data->info;
2275d6a39404SNick Dyer 	struct mxt_dbg *dbg = &data->dbg;
2276d6a39404SNick Dyer 	unsigned int ofs, page;
2277566d533aSNick Dyer 	unsigned int col = 0;
2278566d533aSNick Dyer 	unsigned int col_width;
2279d6a39404SNick Dyer 
2280566d533aSNick Dyer 	if (info->family_id == MXT_FAMILY_1386) {
2281566d533aSNick Dyer 		col_width = info->matrix_ysize / MXT1386_COLUMNS;
2282566d533aSNick Dyer 		col = y / col_width;
2283566d533aSNick Dyer 		y = y % col_width;
2284566d533aSNick Dyer 	} else {
2285566d533aSNick Dyer 		col_width = info->matrix_ysize;
2286566d533aSNick Dyer 	}
2287566d533aSNick Dyer 
2288566d533aSNick Dyer 	ofs = (y + (x * col_width)) * sizeof(u16);
2289d6a39404SNick Dyer 	page = ofs / MXT_DIAGNOSTIC_SIZE;
2290d6a39404SNick Dyer 	ofs %= MXT_DIAGNOSTIC_SIZE;
2291d6a39404SNick Dyer 
2292566d533aSNick Dyer 	if (info->family_id == MXT_FAMILY_1386)
2293566d533aSNick Dyer 		page += col * MXT1386_PAGES_PER_COLUMN;
2294566d533aSNick Dyer 
2295d6a39404SNick Dyer 	return get_unaligned_le16(&dbg->t37_buf[page].data[ofs]);
2296d6a39404SNick Dyer }
2297d6a39404SNick Dyer 
2298d6a39404SNick Dyer static int mxt_convert_debug_pages(struct mxt_data *data, u16 *outbuf)
2299d6a39404SNick Dyer {
2300d6a39404SNick Dyer 	struct mxt_dbg *dbg = &data->dbg;
2301d6a39404SNick Dyer 	unsigned int x = 0;
2302d6a39404SNick Dyer 	unsigned int y = 0;
2303de601f71SNick Dyer 	unsigned int i, rx, ry;
2304d6a39404SNick Dyer 
2305d6a39404SNick Dyer 	for (i = 0; i < dbg->t37_nodes; i++) {
2306de601f71SNick Dyer 		/* Handle orientation */
2307de601f71SNick Dyer 		rx = data->xy_switch ? y : x;
2308de601f71SNick Dyer 		ry = data->xy_switch ? x : y;
2309de601f71SNick Dyer 		rx = data->invertx ? (data->xsize - 1 - rx) : rx;
2310de601f71SNick Dyer 		ry = data->inverty ? (data->ysize - 1 - ry) : ry;
2311de601f71SNick Dyer 
2312de601f71SNick Dyer 		outbuf[i] = mxt_get_debug_value(data, rx, ry);
2313d6a39404SNick Dyer 
2314d6a39404SNick Dyer 		/* Next value */
2315de601f71SNick Dyer 		if (++x >= (data->xy_switch ? data->ysize : data->xsize)) {
2316d6a39404SNick Dyer 			x = 0;
2317d6a39404SNick Dyer 			y++;
2318d6a39404SNick Dyer 		}
2319d6a39404SNick Dyer 	}
2320d6a39404SNick Dyer 
2321d6a39404SNick Dyer 	return 0;
2322d6a39404SNick Dyer }
2323d6a39404SNick Dyer 
2324d6a39404SNick Dyer static int mxt_read_diagnostic_debug(struct mxt_data *data, u8 mode,
2325d6a39404SNick Dyer 				     u16 *outbuf)
2326d6a39404SNick Dyer {
2327d6a39404SNick Dyer 	struct mxt_dbg *dbg = &data->dbg;
2328d6a39404SNick Dyer 	int retries = 0;
2329d6a39404SNick Dyer 	int page;
2330d6a39404SNick Dyer 	int ret;
2331d6a39404SNick Dyer 	u8 cmd = mode;
2332d6a39404SNick Dyer 	struct t37_debug *p;
2333d6a39404SNick Dyer 	u8 cmd_poll;
2334d6a39404SNick Dyer 
2335d6a39404SNick Dyer 	for (page = 0; page < dbg->t37_pages; page++) {
2336d6a39404SNick Dyer 		p = dbg->t37_buf + page;
2337d6a39404SNick Dyer 
2338d6a39404SNick Dyer 		ret = mxt_write_reg(data->client, dbg->diag_cmd_address,
2339d6a39404SNick Dyer 				    cmd);
2340d6a39404SNick Dyer 		if (ret)
2341d6a39404SNick Dyer 			return ret;
2342d6a39404SNick Dyer 
2343d6a39404SNick Dyer 		retries = 0;
2344d6a39404SNick Dyer 		msleep(20);
2345d6a39404SNick Dyer wait_cmd:
2346d6a39404SNick Dyer 		/* Read back command byte */
2347d6a39404SNick Dyer 		ret = __mxt_read_reg(data->client, dbg->diag_cmd_address,
2348d6a39404SNick Dyer 				     sizeof(cmd_poll), &cmd_poll);
2349d6a39404SNick Dyer 		if (ret)
2350d6a39404SNick Dyer 			return ret;
2351d6a39404SNick Dyer 
2352d6a39404SNick Dyer 		/* Field is cleared once the command has been processed */
2353d6a39404SNick Dyer 		if (cmd_poll) {
2354d6a39404SNick Dyer 			if (retries++ > 100)
2355d6a39404SNick Dyer 				return -EINVAL;
2356d6a39404SNick Dyer 
2357d6a39404SNick Dyer 			msleep(20);
2358d6a39404SNick Dyer 			goto wait_cmd;
2359d6a39404SNick Dyer 		}
2360d6a39404SNick Dyer 
2361d6a39404SNick Dyer 		/* Read T37 page */
2362d6a39404SNick Dyer 		ret = __mxt_read_reg(data->client, dbg->t37_address,
2363d6a39404SNick Dyer 				     sizeof(struct t37_debug), p);
2364d6a39404SNick Dyer 		if (ret)
2365d6a39404SNick Dyer 			return ret;
2366d6a39404SNick Dyer 
2367d6a39404SNick Dyer 		if (p->mode != mode || p->page != page) {
2368d6a39404SNick Dyer 			dev_err(&data->client->dev, "T37 page mismatch\n");
2369d6a39404SNick Dyer 			return -EINVAL;
2370d6a39404SNick Dyer 		}
2371d6a39404SNick Dyer 
2372d6a39404SNick Dyer 		dev_dbg(&data->client->dev, "%s page:%d retries:%d\n",
2373d6a39404SNick Dyer 			__func__, page, retries);
2374d6a39404SNick Dyer 
2375d6a39404SNick Dyer 		/* For remaining pages, write PAGEUP rather than mode */
2376d6a39404SNick Dyer 		cmd = MXT_DIAGNOSTIC_PAGEUP;
2377d6a39404SNick Dyer 	}
2378d6a39404SNick Dyer 
2379d6a39404SNick Dyer 	return mxt_convert_debug_pages(data, outbuf);
2380d6a39404SNick Dyer }
2381d6a39404SNick Dyer 
2382ecfdd7e2SNick Dyer static int mxt_queue_setup(struct vb2_queue *q,
2383ecfdd7e2SNick Dyer 		       unsigned int *nbuffers, unsigned int *nplanes,
2384ecfdd7e2SNick Dyer 		       unsigned int sizes[], struct device *alloc_devs[])
2385ecfdd7e2SNick Dyer {
2386ecfdd7e2SNick Dyer 	struct mxt_data *data = q->drv_priv;
2387ecfdd7e2SNick Dyer 	size_t size = data->dbg.t37_nodes * sizeof(u16);
2388ecfdd7e2SNick Dyer 
2389ecfdd7e2SNick Dyer 	if (*nplanes)
2390ecfdd7e2SNick Dyer 		return sizes[0] < size ? -EINVAL : 0;
2391ecfdd7e2SNick Dyer 
2392ecfdd7e2SNick Dyer 	*nplanes = 1;
2393ecfdd7e2SNick Dyer 	sizes[0] = size;
2394ecfdd7e2SNick Dyer 
2395ecfdd7e2SNick Dyer 	return 0;
2396ecfdd7e2SNick Dyer }
2397ecfdd7e2SNick Dyer 
2398ecfdd7e2SNick Dyer static void mxt_buffer_queue(struct vb2_buffer *vb)
2399ecfdd7e2SNick Dyer {
2400ecfdd7e2SNick Dyer 	struct mxt_data *data = vb2_get_drv_priv(vb->vb2_queue);
2401ecfdd7e2SNick Dyer 	u16 *ptr;
2402ecfdd7e2SNick Dyer 	int ret;
240306b3d3f3SNick Dyer 	u8 mode;
2404ecfdd7e2SNick Dyer 
2405ecfdd7e2SNick Dyer 	ptr = vb2_plane_vaddr(vb, 0);
2406ecfdd7e2SNick Dyer 	if (!ptr) {
2407ecfdd7e2SNick Dyer 		dev_err(&data->client->dev, "Error acquiring frame ptr\n");
2408ecfdd7e2SNick Dyer 		goto fault;
2409ecfdd7e2SNick Dyer 	}
2410ecfdd7e2SNick Dyer 
241106b3d3f3SNick Dyer 	switch (data->dbg.input) {
241206b3d3f3SNick Dyer 	case MXT_V4L_INPUT_DELTAS:
241306b3d3f3SNick Dyer 	default:
241406b3d3f3SNick Dyer 		mode = MXT_DIAGNOSTIC_DELTAS;
241506b3d3f3SNick Dyer 		break;
241606b3d3f3SNick Dyer 
241706b3d3f3SNick Dyer 	case MXT_V4L_INPUT_REFS:
241806b3d3f3SNick Dyer 		mode = MXT_DIAGNOSTIC_REFS;
241906b3d3f3SNick Dyer 		break;
242006b3d3f3SNick Dyer 	}
242106b3d3f3SNick Dyer 
242206b3d3f3SNick Dyer 	ret = mxt_read_diagnostic_debug(data, mode, ptr);
2423ecfdd7e2SNick Dyer 	if (ret)
2424ecfdd7e2SNick Dyer 		goto fault;
2425ecfdd7e2SNick Dyer 
2426ecfdd7e2SNick Dyer 	vb2_set_plane_payload(vb, 0, data->dbg.t37_nodes * sizeof(u16));
2427ecfdd7e2SNick Dyer 	vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
2428ecfdd7e2SNick Dyer 	return;
2429ecfdd7e2SNick Dyer 
2430ecfdd7e2SNick Dyer fault:
2431ecfdd7e2SNick Dyer 	vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
2432ecfdd7e2SNick Dyer }
2433ecfdd7e2SNick Dyer 
2434ecfdd7e2SNick Dyer /* V4L2 structures */
2435ecfdd7e2SNick Dyer static const struct vb2_ops mxt_queue_ops = {
2436ecfdd7e2SNick Dyer 	.queue_setup		= mxt_queue_setup,
2437ecfdd7e2SNick Dyer 	.buf_queue		= mxt_buffer_queue,
2438ecfdd7e2SNick Dyer 	.wait_prepare		= vb2_ops_wait_prepare,
2439ecfdd7e2SNick Dyer 	.wait_finish		= vb2_ops_wait_finish,
2440ecfdd7e2SNick Dyer };
2441ecfdd7e2SNick Dyer 
2442ecfdd7e2SNick Dyer static const struct vb2_queue mxt_queue = {
2443ecfdd7e2SNick Dyer 	.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
2444ecfdd7e2SNick Dyer 	.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ,
2445ecfdd7e2SNick Dyer 	.buf_struct_size = sizeof(struct mxt_vb2_buffer),
2446ecfdd7e2SNick Dyer 	.ops = &mxt_queue_ops,
2447ecfdd7e2SNick Dyer 	.mem_ops = &vb2_vmalloc_memops,
2448ecfdd7e2SNick Dyer 	.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC,
2449ecfdd7e2SNick Dyer 	.min_buffers_needed = 1,
2450ecfdd7e2SNick Dyer };
2451ecfdd7e2SNick Dyer 
2452ecfdd7e2SNick Dyer static int mxt_vidioc_querycap(struct file *file, void *priv,
2453ecfdd7e2SNick Dyer 				 struct v4l2_capability *cap)
2454ecfdd7e2SNick Dyer {
2455ecfdd7e2SNick Dyer 	struct mxt_data *data = video_drvdata(file);
2456ecfdd7e2SNick Dyer 
2457ecfdd7e2SNick Dyer 	strlcpy(cap->driver, "atmel_mxt_ts", sizeof(cap->driver));
2458ecfdd7e2SNick Dyer 	strlcpy(cap->card, "atmel_mxt_ts touch", sizeof(cap->card));
2459ecfdd7e2SNick Dyer 	snprintf(cap->bus_info, sizeof(cap->bus_info),
2460ecfdd7e2SNick Dyer 		 "I2C:%s", dev_name(&data->client->dev));
2461ecfdd7e2SNick Dyer 	return 0;
2462ecfdd7e2SNick Dyer }
2463ecfdd7e2SNick Dyer 
2464ecfdd7e2SNick Dyer static int mxt_vidioc_enum_input(struct file *file, void *priv,
2465ecfdd7e2SNick Dyer 				   struct v4l2_input *i)
2466ecfdd7e2SNick Dyer {
246706b3d3f3SNick Dyer 	if (i->index >= MXT_V4L_INPUT_MAX)
2468ecfdd7e2SNick Dyer 		return -EINVAL;
2469ecfdd7e2SNick Dyer 
2470ecfdd7e2SNick Dyer 	i->type = V4L2_INPUT_TYPE_TOUCH;
247106b3d3f3SNick Dyer 
247206b3d3f3SNick Dyer 	switch (i->index) {
247306b3d3f3SNick Dyer 	case MXT_V4L_INPUT_REFS:
247406b3d3f3SNick Dyer 		strlcpy(i->name, "Mutual Capacitance References",
247506b3d3f3SNick Dyer 			sizeof(i->name));
247606b3d3f3SNick Dyer 		break;
247706b3d3f3SNick Dyer 	case MXT_V4L_INPUT_DELTAS:
2478ecfdd7e2SNick Dyer 		strlcpy(i->name, "Mutual Capacitance Deltas", sizeof(i->name));
247906b3d3f3SNick Dyer 		break;
248006b3d3f3SNick Dyer 	}
248106b3d3f3SNick Dyer 
2482ecfdd7e2SNick Dyer 	return 0;
2483ecfdd7e2SNick Dyer }
2484ecfdd7e2SNick Dyer 
2485ecfdd7e2SNick Dyer static int mxt_set_input(struct mxt_data *data, unsigned int i)
2486ecfdd7e2SNick Dyer {
2487ecfdd7e2SNick Dyer 	struct v4l2_pix_format *f = &data->dbg.format;
2488ecfdd7e2SNick Dyer 
248906b3d3f3SNick Dyer 	if (i >= MXT_V4L_INPUT_MAX)
2490ecfdd7e2SNick Dyer 		return -EINVAL;
2491ecfdd7e2SNick Dyer 
249206b3d3f3SNick Dyer 	if (i == MXT_V4L_INPUT_DELTAS)
249306b3d3f3SNick Dyer 		f->pixelformat = V4L2_TCH_FMT_DELTA_TD16;
249406b3d3f3SNick Dyer 	else
249506b3d3f3SNick Dyer 		f->pixelformat = V4L2_TCH_FMT_TU16;
249606b3d3f3SNick Dyer 
2497de601f71SNick Dyer 	f->width = data->xy_switch ? data->ysize : data->xsize;
2498de601f71SNick Dyer 	f->height = data->xy_switch ? data->xsize : data->ysize;
2499ecfdd7e2SNick Dyer 	f->field = V4L2_FIELD_NONE;
2500ecfdd7e2SNick Dyer 	f->colorspace = V4L2_COLORSPACE_RAW;
2501ecfdd7e2SNick Dyer 	f->bytesperline = f->width * sizeof(u16);
2502ecfdd7e2SNick Dyer 	f->sizeimage = f->width * f->height * sizeof(u16);
2503ecfdd7e2SNick Dyer 
2504ecfdd7e2SNick Dyer 	data->dbg.input = i;
2505ecfdd7e2SNick Dyer 
2506ecfdd7e2SNick Dyer 	return 0;
2507ecfdd7e2SNick Dyer }
2508ecfdd7e2SNick Dyer 
2509ecfdd7e2SNick Dyer static int mxt_vidioc_s_input(struct file *file, void *priv, unsigned int i)
2510ecfdd7e2SNick Dyer {
2511ecfdd7e2SNick Dyer 	return mxt_set_input(video_drvdata(file), i);
2512ecfdd7e2SNick Dyer }
2513ecfdd7e2SNick Dyer 
2514ecfdd7e2SNick Dyer static int mxt_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
2515ecfdd7e2SNick Dyer {
2516ecfdd7e2SNick Dyer 	struct mxt_data *data = video_drvdata(file);
2517ecfdd7e2SNick Dyer 
2518ecfdd7e2SNick Dyer 	*i = data->dbg.input;
2519ecfdd7e2SNick Dyer 
2520ecfdd7e2SNick Dyer 	return 0;
2521ecfdd7e2SNick Dyer }
2522ecfdd7e2SNick Dyer 
2523ecfdd7e2SNick Dyer static int mxt_vidioc_fmt(struct file *file, void *priv, struct v4l2_format *f)
2524ecfdd7e2SNick Dyer {
2525ecfdd7e2SNick Dyer 	struct mxt_data *data = video_drvdata(file);
2526ecfdd7e2SNick Dyer 
2527ecfdd7e2SNick Dyer 	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2528ecfdd7e2SNick Dyer 	f->fmt.pix = data->dbg.format;
2529ecfdd7e2SNick Dyer 
2530ecfdd7e2SNick Dyer 	return 0;
2531ecfdd7e2SNick Dyer }
2532ecfdd7e2SNick Dyer 
2533ecfdd7e2SNick Dyer static int mxt_vidioc_enum_fmt(struct file *file, void *priv,
2534ecfdd7e2SNick Dyer 				 struct v4l2_fmtdesc *fmt)
2535ecfdd7e2SNick Dyer {
2536ecfdd7e2SNick Dyer 	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
2537ecfdd7e2SNick Dyer 		return -EINVAL;
2538ecfdd7e2SNick Dyer 
253906b3d3f3SNick Dyer 	switch (fmt->index) {
254006b3d3f3SNick Dyer 	case 0:
254106b3d3f3SNick Dyer 		fmt->pixelformat = V4L2_TCH_FMT_TU16;
254206b3d3f3SNick Dyer 		break;
254306b3d3f3SNick Dyer 
254406b3d3f3SNick Dyer 	case 1:
2545ecfdd7e2SNick Dyer 		fmt->pixelformat = V4L2_TCH_FMT_DELTA_TD16;
254606b3d3f3SNick Dyer 		break;
254706b3d3f3SNick Dyer 
254806b3d3f3SNick Dyer 	default:
254906b3d3f3SNick Dyer 		return -EINVAL;
255006b3d3f3SNick Dyer 	}
255106b3d3f3SNick Dyer 
2552ecfdd7e2SNick Dyer 	return 0;
2553ecfdd7e2SNick Dyer }
2554ecfdd7e2SNick Dyer 
2555ecfdd7e2SNick Dyer static int mxt_vidioc_g_parm(struct file *file, void *fh,
2556ecfdd7e2SNick Dyer 			     struct v4l2_streamparm *a)
2557ecfdd7e2SNick Dyer {
2558ecfdd7e2SNick Dyer 	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
2559ecfdd7e2SNick Dyer 		return -EINVAL;
2560ecfdd7e2SNick Dyer 
2561ecfdd7e2SNick Dyer 	a->parm.capture.readbuffers = 1;
2562ecfdd7e2SNick Dyer 	a->parm.capture.timeperframe.numerator = 1;
2563ecfdd7e2SNick Dyer 	a->parm.capture.timeperframe.denominator = 10;
2564ecfdd7e2SNick Dyer 	return 0;
2565ecfdd7e2SNick Dyer }
2566ecfdd7e2SNick Dyer 
2567ecfdd7e2SNick Dyer static const struct v4l2_ioctl_ops mxt_video_ioctl_ops = {
2568ecfdd7e2SNick Dyer 	.vidioc_querycap        = mxt_vidioc_querycap,
2569ecfdd7e2SNick Dyer 
2570ecfdd7e2SNick Dyer 	.vidioc_enum_fmt_vid_cap = mxt_vidioc_enum_fmt,
2571ecfdd7e2SNick Dyer 	.vidioc_s_fmt_vid_cap   = mxt_vidioc_fmt,
2572ecfdd7e2SNick Dyer 	.vidioc_g_fmt_vid_cap   = mxt_vidioc_fmt,
2573ecfdd7e2SNick Dyer 	.vidioc_try_fmt_vid_cap	= mxt_vidioc_fmt,
2574ecfdd7e2SNick Dyer 	.vidioc_g_parm		= mxt_vidioc_g_parm,
2575ecfdd7e2SNick Dyer 
2576ecfdd7e2SNick Dyer 	.vidioc_enum_input      = mxt_vidioc_enum_input,
2577ecfdd7e2SNick Dyer 	.vidioc_g_input         = mxt_vidioc_g_input,
2578ecfdd7e2SNick Dyer 	.vidioc_s_input         = mxt_vidioc_s_input,
2579ecfdd7e2SNick Dyer 
2580ecfdd7e2SNick Dyer 	.vidioc_reqbufs         = vb2_ioctl_reqbufs,
2581ecfdd7e2SNick Dyer 	.vidioc_create_bufs     = vb2_ioctl_create_bufs,
2582ecfdd7e2SNick Dyer 	.vidioc_querybuf        = vb2_ioctl_querybuf,
2583ecfdd7e2SNick Dyer 	.vidioc_qbuf            = vb2_ioctl_qbuf,
2584ecfdd7e2SNick Dyer 	.vidioc_dqbuf           = vb2_ioctl_dqbuf,
2585ecfdd7e2SNick Dyer 	.vidioc_expbuf          = vb2_ioctl_expbuf,
2586ecfdd7e2SNick Dyer 
2587ecfdd7e2SNick Dyer 	.vidioc_streamon        = vb2_ioctl_streamon,
2588ecfdd7e2SNick Dyer 	.vidioc_streamoff       = vb2_ioctl_streamoff,
2589ecfdd7e2SNick Dyer };
2590ecfdd7e2SNick Dyer 
2591ecfdd7e2SNick Dyer static const struct video_device mxt_video_device = {
2592ecfdd7e2SNick Dyer 	.name = "Atmel maxTouch",
2593ecfdd7e2SNick Dyer 	.fops = &mxt_video_fops,
2594ecfdd7e2SNick Dyer 	.ioctl_ops = &mxt_video_ioctl_ops,
2595ecfdd7e2SNick Dyer 	.release = video_device_release_empty,
2596ecfdd7e2SNick Dyer 	.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TOUCH |
2597ecfdd7e2SNick Dyer 		       V4L2_CAP_READWRITE | V4L2_CAP_STREAMING,
2598ecfdd7e2SNick Dyer };
2599ecfdd7e2SNick Dyer 
2600d6a39404SNick Dyer static void mxt_debug_init(struct mxt_data *data)
2601d6a39404SNick Dyer {
2602068bdb67SNick Dyer 	struct mxt_info *info = data->info;
2603d6a39404SNick Dyer 	struct mxt_dbg *dbg = &data->dbg;
2604d6a39404SNick Dyer 	struct mxt_object *object;
2605ecfdd7e2SNick Dyer 	int error;
2606d6a39404SNick Dyer 
2607d6a39404SNick Dyer 	object = mxt_get_object(data, MXT_GEN_COMMAND_T6);
2608d6a39404SNick Dyer 	if (!object)
2609d6a39404SNick Dyer 		goto error;
2610d6a39404SNick Dyer 
2611d6a39404SNick Dyer 	dbg->diag_cmd_address = object->start_address + MXT_COMMAND_DIAGNOSTIC;
2612d6a39404SNick Dyer 
2613d6a39404SNick Dyer 	object = mxt_get_object(data, MXT_DEBUG_DIAGNOSTIC_T37);
2614d6a39404SNick Dyer 	if (!object)
2615d6a39404SNick Dyer 		goto error;
2616d6a39404SNick Dyer 
2617d6a39404SNick Dyer 	if (mxt_obj_size(object) != sizeof(struct t37_debug)) {
2618d6a39404SNick Dyer 		dev_warn(&data->client->dev, "Bad T37 size");
2619d6a39404SNick Dyer 		goto error;
2620d6a39404SNick Dyer 	}
2621d6a39404SNick Dyer 
2622d6a39404SNick Dyer 	dbg->t37_address = object->start_address;
2623d6a39404SNick Dyer 
2624d6a39404SNick Dyer 	/* Calculate size of data and allocate buffer */
26252786489fSNick Dyer 	dbg->t37_nodes = data->xsize * data->ysize;
2626566d533aSNick Dyer 
2627566d533aSNick Dyer 	if (info->family_id == MXT_FAMILY_1386)
2628566d533aSNick Dyer 		dbg->t37_pages = MXT1386_COLUMNS * MXT1386_PAGES_PER_COLUMN;
2629566d533aSNick Dyer 	else
2630566d533aSNick Dyer 		dbg->t37_pages = DIV_ROUND_UP(data->xsize *
2631d7ddf154SGuenter Roeck 					      info->matrix_ysize *
2632566d533aSNick Dyer 					      sizeof(u16),
2633566d533aSNick Dyer 					      sizeof(dbg->t37_buf->data));
2634d6a39404SNick Dyer 
2635d6a39404SNick Dyer 	dbg->t37_buf = devm_kmalloc_array(&data->client->dev, dbg->t37_pages,
2636d6a39404SNick Dyer 					  sizeof(struct t37_debug), GFP_KERNEL);
2637d6a39404SNick Dyer 	if (!dbg->t37_buf)
2638d6a39404SNick Dyer 		goto error;
2639d6a39404SNick Dyer 
2640ecfdd7e2SNick Dyer 	/* init channel to zero */
2641ecfdd7e2SNick Dyer 	mxt_set_input(data, 0);
2642ecfdd7e2SNick Dyer 
2643ecfdd7e2SNick Dyer 	/* register video device */
2644ecfdd7e2SNick Dyer 	snprintf(dbg->v4l2.name, sizeof(dbg->v4l2.name), "%s", "atmel_mxt_ts");
2645ecfdd7e2SNick Dyer 	error = v4l2_device_register(&data->client->dev, &dbg->v4l2);
2646ecfdd7e2SNick Dyer 	if (error)
2647ecfdd7e2SNick Dyer 		goto error;
2648ecfdd7e2SNick Dyer 
2649ecfdd7e2SNick Dyer 	/* initialize the queue */
2650ecfdd7e2SNick Dyer 	mutex_init(&dbg->lock);
2651ecfdd7e2SNick Dyer 	dbg->queue = mxt_queue;
2652ecfdd7e2SNick Dyer 	dbg->queue.drv_priv = data;
2653ecfdd7e2SNick Dyer 	dbg->queue.lock = &dbg->lock;
2654ecfdd7e2SNick Dyer 	dbg->queue.dev = &data->client->dev;
2655ecfdd7e2SNick Dyer 
2656ecfdd7e2SNick Dyer 	error = vb2_queue_init(&dbg->queue);
2657ecfdd7e2SNick Dyer 	if (error)
2658ecfdd7e2SNick Dyer 		goto error_unreg_v4l2;
2659ecfdd7e2SNick Dyer 
2660ecfdd7e2SNick Dyer 	dbg->vdev = mxt_video_device;
2661ecfdd7e2SNick Dyer 	dbg->vdev.v4l2_dev = &dbg->v4l2;
2662ecfdd7e2SNick Dyer 	dbg->vdev.lock = &dbg->lock;
2663ecfdd7e2SNick Dyer 	dbg->vdev.vfl_dir = VFL_DIR_RX;
2664ecfdd7e2SNick Dyer 	dbg->vdev.queue = &dbg->queue;
2665ecfdd7e2SNick Dyer 	video_set_drvdata(&dbg->vdev, data);
2666ecfdd7e2SNick Dyer 
2667ecfdd7e2SNick Dyer 	error = video_register_device(&dbg->vdev, VFL_TYPE_TOUCH, -1);
2668ecfdd7e2SNick Dyer 	if (error)
2669ecfdd7e2SNick Dyer 		goto error_unreg_v4l2;
2670ecfdd7e2SNick Dyer 
2671d6a39404SNick Dyer 	return;
2672d6a39404SNick Dyer 
2673ecfdd7e2SNick Dyer error_unreg_v4l2:
2674ecfdd7e2SNick Dyer 	v4l2_device_unregister(&dbg->v4l2);
2675d6a39404SNick Dyer error:
2676d6a39404SNick Dyer 	dev_warn(&data->client->dev, "Error initializing T37\n");
2677d6a39404SNick Dyer }
2678d6a39404SNick Dyer #else
2679d6a39404SNick Dyer static void mxt_debug_init(struct mxt_data *data)
2680d6a39404SNick Dyer {
2681d6a39404SNick Dyer }
2682d6a39404SNick Dyer #endif
2683d6a39404SNick Dyer 
268450a77c65SNick Dyer static int mxt_configure_objects(struct mxt_data *data,
268550a77c65SNick Dyer 				 const struct firmware *cfg)
268650a77c65SNick Dyer {
268750a77c65SNick Dyer 	struct device *dev = &data->client->dev;
268850a77c65SNick Dyer 	int error;
268950a77c65SNick Dyer 
26907f3884f7SNick Dyer 	error = mxt_init_t7_power_cfg(data);
26917f3884f7SNick Dyer 	if (error) {
26927f3884f7SNick Dyer 		dev_err(dev, "Failed to initialize power cfg\n");
26937f3884f7SNick Dyer 		return error;
26947f3884f7SNick Dyer 	}
26957f3884f7SNick Dyer 
269650a77c65SNick Dyer 	if (cfg) {
269750a77c65SNick Dyer 		error = mxt_update_cfg(data, cfg);
269850a77c65SNick Dyer 		if (error)
269950a77c65SNick Dyer 			dev_warn(dev, "Error %d updating config\n", error);
270050a77c65SNick Dyer 	}
270150a77c65SNick Dyer 
2702b23157dcSNick Dyer 	if (data->multitouch) {
2703b23157dcSNick Dyer 		error = mxt_initialize_input_device(data);
270450a77c65SNick Dyer 		if (error)
270550a77c65SNick Dyer 			return error;
2706b23157dcSNick Dyer 	} else {
2707b23157dcSNick Dyer 		dev_warn(dev, "No touch object detected\n");
2708b23157dcSNick Dyer 	}
270950a77c65SNick Dyer 
2710d6a39404SNick Dyer 	mxt_debug_init(data);
2711d6a39404SNick Dyer 
271250a77c65SNick Dyer 	return 0;
271350a77c65SNick Dyer }
271450a77c65SNick Dyer 
2715b19fc9ecSDaniel Kurtz /* Firmware Version is returned as Major.Minor.Build */
2716b19fc9ecSDaniel Kurtz static ssize_t mxt_fw_version_show(struct device *dev,
2717b19fc9ecSDaniel Kurtz 				   struct device_attribute *attr, char *buf)
2718b19fc9ecSDaniel Kurtz {
2719b19fc9ecSDaniel Kurtz 	struct mxt_data *data = dev_get_drvdata(dev);
2720068bdb67SNick Dyer 	struct mxt_info *info = data->info;
2721b19fc9ecSDaniel Kurtz 	return scnprintf(buf, PAGE_SIZE, "%u.%u.%02X\n",
2722b19fc9ecSDaniel Kurtz 			 info->version >> 4, info->version & 0xf, info->build);
2723b19fc9ecSDaniel Kurtz }
2724b19fc9ecSDaniel Kurtz 
2725b19fc9ecSDaniel Kurtz /* Hardware Version is returned as FamilyID.VariantID */
2726b19fc9ecSDaniel Kurtz static ssize_t mxt_hw_version_show(struct device *dev,
2727b19fc9ecSDaniel Kurtz 				   struct device_attribute *attr, char *buf)
2728b19fc9ecSDaniel Kurtz {
2729b19fc9ecSDaniel Kurtz 	struct mxt_data *data = dev_get_drvdata(dev);
2730068bdb67SNick Dyer 	struct mxt_info *info = data->info;
2731b19fc9ecSDaniel Kurtz 	return scnprintf(buf, PAGE_SIZE, "%u.%u\n",
2732b19fc9ecSDaniel Kurtz 			 info->family_id, info->variant_id);
2733b19fc9ecSDaniel Kurtz }
2734b19fc9ecSDaniel Kurtz 
2735794eb67eSDaniel Kurtz static ssize_t mxt_show_instance(char *buf, int count,
2736794eb67eSDaniel Kurtz 				 struct mxt_object *object, int instance,
2737794eb67eSDaniel Kurtz 				 const u8 *val)
2738794eb67eSDaniel Kurtz {
2739794eb67eSDaniel Kurtz 	int i;
2740794eb67eSDaniel Kurtz 
27411e0c0c5bSDaniel Kurtz 	if (mxt_obj_instances(object) > 1)
2742794eb67eSDaniel Kurtz 		count += scnprintf(buf + count, PAGE_SIZE - count,
2743794eb67eSDaniel Kurtz 				   "Instance %u\n", instance);
2744794eb67eSDaniel Kurtz 
27451e0c0c5bSDaniel Kurtz 	for (i = 0; i < mxt_obj_size(object); i++)
2746794eb67eSDaniel Kurtz 		count += scnprintf(buf + count, PAGE_SIZE - count,
2747794eb67eSDaniel Kurtz 				"\t[%2u]: %02x (%d)\n", i, val[i], val[i]);
2748794eb67eSDaniel Kurtz 	count += scnprintf(buf + count, PAGE_SIZE - count, "\n");
2749794eb67eSDaniel Kurtz 
2750794eb67eSDaniel Kurtz 	return count;
2751794eb67eSDaniel Kurtz }
2752794eb67eSDaniel Kurtz 
27537686b108SIiro Valkonen static ssize_t mxt_object_show(struct device *dev,
27544cf51c38SJoonyoung Shim 				    struct device_attribute *attr, char *buf)
27554cf51c38SJoonyoung Shim {
27567686b108SIiro Valkonen 	struct mxt_data *data = dev_get_drvdata(dev);
27577686b108SIiro Valkonen 	struct mxt_object *object;
27584cf51c38SJoonyoung Shim 	int count = 0;
27594cf51c38SJoonyoung Shim 	int i, j;
27604cf51c38SJoonyoung Shim 	int error;
276143a91d51SDaniel Kurtz 	u8 *obuf;
27624cf51c38SJoonyoung Shim 
276343a91d51SDaniel Kurtz 	/* Pre-allocate buffer large enough to hold max sized object. */
276443a91d51SDaniel Kurtz 	obuf = kmalloc(256, GFP_KERNEL);
276543a91d51SDaniel Kurtz 	if (!obuf)
276643a91d51SDaniel Kurtz 		return -ENOMEM;
276743a91d51SDaniel Kurtz 
276843a91d51SDaniel Kurtz 	error = 0;
2769068bdb67SNick Dyer 	for (i = 0; i < data->info->object_num; i++) {
27704cf51c38SJoonyoung Shim 		object = data->object_table + i;
27714cf51c38SJoonyoung Shim 
277291630955SDaniel Kurtz 		if (!mxt_object_readable(object->type))
27734cf51c38SJoonyoung Shim 			continue;
27744cf51c38SJoonyoung Shim 
277591630955SDaniel Kurtz 		count += scnprintf(buf + count, PAGE_SIZE - count,
277691630955SDaniel Kurtz 				"T%u:\n", object->type);
27774cf51c38SJoonyoung Shim 
27781e0c0c5bSDaniel Kurtz 		for (j = 0; j < mxt_obj_instances(object); j++) {
27791e0c0c5bSDaniel Kurtz 			u16 size = mxt_obj_size(object);
2780794eb67eSDaniel Kurtz 			u16 addr = object->start_address + j * size;
2781794eb67eSDaniel Kurtz 
2782794eb67eSDaniel Kurtz 			error = __mxt_read_reg(data->client, addr, size, obuf);
27834cf51c38SJoonyoung Shim 			if (error)
2784794eb67eSDaniel Kurtz 				goto done;
27854cf51c38SJoonyoung Shim 
2786794eb67eSDaniel Kurtz 			count = mxt_show_instance(buf, count, object, j, obuf);
27874cf51c38SJoonyoung Shim 		}
27884cf51c38SJoonyoung Shim 	}
27894cf51c38SJoonyoung Shim 
2790794eb67eSDaniel Kurtz done:
279143a91d51SDaniel Kurtz 	kfree(obuf);
279243a91d51SDaniel Kurtz 	return error ?: count;
27934cf51c38SJoonyoung Shim }
27944cf51c38SJoonyoung Shim 
2795f2ac6cb9SNick Dyer static int mxt_check_firmware_format(struct device *dev,
2796f2ac6cb9SNick Dyer 				     const struct firmware *fw)
2797f2ac6cb9SNick Dyer {
2798f2ac6cb9SNick Dyer 	unsigned int pos = 0;
2799f2ac6cb9SNick Dyer 	char c;
2800f2ac6cb9SNick Dyer 
2801f2ac6cb9SNick Dyer 	while (pos < fw->size) {
2802f2ac6cb9SNick Dyer 		c = *(fw->data + pos);
2803f2ac6cb9SNick Dyer 
2804f2ac6cb9SNick Dyer 		if (c < '0' || (c > '9' && c < 'A') || c > 'F')
2805f2ac6cb9SNick Dyer 			return 0;
2806f2ac6cb9SNick Dyer 
2807f2ac6cb9SNick Dyer 		pos++;
2808f2ac6cb9SNick Dyer 	}
2809f2ac6cb9SNick Dyer 
2810f2ac6cb9SNick Dyer 	/*
2811f2ac6cb9SNick Dyer 	 * To convert file try:
2812f2ac6cb9SNick Dyer 	 * xxd -r -p mXTXXX__APP_VX-X-XX.enc > maxtouch.fw
2813f2ac6cb9SNick Dyer 	 */
2814f2ac6cb9SNick Dyer 	dev_err(dev, "Aborting: firmware file must be in binary format\n");
2815f2ac6cb9SNick Dyer 
2816f2ac6cb9SNick Dyer 	return -EINVAL;
2817f2ac6cb9SNick Dyer }
2818f2ac6cb9SNick Dyer 
28197686b108SIiro Valkonen static int mxt_load_fw(struct device *dev, const char *fn)
28204cf51c38SJoonyoung Shim {
28217686b108SIiro Valkonen 	struct mxt_data *data = dev_get_drvdata(dev);
28224cf51c38SJoonyoung Shim 	const struct firmware *fw = NULL;
28234cf51c38SJoonyoung Shim 	unsigned int frame_size;
28244cf51c38SJoonyoung Shim 	unsigned int pos = 0;
2825f943c74aSNick Dyer 	unsigned int retry = 0;
2826f477c758SNick Dyer 	unsigned int frame = 0;
28274cf51c38SJoonyoung Shim 	int ret;
28284cf51c38SJoonyoung Shim 
28294cf51c38SJoonyoung Shim 	ret = request_firmware(&fw, fn, dev);
28304cf51c38SJoonyoung Shim 	if (ret) {
28314cf51c38SJoonyoung Shim 		dev_err(dev, "Unable to open firmware %s\n", fn);
28324cf51c38SJoonyoung Shim 		return ret;
28334cf51c38SJoonyoung Shim 	}
28344cf51c38SJoonyoung Shim 
2835f2ac6cb9SNick Dyer 	/* Check for incorrect enc file */
2836f2ac6cb9SNick Dyer 	ret = mxt_check_firmware_format(dev, fw);
2837f2ac6cb9SNick Dyer 	if (ret)
2838f2ac6cb9SNick Dyer 		goto release_firmware;
2839f2ac6cb9SNick Dyer 
2840a9fdd1e6SNick Dyer 	if (!data->in_bootloader) {
28414cf51c38SJoonyoung Shim 		/* Change to the bootloader mode */
2842d79e7e47SBenson Leung 		data->in_bootloader = true;
2843d79e7e47SBenson Leung 
2844a9fdd1e6SNick Dyer 		ret = mxt_t6_command(data, MXT_COMMAND_RESET,
2845a9fdd1e6SNick Dyer 				     MXT_BOOT_VALUE, false);
2846a4a2ef46SIiro Valkonen 		if (ret)
2847a4a2ef46SIiro Valkonen 			goto release_firmware;
2848a4a2ef46SIiro Valkonen 
28497686b108SIiro Valkonen 		msleep(MXT_RESET_TIME);
28508efaa5e5SNick Dyer 
28518efaa5e5SNick Dyer 		/* Do not need to scan since we know family ID */
28528efaa5e5SNick Dyer 		ret = mxt_lookup_bootloader_address(data, 0);
28538efaa5e5SNick Dyer 		if (ret)
28548efaa5e5SNick Dyer 			goto release_firmware;
285558e4aeeeSStephen Warren 
285658e4aeeeSStephen Warren 		mxt_free_input_device(data);
285758e4aeeeSStephen Warren 		mxt_free_object_table(data);
28588efaa5e5SNick Dyer 	} else {
28598efaa5e5SNick Dyer 		enable_irq(data->irq);
2860a9fdd1e6SNick Dyer 	}
28614cf51c38SJoonyoung Shim 
2862d79e7e47SBenson Leung 	reinit_completion(&data->bl_completion);
2863d79e7e47SBenson Leung 
2864385deb96SNick Dyer 	ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD, false);
2865385deb96SNick Dyer 	if (ret) {
2866385deb96SNick Dyer 		/* Bootloader may still be unlocked from previous attempt */
2867385deb96SNick Dyer 		ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, false);
28684cf51c38SJoonyoung Shim 		if (ret)
2869d79e7e47SBenson Leung 			goto disable_irq;
2870385deb96SNick Dyer 	} else {
2871385deb96SNick Dyer 		dev_info(dev, "Unlocking bootloader\n");
28724cf51c38SJoonyoung Shim 
28734cf51c38SJoonyoung Shim 		/* Unlock bootloader */
28748efaa5e5SNick Dyer 		ret = mxt_send_bootloader_cmd(data, true);
2875385deb96SNick Dyer 		if (ret)
2876385deb96SNick Dyer 			goto disable_irq;
2877385deb96SNick Dyer 	}
28784cf51c38SJoonyoung Shim 
28794cf51c38SJoonyoung Shim 	while (pos < fw->size) {
2880385deb96SNick Dyer 		ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, true);
28814cf51c38SJoonyoung Shim 		if (ret)
2882d79e7e47SBenson Leung 			goto disable_irq;
28834cf51c38SJoonyoung Shim 
28844cf51c38SJoonyoung Shim 		frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1));
28854cf51c38SJoonyoung Shim 
2886f943c74aSNick Dyer 		/* Take account of CRC bytes */
28874cf51c38SJoonyoung Shim 		frame_size += 2;
28884cf51c38SJoonyoung Shim 
28894cf51c38SJoonyoung Shim 		/* Write one frame to device */
2890f28a842dSNick Dyer 		ret = mxt_bootloader_write(data, fw->data + pos, frame_size);
2891f28a842dSNick Dyer 		if (ret)
2892f28a842dSNick Dyer 			goto disable_irq;
28934cf51c38SJoonyoung Shim 
2894385deb96SNick Dyer 		ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS, true);
2895f943c74aSNick Dyer 		if (ret) {
2896f943c74aSNick Dyer 			retry++;
28974cf51c38SJoonyoung Shim 
2898f943c74aSNick Dyer 			/* Back off by 20ms per retry */
2899f943c74aSNick Dyer 			msleep(retry * 20);
2900f943c74aSNick Dyer 
2901f943c74aSNick Dyer 			if (retry > 20) {
2902f943c74aSNick Dyer 				dev_err(dev, "Retry count exceeded\n");
2903f943c74aSNick Dyer 				goto disable_irq;
2904f943c74aSNick Dyer 			}
2905f943c74aSNick Dyer 		} else {
2906f943c74aSNick Dyer 			retry = 0;
29074cf51c38SJoonyoung Shim 			pos += frame_size;
2908f477c758SNick Dyer 			frame++;
2909f943c74aSNick Dyer 		}
29104cf51c38SJoonyoung Shim 
2911f477c758SNick Dyer 		if (frame % 50 == 0)
2912f477c758SNick Dyer 			dev_dbg(dev, "Sent %d frames, %d/%zd bytes\n",
2913f477c758SNick Dyer 				frame, pos, fw->size);
29144cf51c38SJoonyoung Shim 	}
29154cf51c38SJoonyoung Shim 
2916a0434b75SBenson Leung 	/* Wait for flash. */
2917a4a2ef46SIiro Valkonen 	ret = mxt_wait_for_completion(data, &data->bl_completion,
2918a4a2ef46SIiro Valkonen 				      MXT_FW_RESET_TIME);
2919a0434b75SBenson Leung 	if (ret)
2920a0434b75SBenson Leung 		goto disable_irq;
2921a0434b75SBenson Leung 
2922f477c758SNick Dyer 	dev_dbg(dev, "Sent %d frames, %d bytes\n", frame, pos);
2923f477c758SNick Dyer 
2924a0434b75SBenson Leung 	/*
2925a0434b75SBenson Leung 	 * Wait for device to reset. Some bootloader versions do not assert
2926a0434b75SBenson Leung 	 * the CHG line after bootloading has finished, so ignore potential
2927a0434b75SBenson Leung 	 * errors.
2928a0434b75SBenson Leung 	 */
2929a4a2ef46SIiro Valkonen 	mxt_wait_for_completion(data, &data->bl_completion, MXT_FW_RESET_TIME);
2930a0434b75SBenson Leung 
2931d79e7e47SBenson Leung 	data->in_bootloader = false;
2932d79e7e47SBenson Leung 
2933d79e7e47SBenson Leung disable_irq:
2934d79e7e47SBenson Leung 	disable_irq(data->irq);
2935a4a2ef46SIiro Valkonen release_firmware:
29364cf51c38SJoonyoung Shim 	release_firmware(fw);
29374cf51c38SJoonyoung Shim 	return ret;
29384cf51c38SJoonyoung Shim }
29394cf51c38SJoonyoung Shim 
29407686b108SIiro Valkonen static ssize_t mxt_update_fw_store(struct device *dev,
29414cf51c38SJoonyoung Shim 					struct device_attribute *attr,
29424cf51c38SJoonyoung Shim 					const char *buf, size_t count)
29434cf51c38SJoonyoung Shim {
29447686b108SIiro Valkonen 	struct mxt_data *data = dev_get_drvdata(dev);
29454cf51c38SJoonyoung Shim 	int error;
29464cf51c38SJoonyoung Shim 
29477686b108SIiro Valkonen 	error = mxt_load_fw(dev, MXT_FW_NAME);
29484cf51c38SJoonyoung Shim 	if (error) {
29494cf51c38SJoonyoung Shim 		dev_err(dev, "The firmware update failed(%d)\n", error);
29504cf51c38SJoonyoung Shim 		count = error;
29514cf51c38SJoonyoung Shim 	} else {
29527bed6805SNick Dyer 		dev_info(dev, "The firmware update succeeded\n");
29537bed6805SNick Dyer 
2954dd24dcf5SNick Dyer 		error = mxt_initialize(data);
295508960a07SIiro Valkonen 		if (error)
295608960a07SIiro Valkonen 			return error;
2957d79e7e47SBenson Leung 	}
295808960a07SIiro Valkonen 
29594cf51c38SJoonyoung Shim 	return count;
29604cf51c38SJoonyoung Shim }
29614cf51c38SJoonyoung Shim 
2962b19fc9ecSDaniel Kurtz static DEVICE_ATTR(fw_version, S_IRUGO, mxt_fw_version_show, NULL);
2963b19fc9ecSDaniel Kurtz static DEVICE_ATTR(hw_version, S_IRUGO, mxt_hw_version_show, NULL);
296471b3e938SDaniel Kurtz static DEVICE_ATTR(object, S_IRUGO, mxt_object_show, NULL);
296571b3e938SDaniel Kurtz static DEVICE_ATTR(update_fw, S_IWUSR, NULL, mxt_update_fw_store);
29664cf51c38SJoonyoung Shim 
29677686b108SIiro Valkonen static struct attribute *mxt_attrs[] = {
2968b19fc9ecSDaniel Kurtz 	&dev_attr_fw_version.attr,
2969b19fc9ecSDaniel Kurtz 	&dev_attr_hw_version.attr,
29704cf51c38SJoonyoung Shim 	&dev_attr_object.attr,
29714cf51c38SJoonyoung Shim 	&dev_attr_update_fw.attr,
29724cf51c38SJoonyoung Shim 	NULL
29734cf51c38SJoonyoung Shim };
29744cf51c38SJoonyoung Shim 
29757686b108SIiro Valkonen static const struct attribute_group mxt_attr_group = {
29767686b108SIiro Valkonen 	.attrs = mxt_attrs,
29774cf51c38SJoonyoung Shim };
29784cf51c38SJoonyoung Shim 
29797686b108SIiro Valkonen static void mxt_start(struct mxt_data *data)
29804cf51c38SJoonyoung Shim {
2981d80808e1SDmitry Torokhov 	switch (data->suspend_mode) {
29827f3884f7SNick Dyer 	case MXT_SUSPEND_T9_CTRL:
29837f3884f7SNick Dyer 		mxt_soft_reset(data);
29847f3884f7SNick Dyer 
29857f405483SLinus Torvalds 		/* Touch enable */
29867f3884f7SNick Dyer 		/* 0x83 = SCANEN | RPTEN | ENABLE */
29877f3884f7SNick Dyer 		mxt_write_object(data,
29887f3884f7SNick Dyer 				MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0x83);
29897f3884f7SNick Dyer 		break;
29907f3884f7SNick Dyer 
29917f3884f7SNick Dyer 	case MXT_SUSPEND_DEEP_SLEEP:
29927f3884f7SNick Dyer 	default:
29937f3884f7SNick Dyer 		mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN);
29947f3884f7SNick Dyer 
29957f3884f7SNick Dyer 		/* Recalibrate since chip has been in deep sleep */
29967f3884f7SNick Dyer 		mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false);
29977f3884f7SNick Dyer 		break;
29987f3884f7SNick Dyer 	}
29994cf51c38SJoonyoung Shim }
30004cf51c38SJoonyoung Shim 
30017686b108SIiro Valkonen static void mxt_stop(struct mxt_data *data)
30024cf51c38SJoonyoung Shim {
3003d80808e1SDmitry Torokhov 	switch (data->suspend_mode) {
30047f3884f7SNick Dyer 	case MXT_SUSPEND_T9_CTRL:
30057f405483SLinus Torvalds 		/* Touch disable */
30067f3884f7SNick Dyer 		mxt_write_object(data,
30077f3884f7SNick Dyer 				MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0);
30087f3884f7SNick Dyer 		break;
30097f3884f7SNick Dyer 
30107f3884f7SNick Dyer 	case MXT_SUSPEND_DEEP_SLEEP:
30117f3884f7SNick Dyer 	default:
30127f3884f7SNick Dyer 		mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP);
30137f3884f7SNick Dyer 		break;
30147f3884f7SNick Dyer 	}
30154cf51c38SJoonyoung Shim }
30164cf51c38SJoonyoung Shim 
30177686b108SIiro Valkonen static int mxt_input_open(struct input_dev *dev)
30184cf51c38SJoonyoung Shim {
30197686b108SIiro Valkonen 	struct mxt_data *data = input_get_drvdata(dev);
30204cf51c38SJoonyoung Shim 
30217686b108SIiro Valkonen 	mxt_start(data);
30224cf51c38SJoonyoung Shim 
30234cf51c38SJoonyoung Shim 	return 0;
30244cf51c38SJoonyoung Shim }
30254cf51c38SJoonyoung Shim 
30267686b108SIiro Valkonen static void mxt_input_close(struct input_dev *dev)
30274cf51c38SJoonyoung Shim {
30287686b108SIiro Valkonen 	struct mxt_data *data = input_get_drvdata(dev);
30294cf51c38SJoonyoung Shim 
30307686b108SIiro Valkonen 	mxt_stop(data);
30314cf51c38SJoonyoung Shim }
30324cf51c38SJoonyoung Shim 
303396a938aaSDmitry Torokhov static int mxt_parse_device_properties(struct mxt_data *data)
303478188be3SStephen Warren {
303593afb1d6SDmitry Torokhov 	static const char keymap_property[] = "linux,gpio-keymap";
303696a938aaSDmitry Torokhov 	struct device *dev = &data->client->dev;
303778188be3SStephen Warren 	u32 *keymap;
303893afb1d6SDmitry Torokhov 	int n_keys;
303993afb1d6SDmitry Torokhov 	int error;
304078188be3SStephen Warren 
304196a938aaSDmitry Torokhov 	if (device_property_present(dev, keymap_property)) {
30429ed05c94SAndy Shevchenko 		n_keys = device_property_count_u32(dev, keymap_property);
304393afb1d6SDmitry Torokhov 		if (n_keys <= 0) {
304493afb1d6SDmitry Torokhov 			error = n_keys < 0 ? n_keys : -EINVAL;
304596a938aaSDmitry Torokhov 			dev_err(dev, "invalid/malformed '%s' property: %d\n",
304693afb1d6SDmitry Torokhov 				keymap_property, error);
304796a938aaSDmitry Torokhov 			return error;
304893afb1d6SDmitry Torokhov 		}
304978188be3SStephen Warren 
305096a938aaSDmitry Torokhov 		keymap = devm_kmalloc_array(dev, n_keys, sizeof(*keymap),
305178188be3SStephen Warren 					    GFP_KERNEL);
305278188be3SStephen Warren 		if (!keymap)
305396a938aaSDmitry Torokhov 			return -ENOMEM;
305478188be3SStephen Warren 
305596a938aaSDmitry Torokhov 		error = device_property_read_u32_array(dev, keymap_property,
305693afb1d6SDmitry Torokhov 						       keymap, n_keys);
305793afb1d6SDmitry Torokhov 		if (error) {
305896a938aaSDmitry Torokhov 			dev_err(dev, "failed to parse '%s' property: %d\n",
305993afb1d6SDmitry Torokhov 				keymap_property, error);
306096a938aaSDmitry Torokhov 			return error;
306193afb1d6SDmitry Torokhov 		}
306278188be3SStephen Warren 
306396a938aaSDmitry Torokhov 		data->t19_keymap = keymap;
306496a938aaSDmitry Torokhov 		data->t19_num_keys = n_keys;
306578188be3SStephen Warren 	}
306678188be3SStephen Warren 
306796a938aaSDmitry Torokhov 	return 0;
306878188be3SStephen Warren }
306978188be3SStephen Warren 
3070d80808e1SDmitry Torokhov static const struct dmi_system_id chromebook_T9_suspend_dmi[] = {
3071d80808e1SDmitry Torokhov 	{
3072d80808e1SDmitry Torokhov 		.matches = {
3073d80808e1SDmitry Torokhov 			DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
3074d80808e1SDmitry Torokhov 			DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
3075d80808e1SDmitry Torokhov 		},
3076d80808e1SDmitry Torokhov 	},
3077d80808e1SDmitry Torokhov 	{
3078d80808e1SDmitry Torokhov 		.matches = {
3079d80808e1SDmitry Torokhov 			DMI_MATCH(DMI_PRODUCT_NAME, "Peppy"),
3080d80808e1SDmitry Torokhov 		},
3081d80808e1SDmitry Torokhov 	},
3082d80808e1SDmitry Torokhov 	{ }
3083d80808e1SDmitry Torokhov };
3084d80808e1SDmitry Torokhov 
308578188be3SStephen Warren static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
30864cf51c38SJoonyoung Shim {
30877686b108SIiro Valkonen 	struct mxt_data *data;
30884cf51c38SJoonyoung Shim 	int error;
30894cf51c38SJoonyoung Shim 
309096a938aaSDmitry Torokhov 	/*
30917cf432bfSDmitry Torokhov 	 * Ignore devices that do not have device properties attached to
30927cf432bfSDmitry Torokhov 	 * them, as we need help determining whether we are dealing with
30937cf432bfSDmitry Torokhov 	 * touch screen or touchpad.
30947cf432bfSDmitry Torokhov 	 *
30957cf432bfSDmitry Torokhov 	 * So far on x86 the only users of Atmel touch controllers are
30967cf432bfSDmitry Torokhov 	 * Chromebooks, and chromeos_laptop driver will ensure that
30977cf432bfSDmitry Torokhov 	 * necessary properties are provided (if firmware does not do that).
30987cf432bfSDmitry Torokhov 	 */
30997cf432bfSDmitry Torokhov 	if (!device_property_present(&client->dev, "compatible"))
31007cf432bfSDmitry Torokhov 		return -ENXIO;
31017cf432bfSDmitry Torokhov 
31027cf432bfSDmitry Torokhov 	/*
310396a938aaSDmitry Torokhov 	 * Ignore ACPI devices representing bootloader mode.
310496a938aaSDmitry Torokhov 	 *
310596a938aaSDmitry Torokhov 	 * This is a bit of a hack: Google Chromebook BIOS creates ACPI
310696a938aaSDmitry Torokhov 	 * devices for both application and bootloader modes, but we are
310796a938aaSDmitry Torokhov 	 * interested in application mode only (if device is in bootloader
310896a938aaSDmitry Torokhov 	 * mode we'll end up switching into application anyway). So far
310996a938aaSDmitry Torokhov 	 * application mode addresses were all above 0x40, so we'll use it
311096a938aaSDmitry Torokhov 	 * as a threshold.
311196a938aaSDmitry Torokhov 	 */
311296a938aaSDmitry Torokhov 	if (ACPI_COMPANION(&client->dev) && client->addr < 0x40)
311396a938aaSDmitry Torokhov 		return -ENXIO;
31144cf51c38SJoonyoung Shim 
31158cc8446bSSebastian Reichel 	data = devm_kzalloc(&client->dev, sizeof(struct mxt_data), GFP_KERNEL);
31168cc8446bSSebastian Reichel 	if (!data)
31177a53d609SNick Dyer 		return -ENOMEM;
31184cf51c38SJoonyoung Shim 
3119ec02ac2bSDaniel Kurtz 	snprintf(data->phys, sizeof(data->phys), "i2c-%u-%04x/input0",
3120ec02ac2bSDaniel Kurtz 		 client->adapter->nr, client->addr);
312122dfab7fSDaniel Kurtz 
3122910d8051SJoonyoung Shim 	data->client = client;
3123910d8051SJoonyoung Shim 	data->irq = client->irq;
31247a53d609SNick Dyer 	i2c_set_clientdata(client, data);
3125910d8051SJoonyoung Shim 
3126d79e7e47SBenson Leung 	init_completion(&data->bl_completion);
3127a4a2ef46SIiro Valkonen 	init_completion(&data->reset_completion);
3128c3f78043SNick Dyer 	init_completion(&data->crc_completion);
3129d79e7e47SBenson Leung 
3130d80808e1SDmitry Torokhov 	data->suspend_mode = dmi_check_system(chromebook_T9_suspend_dmi) ?
3131d80808e1SDmitry Torokhov 		MXT_SUSPEND_T9_CTRL : MXT_SUSPEND_DEEP_SLEEP;
3132d80808e1SDmitry Torokhov 
313396a938aaSDmitry Torokhov 	error = mxt_parse_device_properties(data);
313496a938aaSDmitry Torokhov 	if (error)
313596a938aaSDmitry Torokhov 		return error;
313696a938aaSDmitry Torokhov 
3137f657b00dSSebastian Reichel 	data->reset_gpio = devm_gpiod_get_optional(&client->dev,
3138f657b00dSSebastian Reichel 						   "reset", GPIOD_OUT_LOW);
3139f657b00dSSebastian Reichel 	if (IS_ERR(data->reset_gpio)) {
3140f657b00dSSebastian Reichel 		error = PTR_ERR(data->reset_gpio);
3141f657b00dSSebastian Reichel 		dev_err(&client->dev, "Failed to get reset gpio: %d\n", error);
3142f657b00dSSebastian Reichel 		return error;
3143f657b00dSSebastian Reichel 	}
3144f657b00dSSebastian Reichel 
31458cc8446bSSebastian Reichel 	error = devm_request_threaded_irq(&client->dev, client->irq,
314696a938aaSDmitry Torokhov 					  NULL, mxt_interrupt, IRQF_ONESHOT,
3147dd24dcf5SNick Dyer 					  client->name, data);
3148dd24dcf5SNick Dyer 	if (error) {
3149dd24dcf5SNick Dyer 		dev_err(&client->dev, "Failed to register interrupt\n");
31508cc8446bSSebastian Reichel 		return error;
3151dd24dcf5SNick Dyer 	}
3152dd24dcf5SNick Dyer 
3153dd24dcf5SNick Dyer 	disable_irq(client->irq);
3154dd24dcf5SNick Dyer 
3155ca1cd36cSSebastian Reichel 	if (data->reset_gpio) {
3156ca1cd36cSSebastian Reichel 		msleep(MXT_RESET_GPIO_TIME);
3157ca1cd36cSSebastian Reichel 		gpiod_set_value(data->reset_gpio, 1);
3158ca1cd36cSSebastian Reichel 		msleep(MXT_RESET_INVALID_CHG);
3159ca1cd36cSSebastian Reichel 	}
3160ca1cd36cSSebastian Reichel 
3161cb159115SDaniel Kurtz 	error = mxt_initialize(data);
3162cb159115SDaniel Kurtz 	if (error)
31638cc8446bSSebastian Reichel 		return error;
31644cf51c38SJoonyoung Shim 
31657686b108SIiro Valkonen 	error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
31667bed6805SNick Dyer 	if (error) {
31677bed6805SNick Dyer 		dev_err(&client->dev, "Failure %d creating sysfs group\n",
31687bed6805SNick Dyer 			error);
31697a53d609SNick Dyer 		goto err_free_object;
31707bed6805SNick Dyer 	}
31714cf51c38SJoonyoung Shim 
31724cf51c38SJoonyoung Shim 	return 0;
31734cf51c38SJoonyoung Shim 
31744cf51c38SJoonyoung Shim err_free_object:
317558e4aeeeSStephen Warren 	mxt_free_input_device(data);
31765f3f9bc2SNick Dyer 	mxt_free_object_table(data);
31774cf51c38SJoonyoung Shim 	return error;
31784cf51c38SJoonyoung Shim }
31794cf51c38SJoonyoung Shim 
3180e2619cf7SBill Pemberton static int mxt_remove(struct i2c_client *client)
31814cf51c38SJoonyoung Shim {
31827686b108SIiro Valkonen 	struct mxt_data *data = i2c_get_clientdata(client);
31834cf51c38SJoonyoung Shim 
31848cc8446bSSebastian Reichel 	disable_irq(data->irq);
31857686b108SIiro Valkonen 	sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
318658e4aeeeSStephen Warren 	mxt_free_input_device(data);
31875f3f9bc2SNick Dyer 	mxt_free_object_table(data);
31884cf51c38SJoonyoung Shim 
31894cf51c38SJoonyoung Shim 	return 0;
31904cf51c38SJoonyoung Shim }
31914cf51c38SJoonyoung Shim 
319202b6a58bSJingoo Han static int __maybe_unused mxt_suspend(struct device *dev)
31934cf51c38SJoonyoung Shim {
31948b5fce06SDmitry Torokhov 	struct i2c_client *client = to_i2c_client(dev);
31957686b108SIiro Valkonen 	struct mxt_data *data = i2c_get_clientdata(client);
31964cf51c38SJoonyoung Shim 	struct input_dev *input_dev = data->input_dev;
31974cf51c38SJoonyoung Shim 
319850fabb02SPan Xinhui 	if (!input_dev)
319950fabb02SPan Xinhui 		return 0;
320050fabb02SPan Xinhui 
32014cf51c38SJoonyoung Shim 	mutex_lock(&input_dev->mutex);
32024cf51c38SJoonyoung Shim 
32034cf51c38SJoonyoung Shim 	if (input_dev->users)
32047686b108SIiro Valkonen 		mxt_stop(data);
32054cf51c38SJoonyoung Shim 
32064cf51c38SJoonyoung Shim 	mutex_unlock(&input_dev->mutex);
32074cf51c38SJoonyoung Shim 
3208463fa44eSEvan Green 	disable_irq(data->irq);
3209463fa44eSEvan Green 
32104cf51c38SJoonyoung Shim 	return 0;
32114cf51c38SJoonyoung Shim }
32124cf51c38SJoonyoung Shim 
321302b6a58bSJingoo Han static int __maybe_unused mxt_resume(struct device *dev)
32144cf51c38SJoonyoung Shim {
32158b5fce06SDmitry Torokhov 	struct i2c_client *client = to_i2c_client(dev);
32167686b108SIiro Valkonen 	struct mxt_data *data = i2c_get_clientdata(client);
32174cf51c38SJoonyoung Shim 	struct input_dev *input_dev = data->input_dev;
32184cf51c38SJoonyoung Shim 
321950fabb02SPan Xinhui 	if (!input_dev)
322050fabb02SPan Xinhui 		return 0;
322150fabb02SPan Xinhui 
3222463fa44eSEvan Green 	enable_irq(data->irq);
3223463fa44eSEvan Green 
32244cf51c38SJoonyoung Shim 	mutex_lock(&input_dev->mutex);
32254cf51c38SJoonyoung Shim 
32264cf51c38SJoonyoung Shim 	if (input_dev->users)
32277686b108SIiro Valkonen 		mxt_start(data);
32284cf51c38SJoonyoung Shim 
32294cf51c38SJoonyoung Shim 	mutex_unlock(&input_dev->mutex);
32304cf51c38SJoonyoung Shim 
32314cf51c38SJoonyoung Shim 	return 0;
32324cf51c38SJoonyoung Shim }
32334cf51c38SJoonyoung Shim 
32343a73c816SDaniel Kurtz static SIMPLE_DEV_PM_OPS(mxt_pm_ops, mxt_suspend, mxt_resume);
32353a73c816SDaniel Kurtz 
323678188be3SStephen Warren static const struct of_device_id mxt_of_match[] = {
323778188be3SStephen Warren 	{ .compatible = "atmel,maxtouch", },
3238f6eeb9e5SJavier Martinez Canillas 	/* Compatibles listed below are deprecated */
3239f6eeb9e5SJavier Martinez Canillas 	{ .compatible = "atmel,qt602240_ts", },
3240f6eeb9e5SJavier Martinez Canillas 	{ .compatible = "atmel,atmel_mxt_ts", },
3241f6eeb9e5SJavier Martinez Canillas 	{ .compatible = "atmel,atmel_mxt_tp", },
3242f6eeb9e5SJavier Martinez Canillas 	{ .compatible = "atmel,mXT224", },
324378188be3SStephen Warren 	{},
324478188be3SStephen Warren };
324578188be3SStephen Warren MODULE_DEVICE_TABLE(of, mxt_of_match);
324678188be3SStephen Warren 
32474f8d8088SDmitry Torokhov #ifdef CONFIG_ACPI
32484f8d8088SDmitry Torokhov static const struct acpi_device_id mxt_acpi_id[] = {
32494f8d8088SDmitry Torokhov 	{ "ATML0000", 0 },	/* Touchpad */
32504f8d8088SDmitry Torokhov 	{ "ATML0001", 0 },	/* Touchscreen */
32514f8d8088SDmitry Torokhov 	{ }
32524f8d8088SDmitry Torokhov };
32534f8d8088SDmitry Torokhov MODULE_DEVICE_TABLE(acpi, mxt_acpi_id);
32544f8d8088SDmitry Torokhov #endif
32554f8d8088SDmitry Torokhov 
32567686b108SIiro Valkonen static const struct i2c_device_id mxt_id[] = {
32574cf51c38SJoonyoung Shim 	{ "qt602240_ts", 0 },
32587686b108SIiro Valkonen 	{ "atmel_mxt_ts", 0 },
325922dfab7fSDaniel Kurtz 	{ "atmel_mxt_tp", 0 },
3260b7d21058SJavier Martinez Canillas 	{ "maxtouch", 0 },
326146ee2a05SChris Leech 	{ "mXT224", 0 },
32624cf51c38SJoonyoung Shim 	{ }
32634cf51c38SJoonyoung Shim };
32647686b108SIiro Valkonen MODULE_DEVICE_TABLE(i2c, mxt_id);
32654cf51c38SJoonyoung Shim 
32667686b108SIiro Valkonen static struct i2c_driver mxt_driver = {
32674cf51c38SJoonyoung Shim 	.driver = {
32687686b108SIiro Valkonen 		.name	= "atmel_mxt_ts",
326996a938aaSDmitry Torokhov 		.of_match_table = mxt_of_match,
32704f8d8088SDmitry Torokhov 		.acpi_match_table = ACPI_PTR(mxt_acpi_id),
32717686b108SIiro Valkonen 		.pm	= &mxt_pm_ops,
32724cf51c38SJoonyoung Shim 	},
32737686b108SIiro Valkonen 	.probe		= mxt_probe,
32741cb0aa88SBill Pemberton 	.remove		= mxt_remove,
32757686b108SIiro Valkonen 	.id_table	= mxt_id,
32764cf51c38SJoonyoung Shim };
32774cf51c38SJoonyoung Shim 
32781b92c1cfSAxel Lin module_i2c_driver(mxt_driver);
32794cf51c38SJoonyoung Shim 
32804cf51c38SJoonyoung Shim /* Module information */
32814cf51c38SJoonyoung Shim MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
32827686b108SIiro Valkonen MODULE_DESCRIPTION("Atmel maXTouch Touchscreen driver");
32834cf51c38SJoonyoung Shim MODULE_LICENSE("GPL");
3284