xref: /linux/drivers/input/touchscreen/atmel_mxt_ts.c (revision d6a39404984094c5e20e1d17a91036ac6b125731)
14cf51c38SJoonyoung Shim /*
27686b108SIiro Valkonen  * Atmel maXTouch Touchscreen driver
34cf51c38SJoonyoung Shim  *
44cf51c38SJoonyoung Shim  * Copyright (C) 2010 Samsung Electronics Co.Ltd
550a77c65SNick Dyer  * Copyright (C) 2011-2014 Atmel Corporation
61e0c0c5bSDaniel Kurtz  * Copyright (C) 2012 Google, Inc.
71e0c0c5bSDaniel Kurtz  *
84cf51c38SJoonyoung Shim  * Author: Joonyoung Shim <jy0922.shim@samsung.com>
94cf51c38SJoonyoung Shim  *
104cf51c38SJoonyoung Shim  * This program is free software; you can redistribute  it and/or modify it
114cf51c38SJoonyoung Shim  * under  the terms of  the GNU General  Public License as published by the
124cf51c38SJoonyoung Shim  * Free Software Foundation;  either version 2 of the  License, or (at your
134cf51c38SJoonyoung Shim  * option) any later version.
144cf51c38SJoonyoung Shim  *
154cf51c38SJoonyoung Shim  */
164cf51c38SJoonyoung Shim 
174f8d8088SDmitry Torokhov #include <linux/acpi.h>
184f8d8088SDmitry Torokhov #include <linux/dmi.h>
194cf51c38SJoonyoung Shim #include <linux/module.h>
20d79e7e47SBenson Leung #include <linux/init.h>
21d79e7e47SBenson Leung #include <linux/completion.h>
224cf51c38SJoonyoung Shim #include <linux/delay.h>
234cf51c38SJoonyoung Shim #include <linux/firmware.h>
244cf51c38SJoonyoung Shim #include <linux/i2c.h>
257f3884f7SNick Dyer #include <linux/platform_data/atmel_mxt_ts.h>
268b86c1c2SJoonyoung Shim #include <linux/input/mt.h>
274cf51c38SJoonyoung Shim #include <linux/interrupt.h>
2878188be3SStephen Warren #include <linux/of.h>
294cf51c38SJoonyoung Shim #include <linux/slab.h>
30b23157dcSNick Dyer #include <asm/unaligned.h>
314cf51c38SJoonyoung Shim 
3250a77c65SNick Dyer /* Firmware files */
337686b108SIiro Valkonen #define MXT_FW_NAME		"maxtouch.fw"
3450a77c65SNick Dyer #define MXT_CFG_NAME		"maxtouch.cfg"
3550a77c65SNick Dyer #define MXT_CFG_MAGIC		"OBP_RAW V1"
364cf51c38SJoonyoung Shim 
374cf51c38SJoonyoung Shim /* Registers */
387686b108SIiro Valkonen #define MXT_OBJECT_START	0x07
397686b108SIiro Valkonen #define MXT_OBJECT_SIZE		6
404ce6fa01SNick Dyer #define MXT_INFO_CHECKSUM_SIZE	3
414ce6fa01SNick Dyer #define MXT_MAX_BLOCK_WRITE	256
424cf51c38SJoonyoung Shim 
434cf51c38SJoonyoung Shim /* Object types */
4481c88a71SIiro Valkonen #define MXT_DEBUG_DIAGNOSTIC_T37	37
4581c88a71SIiro Valkonen #define MXT_GEN_MESSAGE_T5		5
4681c88a71SIiro Valkonen #define MXT_GEN_COMMAND_T6		6
4781c88a71SIiro Valkonen #define MXT_GEN_POWER_T7		7
4881c88a71SIiro Valkonen #define MXT_GEN_ACQUIRE_T8		8
4981c88a71SIiro Valkonen #define MXT_GEN_DATASOURCE_T53		53
5081c88a71SIiro Valkonen #define MXT_TOUCH_MULTI_T9		9
5181c88a71SIiro Valkonen #define MXT_TOUCH_KEYARRAY_T15		15
5281c88a71SIiro Valkonen #define MXT_TOUCH_PROXIMITY_T23		23
5381c88a71SIiro Valkonen #define MXT_TOUCH_PROXKEY_T52		52
5481c88a71SIiro Valkonen #define MXT_PROCI_GRIPFACE_T20		20
5581c88a71SIiro Valkonen #define MXT_PROCG_NOISE_T22		22
5681c88a71SIiro Valkonen #define MXT_PROCI_ONETOUCH_T24		24
5781c88a71SIiro Valkonen #define MXT_PROCI_TWOTOUCH_T27		27
5881c88a71SIiro Valkonen #define MXT_PROCI_GRIP_T40		40
5981c88a71SIiro Valkonen #define MXT_PROCI_PALM_T41		41
6081c88a71SIiro Valkonen #define MXT_PROCI_TOUCHSUPPRESSION_T42	42
6181c88a71SIiro Valkonen #define MXT_PROCI_STYLUS_T47		47
6281c88a71SIiro Valkonen #define MXT_PROCG_NOISESUPPRESSION_T48	48
6381c88a71SIiro Valkonen #define MXT_SPT_COMMSCONFIG_T18		18
6481c88a71SIiro Valkonen #define MXT_SPT_GPIOPWM_T19		19
6581c88a71SIiro Valkonen #define MXT_SPT_SELFTEST_T25		25
6681c88a71SIiro Valkonen #define MXT_SPT_CTECONFIG_T28		28
6781c88a71SIiro Valkonen #define MXT_SPT_USERDATA_T38		38
6881c88a71SIiro Valkonen #define MXT_SPT_DIGITIZER_T43		43
6981c88a71SIiro Valkonen #define MXT_SPT_MESSAGECOUNT_T44	44
7081c88a71SIiro Valkonen #define MXT_SPT_CTECONFIG_T46		46
71b23157dcSNick Dyer #define MXT_TOUCH_MULTITOUCHSCREEN_T100 100
724cf51c38SJoonyoung Shim 
735f3f9bc2SNick Dyer /* MXT_GEN_MESSAGE_T5 object */
745f3f9bc2SNick Dyer #define MXT_RPTID_NOMSG		0xff
755f3f9bc2SNick Dyer 
7681c88a71SIiro Valkonen /* MXT_GEN_COMMAND_T6 field */
777686b108SIiro Valkonen #define MXT_COMMAND_RESET	0
787686b108SIiro Valkonen #define MXT_COMMAND_BACKUPNV	1
797686b108SIiro Valkonen #define MXT_COMMAND_CALIBRATE	2
807686b108SIiro Valkonen #define MXT_COMMAND_REPORTALL	3
817686b108SIiro Valkonen #define MXT_COMMAND_DIAGNOSTIC	5
824cf51c38SJoonyoung Shim 
83a4a2ef46SIiro Valkonen /* Define for T6 status byte */
84a4a2ef46SIiro Valkonen #define MXT_T6_STATUS_RESET	(1 << 7)
85497767d1SNick Dyer #define MXT_T6_STATUS_OFL	(1 << 6)
86497767d1SNick Dyer #define MXT_T6_STATUS_SIGERR	(1 << 5)
87497767d1SNick Dyer #define MXT_T6_STATUS_CAL	(1 << 4)
88497767d1SNick Dyer #define MXT_T6_STATUS_CFGERR	(1 << 3)
89497767d1SNick Dyer #define MXT_T6_STATUS_COMSERR	(1 << 2)
90a4a2ef46SIiro Valkonen 
9181c88a71SIiro Valkonen /* MXT_GEN_POWER_T7 field */
927f3884f7SNick Dyer struct t7_config {
937f3884f7SNick Dyer 	u8 idle;
947f3884f7SNick Dyer 	u8 active;
957f3884f7SNick Dyer } __packed;
967f3884f7SNick Dyer 
977f3884f7SNick Dyer #define MXT_POWER_CFG_RUN		0
987f3884f7SNick Dyer #define MXT_POWER_CFG_DEEPSLEEP		1
994cf51c38SJoonyoung Shim 
10081c88a71SIiro Valkonen /* MXT_TOUCH_MULTI_T9 field */
1017f3884f7SNick Dyer #define MXT_T9_CTRL		0
10261dc1abaSNick Dyer #define MXT_T9_ORIENT		9
10361dc1abaSNick Dyer #define MXT_T9_RANGE		18
10461dc1abaSNick Dyer 
105f3889ed1SNick Dyer /* MXT_TOUCH_MULTI_T9 status */
106f3889ed1SNick Dyer #define MXT_T9_UNGRIP		(1 << 0)
107f3889ed1SNick Dyer #define MXT_T9_SUPPRESS		(1 << 1)
108f3889ed1SNick Dyer #define MXT_T9_AMP		(1 << 2)
109f3889ed1SNick Dyer #define MXT_T9_VECTOR		(1 << 3)
110f3889ed1SNick Dyer #define MXT_T9_MOVE		(1 << 4)
111f3889ed1SNick Dyer #define MXT_T9_RELEASE		(1 << 5)
112f3889ed1SNick Dyer #define MXT_T9_PRESS		(1 << 6)
113f3889ed1SNick Dyer #define MXT_T9_DETECT		(1 << 7)
114f3889ed1SNick Dyer 
11561dc1abaSNick Dyer struct t9_range {
1161c0276d5SNick Dyer 	__le16 x;
1171c0276d5SNick Dyer 	__le16 y;
11861dc1abaSNick Dyer } __packed;
11961dc1abaSNick Dyer 
120f3889ed1SNick Dyer /* MXT_TOUCH_MULTI_T9 orient */
121f3889ed1SNick Dyer #define MXT_T9_ORIENT_SWITCH	(1 << 0)
1224cf51c38SJoonyoung Shim 
12381c88a71SIiro Valkonen /* MXT_SPT_COMMSCONFIG_T18 */
1247686b108SIiro Valkonen #define MXT_COMMS_CTRL		0
1257686b108SIiro Valkonen #define MXT_COMMS_CMD		1
1264cf51c38SJoonyoung Shim 
127*d6a39404SNick Dyer /* MXT_DEBUG_DIAGNOSTIC_T37 */
128*d6a39404SNick Dyer #define MXT_DIAGNOSTIC_PAGEUP	0x01
129*d6a39404SNick Dyer #define MXT_DIAGNOSTIC_DELTAS	0x10
130*d6a39404SNick Dyer #define MXT_DIAGNOSTIC_SIZE	128
131*d6a39404SNick Dyer 
132*d6a39404SNick Dyer struct t37_debug {
133*d6a39404SNick Dyer #ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37
134*d6a39404SNick Dyer 	u8 mode;
135*d6a39404SNick Dyer 	u8 page;
136*d6a39404SNick Dyer 	u8 data[MXT_DIAGNOSTIC_SIZE];
137*d6a39404SNick Dyer #endif
138*d6a39404SNick Dyer };
139*d6a39404SNick Dyer 
14081c88a71SIiro Valkonen /* Define for MXT_GEN_COMMAND_T6 */
1417686b108SIiro Valkonen #define MXT_BOOT_VALUE		0xa5
142a4a2ef46SIiro Valkonen #define MXT_RESET_VALUE		0x01
1437686b108SIiro Valkonen #define MXT_BACKUP_VALUE	0x55
144a4a2ef46SIiro Valkonen 
145b23157dcSNick Dyer /* T100 Multiple Touch Touchscreen */
146b23157dcSNick Dyer #define MXT_T100_CTRL		0
147b23157dcSNick Dyer #define MXT_T100_CFG1		1
148b23157dcSNick Dyer #define MXT_T100_TCHAUX		3
149b23157dcSNick Dyer #define MXT_T100_XRANGE		13
150b23157dcSNick Dyer #define MXT_T100_YRANGE		24
151b23157dcSNick Dyer 
152b23157dcSNick Dyer #define MXT_T100_CFG_SWITCHXY	BIT(5)
153b23157dcSNick Dyer 
154b23157dcSNick Dyer #define MXT_T100_TCHAUX_VECT	BIT(0)
155b23157dcSNick Dyer #define MXT_T100_TCHAUX_AMPL	BIT(1)
156b23157dcSNick Dyer #define MXT_T100_TCHAUX_AREA	BIT(2)
157b23157dcSNick Dyer 
158b23157dcSNick Dyer #define MXT_T100_DETECT		BIT(7)
159b23157dcSNick Dyer #define MXT_T100_TYPE_MASK	0x70
160b23157dcSNick Dyer 
161b23157dcSNick Dyer enum t100_type {
162b23157dcSNick Dyer 	MXT_T100_TYPE_FINGER		= 1,
163b23157dcSNick Dyer 	MXT_T100_TYPE_PASSIVE_STYLUS	= 2,
164b23157dcSNick Dyer 	MXT_T100_TYPE_HOVERING_FINGER	= 4,
165b23157dcSNick Dyer 	MXT_T100_TYPE_GLOVE		= 5,
166b23157dcSNick Dyer 	MXT_T100_TYPE_LARGE_TOUCH	= 6,
167b23157dcSNick Dyer };
168b23157dcSNick Dyer 
169b23157dcSNick Dyer #define MXT_DISTANCE_ACTIVE_TOUCH	0
170b23157dcSNick Dyer #define MXT_DISTANCE_HOVERING		1
171b23157dcSNick Dyer 
172b23157dcSNick Dyer #define MXT_TOUCH_MAJOR_DEFAULT		1
173b23157dcSNick Dyer #define MXT_PRESSURE_DEFAULT		1
174b23157dcSNick Dyer 
175a4a2ef46SIiro Valkonen /* Delay times */
1768343bce1SLinus Torvalds #define MXT_BACKUP_TIME		50	/* msec */
1778343bce1SLinus Torvalds #define MXT_RESET_TIME		200	/* msec */
178a4a2ef46SIiro Valkonen #define MXT_RESET_TIMEOUT	3000	/* msec */
179c3f78043SNick Dyer #define MXT_CRC_TIMEOUT		1000	/* msec */
180a0434b75SBenson Leung #define MXT_FW_RESET_TIME	3000	/* msec */
181a0434b75SBenson Leung #define MXT_FW_CHG_TIMEOUT	300	/* msec */
1824cf51c38SJoonyoung Shim 
1834cf51c38SJoonyoung Shim /* Command to unlock bootloader */
1847686b108SIiro Valkonen #define MXT_UNLOCK_CMD_MSB	0xaa
1857686b108SIiro Valkonen #define MXT_UNLOCK_CMD_LSB	0xdc
1864cf51c38SJoonyoung Shim 
1874cf51c38SJoonyoung Shim /* Bootloader mode status */
1887686b108SIiro Valkonen #define MXT_WAITING_BOOTLOAD_CMD	0xc0	/* valid 7 6 bit only */
1897686b108SIiro Valkonen #define MXT_WAITING_FRAME_DATA	0x80	/* valid 7 6 bit only */
1907686b108SIiro Valkonen #define MXT_FRAME_CRC_CHECK	0x02
1917686b108SIiro Valkonen #define MXT_FRAME_CRC_FAIL	0x03
1927686b108SIiro Valkonen #define MXT_FRAME_CRC_PASS	0x04
1937686b108SIiro Valkonen #define MXT_APP_CRC_FAIL	0x40	/* valid 7 8 bit only */
1947686b108SIiro Valkonen #define MXT_BOOT_STATUS_MASK	0x3f
195e57a66aaSNick Dyer #define MXT_BOOT_EXTENDED_ID	(1 << 5)
196e57a66aaSNick Dyer #define MXT_BOOT_ID_MASK	0x1f
1974cf51c38SJoonyoung Shim 
1984cf51c38SJoonyoung Shim /* Touchscreen absolute values */
1997686b108SIiro Valkonen #define MXT_MAX_AREA		0xff
2004cf51c38SJoonyoung Shim 
20122dfab7fSDaniel Kurtz #define MXT_PIXELS_PER_MM	20
20222dfab7fSDaniel Kurtz 
2037686b108SIiro Valkonen struct mxt_info {
2044cf51c38SJoonyoung Shim 	u8 family_id;
2054cf51c38SJoonyoung Shim 	u8 variant_id;
2064cf51c38SJoonyoung Shim 	u8 version;
2074cf51c38SJoonyoung Shim 	u8 build;
2084cf51c38SJoonyoung Shim 	u8 matrix_xsize;
2094cf51c38SJoonyoung Shim 	u8 matrix_ysize;
2104cf51c38SJoonyoung Shim 	u8 object_num;
2114cf51c38SJoonyoung Shim };
2124cf51c38SJoonyoung Shim 
2137686b108SIiro Valkonen struct mxt_object {
2144cf51c38SJoonyoung Shim 	u8 type;
2154cf51c38SJoonyoung Shim 	u16 start_address;
2161e0c0c5bSDaniel Kurtz 	u8 size_minus_one;
2171e0c0c5bSDaniel Kurtz 	u8 instances_minus_one;
2184cf51c38SJoonyoung Shim 	u8 num_report_ids;
219333e5a9aSDaniel Kurtz } __packed;
2204cf51c38SJoonyoung Shim 
221*d6a39404SNick Dyer struct mxt_dbg {
222*d6a39404SNick Dyer 	u16 t37_address;
223*d6a39404SNick Dyer 	u16 diag_cmd_address;
224*d6a39404SNick Dyer 	struct t37_debug *t37_buf;
225*d6a39404SNick Dyer 	unsigned int t37_pages;
226*d6a39404SNick Dyer 	unsigned int t37_nodes;
227*d6a39404SNick Dyer };
228*d6a39404SNick Dyer 
2294cf51c38SJoonyoung Shim /* Each client has this additional data */
2307686b108SIiro Valkonen struct mxt_data {
2314cf51c38SJoonyoung Shim 	struct i2c_client *client;
2324cf51c38SJoonyoung Shim 	struct input_dev *input_dev;
233ec02ac2bSDaniel Kurtz 	char phys[64];		/* device physical location */
2347686b108SIiro Valkonen 	const struct mxt_platform_data *pdata;
2357686b108SIiro Valkonen 	struct mxt_object *object_table;
2367686b108SIiro Valkonen 	struct mxt_info info;
2374cf51c38SJoonyoung Shim 	unsigned int irq;
238910d8051SJoonyoung Shim 	unsigned int max_x;
239910d8051SJoonyoung Shim 	unsigned int max_y;
2401c0276d5SNick Dyer 	bool xy_switch;
241d79e7e47SBenson Leung 	bool in_bootloader;
2424ce6fa01SNick Dyer 	u16 mem_size;
243b23157dcSNick Dyer 	u8 t100_aux_ampl;
244b23157dcSNick Dyer 	u8 t100_aux_area;
245b23157dcSNick Dyer 	u8 t100_aux_vect;
2469d8dc3e5SNick Dyer 	u8 max_reportid;
247c3f78043SNick Dyer 	u32 config_crc;
2484ce6fa01SNick Dyer 	u32 info_crc;
249f28a842dSNick Dyer 	u8 bootloader_addr;
2505f3f9bc2SNick Dyer 	u8 *msg_buf;
251497767d1SNick Dyer 	u8 t6_status;
252b9b05a89SNick Dyer 	bool update_input;
2539d8dc3e5SNick Dyer 	u8 last_message_count;
2549d8dc3e5SNick Dyer 	u8 num_touchids;
255b23157dcSNick Dyer 	u8 multitouch;
2567f3884f7SNick Dyer 	struct t7_config t7_cfg;
257*d6a39404SNick Dyer 	struct mxt_dbg dbg;
258333e5a9aSDaniel Kurtz 
259333e5a9aSDaniel Kurtz 	/* Cached parameters from object table */
260b9b05a89SNick Dyer 	u16 T5_address;
2615f3f9bc2SNick Dyer 	u8 T5_msg_size;
262fdf80421SDaniel Kurtz 	u8 T6_reportid;
263a4a2ef46SIiro Valkonen 	u16 T6_address;
2644ce6fa01SNick Dyer 	u16 T7_address;
265333e5a9aSDaniel Kurtz 	u8 T9_reportid_min;
266333e5a9aSDaniel Kurtz 	u8 T9_reportid_max;
26722dfab7fSDaniel Kurtz 	u8 T19_reportid;
2689d8dc3e5SNick Dyer 	u16 T44_address;
269b23157dcSNick Dyer 	u8 T100_reportid_min;
270b23157dcSNick Dyer 	u8 T100_reportid_max;
271d79e7e47SBenson Leung 
272d79e7e47SBenson Leung 	/* for fw update in bootloader */
273d79e7e47SBenson Leung 	struct completion bl_completion;
274a4a2ef46SIiro Valkonen 
275a4a2ef46SIiro Valkonen 	/* for reset handling */
276a4a2ef46SIiro Valkonen 	struct completion reset_completion;
277c3f78043SNick Dyer 
278c3f78043SNick Dyer 	/* for config update handling */
279c3f78043SNick Dyer 	struct completion crc_completion;
2804cf51c38SJoonyoung Shim };
2814cf51c38SJoonyoung Shim 
2821e0c0c5bSDaniel Kurtz static size_t mxt_obj_size(const struct mxt_object *obj)
2831e0c0c5bSDaniel Kurtz {
2841e0c0c5bSDaniel Kurtz 	return obj->size_minus_one + 1;
2851e0c0c5bSDaniel Kurtz }
2861e0c0c5bSDaniel Kurtz 
2871e0c0c5bSDaniel Kurtz static size_t mxt_obj_instances(const struct mxt_object *obj)
2881e0c0c5bSDaniel Kurtz {
2891e0c0c5bSDaniel Kurtz 	return obj->instances_minus_one + 1;
2901e0c0c5bSDaniel Kurtz }
2911e0c0c5bSDaniel Kurtz 
2927686b108SIiro Valkonen static bool mxt_object_readable(unsigned int type)
2934cf51c38SJoonyoung Shim {
2944cf51c38SJoonyoung Shim 	switch (type) {
29581c88a71SIiro Valkonen 	case MXT_GEN_COMMAND_T6:
29681c88a71SIiro Valkonen 	case MXT_GEN_POWER_T7:
29781c88a71SIiro Valkonen 	case MXT_GEN_ACQUIRE_T8:
29881c88a71SIiro Valkonen 	case MXT_GEN_DATASOURCE_T53:
29981c88a71SIiro Valkonen 	case MXT_TOUCH_MULTI_T9:
30081c88a71SIiro Valkonen 	case MXT_TOUCH_KEYARRAY_T15:
30181c88a71SIiro Valkonen 	case MXT_TOUCH_PROXIMITY_T23:
30281c88a71SIiro Valkonen 	case MXT_TOUCH_PROXKEY_T52:
30381c88a71SIiro Valkonen 	case MXT_PROCI_GRIPFACE_T20:
30481c88a71SIiro Valkonen 	case MXT_PROCG_NOISE_T22:
30581c88a71SIiro Valkonen 	case MXT_PROCI_ONETOUCH_T24:
30681c88a71SIiro Valkonen 	case MXT_PROCI_TWOTOUCH_T27:
30781c88a71SIiro Valkonen 	case MXT_PROCI_GRIP_T40:
30881c88a71SIiro Valkonen 	case MXT_PROCI_PALM_T41:
30981c88a71SIiro Valkonen 	case MXT_PROCI_TOUCHSUPPRESSION_T42:
31081c88a71SIiro Valkonen 	case MXT_PROCI_STYLUS_T47:
31181c88a71SIiro Valkonen 	case MXT_PROCG_NOISESUPPRESSION_T48:
31281c88a71SIiro Valkonen 	case MXT_SPT_COMMSCONFIG_T18:
31381c88a71SIiro Valkonen 	case MXT_SPT_GPIOPWM_T19:
31481c88a71SIiro Valkonen 	case MXT_SPT_SELFTEST_T25:
31581c88a71SIiro Valkonen 	case MXT_SPT_CTECONFIG_T28:
31681c88a71SIiro Valkonen 	case MXT_SPT_USERDATA_T38:
31781c88a71SIiro Valkonen 	case MXT_SPT_DIGITIZER_T43:
31881c88a71SIiro Valkonen 	case MXT_SPT_CTECONFIG_T46:
3194cf51c38SJoonyoung Shim 		return true;
3204cf51c38SJoonyoung Shim 	default:
3214cf51c38SJoonyoung Shim 		return false;
3224cf51c38SJoonyoung Shim 	}
3234cf51c38SJoonyoung Shim }
3244cf51c38SJoonyoung Shim 
3255f3f9bc2SNick Dyer static void mxt_dump_message(struct mxt_data *data, u8 *message)
3264cf51c38SJoonyoung Shim {
3275f3f9bc2SNick Dyer 	dev_dbg(&data->client->dev, "message: %*ph\n",
3285f3f9bc2SNick Dyer 		data->T5_msg_size, message);
3294cf51c38SJoonyoung Shim }
3304cf51c38SJoonyoung Shim 
331a4a2ef46SIiro Valkonen static int mxt_wait_for_completion(struct mxt_data *data,
332a4a2ef46SIiro Valkonen 				   struct completion *comp,
333a4a2ef46SIiro Valkonen 				   unsigned int timeout_ms)
3344cf51c38SJoonyoung Shim {
335d79e7e47SBenson Leung 	struct device *dev = &data->client->dev;
336d79e7e47SBenson Leung 	unsigned long timeout = msecs_to_jiffies(timeout_ms);
337d79e7e47SBenson Leung 	long ret;
338d79e7e47SBenson Leung 
339d79e7e47SBenson Leung 	ret = wait_for_completion_interruptible_timeout(comp, timeout);
340d79e7e47SBenson Leung 	if (ret < 0) {
341d79e7e47SBenson Leung 		return ret;
342d79e7e47SBenson Leung 	} else if (ret == 0) {
343d79e7e47SBenson Leung 		dev_err(dev, "Wait for completion timed out.\n");
344d79e7e47SBenson Leung 		return -ETIMEDOUT;
345d79e7e47SBenson Leung 	}
346d79e7e47SBenson Leung 	return 0;
347d79e7e47SBenson Leung }
348d79e7e47SBenson Leung 
349f28a842dSNick Dyer static int mxt_bootloader_read(struct mxt_data *data,
350f28a842dSNick Dyer 			       u8 *val, unsigned int count)
351f28a842dSNick Dyer {
352f28a842dSNick Dyer 	int ret;
353f28a842dSNick Dyer 	struct i2c_msg msg;
354f28a842dSNick Dyer 
355f28a842dSNick Dyer 	msg.addr = data->bootloader_addr;
356f28a842dSNick Dyer 	msg.flags = data->client->flags & I2C_M_TEN;
357f28a842dSNick Dyer 	msg.flags |= I2C_M_RD;
358f28a842dSNick Dyer 	msg.len = count;
359f28a842dSNick Dyer 	msg.buf = val;
360f28a842dSNick Dyer 
361f28a842dSNick Dyer 	ret = i2c_transfer(data->client->adapter, &msg, 1);
362f28a842dSNick Dyer 	if (ret == 1) {
363f28a842dSNick Dyer 		ret = 0;
364f28a842dSNick Dyer 	} else {
365f28a842dSNick Dyer 		ret = ret < 0 ? ret : -EIO;
366f28a842dSNick Dyer 		dev_err(&data->client->dev, "%s: i2c recv failed (%d)\n",
367f28a842dSNick Dyer 			__func__, ret);
368f28a842dSNick Dyer 	}
369f28a842dSNick Dyer 
370f28a842dSNick Dyer 	return ret;
371f28a842dSNick Dyer }
372f28a842dSNick Dyer 
373f28a842dSNick Dyer static int mxt_bootloader_write(struct mxt_data *data,
374f28a842dSNick Dyer 				const u8 * const val, unsigned int count)
375f28a842dSNick Dyer {
376f28a842dSNick Dyer 	int ret;
377f28a842dSNick Dyer 	struct i2c_msg msg;
378f28a842dSNick Dyer 
379f28a842dSNick Dyer 	msg.addr = data->bootloader_addr;
380f28a842dSNick Dyer 	msg.flags = data->client->flags & I2C_M_TEN;
381f28a842dSNick Dyer 	msg.len = count;
382f28a842dSNick Dyer 	msg.buf = (u8 *)val;
383f28a842dSNick Dyer 
384f28a842dSNick Dyer 	ret = i2c_transfer(data->client->adapter, &msg, 1);
385f28a842dSNick Dyer 	if (ret == 1) {
386f28a842dSNick Dyer 		ret = 0;
387f28a842dSNick Dyer 	} else {
388f28a842dSNick Dyer 		ret = ret < 0 ? ret : -EIO;
389f28a842dSNick Dyer 		dev_err(&data->client->dev, "%s: i2c send failed (%d)\n",
390f28a842dSNick Dyer 			__func__, ret);
391f28a842dSNick Dyer 	}
392f28a842dSNick Dyer 
393f28a842dSNick Dyer 	return ret;
394f28a842dSNick Dyer }
395f28a842dSNick Dyer 
3968efaa5e5SNick Dyer static int mxt_lookup_bootloader_address(struct mxt_data *data, bool retry)
397f28a842dSNick Dyer {
398f28a842dSNick Dyer 	u8 appmode = data->client->addr;
399f28a842dSNick Dyer 	u8 bootloader;
400f28a842dSNick Dyer 
401f28a842dSNick Dyer 	switch (appmode) {
402f28a842dSNick Dyer 	case 0x4a:
403f28a842dSNick Dyer 	case 0x4b:
40444a0bab2SNick Dyer 		/* Chips after 1664S use different scheme */
4058efaa5e5SNick Dyer 		if (retry || data->info.family_id >= 0xa2) {
40644a0bab2SNick Dyer 			bootloader = appmode - 0x24;
40744a0bab2SNick Dyer 			break;
40844a0bab2SNick Dyer 		}
40944a0bab2SNick Dyer 		/* Fall through for normal case */
410f28a842dSNick Dyer 	case 0x4c:
411f28a842dSNick Dyer 	case 0x4d:
412f28a842dSNick Dyer 	case 0x5a:
413f28a842dSNick Dyer 	case 0x5b:
414f28a842dSNick Dyer 		bootloader = appmode - 0x26;
415f28a842dSNick Dyer 		break;
4166cd1ab0fSDmitry Torokhov 
417f28a842dSNick Dyer 	default:
418f28a842dSNick Dyer 		dev_err(&data->client->dev,
419f28a842dSNick Dyer 			"Appmode i2c address 0x%02x not found\n",
420f28a842dSNick Dyer 			appmode);
421f28a842dSNick Dyer 		return -EINVAL;
422f28a842dSNick Dyer 	}
423f28a842dSNick Dyer 
424f28a842dSNick Dyer 	data->bootloader_addr = bootloader;
425f28a842dSNick Dyer 	return 0;
426f28a842dSNick Dyer }
427f28a842dSNick Dyer 
4286cd1ab0fSDmitry Torokhov static int mxt_probe_bootloader(struct mxt_data *data, bool alt_address)
429a9fdd1e6SNick Dyer {
430a9fdd1e6SNick Dyer 	struct device *dev = &data->client->dev;
4316cd1ab0fSDmitry Torokhov 	int error;
432a9fdd1e6SNick Dyer 	u8 val;
433a9fdd1e6SNick Dyer 	bool crc_failure;
434a9fdd1e6SNick Dyer 
4356cd1ab0fSDmitry Torokhov 	error = mxt_lookup_bootloader_address(data, alt_address);
4366cd1ab0fSDmitry Torokhov 	if (error)
4376cd1ab0fSDmitry Torokhov 		return error;
438a9fdd1e6SNick Dyer 
4396cd1ab0fSDmitry Torokhov 	error = mxt_bootloader_read(data, &val, 1);
4406cd1ab0fSDmitry Torokhov 	if (error)
4416cd1ab0fSDmitry Torokhov 		return error;
442a9fdd1e6SNick Dyer 
443a9fdd1e6SNick Dyer 	/* Check app crc fail mode */
444a9fdd1e6SNick Dyer 	crc_failure = (val & ~MXT_BOOT_STATUS_MASK) == MXT_APP_CRC_FAIL;
445a9fdd1e6SNick Dyer 
446a9fdd1e6SNick Dyer 	dev_err(dev, "Detected bootloader, status:%02X%s\n",
447a9fdd1e6SNick Dyer 			val, crc_failure ? ", APP_CRC_FAIL" : "");
448a9fdd1e6SNick Dyer 
449a9fdd1e6SNick Dyer 	return 0;
450a9fdd1e6SNick Dyer }
451a9fdd1e6SNick Dyer 
452e57a66aaSNick Dyer static u8 mxt_get_bootloader_version(struct mxt_data *data, u8 val)
453e57a66aaSNick Dyer {
454e57a66aaSNick Dyer 	struct device *dev = &data->client->dev;
455e57a66aaSNick Dyer 	u8 buf[3];
456e57a66aaSNick Dyer 
457e57a66aaSNick Dyer 	if (val & MXT_BOOT_EXTENDED_ID) {
458e57a66aaSNick Dyer 		if (mxt_bootloader_read(data, &buf[0], 3) != 0) {
459e57a66aaSNick Dyer 			dev_err(dev, "%s: i2c failure\n", __func__);
46068807a0cSNick Dyer 			return val;
461e57a66aaSNick Dyer 		}
462e57a66aaSNick Dyer 
463e57a66aaSNick Dyer 		dev_dbg(dev, "Bootloader ID:%d Version:%d\n", buf[1], buf[2]);
464e57a66aaSNick Dyer 
465e57a66aaSNick Dyer 		return buf[0];
466e57a66aaSNick Dyer 	} else {
467e57a66aaSNick Dyer 		dev_dbg(dev, "Bootloader ID:%d\n", val & MXT_BOOT_ID_MASK);
468e57a66aaSNick Dyer 
469e57a66aaSNick Dyer 		return val;
470e57a66aaSNick Dyer 	}
471e57a66aaSNick Dyer }
472e57a66aaSNick Dyer 
473385deb96SNick Dyer static int mxt_check_bootloader(struct mxt_data *data, unsigned int state,
474385deb96SNick Dyer 				bool wait)
475d79e7e47SBenson Leung {
476f28a842dSNick Dyer 	struct device *dev = &data->client->dev;
4774cf51c38SJoonyoung Shim 	u8 val;
478d79e7e47SBenson Leung 	int ret;
4794cf51c38SJoonyoung Shim 
4804cf51c38SJoonyoung Shim recheck:
481385deb96SNick Dyer 	if (wait) {
482d79e7e47SBenson Leung 		/*
483d79e7e47SBenson Leung 		 * In application update mode, the interrupt
484d79e7e47SBenson Leung 		 * line signals state transitions. We must wait for the
485d79e7e47SBenson Leung 		 * CHG assertion before reading the status byte.
486d79e7e47SBenson Leung 		 * Once the status byte has been read, the line is deasserted.
487d79e7e47SBenson Leung 		 */
488a4a2ef46SIiro Valkonen 		ret = mxt_wait_for_completion(data, &data->bl_completion,
489a4a2ef46SIiro Valkonen 					      MXT_FW_CHG_TIMEOUT);
490d79e7e47SBenson Leung 		if (ret) {
491d79e7e47SBenson Leung 			/*
492d79e7e47SBenson Leung 			 * TODO: handle -ERESTARTSYS better by terminating
493d79e7e47SBenson Leung 			 * fw update process before returning to userspace
494d79e7e47SBenson Leung 			 * by writing length 0x000 to device (iff we are in
495d79e7e47SBenson Leung 			 * WAITING_FRAME_DATA state).
496d79e7e47SBenson Leung 			 */
497f28a842dSNick Dyer 			dev_err(dev, "Update wait error %d\n", ret);
498d79e7e47SBenson Leung 			return ret;
499d79e7e47SBenson Leung 		}
500d79e7e47SBenson Leung 	}
501d79e7e47SBenson Leung 
502f28a842dSNick Dyer 	ret = mxt_bootloader_read(data, &val, 1);
503f28a842dSNick Dyer 	if (ret)
504f28a842dSNick Dyer 		return ret;
5054cf51c38SJoonyoung Shim 
506e57a66aaSNick Dyer 	if (state == MXT_WAITING_BOOTLOAD_CMD)
507e57a66aaSNick Dyer 		val = mxt_get_bootloader_version(data, val);
508e57a66aaSNick Dyer 
5094cf51c38SJoonyoung Shim 	switch (state) {
5107686b108SIiro Valkonen 	case MXT_WAITING_BOOTLOAD_CMD:
5117686b108SIiro Valkonen 	case MXT_WAITING_FRAME_DATA:
512a9fdd1e6SNick Dyer 	case MXT_APP_CRC_FAIL:
5137686b108SIiro Valkonen 		val &= ~MXT_BOOT_STATUS_MASK;
5144cf51c38SJoonyoung Shim 		break;
5157686b108SIiro Valkonen 	case MXT_FRAME_CRC_PASS:
516f943c74aSNick Dyer 		if (val == MXT_FRAME_CRC_CHECK) {
5174cf51c38SJoonyoung Shim 			goto recheck;
518f943c74aSNick Dyer 		} else if (val == MXT_FRAME_CRC_FAIL) {
519f943c74aSNick Dyer 			dev_err(dev, "Bootloader CRC fail\n");
520f943c74aSNick Dyer 			return -EINVAL;
521f943c74aSNick Dyer 		}
5224cf51c38SJoonyoung Shim 		break;
5234cf51c38SJoonyoung Shim 	default:
5244cf51c38SJoonyoung Shim 		return -EINVAL;
5254cf51c38SJoonyoung Shim 	}
5264cf51c38SJoonyoung Shim 
5274cf51c38SJoonyoung Shim 	if (val != state) {
528f28a842dSNick Dyer 		dev_err(dev, "Invalid bootloader state %02X != %02X\n",
5297bed6805SNick Dyer 			val, state);
5304cf51c38SJoonyoung Shim 		return -EINVAL;
5314cf51c38SJoonyoung Shim 	}
5324cf51c38SJoonyoung Shim 
5334cf51c38SJoonyoung Shim 	return 0;
5344cf51c38SJoonyoung Shim }
5354cf51c38SJoonyoung Shim 
5368efaa5e5SNick Dyer static int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock)
5374cf51c38SJoonyoung Shim {
538f28a842dSNick Dyer 	int ret;
5394cf51c38SJoonyoung Shim 	u8 buf[2];
5404cf51c38SJoonyoung Shim 
5418efaa5e5SNick Dyer 	if (unlock) {
5427686b108SIiro Valkonen 		buf[0] = MXT_UNLOCK_CMD_LSB;
5437686b108SIiro Valkonen 		buf[1] = MXT_UNLOCK_CMD_MSB;
5448efaa5e5SNick Dyer 	} else {
5458efaa5e5SNick Dyer 		buf[0] = 0x01;
5468efaa5e5SNick Dyer 		buf[1] = 0x01;
5478efaa5e5SNick Dyer 	}
5484cf51c38SJoonyoung Shim 
549f28a842dSNick Dyer 	ret = mxt_bootloader_write(data, buf, 2);
550f28a842dSNick Dyer 	if (ret)
551f28a842dSNick Dyer 		return ret;
5524cf51c38SJoonyoung Shim 
5534cf51c38SJoonyoung Shim 	return 0;
5544cf51c38SJoonyoung Shim }
5554cf51c38SJoonyoung Shim 
5567686b108SIiro Valkonen static int __mxt_read_reg(struct i2c_client *client,
5574cf51c38SJoonyoung Shim 			       u16 reg, u16 len, void *val)
5584cf51c38SJoonyoung Shim {
5594cf51c38SJoonyoung Shim 	struct i2c_msg xfer[2];
5604cf51c38SJoonyoung Shim 	u8 buf[2];
561771733e3SDaniel Kurtz 	int ret;
5624cf51c38SJoonyoung Shim 
5634cf51c38SJoonyoung Shim 	buf[0] = reg & 0xff;
5644cf51c38SJoonyoung Shim 	buf[1] = (reg >> 8) & 0xff;
5654cf51c38SJoonyoung Shim 
5664cf51c38SJoonyoung Shim 	/* Write register */
5674cf51c38SJoonyoung Shim 	xfer[0].addr = client->addr;
5684cf51c38SJoonyoung Shim 	xfer[0].flags = 0;
5694cf51c38SJoonyoung Shim 	xfer[0].len = 2;
5704cf51c38SJoonyoung Shim 	xfer[0].buf = buf;
5714cf51c38SJoonyoung Shim 
5724cf51c38SJoonyoung Shim 	/* Read data */
5734cf51c38SJoonyoung Shim 	xfer[1].addr = client->addr;
5744cf51c38SJoonyoung Shim 	xfer[1].flags = I2C_M_RD;
5754cf51c38SJoonyoung Shim 	xfer[1].len = len;
5764cf51c38SJoonyoung Shim 	xfer[1].buf = val;
5774cf51c38SJoonyoung Shim 
578771733e3SDaniel Kurtz 	ret = i2c_transfer(client->adapter, xfer, 2);
579771733e3SDaniel Kurtz 	if (ret == 2) {
580771733e3SDaniel Kurtz 		ret = 0;
581771733e3SDaniel Kurtz 	} else {
582771733e3SDaniel Kurtz 		if (ret >= 0)
583771733e3SDaniel Kurtz 			ret = -EIO;
584771733e3SDaniel Kurtz 		dev_err(&client->dev, "%s: i2c transfer failed (%d)\n",
585771733e3SDaniel Kurtz 			__func__, ret);
5864cf51c38SJoonyoung Shim 	}
5874cf51c38SJoonyoung Shim 
588771733e3SDaniel Kurtz 	return ret;
5894cf51c38SJoonyoung Shim }
5904cf51c38SJoonyoung Shim 
5919638ab7cSDaniel Kurtz static int __mxt_write_reg(struct i2c_client *client, u16 reg, u16 len,
5929638ab7cSDaniel Kurtz 			   const void *val)
5934cf51c38SJoonyoung Shim {
5949638ab7cSDaniel Kurtz 	u8 *buf;
5959638ab7cSDaniel Kurtz 	size_t count;
596771733e3SDaniel Kurtz 	int ret;
5974cf51c38SJoonyoung Shim 
5989638ab7cSDaniel Kurtz 	count = len + 2;
5999638ab7cSDaniel Kurtz 	buf = kmalloc(count, GFP_KERNEL);
6009638ab7cSDaniel Kurtz 	if (!buf)
6019638ab7cSDaniel Kurtz 		return -ENOMEM;
6024cf51c38SJoonyoung Shim 
6034cf51c38SJoonyoung Shim 	buf[0] = reg & 0xff;
6044cf51c38SJoonyoung Shim 	buf[1] = (reg >> 8) & 0xff;
6059638ab7cSDaniel Kurtz 	memcpy(&buf[2], val, len);
6064cf51c38SJoonyoung Shim 
6079638ab7cSDaniel Kurtz 	ret = i2c_master_send(client, buf, count);
6089638ab7cSDaniel Kurtz 	if (ret == count) {
609771733e3SDaniel Kurtz 		ret = 0;
610771733e3SDaniel Kurtz 	} else {
611771733e3SDaniel Kurtz 		if (ret >= 0)
612771733e3SDaniel Kurtz 			ret = -EIO;
613771733e3SDaniel Kurtz 		dev_err(&client->dev, "%s: i2c send failed (%d)\n",
614771733e3SDaniel Kurtz 			__func__, ret);
6154cf51c38SJoonyoung Shim 	}
6164cf51c38SJoonyoung Shim 
6179638ab7cSDaniel Kurtz 	kfree(buf);
618771733e3SDaniel Kurtz 	return ret;
6194cf51c38SJoonyoung Shim }
6204cf51c38SJoonyoung Shim 
6219638ab7cSDaniel Kurtz static int mxt_write_reg(struct i2c_client *client, u16 reg, u8 val)
6224cf51c38SJoonyoung Shim {
6239638ab7cSDaniel Kurtz 	return __mxt_write_reg(client, reg, 1, &val);
6244cf51c38SJoonyoung Shim }
6254cf51c38SJoonyoung Shim 
6267686b108SIiro Valkonen static struct mxt_object *
6277686b108SIiro Valkonen mxt_get_object(struct mxt_data *data, u8 type)
6284cf51c38SJoonyoung Shim {
6297686b108SIiro Valkonen 	struct mxt_object *object;
6304cf51c38SJoonyoung Shim 	int i;
6314cf51c38SJoonyoung Shim 
6324cf51c38SJoonyoung Shim 	for (i = 0; i < data->info.object_num; i++) {
6334cf51c38SJoonyoung Shim 		object = data->object_table + i;
6344cf51c38SJoonyoung Shim 		if (object->type == type)
6354cf51c38SJoonyoung Shim 			return object;
6364cf51c38SJoonyoung Shim 	}
6374cf51c38SJoonyoung Shim 
63850a77c65SNick Dyer 	dev_warn(&data->client->dev, "Invalid object type T%u\n", type);
6394cf51c38SJoonyoung Shim 	return NULL;
6404cf51c38SJoonyoung Shim }
6414cf51c38SJoonyoung Shim 
642497767d1SNick Dyer static void mxt_proc_t6_messages(struct mxt_data *data, u8 *msg)
643497767d1SNick Dyer {
644497767d1SNick Dyer 	struct device *dev = &data->client->dev;
645497767d1SNick Dyer 	u8 status = msg[1];
646497767d1SNick Dyer 	u32 crc = msg[2] | (msg[3] << 8) | (msg[4] << 16);
647497767d1SNick Dyer 
648497767d1SNick Dyer 	complete(&data->crc_completion);
649497767d1SNick Dyer 
650497767d1SNick Dyer 	if (crc != data->config_crc) {
651497767d1SNick Dyer 		data->config_crc = crc;
652497767d1SNick Dyer 		dev_dbg(dev, "T6 Config Checksum: 0x%06X\n", crc);
653497767d1SNick Dyer 	}
654497767d1SNick Dyer 
655497767d1SNick Dyer 	/* Detect reset */
656497767d1SNick Dyer 	if (status & MXT_T6_STATUS_RESET)
657497767d1SNick Dyer 		complete(&data->reset_completion);
658497767d1SNick Dyer 
659497767d1SNick Dyer 	/* Output debug if status has changed */
660497767d1SNick Dyer 	if (status != data->t6_status)
661497767d1SNick Dyer 		dev_dbg(dev, "T6 Status 0x%02X%s%s%s%s%s%s%s\n",
662497767d1SNick Dyer 			status,
663497767d1SNick Dyer 			status == 0 ? " OK" : "",
664497767d1SNick Dyer 			status & MXT_T6_STATUS_RESET ? " RESET" : "",
665497767d1SNick Dyer 			status & MXT_T6_STATUS_OFL ? " OFL" : "",
666497767d1SNick Dyer 			status & MXT_T6_STATUS_SIGERR ? " SIGERR" : "",
667497767d1SNick Dyer 			status & MXT_T6_STATUS_CAL ? " CAL" : "",
668497767d1SNick Dyer 			status & MXT_T6_STATUS_CFGERR ? " CFGERR" : "",
669497767d1SNick Dyer 			status & MXT_T6_STATUS_COMSERR ? " COMSERR" : "");
670497767d1SNick Dyer 
671497767d1SNick Dyer 	/* Save current status */
672497767d1SNick Dyer 	data->t6_status = status;
673497767d1SNick Dyer }
674497767d1SNick Dyer 
6757f405483SLinus Torvalds static int mxt_write_object(struct mxt_data *data,
6767f405483SLinus Torvalds 				 u8 type, u8 offset, u8 val)
6777f405483SLinus Torvalds {
6787f405483SLinus Torvalds 	struct mxt_object *object;
6797f405483SLinus Torvalds 	u16 reg;
6807f405483SLinus Torvalds 
6817f405483SLinus Torvalds 	object = mxt_get_object(data, type);
6827f405483SLinus Torvalds 	if (!object || offset >= mxt_obj_size(object))
6837f405483SLinus Torvalds 		return -EINVAL;
6847f405483SLinus Torvalds 
6857f405483SLinus Torvalds 	reg = object->start_address;
6867f405483SLinus Torvalds 	return mxt_write_reg(data->client, reg + offset, val);
6877f405483SLinus Torvalds }
6887f405483SLinus Torvalds 
6895f3f9bc2SNick Dyer static void mxt_input_button(struct mxt_data *data, u8 *message)
69022dfab7fSDaniel Kurtz {
69122dfab7fSDaniel Kurtz 	struct input_dev *input = data->input_dev;
692fb5e4c3eSNick Dyer 	const struct mxt_platform_data *pdata = data->pdata;
69322dfab7fSDaniel Kurtz 	int i;
69422dfab7fSDaniel Kurtz 
695fb5e4c3eSNick Dyer 	for (i = 0; i < pdata->t19_num_keys; i++) {
696fb5e4c3eSNick Dyer 		if (pdata->t19_keymap[i] == KEY_RESERVED)
69722dfab7fSDaniel Kurtz 			continue;
698c37f6d38SDmitry Torokhov 
699c37f6d38SDmitry Torokhov 		/* Active-low switch */
700c37f6d38SDmitry Torokhov 		input_report_key(input, pdata->t19_keymap[i],
701c37f6d38SDmitry Torokhov 				 !(message[1] & BIT(i)));
70222dfab7fSDaniel Kurtz 	}
70322dfab7fSDaniel Kurtz }
70422dfab7fSDaniel Kurtz 
705b735fbe0SBenson Leung static void mxt_input_sync(struct mxt_data *data)
706eef820dcSNick Dyer {
707b735fbe0SBenson Leung 	input_mt_report_pointer_emulation(data->input_dev,
708b735fbe0SBenson Leung 					  data->pdata->t19_num_keys);
709b735fbe0SBenson Leung 	input_sync(data->input_dev);
710eef820dcSNick Dyer }
711eef820dcSNick Dyer 
712b9b05a89SNick Dyer static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
7134cf51c38SJoonyoung Shim {
7144cf51c38SJoonyoung Shim 	struct device *dev = &data->client->dev;
715fba5bc31SDaniel Kurtz 	struct input_dev *input_dev = data->input_dev;
7165f3f9bc2SNick Dyer 	int id;
7175f3f9bc2SNick Dyer 	u8 status;
7184cf51c38SJoonyoung Shim 	int x;
7194cf51c38SJoonyoung Shim 	int y;
7204cf51c38SJoonyoung Shim 	int area;
721fea9e467SNick Dyer 	int amplitude;
7224cf51c38SJoonyoung Shim 
7235f3f9bc2SNick Dyer 	id = message[0] - data->T9_reportid_min;
7245f3f9bc2SNick Dyer 	status = message[1];
7255f3f9bc2SNick Dyer 	x = (message[2] << 4) | ((message[4] >> 4) & 0xf);
7265f3f9bc2SNick Dyer 	y = (message[3] << 4) | ((message[4] & 0xf));
727eef820dcSNick Dyer 
728eef820dcSNick Dyer 	/* Handle 10/12 bit switching */
729910d8051SJoonyoung Shim 	if (data->max_x < 1024)
730eef820dcSNick Dyer 		x >>= 2;
731910d8051SJoonyoung Shim 	if (data->max_y < 1024)
732eef820dcSNick Dyer 		y >>= 2;
733910d8051SJoonyoung Shim 
7345f3f9bc2SNick Dyer 	area = message[5];
7355f3f9bc2SNick Dyer 	amplitude = message[6];
7364cf51c38SJoonyoung Shim 
737b2e459b8SDaniel Kurtz 	dev_dbg(dev,
738b2e459b8SDaniel Kurtz 		"[%u] %c%c%c%c%c%c%c%c x: %5u y: %5u area: %3u amp: %3u\n",
739b2e459b8SDaniel Kurtz 		id,
740f3889ed1SNick Dyer 		(status & MXT_T9_DETECT) ? 'D' : '.',
741f3889ed1SNick Dyer 		(status & MXT_T9_PRESS) ? 'P' : '.',
742f3889ed1SNick Dyer 		(status & MXT_T9_RELEASE) ? 'R' : '.',
743f3889ed1SNick Dyer 		(status & MXT_T9_MOVE) ? 'M' : '.',
744f3889ed1SNick Dyer 		(status & MXT_T9_VECTOR) ? 'V' : '.',
745f3889ed1SNick Dyer 		(status & MXT_T9_AMP) ? 'A' : '.',
746f3889ed1SNick Dyer 		(status & MXT_T9_SUPPRESS) ? 'S' : '.',
747f3889ed1SNick Dyer 		(status & MXT_T9_UNGRIP) ? 'U' : '.',
748fea9e467SNick Dyer 		x, y, area, amplitude);
7494cf51c38SJoonyoung Shim 
750fba5bc31SDaniel Kurtz 	input_mt_slot(input_dev, id);
7514cf51c38SJoonyoung Shim 
752f3889ed1SNick Dyer 	if (status & MXT_T9_DETECT) {
753eef820dcSNick Dyer 		/*
754eef820dcSNick Dyer 		 * Multiple bits may be set if the host is slow to read
755eef820dcSNick Dyer 		 * the status messages, indicating all the events that
756eef820dcSNick Dyer 		 * have happened.
757eef820dcSNick Dyer 		 */
758eef820dcSNick Dyer 		if (status & MXT_T9_RELEASE) {
759eef820dcSNick Dyer 			input_mt_report_slot_state(input_dev,
760eef820dcSNick Dyer 						   MT_TOOL_FINGER, 0);
761b735fbe0SBenson Leung 			mxt_input_sync(data);
762eef820dcSNick Dyer 		}
763eef820dcSNick Dyer 
764eef820dcSNick Dyer 		/* Touch active */
765eef820dcSNick Dyer 		input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1);
766fba5bc31SDaniel Kurtz 		input_report_abs(input_dev, ABS_MT_POSITION_X, x);
767fba5bc31SDaniel Kurtz 		input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
768fea9e467SNick Dyer 		input_report_abs(input_dev, ABS_MT_PRESSURE, amplitude);
769fba5bc31SDaniel Kurtz 		input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area);
770eef820dcSNick Dyer 	} else {
771eef820dcSNick Dyer 		/* Touch no longer active, close out slot */
772eef820dcSNick Dyer 		input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);
773fba5bc31SDaniel Kurtz 	}
774b9b05a89SNick Dyer 
775b9b05a89SNick Dyer 	data->update_input = true;
7764cf51c38SJoonyoung Shim }
7774cf51c38SJoonyoung Shim 
778b23157dcSNick Dyer static void mxt_proc_t100_message(struct mxt_data *data, u8 *message)
779b23157dcSNick Dyer {
780b23157dcSNick Dyer 	struct device *dev = &data->client->dev;
781b23157dcSNick Dyer 	struct input_dev *input_dev = data->input_dev;
782b23157dcSNick Dyer 	int id;
783b23157dcSNick Dyer 	u8 status;
784b23157dcSNick Dyer 	u8 type = 0;
785b23157dcSNick Dyer 	u16 x;
786b23157dcSNick Dyer 	u16 y;
787b23157dcSNick Dyer 	int distance = 0;
788b23157dcSNick Dyer 	int tool = 0;
789b23157dcSNick Dyer 	u8 major = 0;
790b23157dcSNick Dyer 	u8 pressure = 0;
791b23157dcSNick Dyer 	u8 orientation = 0;
792b23157dcSNick Dyer 
793b23157dcSNick Dyer 	id = message[0] - data->T100_reportid_min - 2;
794b23157dcSNick Dyer 
795b23157dcSNick Dyer 	/* ignore SCRSTATUS events */
796b23157dcSNick Dyer 	if (id < 0)
797b23157dcSNick Dyer 		return;
798b23157dcSNick Dyer 
799b23157dcSNick Dyer 	status = message[1];
800b23157dcSNick Dyer 	x = get_unaligned_le16(&message[2]);
801b23157dcSNick Dyer 	y = get_unaligned_le16(&message[4]);
802b23157dcSNick Dyer 
803b23157dcSNick Dyer 	if (status & MXT_T100_DETECT) {
804b23157dcSNick Dyer 		type = (status & MXT_T100_TYPE_MASK) >> 4;
805b23157dcSNick Dyer 
806b23157dcSNick Dyer 		switch (type) {
807b23157dcSNick Dyer 		case MXT_T100_TYPE_HOVERING_FINGER:
808b23157dcSNick Dyer 			tool = MT_TOOL_FINGER;
809b23157dcSNick Dyer 			distance = MXT_DISTANCE_HOVERING;
810b23157dcSNick Dyer 
811b23157dcSNick Dyer 			if (data->t100_aux_vect)
812b23157dcSNick Dyer 				orientation = message[data->t100_aux_vect];
813b23157dcSNick Dyer 
814b23157dcSNick Dyer 			break;
815b23157dcSNick Dyer 
816b23157dcSNick Dyer 		case MXT_T100_TYPE_FINGER:
817b23157dcSNick Dyer 		case MXT_T100_TYPE_GLOVE:
818b23157dcSNick Dyer 			tool = MT_TOOL_FINGER;
819b23157dcSNick Dyer 			distance = MXT_DISTANCE_ACTIVE_TOUCH;
820b23157dcSNick Dyer 
821b23157dcSNick Dyer 			if (data->t100_aux_area)
822b23157dcSNick Dyer 				major = message[data->t100_aux_area];
823b23157dcSNick Dyer 
824b23157dcSNick Dyer 			if (data->t100_aux_ampl)
825b23157dcSNick Dyer 				pressure = message[data->t100_aux_ampl];
826b23157dcSNick Dyer 
827b23157dcSNick Dyer 			if (data->t100_aux_vect)
828b23157dcSNick Dyer 				orientation = message[data->t100_aux_vect];
829b23157dcSNick Dyer 
830b23157dcSNick Dyer 			break;
831b23157dcSNick Dyer 
832b23157dcSNick Dyer 		case MXT_T100_TYPE_PASSIVE_STYLUS:
833b23157dcSNick Dyer 			tool = MT_TOOL_PEN;
834b23157dcSNick Dyer 
835b23157dcSNick Dyer 			/*
836b23157dcSNick Dyer 			 * Passive stylus is reported with size zero so
837b23157dcSNick Dyer 			 * hardcode.
838b23157dcSNick Dyer 			 */
839b23157dcSNick Dyer 			major = MXT_TOUCH_MAJOR_DEFAULT;
840b23157dcSNick Dyer 
841b23157dcSNick Dyer 			if (data->t100_aux_ampl)
842b23157dcSNick Dyer 				pressure = message[data->t100_aux_ampl];
843b23157dcSNick Dyer 
844b23157dcSNick Dyer 			break;
845b23157dcSNick Dyer 
846b23157dcSNick Dyer 		case MXT_T100_TYPE_LARGE_TOUCH:
847b23157dcSNick Dyer 			/* Ignore suppressed touch */
848b23157dcSNick Dyer 			break;
849b23157dcSNick Dyer 
850b23157dcSNick Dyer 		default:
851b23157dcSNick Dyer 			dev_dbg(dev, "Unexpected T100 type\n");
852b23157dcSNick Dyer 			return;
853b23157dcSNick Dyer 		}
854b23157dcSNick Dyer 	}
855b23157dcSNick Dyer 
856b23157dcSNick Dyer 	/*
857b23157dcSNick Dyer 	 * Values reported should be non-zero if tool is touching the
858b23157dcSNick Dyer 	 * device
859b23157dcSNick Dyer 	 */
860b23157dcSNick Dyer 	if (!pressure && type != MXT_T100_TYPE_HOVERING_FINGER)
861b23157dcSNick Dyer 		pressure = MXT_PRESSURE_DEFAULT;
862b23157dcSNick Dyer 
863b23157dcSNick Dyer 	input_mt_slot(input_dev, id);
864b23157dcSNick Dyer 
865b23157dcSNick Dyer 	if (status & MXT_T100_DETECT) {
866b23157dcSNick Dyer 		dev_dbg(dev, "[%u] type:%u x:%u y:%u a:%02X p:%02X v:%02X\n",
867b23157dcSNick Dyer 			id, type, x, y, major, pressure, orientation);
868b23157dcSNick Dyer 
869b23157dcSNick Dyer 		input_mt_report_slot_state(input_dev, tool, 1);
870b23157dcSNick Dyer 		input_report_abs(input_dev, ABS_MT_POSITION_X, x);
871b23157dcSNick Dyer 		input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
872b23157dcSNick Dyer 		input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, major);
873b23157dcSNick Dyer 		input_report_abs(input_dev, ABS_MT_PRESSURE, pressure);
874b23157dcSNick Dyer 		input_report_abs(input_dev, ABS_MT_DISTANCE, distance);
875b23157dcSNick Dyer 		input_report_abs(input_dev, ABS_MT_ORIENTATION, orientation);
876b23157dcSNick Dyer 	} else {
877b23157dcSNick Dyer 		dev_dbg(dev, "[%u] release\n", id);
878b23157dcSNick Dyer 
879b23157dcSNick Dyer 		/* close out slot */
880b23157dcSNick Dyer 		input_mt_report_slot_state(input_dev, 0, 0);
881b23157dcSNick Dyer 	}
882b23157dcSNick Dyer 
883b23157dcSNick Dyer 	data->update_input = true;
884b23157dcSNick Dyer }
885b23157dcSNick Dyer 
886b9b05a89SNick Dyer static int mxt_proc_message(struct mxt_data *data, u8 *message)
88704a79181SDaniel Kurtz {
888b9b05a89SNick Dyer 	u8 report_id = message[0];
889b9b05a89SNick Dyer 
890b9b05a89SNick Dyer 	if (report_id == MXT_RPTID_NOMSG)
891b9b05a89SNick Dyer 		return 0;
892b9b05a89SNick Dyer 
893b9b05a89SNick Dyer 	if (report_id == data->T6_reportid) {
894b9b05a89SNick Dyer 		mxt_proc_t6_messages(data, message);
895b9b05a89SNick Dyer 	} else if (!data->input_dev) {
896b9b05a89SNick Dyer 		/*
897b9b05a89SNick Dyer 		 * Do not report events if input device
898b9b05a89SNick Dyer 		 * is not yet registered.
899b9b05a89SNick Dyer 		 */
900b9b05a89SNick Dyer 		mxt_dump_message(data, message);
901b23157dcSNick Dyer 	} else if (report_id >= data->T9_reportid_min &&
902b23157dcSNick Dyer 		   report_id <= data->T9_reportid_max) {
903b9b05a89SNick Dyer 		mxt_proc_t9_message(data, message);
904b23157dcSNick Dyer 	} else if (report_id >= data->T100_reportid_min &&
905b23157dcSNick Dyer 		   report_id <= data->T100_reportid_max) {
906b23157dcSNick Dyer 		mxt_proc_t100_message(data, message);
907b9b05a89SNick Dyer 	} else if (report_id == data->T19_reportid) {
908b9b05a89SNick Dyer 		mxt_input_button(data, message);
909b9b05a89SNick Dyer 		data->update_input = true;
910b9b05a89SNick Dyer 	} else {
911b9b05a89SNick Dyer 		mxt_dump_message(data, message);
912b9b05a89SNick Dyer 	}
913b9b05a89SNick Dyer 
914b9b05a89SNick Dyer 	return 1;
915b9b05a89SNick Dyer }
916b9b05a89SNick Dyer 
9179d8dc3e5SNick Dyer static int mxt_read_and_process_messages(struct mxt_data *data, u8 count)
918b9b05a89SNick Dyer {
919b9b05a89SNick Dyer 	struct device *dev = &data->client->dev;
920b9b05a89SNick Dyer 	int ret;
9219d8dc3e5SNick Dyer 	int i;
9229d8dc3e5SNick Dyer 	u8 num_valid = 0;
923b9b05a89SNick Dyer 
9249d8dc3e5SNick Dyer 	/* Safety check for msg_buf */
9259d8dc3e5SNick Dyer 	if (count > data->max_reportid)
9269d8dc3e5SNick Dyer 		return -EINVAL;
9279d8dc3e5SNick Dyer 
9289d8dc3e5SNick Dyer 	/* Process remaining messages if necessary */
929b9b05a89SNick Dyer 	ret = __mxt_read_reg(data->client, data->T5_address,
9309d8dc3e5SNick Dyer 				data->T5_msg_size * count, data->msg_buf);
931b9b05a89SNick Dyer 	if (ret) {
9329d8dc3e5SNick Dyer 		dev_err(dev, "Failed to read %u messages (%d)\n", count, ret);
933b9b05a89SNick Dyer 		return ret;
934b9b05a89SNick Dyer 	}
935b9b05a89SNick Dyer 
9369d8dc3e5SNick Dyer 	for (i = 0;  i < count; i++) {
9379d8dc3e5SNick Dyer 		ret = mxt_proc_message(data,
9389d8dc3e5SNick Dyer 			data->msg_buf + data->T5_msg_size * i);
9399d8dc3e5SNick Dyer 
9409d8dc3e5SNick Dyer 		if (ret == 1)
9419d8dc3e5SNick Dyer 			num_valid++;
9424cf51c38SJoonyoung Shim 	}
9434cf51c38SJoonyoung Shim 
9449d8dc3e5SNick Dyer 	/* return number of messages read */
9459d8dc3e5SNick Dyer 	return num_valid;
9469d8dc3e5SNick Dyer }
9474cf51c38SJoonyoung Shim 
9489d8dc3e5SNick Dyer static irqreturn_t mxt_process_messages_t44(struct mxt_data *data)
9499d8dc3e5SNick Dyer {
9509d8dc3e5SNick Dyer 	struct device *dev = &data->client->dev;
9519d8dc3e5SNick Dyer 	int ret;
9529d8dc3e5SNick Dyer 	u8 count, num_left;
9539d8dc3e5SNick Dyer 
9549d8dc3e5SNick Dyer 	/* Read T44 and T5 together */
9559d8dc3e5SNick Dyer 	ret = __mxt_read_reg(data->client, data->T44_address,
9569d8dc3e5SNick Dyer 		data->T5_msg_size + 1, data->msg_buf);
9579d8dc3e5SNick Dyer 	if (ret) {
9589d8dc3e5SNick Dyer 		dev_err(dev, "Failed to read T44 and T5 (%d)\n", ret);
9598d4e1639SNick Dyer 		return IRQ_NONE;
9609d8dc3e5SNick Dyer 	}
9619d8dc3e5SNick Dyer 
9629d8dc3e5SNick Dyer 	count = data->msg_buf[0];
9639d8dc3e5SNick Dyer 
964651b4608SNick Dyer 	/*
965507584e2SNick Dyer 	 * This condition may be caused by the CHG line being configured in
966507584e2SNick Dyer 	 * Mode 0. It results in unnecessary I2C operations but it is benign.
967651b4608SNick Dyer 	 */
968507584e2SNick Dyer 	if (count == 0)
9699d8dc3e5SNick Dyer 		return IRQ_NONE;
970507584e2SNick Dyer 
971507584e2SNick Dyer 	if (count > data->max_reportid) {
972507584e2SNick Dyer 		dev_warn(dev, "T44 count %d exceeded max report id\n", count);
9739d8dc3e5SNick Dyer 		count = data->max_reportid;
9749d8dc3e5SNick Dyer 	}
9759d8dc3e5SNick Dyer 
9769d8dc3e5SNick Dyer 	/* Process first message */
9779d8dc3e5SNick Dyer 	ret = mxt_proc_message(data, data->msg_buf + 1);
9789d8dc3e5SNick Dyer 	if (ret < 0) {
9799d8dc3e5SNick Dyer 		dev_warn(dev, "Unexpected invalid message\n");
9809d8dc3e5SNick Dyer 		return IRQ_NONE;
9819d8dc3e5SNick Dyer 	}
9829d8dc3e5SNick Dyer 
9839d8dc3e5SNick Dyer 	num_left = count - 1;
9849d8dc3e5SNick Dyer 
9859d8dc3e5SNick Dyer 	/* Process remaining messages if necessary */
9869d8dc3e5SNick Dyer 	if (num_left) {
9879d8dc3e5SNick Dyer 		ret = mxt_read_and_process_messages(data, num_left);
9889d8dc3e5SNick Dyer 		if (ret < 0)
9899d8dc3e5SNick Dyer 			goto end;
9909d8dc3e5SNick Dyer 		else if (ret != num_left)
9919d8dc3e5SNick Dyer 			dev_warn(dev, "Unexpected invalid message\n");
9929d8dc3e5SNick Dyer 	}
9939d8dc3e5SNick Dyer 
9949d8dc3e5SNick Dyer end:
9959d8dc3e5SNick Dyer 	if (data->update_input) {
9969d8dc3e5SNick Dyer 		mxt_input_sync(data);
9979d8dc3e5SNick Dyer 		data->update_input = false;
9989d8dc3e5SNick Dyer 	}
9999d8dc3e5SNick Dyer 
10009d8dc3e5SNick Dyer 	return IRQ_HANDLED;
10019d8dc3e5SNick Dyer }
10029d8dc3e5SNick Dyer 
10039d8dc3e5SNick Dyer static int mxt_process_messages_until_invalid(struct mxt_data *data)
10049d8dc3e5SNick Dyer {
10059d8dc3e5SNick Dyer 	struct device *dev = &data->client->dev;
10069d8dc3e5SNick Dyer 	int count, read;
10079d8dc3e5SNick Dyer 	u8 tries = 2;
10089d8dc3e5SNick Dyer 
10099d8dc3e5SNick Dyer 	count = data->max_reportid;
10109d8dc3e5SNick Dyer 
10119d8dc3e5SNick Dyer 	/* Read messages until we force an invalid */
10129d8dc3e5SNick Dyer 	do {
10139d8dc3e5SNick Dyer 		read = mxt_read_and_process_messages(data, count);
10149d8dc3e5SNick Dyer 		if (read < count)
10159d8dc3e5SNick Dyer 			return 0;
10169d8dc3e5SNick Dyer 	} while (--tries);
10179d8dc3e5SNick Dyer 
10189d8dc3e5SNick Dyer 	if (data->update_input) {
10199d8dc3e5SNick Dyer 		mxt_input_sync(data);
10209d8dc3e5SNick Dyer 		data->update_input = false;
10219d8dc3e5SNick Dyer 	}
10229d8dc3e5SNick Dyer 
10239d8dc3e5SNick Dyer 	dev_err(dev, "CHG pin isn't cleared\n");
10249d8dc3e5SNick Dyer 	return -EBUSY;
10259d8dc3e5SNick Dyer }
10269d8dc3e5SNick Dyer 
10279d8dc3e5SNick Dyer static irqreturn_t mxt_process_messages(struct mxt_data *data)
10289d8dc3e5SNick Dyer {
10299d8dc3e5SNick Dyer 	int total_handled, num_handled;
10309d8dc3e5SNick Dyer 	u8 count = data->last_message_count;
10319d8dc3e5SNick Dyer 
10329d8dc3e5SNick Dyer 	if (count < 1 || count > data->max_reportid)
10339d8dc3e5SNick Dyer 		count = 1;
10349d8dc3e5SNick Dyer 
10359d8dc3e5SNick Dyer 	/* include final invalid message */
10369d8dc3e5SNick Dyer 	total_handled = mxt_read_and_process_messages(data, count + 1);
10379d8dc3e5SNick Dyer 	if (total_handled < 0)
10389d8dc3e5SNick Dyer 		return IRQ_NONE;
10399d8dc3e5SNick Dyer 	/* if there were invalid messages, then we are done */
10409d8dc3e5SNick Dyer 	else if (total_handled <= count)
10419d8dc3e5SNick Dyer 		goto update_count;
10429d8dc3e5SNick Dyer 
10439d8dc3e5SNick Dyer 	/* keep reading two msgs until one is invalid or reportid limit */
10449d8dc3e5SNick Dyer 	do {
10459d8dc3e5SNick Dyer 		num_handled = mxt_read_and_process_messages(data, 2);
10469d8dc3e5SNick Dyer 		if (num_handled < 0)
10479d8dc3e5SNick Dyer 			return IRQ_NONE;
10489d8dc3e5SNick Dyer 
10499d8dc3e5SNick Dyer 		total_handled += num_handled;
10509d8dc3e5SNick Dyer 
10519d8dc3e5SNick Dyer 		if (num_handled < 2)
10529d8dc3e5SNick Dyer 			break;
10539d8dc3e5SNick Dyer 	} while (total_handled < data->num_touchids);
10549d8dc3e5SNick Dyer 
10559d8dc3e5SNick Dyer update_count:
10569d8dc3e5SNick Dyer 	data->last_message_count = total_handled;
10574cf51c38SJoonyoung Shim 
1058b9b05a89SNick Dyer 	if (data->update_input) {
1059b735fbe0SBenson Leung 		mxt_input_sync(data);
1060b9b05a89SNick Dyer 		data->update_input = false;
1061b9b05a89SNick Dyer 	}
106264464ae8SDaniel Kurtz 
10634cf51c38SJoonyoung Shim 	return IRQ_HANDLED;
10644cf51c38SJoonyoung Shim }
10654cf51c38SJoonyoung Shim 
1066d79e7e47SBenson Leung static irqreturn_t mxt_interrupt(int irq, void *dev_id)
1067d79e7e47SBenson Leung {
1068d79e7e47SBenson Leung 	struct mxt_data *data = dev_id;
1069d79e7e47SBenson Leung 
1070d79e7e47SBenson Leung 	if (data->in_bootloader) {
1071d79e7e47SBenson Leung 		/* bootloader state transition completion */
1072d79e7e47SBenson Leung 		complete(&data->bl_completion);
1073d79e7e47SBenson Leung 		return IRQ_HANDLED;
1074d79e7e47SBenson Leung 	}
1075d79e7e47SBenson Leung 
1076dd24dcf5SNick Dyer 	if (!data->object_table)
1077dd24dcf5SNick Dyer 		return IRQ_HANDLED;
1078dd24dcf5SNick Dyer 
10799d8dc3e5SNick Dyer 	if (data->T44_address) {
10809d8dc3e5SNick Dyer 		return mxt_process_messages_t44(data);
10819d8dc3e5SNick Dyer 	} else {
10829d8dc3e5SNick Dyer 		return mxt_process_messages(data);
10839d8dc3e5SNick Dyer 	}
1084d79e7e47SBenson Leung }
1085d79e7e47SBenson Leung 
1086a4a2ef46SIiro Valkonen static int mxt_t6_command(struct mxt_data *data, u16 cmd_offset,
1087a4a2ef46SIiro Valkonen 			  u8 value, bool wait)
1088a4a2ef46SIiro Valkonen {
1089a4a2ef46SIiro Valkonen 	u16 reg;
1090a4a2ef46SIiro Valkonen 	u8 command_register;
1091a4a2ef46SIiro Valkonen 	int timeout_counter = 0;
1092a4a2ef46SIiro Valkonen 	int ret;
1093a4a2ef46SIiro Valkonen 
1094a4a2ef46SIiro Valkonen 	reg = data->T6_address + cmd_offset;
1095a4a2ef46SIiro Valkonen 
1096a4a2ef46SIiro Valkonen 	ret = mxt_write_reg(data->client, reg, value);
1097a4a2ef46SIiro Valkonen 	if (ret)
1098a4a2ef46SIiro Valkonen 		return ret;
1099a4a2ef46SIiro Valkonen 
1100a4a2ef46SIiro Valkonen 	if (!wait)
1101a4a2ef46SIiro Valkonen 		return 0;
1102a4a2ef46SIiro Valkonen 
1103a4a2ef46SIiro Valkonen 	do {
1104a4a2ef46SIiro Valkonen 		msleep(20);
1105a4a2ef46SIiro Valkonen 		ret = __mxt_read_reg(data->client, reg, 1, &command_register);
1106a4a2ef46SIiro Valkonen 		if (ret)
1107a4a2ef46SIiro Valkonen 			return ret;
1108a4a2ef46SIiro Valkonen 	} while (command_register != 0 && timeout_counter++ <= 100);
1109a4a2ef46SIiro Valkonen 
1110a4a2ef46SIiro Valkonen 	if (timeout_counter > 100) {
1111a4a2ef46SIiro Valkonen 		dev_err(&data->client->dev, "Command failed!\n");
1112a4a2ef46SIiro Valkonen 		return -EIO;
1113a4a2ef46SIiro Valkonen 	}
1114a4a2ef46SIiro Valkonen 
1115a4a2ef46SIiro Valkonen 	return 0;
1116a4a2ef46SIiro Valkonen }
1117a4a2ef46SIiro Valkonen 
1118eb43335cSNick Dyer static int mxt_acquire_irq(struct mxt_data *data)
1119eb43335cSNick Dyer {
1120eb43335cSNick Dyer 	int error;
1121eb43335cSNick Dyer 
1122eb43335cSNick Dyer 	enable_irq(data->irq);
1123eb43335cSNick Dyer 
1124eb43335cSNick Dyer 	error = mxt_process_messages_until_invalid(data);
1125eb43335cSNick Dyer 	if (error)
1126eb43335cSNick Dyer 		return error;
1127eb43335cSNick Dyer 
1128eb43335cSNick Dyer 	return 0;
1129eb43335cSNick Dyer }
1130eb43335cSNick Dyer 
1131a4a2ef46SIiro Valkonen static int mxt_soft_reset(struct mxt_data *data)
1132a4a2ef46SIiro Valkonen {
1133a4a2ef46SIiro Valkonen 	struct device *dev = &data->client->dev;
1134a4a2ef46SIiro Valkonen 	int ret = 0;
1135a4a2ef46SIiro Valkonen 
1136885f3fb9SNick Dyer 	dev_info(dev, "Resetting device\n");
1137885f3fb9SNick Dyer 
1138885f3fb9SNick Dyer 	disable_irq(data->irq);
1139a4a2ef46SIiro Valkonen 
1140a4a2ef46SIiro Valkonen 	reinit_completion(&data->reset_completion);
1141a4a2ef46SIiro Valkonen 
1142a4a2ef46SIiro Valkonen 	ret = mxt_t6_command(data, MXT_COMMAND_RESET, MXT_RESET_VALUE, false);
1143a4a2ef46SIiro Valkonen 	if (ret)
1144a4a2ef46SIiro Valkonen 		return ret;
1145a4a2ef46SIiro Valkonen 
1146885f3fb9SNick Dyer 	/* Ignore CHG line for 100ms after reset */
1147885f3fb9SNick Dyer 	msleep(100);
1148885f3fb9SNick Dyer 
1149eb43335cSNick Dyer 	mxt_acquire_irq(data);
1150885f3fb9SNick Dyer 
1151a4a2ef46SIiro Valkonen 	ret = mxt_wait_for_completion(data, &data->reset_completion,
1152a4a2ef46SIiro Valkonen 				      MXT_RESET_TIMEOUT);
1153a4a2ef46SIiro Valkonen 	if (ret)
1154a4a2ef46SIiro Valkonen 		return ret;
1155a4a2ef46SIiro Valkonen 
1156a4a2ef46SIiro Valkonen 	return 0;
1157a4a2ef46SIiro Valkonen }
1158a4a2ef46SIiro Valkonen 
1159c3f78043SNick Dyer static void mxt_update_crc(struct mxt_data *data, u8 cmd, u8 value)
1160c3f78043SNick Dyer {
1161c3f78043SNick Dyer 	/*
1162c3f78043SNick Dyer 	 * On failure, CRC is set to 0 and config will always be
1163c3f78043SNick Dyer 	 * downloaded.
1164c3f78043SNick Dyer 	 */
1165c3f78043SNick Dyer 	data->config_crc = 0;
1166c3f78043SNick Dyer 	reinit_completion(&data->crc_completion);
1167c3f78043SNick Dyer 
1168c3f78043SNick Dyer 	mxt_t6_command(data, cmd, value, true);
1169c3f78043SNick Dyer 
1170c3f78043SNick Dyer 	/*
1171c3f78043SNick Dyer 	 * Wait for crc message. On failure, CRC is set to 0 and config will
1172c3f78043SNick Dyer 	 * always be downloaded.
1173c3f78043SNick Dyer 	 */
1174c3f78043SNick Dyer 	mxt_wait_for_completion(data, &data->crc_completion, MXT_CRC_TIMEOUT);
1175c3f78043SNick Dyer }
1176c3f78043SNick Dyer 
11774ce6fa01SNick Dyer static void mxt_calc_crc24(u32 *crc, u8 firstbyte, u8 secondbyte)
11784ce6fa01SNick Dyer {
11794ce6fa01SNick Dyer 	static const unsigned int crcpoly = 0x80001B;
11804ce6fa01SNick Dyer 	u32 result;
11814ce6fa01SNick Dyer 	u32 data_word;
11824ce6fa01SNick Dyer 
11834ce6fa01SNick Dyer 	data_word = (secondbyte << 8) | firstbyte;
11844ce6fa01SNick Dyer 	result = ((*crc << 1) ^ data_word);
11854ce6fa01SNick Dyer 
11864ce6fa01SNick Dyer 	if (result & 0x1000000)
11874ce6fa01SNick Dyer 		result ^= crcpoly;
11884ce6fa01SNick Dyer 
11894ce6fa01SNick Dyer 	*crc = result;
11904ce6fa01SNick Dyer }
11914ce6fa01SNick Dyer 
11924ce6fa01SNick Dyer static u32 mxt_calculate_crc(u8 *base, off_t start_off, off_t end_off)
11934ce6fa01SNick Dyer {
11944ce6fa01SNick Dyer 	u32 crc = 0;
11954ce6fa01SNick Dyer 	u8 *ptr = base + start_off;
11964ce6fa01SNick Dyer 	u8 *last_val = base + end_off - 1;
11974ce6fa01SNick Dyer 
11984ce6fa01SNick Dyer 	if (end_off < start_off)
11994ce6fa01SNick Dyer 		return -EINVAL;
12004ce6fa01SNick Dyer 
12014ce6fa01SNick Dyer 	while (ptr < last_val) {
12024ce6fa01SNick Dyer 		mxt_calc_crc24(&crc, *ptr, *(ptr + 1));
12034ce6fa01SNick Dyer 		ptr += 2;
12044ce6fa01SNick Dyer 	}
12054ce6fa01SNick Dyer 
12064ce6fa01SNick Dyer 	/* if len is odd, fill the last byte with 0 */
12074ce6fa01SNick Dyer 	if (ptr == last_val)
12084ce6fa01SNick Dyer 		mxt_calc_crc24(&crc, *ptr, 0);
12094ce6fa01SNick Dyer 
12104ce6fa01SNick Dyer 	/* Mask to 24-bit */
12114ce6fa01SNick Dyer 	crc &= 0x00FFFFFF;
12124ce6fa01SNick Dyer 
12134ce6fa01SNick Dyer 	return crc;
12144ce6fa01SNick Dyer }
12154ce6fa01SNick Dyer 
1216efdbd7aeSDmitry Torokhov static int mxt_prepare_cfg_mem(struct mxt_data *data,
1217efdbd7aeSDmitry Torokhov 			       const struct firmware *cfg,
1218efdbd7aeSDmitry Torokhov 			       unsigned int data_pos,
1219efdbd7aeSDmitry Torokhov 			       unsigned int cfg_start_ofs,
1220efdbd7aeSDmitry Torokhov 			       u8 *config_mem,
1221efdbd7aeSDmitry Torokhov 			       size_t config_mem_size)
12224cf51c38SJoonyoung Shim {
12234cf51c38SJoonyoung Shim 	struct device *dev = &data->client->dev;
122450a77c65SNick Dyer 	struct mxt_object *object;
1225efdbd7aeSDmitry Torokhov 	unsigned int type, instance, size, byte_offset;
122650a77c65SNick Dyer 	int offset;
1227efdbd7aeSDmitry Torokhov 	int ret;
122850a77c65SNick Dyer 	int i;
122950a77c65SNick Dyer 	u16 reg;
1230efdbd7aeSDmitry Torokhov 	u8 val;
123150a77c65SNick Dyer 
12324ce6fa01SNick Dyer 	while (data_pos < cfg->size) {
123350a77c65SNick Dyer 		/* Read type, instance, length */
12344ce6fa01SNick Dyer 		ret = sscanf(cfg->data + data_pos, "%x %x %x%n",
123550a77c65SNick Dyer 			     &type, &instance, &size, &offset);
123650a77c65SNick Dyer 		if (ret == 0) {
123750a77c65SNick Dyer 			/* EOF */
12384ce6fa01SNick Dyer 			break;
123950a77c65SNick Dyer 		} else if (ret != 3) {
124050a77c65SNick Dyer 			dev_err(dev, "Bad format: failed to parse object\n");
1241efdbd7aeSDmitry Torokhov 			return -EINVAL;
124250a77c65SNick Dyer 		}
12434ce6fa01SNick Dyer 		data_pos += offset;
124450a77c65SNick Dyer 
124550a77c65SNick Dyer 		object = mxt_get_object(data, type);
124650a77c65SNick Dyer 		if (!object) {
124750a77c65SNick Dyer 			/* Skip object */
124850a77c65SNick Dyer 			for (i = 0; i < size; i++) {
12494ce6fa01SNick Dyer 				ret = sscanf(cfg->data + data_pos, "%hhx%n",
1250041fa159SDmitry Torokhov 					     &val, &offset);
1251041fa159SDmitry Torokhov 				if (ret != 1) {
1252041fa159SDmitry Torokhov 					dev_err(dev, "Bad format in T%d at %d\n",
1253041fa159SDmitry Torokhov 						type, i);
1254041fa159SDmitry Torokhov 					return -EINVAL;
1255041fa159SDmitry Torokhov 				}
12564ce6fa01SNick Dyer 				data_pos += offset;
125750a77c65SNick Dyer 			}
125850a77c65SNick Dyer 			continue;
125950a77c65SNick Dyer 		}
126050a77c65SNick Dyer 
126150a77c65SNick Dyer 		if (size > mxt_obj_size(object)) {
12624ce6fa01SNick Dyer 			/*
12634ce6fa01SNick Dyer 			 * Either we are in fallback mode due to wrong
12644ce6fa01SNick Dyer 			 * config or config from a later fw version,
12654ce6fa01SNick Dyer 			 * or the file is corrupt or hand-edited.
12664ce6fa01SNick Dyer 			 */
12674ce6fa01SNick Dyer 			dev_warn(dev, "Discarding %zu byte(s) in T%u\n",
126850a77c65SNick Dyer 				 size - mxt_obj_size(object), type);
12694ce6fa01SNick Dyer 		} else if (mxt_obj_size(object) > size) {
12704ce6fa01SNick Dyer 			/*
12714ce6fa01SNick Dyer 			 * If firmware is upgraded, new bytes may be added to
12724ce6fa01SNick Dyer 			 * end of objects. It is generally forward compatible
12734ce6fa01SNick Dyer 			 * to zero these bytes - previous behaviour will be
12744ce6fa01SNick Dyer 			 * retained. However this does invalidate the CRC and
12754ce6fa01SNick Dyer 			 * will force fallback mode until the configuration is
12764ce6fa01SNick Dyer 			 * updated. We warn here but do nothing else - the
12774ce6fa01SNick Dyer 			 * malloc has zeroed the entire configuration.
12784ce6fa01SNick Dyer 			 */
12794ce6fa01SNick Dyer 			dev_warn(dev, "Zeroing %zu byte(s) in T%d\n",
12804ce6fa01SNick Dyer 				 mxt_obj_size(object) - size, type);
128150a77c65SNick Dyer 		}
128250a77c65SNick Dyer 
128350a77c65SNick Dyer 		if (instance >= mxt_obj_instances(object)) {
128450a77c65SNick Dyer 			dev_err(dev, "Object instances exceeded!\n");
1285efdbd7aeSDmitry Torokhov 			return -EINVAL;
128650a77c65SNick Dyer 		}
128750a77c65SNick Dyer 
128850a77c65SNick Dyer 		reg = object->start_address + mxt_obj_size(object) * instance;
128950a77c65SNick Dyer 
129050a77c65SNick Dyer 		for (i = 0; i < size; i++) {
12914ce6fa01SNick Dyer 			ret = sscanf(cfg->data + data_pos, "%hhx%n",
129250a77c65SNick Dyer 				     &val,
129350a77c65SNick Dyer 				     &offset);
129450a77c65SNick Dyer 			if (ret != 1) {
1295041fa159SDmitry Torokhov 				dev_err(dev, "Bad format in T%d at %d\n",
1296041fa159SDmitry Torokhov 					type, i);
1297efdbd7aeSDmitry Torokhov 				return -EINVAL;
129850a77c65SNick Dyer 			}
12994ce6fa01SNick Dyer 			data_pos += offset;
130050a77c65SNick Dyer 
130150a77c65SNick Dyer 			if (i > mxt_obj_size(object))
13024cf51c38SJoonyoung Shim 				continue;
13034cf51c38SJoonyoung Shim 
13044ce6fa01SNick Dyer 			byte_offset = reg + i - cfg_start_ofs;
130550a77c65SNick Dyer 
1306041fa159SDmitry Torokhov 			if (byte_offset >= 0 && byte_offset < config_mem_size) {
13074ce6fa01SNick Dyer 				*(config_mem + byte_offset) = val;
13084ce6fa01SNick Dyer 			} else {
13094ce6fa01SNick Dyer 				dev_err(dev, "Bad object: reg:%d, T%d, ofs=%d\n",
13104ce6fa01SNick Dyer 					reg, object->type, byte_offset);
1311efdbd7aeSDmitry Torokhov 				return -EINVAL;
1312efdbd7aeSDmitry Torokhov 			}
1313efdbd7aeSDmitry Torokhov 		}
1314efdbd7aeSDmitry Torokhov 	}
1315efdbd7aeSDmitry Torokhov 
1316efdbd7aeSDmitry Torokhov 	return 0;
1317efdbd7aeSDmitry Torokhov }
1318efdbd7aeSDmitry Torokhov 
1319efdbd7aeSDmitry Torokhov static int mxt_upload_cfg_mem(struct mxt_data *data, unsigned int cfg_start,
1320efdbd7aeSDmitry Torokhov 			      u8 *config_mem, size_t config_mem_size)
1321efdbd7aeSDmitry Torokhov {
1322efdbd7aeSDmitry Torokhov 	unsigned int byte_offset = 0;
1323efdbd7aeSDmitry Torokhov 	int error;
1324efdbd7aeSDmitry Torokhov 
1325efdbd7aeSDmitry Torokhov 	/* Write configuration as blocks */
1326efdbd7aeSDmitry Torokhov 	while (byte_offset < config_mem_size) {
1327efdbd7aeSDmitry Torokhov 		unsigned int size = config_mem_size - byte_offset;
1328efdbd7aeSDmitry Torokhov 
1329efdbd7aeSDmitry Torokhov 		if (size > MXT_MAX_BLOCK_WRITE)
1330efdbd7aeSDmitry Torokhov 			size = MXT_MAX_BLOCK_WRITE;
1331efdbd7aeSDmitry Torokhov 
1332efdbd7aeSDmitry Torokhov 		error = __mxt_write_reg(data->client,
1333efdbd7aeSDmitry Torokhov 					cfg_start + byte_offset,
1334efdbd7aeSDmitry Torokhov 					size, config_mem + byte_offset);
1335efdbd7aeSDmitry Torokhov 		if (error) {
1336efdbd7aeSDmitry Torokhov 			dev_err(&data->client->dev,
1337efdbd7aeSDmitry Torokhov 				"Config write error, ret=%d\n", error);
1338efdbd7aeSDmitry Torokhov 			return error;
1339efdbd7aeSDmitry Torokhov 		}
1340efdbd7aeSDmitry Torokhov 
1341efdbd7aeSDmitry Torokhov 		byte_offset += size;
1342efdbd7aeSDmitry Torokhov 	}
1343efdbd7aeSDmitry Torokhov 
1344efdbd7aeSDmitry Torokhov 	return 0;
1345efdbd7aeSDmitry Torokhov }
1346efdbd7aeSDmitry Torokhov 
13477f3884f7SNick Dyer static int mxt_init_t7_power_cfg(struct mxt_data *data);
13487f3884f7SNick Dyer 
1349efdbd7aeSDmitry Torokhov /*
1350efdbd7aeSDmitry Torokhov  * mxt_update_cfg - download configuration to chip
1351efdbd7aeSDmitry Torokhov  *
1352efdbd7aeSDmitry Torokhov  * Atmel Raw Config File Format
1353efdbd7aeSDmitry Torokhov  *
1354efdbd7aeSDmitry Torokhov  * The first four lines of the raw config file contain:
1355efdbd7aeSDmitry Torokhov  *  1) Version
1356efdbd7aeSDmitry Torokhov  *  2) Chip ID Information (first 7 bytes of device memory)
1357efdbd7aeSDmitry Torokhov  *  3) Chip Information Block 24-bit CRC Checksum
1358efdbd7aeSDmitry Torokhov  *  4) Chip Configuration 24-bit CRC Checksum
1359efdbd7aeSDmitry Torokhov  *
1360efdbd7aeSDmitry Torokhov  * The rest of the file consists of one line per object instance:
1361efdbd7aeSDmitry Torokhov  *   <TYPE> <INSTANCE> <SIZE> <CONTENTS>
1362efdbd7aeSDmitry Torokhov  *
1363efdbd7aeSDmitry Torokhov  *   <TYPE> - 2-byte object type as hex
1364efdbd7aeSDmitry Torokhov  *   <INSTANCE> - 2-byte object instance number as hex
1365efdbd7aeSDmitry Torokhov  *   <SIZE> - 2-byte object size as hex
1366efdbd7aeSDmitry Torokhov  *   <CONTENTS> - array of <SIZE> 1-byte hex values
1367efdbd7aeSDmitry Torokhov  */
1368efdbd7aeSDmitry Torokhov static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
1369efdbd7aeSDmitry Torokhov {
1370efdbd7aeSDmitry Torokhov 	struct device *dev = &data->client->dev;
1371efdbd7aeSDmitry Torokhov 	struct mxt_info cfg_info;
1372efdbd7aeSDmitry Torokhov 	int ret;
1373efdbd7aeSDmitry Torokhov 	int offset;
1374efdbd7aeSDmitry Torokhov 	int data_pos;
1375efdbd7aeSDmitry Torokhov 	int i;
1376efdbd7aeSDmitry Torokhov 	int cfg_start_ofs;
1377efdbd7aeSDmitry Torokhov 	u32 info_crc, config_crc, calculated_crc;
1378efdbd7aeSDmitry Torokhov 	u8 *config_mem;
1379efdbd7aeSDmitry Torokhov 	size_t config_mem_size;
1380efdbd7aeSDmitry Torokhov 
1381efdbd7aeSDmitry Torokhov 	mxt_update_crc(data, MXT_COMMAND_REPORTALL, 1);
1382efdbd7aeSDmitry Torokhov 
1383efdbd7aeSDmitry Torokhov 	if (strncmp(cfg->data, MXT_CFG_MAGIC, strlen(MXT_CFG_MAGIC))) {
1384efdbd7aeSDmitry Torokhov 		dev_err(dev, "Unrecognised config file\n");
1385efdbd7aeSDmitry Torokhov 		return -EINVAL;
1386efdbd7aeSDmitry Torokhov 	}
1387efdbd7aeSDmitry Torokhov 
1388efdbd7aeSDmitry Torokhov 	data_pos = strlen(MXT_CFG_MAGIC);
1389efdbd7aeSDmitry Torokhov 
1390efdbd7aeSDmitry Torokhov 	/* Load information block and check */
1391efdbd7aeSDmitry Torokhov 	for (i = 0; i < sizeof(struct mxt_info); i++) {
1392efdbd7aeSDmitry Torokhov 		ret = sscanf(cfg->data + data_pos, "%hhx%n",
1393efdbd7aeSDmitry Torokhov 			     (unsigned char *)&cfg_info + i,
1394efdbd7aeSDmitry Torokhov 			     &offset);
1395efdbd7aeSDmitry Torokhov 		if (ret != 1) {
1396efdbd7aeSDmitry Torokhov 			dev_err(dev, "Bad format\n");
1397efdbd7aeSDmitry Torokhov 			return -EINVAL;
1398efdbd7aeSDmitry Torokhov 		}
1399efdbd7aeSDmitry Torokhov 
1400efdbd7aeSDmitry Torokhov 		data_pos += offset;
1401efdbd7aeSDmitry Torokhov 	}
1402efdbd7aeSDmitry Torokhov 
1403efdbd7aeSDmitry Torokhov 	if (cfg_info.family_id != data->info.family_id) {
1404efdbd7aeSDmitry Torokhov 		dev_err(dev, "Family ID mismatch!\n");
1405efdbd7aeSDmitry Torokhov 		return -EINVAL;
1406efdbd7aeSDmitry Torokhov 	}
1407efdbd7aeSDmitry Torokhov 
1408efdbd7aeSDmitry Torokhov 	if (cfg_info.variant_id != data->info.variant_id) {
1409efdbd7aeSDmitry Torokhov 		dev_err(dev, "Variant ID mismatch!\n");
1410efdbd7aeSDmitry Torokhov 		return -EINVAL;
1411efdbd7aeSDmitry Torokhov 	}
1412efdbd7aeSDmitry Torokhov 
1413efdbd7aeSDmitry Torokhov 	/* Read CRCs */
1414efdbd7aeSDmitry Torokhov 	ret = sscanf(cfg->data + data_pos, "%x%n", &info_crc, &offset);
1415efdbd7aeSDmitry Torokhov 	if (ret != 1) {
1416efdbd7aeSDmitry Torokhov 		dev_err(dev, "Bad format: failed to parse Info CRC\n");
1417efdbd7aeSDmitry Torokhov 		return -EINVAL;
1418efdbd7aeSDmitry Torokhov 	}
1419efdbd7aeSDmitry Torokhov 	data_pos += offset;
1420efdbd7aeSDmitry Torokhov 
1421efdbd7aeSDmitry Torokhov 	ret = sscanf(cfg->data + data_pos, "%x%n", &config_crc, &offset);
1422efdbd7aeSDmitry Torokhov 	if (ret != 1) {
1423efdbd7aeSDmitry Torokhov 		dev_err(dev, "Bad format: failed to parse Config CRC\n");
1424efdbd7aeSDmitry Torokhov 		return -EINVAL;
1425efdbd7aeSDmitry Torokhov 	}
1426efdbd7aeSDmitry Torokhov 	data_pos += offset;
1427efdbd7aeSDmitry Torokhov 
1428efdbd7aeSDmitry Torokhov 	/*
1429efdbd7aeSDmitry Torokhov 	 * The Info Block CRC is calculated over mxt_info and the object
1430efdbd7aeSDmitry Torokhov 	 * table. If it does not match then we are trying to load the
1431efdbd7aeSDmitry Torokhov 	 * configuration from a different chip or firmware version, so
1432efdbd7aeSDmitry Torokhov 	 * the configuration CRC is invalid anyway.
1433efdbd7aeSDmitry Torokhov 	 */
1434efdbd7aeSDmitry Torokhov 	if (info_crc == data->info_crc) {
1435efdbd7aeSDmitry Torokhov 		if (config_crc == 0 || data->config_crc == 0) {
1436efdbd7aeSDmitry Torokhov 			dev_info(dev, "CRC zero, attempting to apply config\n");
1437efdbd7aeSDmitry Torokhov 		} else if (config_crc == data->config_crc) {
1438efdbd7aeSDmitry Torokhov 			dev_dbg(dev, "Config CRC 0x%06X: OK\n",
1439efdbd7aeSDmitry Torokhov 				 data->config_crc);
1440efdbd7aeSDmitry Torokhov 			return 0;
1441efdbd7aeSDmitry Torokhov 		} else {
1442efdbd7aeSDmitry Torokhov 			dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n",
1443efdbd7aeSDmitry Torokhov 				 data->config_crc, config_crc);
1444efdbd7aeSDmitry Torokhov 		}
1445efdbd7aeSDmitry Torokhov 	} else {
1446efdbd7aeSDmitry Torokhov 		dev_warn(dev,
1447efdbd7aeSDmitry Torokhov 			 "Warning: Info CRC error - device=0x%06X file=0x%06X\n",
1448efdbd7aeSDmitry Torokhov 			 data->info_crc, info_crc);
1449efdbd7aeSDmitry Torokhov 	}
1450efdbd7aeSDmitry Torokhov 
1451efdbd7aeSDmitry Torokhov 	/* Malloc memory to store configuration */
1452efdbd7aeSDmitry Torokhov 	cfg_start_ofs = MXT_OBJECT_START +
1453efdbd7aeSDmitry Torokhov 			data->info.object_num * sizeof(struct mxt_object) +
1454efdbd7aeSDmitry Torokhov 			MXT_INFO_CHECKSUM_SIZE;
1455efdbd7aeSDmitry Torokhov 	config_mem_size = data->mem_size - cfg_start_ofs;
1456efdbd7aeSDmitry Torokhov 	config_mem = kzalloc(config_mem_size, GFP_KERNEL);
1457efdbd7aeSDmitry Torokhov 	if (!config_mem) {
1458efdbd7aeSDmitry Torokhov 		dev_err(dev, "Failed to allocate memory\n");
1459efdbd7aeSDmitry Torokhov 		return -ENOMEM;
1460efdbd7aeSDmitry Torokhov 	}
1461efdbd7aeSDmitry Torokhov 
1462efdbd7aeSDmitry Torokhov 	ret = mxt_prepare_cfg_mem(data, cfg, data_pos, cfg_start_ofs,
1463efdbd7aeSDmitry Torokhov 				  config_mem, config_mem_size);
1464efdbd7aeSDmitry Torokhov 	if (ret)
14654ce6fa01SNick Dyer 		goto release_mem;
14664cf51c38SJoonyoung Shim 
14674ce6fa01SNick Dyer 	/* Calculate crc of the received configs (not the raw config file) */
14684ce6fa01SNick Dyer 	if (data->T7_address < cfg_start_ofs) {
14694ce6fa01SNick Dyer 		dev_err(dev, "Bad T7 address, T7addr = %x, config offset %x\n",
14704ce6fa01SNick Dyer 			data->T7_address, cfg_start_ofs);
14714ce6fa01SNick Dyer 		ret = 0;
14724ce6fa01SNick Dyer 		goto release_mem;
14734ce6fa01SNick Dyer 	}
14744ce6fa01SNick Dyer 
14754ce6fa01SNick Dyer 	calculated_crc = mxt_calculate_crc(config_mem,
14764ce6fa01SNick Dyer 					   data->T7_address - cfg_start_ofs,
14774ce6fa01SNick Dyer 					   config_mem_size);
14784ce6fa01SNick Dyer 
1479efdbd7aeSDmitry Torokhov 	if (config_crc > 0 && config_crc != calculated_crc)
14804ce6fa01SNick Dyer 		dev_warn(dev, "Config CRC error, calculated=%06X, file=%06X\n",
14814ce6fa01SNick Dyer 			 calculated_crc, config_crc);
14824ce6fa01SNick Dyer 
1483efdbd7aeSDmitry Torokhov 	ret = mxt_upload_cfg_mem(data, cfg_start_ofs,
1484efdbd7aeSDmitry Torokhov 				 config_mem, config_mem_size);
1485efdbd7aeSDmitry Torokhov 	if (ret)
14864ce6fa01SNick Dyer 		goto release_mem;
14874ce6fa01SNick Dyer 
1488c3f78043SNick Dyer 	mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE);
1489c3f78043SNick Dyer 
1490c3f78043SNick Dyer 	ret = mxt_soft_reset(data);
1491c3f78043SNick Dyer 	if (ret)
14924ce6fa01SNick Dyer 		goto release_mem;
1493c3f78043SNick Dyer 
1494c3f78043SNick Dyer 	dev_info(dev, "Config successfully updated\n");
1495c3f78043SNick Dyer 
14967f3884f7SNick Dyer 	/* T7 config may have changed */
14977f3884f7SNick Dyer 	mxt_init_t7_power_cfg(data);
14987f3884f7SNick Dyer 
14994ce6fa01SNick Dyer release_mem:
15004ce6fa01SNick Dyer 	kfree(config_mem);
150150a77c65SNick Dyer 	return ret;
15024cf51c38SJoonyoung Shim }
15034cf51c38SJoonyoung Shim 
15047686b108SIiro Valkonen static int mxt_get_info(struct mxt_data *data)
15054cf51c38SJoonyoung Shim {
15064cf51c38SJoonyoung Shim 	struct i2c_client *client = data->client;
15077686b108SIiro Valkonen 	struct mxt_info *info = &data->info;
15084cf51c38SJoonyoung Shim 	int error;
15094cf51c38SJoonyoung Shim 
151023003a84SDaniel Kurtz 	/* Read 7-byte info block starting at address 0 */
1511146c6a66SNick Dyer 	error = __mxt_read_reg(client, 0, sizeof(*info), info);
15124cf51c38SJoonyoung Shim 	if (error)
15134cf51c38SJoonyoung Shim 		return error;
15144cf51c38SJoonyoung Shim 
15154cf51c38SJoonyoung Shim 	return 0;
15164cf51c38SJoonyoung Shim }
15174cf51c38SJoonyoung Shim 
151858e4aeeeSStephen Warren static void mxt_free_input_device(struct mxt_data *data)
15195f3f9bc2SNick Dyer {
152058e4aeeeSStephen Warren 	if (data->input_dev) {
15215f3f9bc2SNick Dyer 		input_unregister_device(data->input_dev);
15225f3f9bc2SNick Dyer 		data->input_dev = NULL;
152358e4aeeeSStephen Warren 	}
152458e4aeeeSStephen Warren }
15255f3f9bc2SNick Dyer 
152658e4aeeeSStephen Warren static void mxt_free_object_table(struct mxt_data *data)
152758e4aeeeSStephen Warren {
15285f3f9bc2SNick Dyer 	kfree(data->object_table);
15295f3f9bc2SNick Dyer 	data->object_table = NULL;
15305f3f9bc2SNick Dyer 	kfree(data->msg_buf);
15315f3f9bc2SNick Dyer 	data->msg_buf = NULL;
1532b9b05a89SNick Dyer 	data->T5_address = 0;
15335f3f9bc2SNick Dyer 	data->T5_msg_size = 0;
15345f3f9bc2SNick Dyer 	data->T6_reportid = 0;
15355f3f9bc2SNick Dyer 	data->T7_address = 0;
15365f3f9bc2SNick Dyer 	data->T9_reportid_min = 0;
15375f3f9bc2SNick Dyer 	data->T9_reportid_max = 0;
15385f3f9bc2SNick Dyer 	data->T19_reportid = 0;
15399d8dc3e5SNick Dyer 	data->T44_address = 0;
1540b23157dcSNick Dyer 	data->T100_reportid_min = 0;
1541b23157dcSNick Dyer 	data->T100_reportid_max = 0;
15429d8dc3e5SNick Dyer 	data->max_reportid = 0;
15435f3f9bc2SNick Dyer }
15445f3f9bc2SNick Dyer 
15457686b108SIiro Valkonen static int mxt_get_object_table(struct mxt_data *data)
15464cf51c38SJoonyoung Shim {
1547333e5a9aSDaniel Kurtz 	struct i2c_client *client = data->client;
1548333e5a9aSDaniel Kurtz 	size_t table_size;
1549dd24dcf5SNick Dyer 	struct mxt_object *object_table;
15504cf51c38SJoonyoung Shim 	int error;
15514cf51c38SJoonyoung Shim 	int i;
1552333e5a9aSDaniel Kurtz 	u8 reportid;
15534ce6fa01SNick Dyer 	u16 end_address;
15544cf51c38SJoonyoung Shim 
1555333e5a9aSDaniel Kurtz 	table_size = data->info.object_num * sizeof(struct mxt_object);
1556dd24dcf5SNick Dyer 	object_table = kzalloc(table_size, GFP_KERNEL);
1557dd24dcf5SNick Dyer 	if (!object_table) {
1558dd24dcf5SNick Dyer 		dev_err(&data->client->dev, "Failed to allocate memory\n");
1559dd24dcf5SNick Dyer 		return -ENOMEM;
1560dd24dcf5SNick Dyer 	}
1561dd24dcf5SNick Dyer 
1562333e5a9aSDaniel Kurtz 	error = __mxt_read_reg(client, MXT_OBJECT_START, table_size,
1563dd24dcf5SNick Dyer 			object_table);
1564dd24dcf5SNick Dyer 	if (error) {
1565dd24dcf5SNick Dyer 		kfree(object_table);
15664cf51c38SJoonyoung Shim 		return error;
1567dd24dcf5SNick Dyer 	}
15684cf51c38SJoonyoung Shim 
1569333e5a9aSDaniel Kurtz 	/* Valid Report IDs start counting from 1 */
1570333e5a9aSDaniel Kurtz 	reportid = 1;
15714ce6fa01SNick Dyer 	data->mem_size = 0;
1572333e5a9aSDaniel Kurtz 	for (i = 0; i < data->info.object_num; i++) {
1573dd24dcf5SNick Dyer 		struct mxt_object *object = object_table + i;
1574333e5a9aSDaniel Kurtz 		u8 min_id, max_id;
1575333e5a9aSDaniel Kurtz 
1576333e5a9aSDaniel Kurtz 		le16_to_cpus(&object->start_address);
15774cf51c38SJoonyoung Shim 
15784cf51c38SJoonyoung Shim 		if (object->num_report_ids) {
1579333e5a9aSDaniel Kurtz 			min_id = reportid;
15804cf51c38SJoonyoung Shim 			reportid += object->num_report_ids *
15811e0c0c5bSDaniel Kurtz 					mxt_obj_instances(object);
1582333e5a9aSDaniel Kurtz 			max_id = reportid - 1;
1583333e5a9aSDaniel Kurtz 		} else {
1584333e5a9aSDaniel Kurtz 			min_id = 0;
1585333e5a9aSDaniel Kurtz 			max_id = 0;
1586333e5a9aSDaniel Kurtz 		}
1587333e5a9aSDaniel Kurtz 
1588333e5a9aSDaniel Kurtz 		dev_dbg(&data->client->dev,
15897bed6805SNick Dyer 			"T%u Start:%u Size:%zu Instances:%zu Report IDs:%u-%u\n",
15901e0c0c5bSDaniel Kurtz 			object->type, object->start_address,
15911e0c0c5bSDaniel Kurtz 			mxt_obj_size(object), mxt_obj_instances(object),
15921e0c0c5bSDaniel Kurtz 			min_id, max_id);
1593333e5a9aSDaniel Kurtz 
1594333e5a9aSDaniel Kurtz 		switch (object->type) {
15955f3f9bc2SNick Dyer 		case MXT_GEN_MESSAGE_T5:
1596437d4f37SNick Dyer 			if (data->info.family_id == 0x80 &&
1597437d4f37SNick Dyer 			    data->info.version < 0x20) {
15989d8dc3e5SNick Dyer 				/*
1599437d4f37SNick Dyer 				 * On mXT224 firmware versions prior to V2.0
1600437d4f37SNick Dyer 				 * read and discard unused CRC byte otherwise
1601437d4f37SNick Dyer 				 * DMA reads are misaligned.
16029d8dc3e5SNick Dyer 				 */
16039d8dc3e5SNick Dyer 				data->T5_msg_size = mxt_obj_size(object);
16049d8dc3e5SNick Dyer 			} else {
16059d8dc3e5SNick Dyer 				/* CRC not enabled, so skip last byte */
16065f3f9bc2SNick Dyer 				data->T5_msg_size = mxt_obj_size(object) - 1;
16079d8dc3e5SNick Dyer 			}
1608b9b05a89SNick Dyer 			data->T5_address = object->start_address;
1609041fa159SDmitry Torokhov 			break;
1610fdf80421SDaniel Kurtz 		case MXT_GEN_COMMAND_T6:
1611fdf80421SDaniel Kurtz 			data->T6_reportid = min_id;
1612a4a2ef46SIiro Valkonen 			data->T6_address = object->start_address;
1613fdf80421SDaniel Kurtz 			break;
16144ce6fa01SNick Dyer 		case MXT_GEN_POWER_T7:
16154ce6fa01SNick Dyer 			data->T7_address = object->start_address;
16164ce6fa01SNick Dyer 			break;
1617333e5a9aSDaniel Kurtz 		case MXT_TOUCH_MULTI_T9:
1618b23157dcSNick Dyer 			data->multitouch = MXT_TOUCH_MULTI_T9;
1619333e5a9aSDaniel Kurtz 			data->T9_reportid_min = min_id;
1620333e5a9aSDaniel Kurtz 			data->T9_reportid_max = max_id;
16219d8dc3e5SNick Dyer 			data->num_touchids = object->num_report_ids
16229d8dc3e5SNick Dyer 						* mxt_obj_instances(object);
16239d8dc3e5SNick Dyer 			break;
16249d8dc3e5SNick Dyer 		case MXT_SPT_MESSAGECOUNT_T44:
16259d8dc3e5SNick Dyer 			data->T44_address = object->start_address;
1626333e5a9aSDaniel Kurtz 			break;
162722dfab7fSDaniel Kurtz 		case MXT_SPT_GPIOPWM_T19:
162822dfab7fSDaniel Kurtz 			data->T19_reportid = min_id;
162922dfab7fSDaniel Kurtz 			break;
1630b23157dcSNick Dyer 		case MXT_TOUCH_MULTITOUCHSCREEN_T100:
1631b23157dcSNick Dyer 			data->multitouch = MXT_TOUCH_MULTITOUCHSCREEN_T100;
1632b23157dcSNick Dyer 			data->T100_reportid_min = min_id;
1633b23157dcSNick Dyer 			data->T100_reportid_max = max_id;
1634b23157dcSNick Dyer 			/* first two report IDs reserved */
1635b23157dcSNick Dyer 			data->num_touchids = object->num_report_ids - 2;
1636b23157dcSNick Dyer 			break;
16374cf51c38SJoonyoung Shim 		}
16384ce6fa01SNick Dyer 
16394ce6fa01SNick Dyer 		end_address = object->start_address
16404ce6fa01SNick Dyer 			+ mxt_obj_size(object) * mxt_obj_instances(object) - 1;
16414ce6fa01SNick Dyer 
16424ce6fa01SNick Dyer 		if (end_address >= data->mem_size)
16434ce6fa01SNick Dyer 			data->mem_size = end_address + 1;
16444cf51c38SJoonyoung Shim 	}
16454cf51c38SJoonyoung Shim 
16469d8dc3e5SNick Dyer 	/* Store maximum reportid */
16479d8dc3e5SNick Dyer 	data->max_reportid = reportid;
16489d8dc3e5SNick Dyer 
16499d8dc3e5SNick Dyer 	/* If T44 exists, T5 position has to be directly after */
16509d8dc3e5SNick Dyer 	if (data->T44_address && (data->T5_address != data->T44_address + 1)) {
16519d8dc3e5SNick Dyer 		dev_err(&client->dev, "Invalid T44 position\n");
16529d8dc3e5SNick Dyer 		error = -EINVAL;
16539d8dc3e5SNick Dyer 		goto free_object_table;
16549d8dc3e5SNick Dyer 	}
16559d8dc3e5SNick Dyer 
16569d8dc3e5SNick Dyer 	data->msg_buf = kcalloc(data->max_reportid,
16579d8dc3e5SNick Dyer 				data->T5_msg_size, GFP_KERNEL);
16585f3f9bc2SNick Dyer 	if (!data->msg_buf) {
16595f3f9bc2SNick Dyer 		dev_err(&client->dev, "Failed to allocate message buffer\n");
16605f3f9bc2SNick Dyer 		error = -ENOMEM;
16615f3f9bc2SNick Dyer 		goto free_object_table;
16625f3f9bc2SNick Dyer 	}
16635f3f9bc2SNick Dyer 
1664dd24dcf5SNick Dyer 	data->object_table = object_table;
1665dd24dcf5SNick Dyer 
16664cf51c38SJoonyoung Shim 	return 0;
16674cf51c38SJoonyoung Shim 
16685f3f9bc2SNick Dyer free_object_table:
16695f3f9bc2SNick Dyer 	mxt_free_object_table(data);
16705f3f9bc2SNick Dyer 	return error;
16717d4fa100SDaniel Kurtz }
16727d4fa100SDaniel Kurtz 
167361dc1abaSNick Dyer static int mxt_read_t9_resolution(struct mxt_data *data)
167461dc1abaSNick Dyer {
167561dc1abaSNick Dyer 	struct i2c_client *client = data->client;
167661dc1abaSNick Dyer 	int error;
167761dc1abaSNick Dyer 	struct t9_range range;
167861dc1abaSNick Dyer 	unsigned char orient;
167961dc1abaSNick Dyer 	struct mxt_object *object;
168061dc1abaSNick Dyer 
168161dc1abaSNick Dyer 	object = mxt_get_object(data, MXT_TOUCH_MULTI_T9);
168261dc1abaSNick Dyer 	if (!object)
168361dc1abaSNick Dyer 		return -EINVAL;
168461dc1abaSNick Dyer 
168561dc1abaSNick Dyer 	error = __mxt_read_reg(client,
168661dc1abaSNick Dyer 			       object->start_address + MXT_T9_RANGE,
168761dc1abaSNick Dyer 			       sizeof(range), &range);
168861dc1abaSNick Dyer 	if (error)
168961dc1abaSNick Dyer 		return error;
169061dc1abaSNick Dyer 
16911c0276d5SNick Dyer 	data->max_x = get_unaligned_le16(&range.x);
16921c0276d5SNick Dyer 	data->max_y = get_unaligned_le16(&range.y);
169361dc1abaSNick Dyer 
169461dc1abaSNick Dyer 	error =  __mxt_read_reg(client,
169561dc1abaSNick Dyer 				object->start_address + MXT_T9_ORIENT,
169661dc1abaSNick Dyer 				1, &orient);
169761dc1abaSNick Dyer 	if (error)
169861dc1abaSNick Dyer 		return error;
169961dc1abaSNick Dyer 
17001c0276d5SNick Dyer 	data->xy_switch = orient & MXT_T9_ORIENT_SWITCH;
170161dc1abaSNick Dyer 
170261dc1abaSNick Dyer 	return 0;
170361dc1abaSNick Dyer }
170461dc1abaSNick Dyer 
1705b23157dcSNick Dyer static int mxt_read_t100_config(struct mxt_data *data)
1706b23157dcSNick Dyer {
1707b23157dcSNick Dyer 	struct i2c_client *client = data->client;
1708b23157dcSNick Dyer 	int error;
1709b23157dcSNick Dyer 	struct mxt_object *object;
1710b23157dcSNick Dyer 	u16 range_x, range_y;
1711b23157dcSNick Dyer 	u8 cfg, tchaux;
1712b23157dcSNick Dyer 	u8 aux;
1713b23157dcSNick Dyer 
1714b23157dcSNick Dyer 	object = mxt_get_object(data, MXT_TOUCH_MULTITOUCHSCREEN_T100);
1715b23157dcSNick Dyer 	if (!object)
1716b23157dcSNick Dyer 		return -EINVAL;
1717b23157dcSNick Dyer 
17181c0276d5SNick Dyer 	/* read touchscreen dimensions */
1719b23157dcSNick Dyer 	error = __mxt_read_reg(client,
1720b23157dcSNick Dyer 			       object->start_address + MXT_T100_XRANGE,
1721b23157dcSNick Dyer 			       sizeof(range_x), &range_x);
1722b23157dcSNick Dyer 	if (error)
1723b23157dcSNick Dyer 		return error;
1724b23157dcSNick Dyer 
17251c0276d5SNick Dyer 	data->max_x = get_unaligned_le16(&range_x);
1726b23157dcSNick Dyer 
1727b23157dcSNick Dyer 	error = __mxt_read_reg(client,
1728b23157dcSNick Dyer 			       object->start_address + MXT_T100_YRANGE,
1729b23157dcSNick Dyer 			       sizeof(range_y), &range_y);
1730b23157dcSNick Dyer 	if (error)
1731b23157dcSNick Dyer 		return error;
1732b23157dcSNick Dyer 
17331c0276d5SNick Dyer 	data->max_y = get_unaligned_le16(&range_y);
1734b23157dcSNick Dyer 
17351c0276d5SNick Dyer 	/* read orientation config */
1736b23157dcSNick Dyer 	error =  __mxt_read_reg(client,
1737b23157dcSNick Dyer 				object->start_address + MXT_T100_CFG1,
1738b23157dcSNick Dyer 				1, &cfg);
1739b23157dcSNick Dyer 	if (error)
1740b23157dcSNick Dyer 		return error;
1741b23157dcSNick Dyer 
17421c0276d5SNick Dyer 	data->xy_switch = cfg & MXT_T100_CFG_SWITCHXY;
17431c0276d5SNick Dyer 
17441c0276d5SNick Dyer 	/* allocate aux bytes */
1745b23157dcSNick Dyer 	error =  __mxt_read_reg(client,
1746b23157dcSNick Dyer 				object->start_address + MXT_T100_TCHAUX,
1747b23157dcSNick Dyer 				1, &tchaux);
1748b23157dcSNick Dyer 	if (error)
1749b23157dcSNick Dyer 		return error;
1750b23157dcSNick Dyer 
1751b23157dcSNick Dyer 	aux = 6;
1752b23157dcSNick Dyer 
1753b23157dcSNick Dyer 	if (tchaux & MXT_T100_TCHAUX_VECT)
1754b23157dcSNick Dyer 		data->t100_aux_vect = aux++;
1755b23157dcSNick Dyer 
1756b23157dcSNick Dyer 	if (tchaux & MXT_T100_TCHAUX_AMPL)
1757b23157dcSNick Dyer 		data->t100_aux_ampl = aux++;
1758b23157dcSNick Dyer 
1759b23157dcSNick Dyer 	if (tchaux & MXT_T100_TCHAUX_AREA)
1760b23157dcSNick Dyer 		data->t100_aux_area = aux++;
1761b23157dcSNick Dyer 
1762b23157dcSNick Dyer 	dev_dbg(&client->dev,
1763b23157dcSNick Dyer 		"T100 aux mappings vect:%u ampl:%u area:%u\n",
1764b23157dcSNick Dyer 		data->t100_aux_vect, data->t100_aux_ampl, data->t100_aux_area);
1765b23157dcSNick Dyer 
1766b23157dcSNick Dyer 	return 0;
1767b23157dcSNick Dyer }
1768b23157dcSNick Dyer 
17697a53d609SNick Dyer static int mxt_input_open(struct input_dev *dev);
17707a53d609SNick Dyer static void mxt_input_close(struct input_dev *dev);
17717a53d609SNick Dyer 
1772b6d2d328SSjoerd Simons static void mxt_set_up_as_touchpad(struct input_dev *input_dev,
1773b6d2d328SSjoerd Simons 				   struct mxt_data *data)
1774b6d2d328SSjoerd Simons {
1775b6d2d328SSjoerd Simons 	const struct mxt_platform_data *pdata = data->pdata;
1776b6d2d328SSjoerd Simons 	int i;
1777b6d2d328SSjoerd Simons 
1778b6d2d328SSjoerd Simons 	input_dev->name = "Atmel maXTouch Touchpad";
1779b6d2d328SSjoerd Simons 
1780b6d2d328SSjoerd Simons 	__set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
1781b6d2d328SSjoerd Simons 
1782b6d2d328SSjoerd Simons 	input_abs_set_res(input_dev, ABS_X, MXT_PIXELS_PER_MM);
1783b6d2d328SSjoerd Simons 	input_abs_set_res(input_dev, ABS_Y, MXT_PIXELS_PER_MM);
1784b6d2d328SSjoerd Simons 	input_abs_set_res(input_dev, ABS_MT_POSITION_X,
1785b6d2d328SSjoerd Simons 			  MXT_PIXELS_PER_MM);
1786b6d2d328SSjoerd Simons 	input_abs_set_res(input_dev, ABS_MT_POSITION_Y,
1787b6d2d328SSjoerd Simons 			  MXT_PIXELS_PER_MM);
1788b6d2d328SSjoerd Simons 
1789b6d2d328SSjoerd Simons 	for (i = 0; i < pdata->t19_num_keys; i++)
1790b6d2d328SSjoerd Simons 		if (pdata->t19_keymap[i] != KEY_RESERVED)
1791b6d2d328SSjoerd Simons 			input_set_capability(input_dev, EV_KEY,
1792b6d2d328SSjoerd Simons 					     pdata->t19_keymap[i]);
1793b6d2d328SSjoerd Simons }
1794b6d2d328SSjoerd Simons 
1795b23157dcSNick Dyer static int mxt_initialize_input_device(struct mxt_data *data)
17967a53d609SNick Dyer {
17977a53d609SNick Dyer 	const struct mxt_platform_data *pdata = data->pdata;
1798b6d2d328SSjoerd Simons 	struct device *dev = &data->client->dev;
17997a53d609SNick Dyer 	struct input_dev *input_dev;
18007a53d609SNick Dyer 	int error;
18017a53d609SNick Dyer 	unsigned int num_mt_slots;
18027a53d609SNick Dyer 	unsigned int mt_flags = 0;
18037a53d609SNick Dyer 
1804b23157dcSNick Dyer 	switch (data->multitouch) {
1805b23157dcSNick Dyer 	case MXT_TOUCH_MULTI_T9:
1806b23157dcSNick Dyer 		num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1;
18077a53d609SNick Dyer 		error = mxt_read_t9_resolution(data);
18087a53d609SNick Dyer 		if (error)
18097a53d609SNick Dyer 			dev_warn(dev, "Failed to initialize T9 resolution\n");
1810b23157dcSNick Dyer 		break;
1811b23157dcSNick Dyer 
1812b23157dcSNick Dyer 	case MXT_TOUCH_MULTITOUCHSCREEN_T100:
1813b23157dcSNick Dyer 		num_mt_slots = data->num_touchids;
1814b23157dcSNick Dyer 		error = mxt_read_t100_config(data);
1815b23157dcSNick Dyer 		if (error)
1816b23157dcSNick Dyer 			dev_warn(dev, "Failed to read T100 config\n");
1817b23157dcSNick Dyer 		break;
1818b23157dcSNick Dyer 
1819b23157dcSNick Dyer 	default:
1820b23157dcSNick Dyer 		dev_err(dev, "Invalid multitouch object\n");
1821b23157dcSNick Dyer 		return -EINVAL;
1822b23157dcSNick Dyer 	}
18237a53d609SNick Dyer 
18241c0276d5SNick Dyer 	/* Handle default values and orientation switch */
18251c0276d5SNick Dyer 	if (data->max_x == 0)
18261c0276d5SNick Dyer 		data->max_x = 1023;
18271c0276d5SNick Dyer 
18281c0276d5SNick Dyer 	if (data->max_y == 0)
18291c0276d5SNick Dyer 		data->max_y = 1023;
18301c0276d5SNick Dyer 
18311c0276d5SNick Dyer 	if (data->xy_switch)
18321c0276d5SNick Dyer 		swap(data->max_x, data->max_y);
18331c0276d5SNick Dyer 
18341c0276d5SNick Dyer 	dev_info(dev, "Touchscreen size X%uY%u\n", data->max_x, data->max_y);
18351c0276d5SNick Dyer 
18361c0276d5SNick Dyer 	/* Register input device */
18377a53d609SNick Dyer 	input_dev = input_allocate_device();
18387a53d609SNick Dyer 	if (!input_dev) {
18397a53d609SNick Dyer 		dev_err(dev, "Failed to allocate memory\n");
18407a53d609SNick Dyer 		return -ENOMEM;
18417a53d609SNick Dyer 	}
18427a53d609SNick Dyer 
18437a53d609SNick Dyer 	input_dev->name = "Atmel maXTouch Touchscreen";
18447a53d609SNick Dyer 	input_dev->phys = data->phys;
18457a53d609SNick Dyer 	input_dev->id.bustype = BUS_I2C;
18467a53d609SNick Dyer 	input_dev->dev.parent = dev;
18477a53d609SNick Dyer 	input_dev->open = mxt_input_open;
18487a53d609SNick Dyer 	input_dev->close = mxt_input_close;
18497a53d609SNick Dyer 
1850b23157dcSNick Dyer 	input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
18517a53d609SNick Dyer 
18527a53d609SNick Dyer 	/* For single touch */
1853b23157dcSNick Dyer 	input_set_abs_params(input_dev, ABS_X, 0, data->max_x, 0, 0);
1854b23157dcSNick Dyer 	input_set_abs_params(input_dev, ABS_Y, 0, data->max_y, 0, 0);
1855b23157dcSNick Dyer 
1856b23157dcSNick Dyer 	if (data->multitouch == MXT_TOUCH_MULTI_T9 ||
1857b23157dcSNick Dyer 	    (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 &&
1858b23157dcSNick Dyer 	     data->t100_aux_ampl)) {
1859b23157dcSNick Dyer 		input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0);
1860b23157dcSNick Dyer 	}
18617a53d609SNick Dyer 
1862b6d2d328SSjoerd Simons 	/* If device has buttons we assume it is a touchpad */
1863b6d2d328SSjoerd Simons 	if (pdata->t19_num_keys) {
1864b6d2d328SSjoerd Simons 		mxt_set_up_as_touchpad(input_dev, data);
1865b6d2d328SSjoerd Simons 		mt_flags |= INPUT_MT_POINTER;
1866eafc0c87SNick Dyer 	} else {
1867eafc0c87SNick Dyer 		mt_flags |= INPUT_MT_DIRECT;
1868b6d2d328SSjoerd Simons 	}
1869b6d2d328SSjoerd Simons 
18707a53d609SNick Dyer 	/* For multi touch */
18717a53d609SNick Dyer 	error = input_mt_init_slots(input_dev, num_mt_slots, mt_flags);
18727a53d609SNick Dyer 	if (error) {
18737a53d609SNick Dyer 		dev_err(dev, "Error %d initialising slots\n", error);
18747a53d609SNick Dyer 		goto err_free_mem;
18757a53d609SNick Dyer 	}
18767a53d609SNick Dyer 
1877b23157dcSNick Dyer 	if (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100) {
1878b23157dcSNick Dyer 		input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
1879b23157dcSNick Dyer 				     0, MT_TOOL_MAX, 0, 0);
1880b23157dcSNick Dyer 		input_set_abs_params(input_dev, ABS_MT_DISTANCE,
1881b23157dcSNick Dyer 				     MXT_DISTANCE_ACTIVE_TOUCH,
1882b23157dcSNick Dyer 				     MXT_DISTANCE_HOVERING,
1883b23157dcSNick Dyer 				     0, 0);
1884b23157dcSNick Dyer 	}
1885b23157dcSNick Dyer 
18867a53d609SNick Dyer 	input_set_abs_params(input_dev, ABS_MT_POSITION_X,
18877a53d609SNick Dyer 			     0, data->max_x, 0, 0);
18887a53d609SNick Dyer 	input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
18897a53d609SNick Dyer 			     0, data->max_y, 0, 0);
1890b23157dcSNick Dyer 
1891b23157dcSNick Dyer 	if (data->multitouch == MXT_TOUCH_MULTI_T9 ||
1892b23157dcSNick Dyer 	    (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 &&
1893b23157dcSNick Dyer 	     data->t100_aux_area)) {
1894b23157dcSNick Dyer 		input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
1895b23157dcSNick Dyer 				     0, MXT_MAX_AREA, 0, 0);
1896b23157dcSNick Dyer 	}
1897b23157dcSNick Dyer 
1898b23157dcSNick Dyer 	if (data->multitouch == MXT_TOUCH_MULTI_T9 ||
1899b23157dcSNick Dyer 	    (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 &&
1900b23157dcSNick Dyer 	     data->t100_aux_ampl)) {
19017a53d609SNick Dyer 		input_set_abs_params(input_dev, ABS_MT_PRESSURE,
19027a53d609SNick Dyer 				     0, 255, 0, 0);
1903b23157dcSNick Dyer 	}
1904b23157dcSNick Dyer 
1905b23157dcSNick Dyer 	if (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 &&
1906b23157dcSNick Dyer 	    data->t100_aux_vect) {
1907b23157dcSNick Dyer 		input_set_abs_params(input_dev, ABS_MT_ORIENTATION,
1908b23157dcSNick Dyer 				     0, 255, 0, 0);
1909b23157dcSNick Dyer 	}
1910b23157dcSNick Dyer 
1911b23157dcSNick Dyer 	if (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 &&
1912b23157dcSNick Dyer 	    data->t100_aux_ampl) {
1913b23157dcSNick Dyer 		input_set_abs_params(input_dev, ABS_MT_PRESSURE,
1914b23157dcSNick Dyer 				     0, 255, 0, 0);
1915b23157dcSNick Dyer 	}
1916b23157dcSNick Dyer 
1917b23157dcSNick Dyer 	if (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 &&
1918b23157dcSNick Dyer 	    data->t100_aux_vect) {
1919b23157dcSNick Dyer 		input_set_abs_params(input_dev, ABS_MT_ORIENTATION,
1920b23157dcSNick Dyer 				     0, 255, 0, 0);
1921b23157dcSNick Dyer 	}
19227a53d609SNick Dyer 
19237a53d609SNick Dyer 	input_set_drvdata(input_dev, data);
19247a53d609SNick Dyer 
19257a53d609SNick Dyer 	error = input_register_device(input_dev);
19267a53d609SNick Dyer 	if (error) {
19277a53d609SNick Dyer 		dev_err(dev, "Error %d registering input device\n", error);
19287a53d609SNick Dyer 		goto err_free_mem;
19297a53d609SNick Dyer 	}
19307a53d609SNick Dyer 
19317a53d609SNick Dyer 	data->input_dev = input_dev;
19327a53d609SNick Dyer 
19337a53d609SNick Dyer 	return 0;
19347a53d609SNick Dyer 
19357a53d609SNick Dyer err_free_mem:
19367a53d609SNick Dyer 	input_free_device(input_dev);
19377a53d609SNick Dyer 	return error;
19387a53d609SNick Dyer }
19397a53d609SNick Dyer 
194050a77c65SNick Dyer static int mxt_configure_objects(struct mxt_data *data,
194150a77c65SNick Dyer 				 const struct firmware *cfg);
194250a77c65SNick Dyer 
194350a77c65SNick Dyer static void mxt_config_cb(const struct firmware *cfg, void *ctx)
194450a77c65SNick Dyer {
194550a77c65SNick Dyer 	mxt_configure_objects(ctx, cfg);
1946efdbd7aeSDmitry Torokhov 	release_firmware(cfg);
194750a77c65SNick Dyer }
194850a77c65SNick Dyer 
19497686b108SIiro Valkonen static int mxt_initialize(struct mxt_data *data)
19504cf51c38SJoonyoung Shim {
19514cf51c38SJoonyoung Shim 	struct i2c_client *client = data->client;
19526cd1ab0fSDmitry Torokhov 	int recovery_attempts = 0;
19534cf51c38SJoonyoung Shim 	int error;
19544cf51c38SJoonyoung Shim 
19556cd1ab0fSDmitry Torokhov 	while (1) {
19567686b108SIiro Valkonen 		error = mxt_get_info(data);
19576cd1ab0fSDmitry Torokhov 		if (!error)
19586cd1ab0fSDmitry Torokhov 			break;
19596cd1ab0fSDmitry Torokhov 
19606cd1ab0fSDmitry Torokhov 		/* Check bootloader state */
19616cd1ab0fSDmitry Torokhov 		error = mxt_probe_bootloader(data, false);
1962a9fdd1e6SNick Dyer 		if (error) {
19636cd1ab0fSDmitry Torokhov 			dev_info(&client->dev, "Trying alternate bootloader address\n");
19646cd1ab0fSDmitry Torokhov 			error = mxt_probe_bootloader(data, true);
19658efaa5e5SNick Dyer 			if (error) {
19668efaa5e5SNick Dyer 				/* Chip is not in appmode or bootloader mode */
19674cf51c38SJoonyoung Shim 				return error;
19688efaa5e5SNick Dyer 			}
19696cd1ab0fSDmitry Torokhov 		}
19704cf51c38SJoonyoung Shim 
19716cd1ab0fSDmitry Torokhov 		/* OK, we are in bootloader, see if we can recover */
19726cd1ab0fSDmitry Torokhov 		if (++recovery_attempts > 1) {
19738efaa5e5SNick Dyer 			dev_err(&client->dev, "Could not recover from bootloader mode\n");
19748efaa5e5SNick Dyer 			/*
19758efaa5e5SNick Dyer 			 * We can reflash from this state, so do not
19766cd1ab0fSDmitry Torokhov 			 * abort initialization.
19778efaa5e5SNick Dyer 			 */
1978a9fdd1e6SNick Dyer 			data->in_bootloader = true;
1979a9fdd1e6SNick Dyer 			return 0;
1980a9fdd1e6SNick Dyer 		}
1981a9fdd1e6SNick Dyer 
19828efaa5e5SNick Dyer 		/* Attempt to exit bootloader into app mode */
19838efaa5e5SNick Dyer 		mxt_send_bootloader_cmd(data, false);
19848efaa5e5SNick Dyer 		msleep(MXT_FW_RESET_TIME);
19858efaa5e5SNick Dyer 	}
19868efaa5e5SNick Dyer 
19874cf51c38SJoonyoung Shim 	/* Get object table information */
19887686b108SIiro Valkonen 	error = mxt_get_object_table(data);
19897bed6805SNick Dyer 	if (error) {
19907bed6805SNick Dyer 		dev_err(&client->dev, "Error %d reading object table\n", error);
1991dd24dcf5SNick Dyer 		return error;
19927bed6805SNick Dyer 	}
19934cf51c38SJoonyoung Shim 
1994041fa159SDmitry Torokhov 	error = mxt_acquire_irq(data);
1995dd24dcf5SNick Dyer 	if (error)
1996dd24dcf5SNick Dyer 		goto err_free_object_table;
1997dd24dcf5SNick Dyer 
19986cd1ab0fSDmitry Torokhov 	error = request_firmware_nowait(THIS_MODULE, true, MXT_CFG_NAME,
19996cd1ab0fSDmitry Torokhov 					&client->dev, GFP_KERNEL, data,
200050a77c65SNick Dyer 					mxt_config_cb);
20016cd1ab0fSDmitry Torokhov 	if (error) {
20026cd1ab0fSDmitry Torokhov 		dev_err(&client->dev, "Failed to invoke firmware loader: %d\n",
20036cd1ab0fSDmitry Torokhov 			error);
20046cd1ab0fSDmitry Torokhov 		goto err_free_object_table;
20056cd1ab0fSDmitry Torokhov 	}
20064cf51c38SJoonyoung Shim 
20074cf51c38SJoonyoung Shim 	return 0;
20087d4fa100SDaniel Kurtz 
20097d4fa100SDaniel Kurtz err_free_object_table:
20107d4fa100SDaniel Kurtz 	mxt_free_object_table(data);
20117d4fa100SDaniel Kurtz 	return error;
20124cf51c38SJoonyoung Shim }
20134cf51c38SJoonyoung Shim 
20147f3884f7SNick Dyer static int mxt_set_t7_power_cfg(struct mxt_data *data, u8 sleep)
20157f3884f7SNick Dyer {
20167f3884f7SNick Dyer 	struct device *dev = &data->client->dev;
20177f3884f7SNick Dyer 	int error;
20187f3884f7SNick Dyer 	struct t7_config *new_config;
20197f3884f7SNick Dyer 	struct t7_config deepsleep = { .active = 0, .idle = 0 };
20207f3884f7SNick Dyer 
20217f3884f7SNick Dyer 	if (sleep == MXT_POWER_CFG_DEEPSLEEP)
20227f3884f7SNick Dyer 		new_config = &deepsleep;
20237f3884f7SNick Dyer 	else
20247f3884f7SNick Dyer 		new_config = &data->t7_cfg;
20257f3884f7SNick Dyer 
20267f3884f7SNick Dyer 	error = __mxt_write_reg(data->client, data->T7_address,
20277f3884f7SNick Dyer 				sizeof(data->t7_cfg), new_config);
20287f3884f7SNick Dyer 	if (error)
20297f3884f7SNick Dyer 		return error;
20307f3884f7SNick Dyer 
20317f3884f7SNick Dyer 	dev_dbg(dev, "Set T7 ACTV:%d IDLE:%d\n",
20327f3884f7SNick Dyer 		new_config->active, new_config->idle);
20337f3884f7SNick Dyer 
20347f3884f7SNick Dyer 	return 0;
20357f3884f7SNick Dyer }
20367f3884f7SNick Dyer 
20377f3884f7SNick Dyer static int mxt_init_t7_power_cfg(struct mxt_data *data)
20387f3884f7SNick Dyer {
20397f3884f7SNick Dyer 	struct device *dev = &data->client->dev;
20407f3884f7SNick Dyer 	int error;
20417f3884f7SNick Dyer 	bool retry = false;
20427f3884f7SNick Dyer 
20437f3884f7SNick Dyer recheck:
20447f3884f7SNick Dyer 	error = __mxt_read_reg(data->client, data->T7_address,
20457f3884f7SNick Dyer 				sizeof(data->t7_cfg), &data->t7_cfg);
20467f3884f7SNick Dyer 	if (error)
20477f3884f7SNick Dyer 		return error;
20487f3884f7SNick Dyer 
20497f3884f7SNick Dyer 	if (data->t7_cfg.active == 0 || data->t7_cfg.idle == 0) {
20507f3884f7SNick Dyer 		if (!retry) {
20517f3884f7SNick Dyer 			dev_dbg(dev, "T7 cfg zero, resetting\n");
20527f3884f7SNick Dyer 			mxt_soft_reset(data);
20537f3884f7SNick Dyer 			retry = true;
20547f3884f7SNick Dyer 			goto recheck;
20557f3884f7SNick Dyer 		} else {
20567f3884f7SNick Dyer 			dev_dbg(dev, "T7 cfg zero after reset, overriding\n");
20577f3884f7SNick Dyer 			data->t7_cfg.active = 20;
20587f3884f7SNick Dyer 			data->t7_cfg.idle = 100;
20597f3884f7SNick Dyer 			return mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN);
20607f3884f7SNick Dyer 		}
20617f3884f7SNick Dyer 	}
20627f3884f7SNick Dyer 
20637f3884f7SNick Dyer 	dev_dbg(dev, "Initialized power cfg: ACTV %d, IDLE %d\n",
20647f3884f7SNick Dyer 		data->t7_cfg.active, data->t7_cfg.idle);
20657f3884f7SNick Dyer 	return 0;
20667f3884f7SNick Dyer }
20677f3884f7SNick Dyer 
2068*d6a39404SNick Dyer #ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37
2069*d6a39404SNick Dyer static u16 mxt_get_debug_value(struct mxt_data *data, unsigned int x,
2070*d6a39404SNick Dyer 			       unsigned int y)
2071*d6a39404SNick Dyer {
2072*d6a39404SNick Dyer 	struct mxt_dbg *dbg = &data->dbg;
2073*d6a39404SNick Dyer 	unsigned int ofs, page;
2074*d6a39404SNick Dyer 
2075*d6a39404SNick Dyer 	ofs = (y + (x * data->info.matrix_ysize)) * sizeof(u16);
2076*d6a39404SNick Dyer 	page = ofs / MXT_DIAGNOSTIC_SIZE;
2077*d6a39404SNick Dyer 	ofs %= MXT_DIAGNOSTIC_SIZE;
2078*d6a39404SNick Dyer 
2079*d6a39404SNick Dyer 	return get_unaligned_le16(&dbg->t37_buf[page].data[ofs]);
2080*d6a39404SNick Dyer }
2081*d6a39404SNick Dyer 
2082*d6a39404SNick Dyer static int mxt_convert_debug_pages(struct mxt_data *data, u16 *outbuf)
2083*d6a39404SNick Dyer {
2084*d6a39404SNick Dyer 	struct mxt_dbg *dbg = &data->dbg;
2085*d6a39404SNick Dyer 	unsigned int x = 0;
2086*d6a39404SNick Dyer 	unsigned int y = 0;
2087*d6a39404SNick Dyer 	unsigned int i;
2088*d6a39404SNick Dyer 
2089*d6a39404SNick Dyer 	for (i = 0; i < dbg->t37_nodes; i++) {
2090*d6a39404SNick Dyer 		outbuf[i] = mxt_get_debug_value(data, x, y);
2091*d6a39404SNick Dyer 
2092*d6a39404SNick Dyer 		/* Next value */
2093*d6a39404SNick Dyer 		if (++x >= data->info.matrix_xsize) {
2094*d6a39404SNick Dyer 			x = 0;
2095*d6a39404SNick Dyer 			y++;
2096*d6a39404SNick Dyer 		}
2097*d6a39404SNick Dyer 	}
2098*d6a39404SNick Dyer 
2099*d6a39404SNick Dyer 	return 0;
2100*d6a39404SNick Dyer }
2101*d6a39404SNick Dyer 
2102*d6a39404SNick Dyer static int mxt_read_diagnostic_debug(struct mxt_data *data, u8 mode,
2103*d6a39404SNick Dyer 				     u16 *outbuf)
2104*d6a39404SNick Dyer {
2105*d6a39404SNick Dyer 	struct mxt_dbg *dbg = &data->dbg;
2106*d6a39404SNick Dyer 	int retries = 0;
2107*d6a39404SNick Dyer 	int page;
2108*d6a39404SNick Dyer 	int ret;
2109*d6a39404SNick Dyer 	u8 cmd = mode;
2110*d6a39404SNick Dyer 	struct t37_debug *p;
2111*d6a39404SNick Dyer 	u8 cmd_poll;
2112*d6a39404SNick Dyer 
2113*d6a39404SNick Dyer 	for (page = 0; page < dbg->t37_pages; page++) {
2114*d6a39404SNick Dyer 		p = dbg->t37_buf + page;
2115*d6a39404SNick Dyer 
2116*d6a39404SNick Dyer 		ret = mxt_write_reg(data->client, dbg->diag_cmd_address,
2117*d6a39404SNick Dyer 				    cmd);
2118*d6a39404SNick Dyer 		if (ret)
2119*d6a39404SNick Dyer 			return ret;
2120*d6a39404SNick Dyer 
2121*d6a39404SNick Dyer 		retries = 0;
2122*d6a39404SNick Dyer 		msleep(20);
2123*d6a39404SNick Dyer wait_cmd:
2124*d6a39404SNick Dyer 		/* Read back command byte */
2125*d6a39404SNick Dyer 		ret = __mxt_read_reg(data->client, dbg->diag_cmd_address,
2126*d6a39404SNick Dyer 				     sizeof(cmd_poll), &cmd_poll);
2127*d6a39404SNick Dyer 		if (ret)
2128*d6a39404SNick Dyer 			return ret;
2129*d6a39404SNick Dyer 
2130*d6a39404SNick Dyer 		/* Field is cleared once the command has been processed */
2131*d6a39404SNick Dyer 		if (cmd_poll) {
2132*d6a39404SNick Dyer 			if (retries++ > 100)
2133*d6a39404SNick Dyer 				return -EINVAL;
2134*d6a39404SNick Dyer 
2135*d6a39404SNick Dyer 			msleep(20);
2136*d6a39404SNick Dyer 			goto wait_cmd;
2137*d6a39404SNick Dyer 		}
2138*d6a39404SNick Dyer 
2139*d6a39404SNick Dyer 		/* Read T37 page */
2140*d6a39404SNick Dyer 		ret = __mxt_read_reg(data->client, dbg->t37_address,
2141*d6a39404SNick Dyer 				     sizeof(struct t37_debug), p);
2142*d6a39404SNick Dyer 		if (ret)
2143*d6a39404SNick Dyer 			return ret;
2144*d6a39404SNick Dyer 
2145*d6a39404SNick Dyer 		if (p->mode != mode || p->page != page) {
2146*d6a39404SNick Dyer 			dev_err(&data->client->dev, "T37 page mismatch\n");
2147*d6a39404SNick Dyer 			return -EINVAL;
2148*d6a39404SNick Dyer 		}
2149*d6a39404SNick Dyer 
2150*d6a39404SNick Dyer 		dev_dbg(&data->client->dev, "%s page:%d retries:%d\n",
2151*d6a39404SNick Dyer 			__func__, page, retries);
2152*d6a39404SNick Dyer 
2153*d6a39404SNick Dyer 		/* For remaining pages, write PAGEUP rather than mode */
2154*d6a39404SNick Dyer 		cmd = MXT_DIAGNOSTIC_PAGEUP;
2155*d6a39404SNick Dyer 	}
2156*d6a39404SNick Dyer 
2157*d6a39404SNick Dyer 	return mxt_convert_debug_pages(data, outbuf);
2158*d6a39404SNick Dyer }
2159*d6a39404SNick Dyer 
2160*d6a39404SNick Dyer static void mxt_debug_init(struct mxt_data *data)
2161*d6a39404SNick Dyer {
2162*d6a39404SNick Dyer 	struct mxt_dbg *dbg = &data->dbg;
2163*d6a39404SNick Dyer 	struct mxt_object *object;
2164*d6a39404SNick Dyer 
2165*d6a39404SNick Dyer 	object = mxt_get_object(data, MXT_GEN_COMMAND_T6);
2166*d6a39404SNick Dyer 	if (!object)
2167*d6a39404SNick Dyer 		goto error;
2168*d6a39404SNick Dyer 
2169*d6a39404SNick Dyer 	dbg->diag_cmd_address = object->start_address + MXT_COMMAND_DIAGNOSTIC;
2170*d6a39404SNick Dyer 
2171*d6a39404SNick Dyer 	object = mxt_get_object(data, MXT_DEBUG_DIAGNOSTIC_T37);
2172*d6a39404SNick Dyer 	if (!object)
2173*d6a39404SNick Dyer 		goto error;
2174*d6a39404SNick Dyer 
2175*d6a39404SNick Dyer 	if (mxt_obj_size(object) != sizeof(struct t37_debug)) {
2176*d6a39404SNick Dyer 		dev_warn(&data->client->dev, "Bad T37 size");
2177*d6a39404SNick Dyer 		goto error;
2178*d6a39404SNick Dyer 	}
2179*d6a39404SNick Dyer 
2180*d6a39404SNick Dyer 	dbg->t37_address = object->start_address;
2181*d6a39404SNick Dyer 
2182*d6a39404SNick Dyer 	/* Calculate size of data and allocate buffer */
2183*d6a39404SNick Dyer 	dbg->t37_nodes = data->info.matrix_xsize * data->info.matrix_ysize;
2184*d6a39404SNick Dyer 	dbg->t37_pages = DIV_ROUND_UP(dbg->t37_nodes * sizeof(u16),
2185*d6a39404SNick Dyer 				      sizeof(dbg->t37_buf->data));
2186*d6a39404SNick Dyer 
2187*d6a39404SNick Dyer 	dbg->t37_buf = devm_kmalloc_array(&data->client->dev, dbg->t37_pages,
2188*d6a39404SNick Dyer 					  sizeof(struct t37_debug), GFP_KERNEL);
2189*d6a39404SNick Dyer 	if (!dbg->t37_buf)
2190*d6a39404SNick Dyer 		goto error;
2191*d6a39404SNick Dyer 
2192*d6a39404SNick Dyer 	return;
2193*d6a39404SNick Dyer 
2194*d6a39404SNick Dyer error:
2195*d6a39404SNick Dyer 	dev_warn(&data->client->dev, "Error initializing T37\n");
2196*d6a39404SNick Dyer }
2197*d6a39404SNick Dyer #else
2198*d6a39404SNick Dyer static void mxt_debug_init(struct mxt_data *data)
2199*d6a39404SNick Dyer {
2200*d6a39404SNick Dyer }
2201*d6a39404SNick Dyer #endif
2202*d6a39404SNick Dyer 
220350a77c65SNick Dyer static int mxt_configure_objects(struct mxt_data *data,
220450a77c65SNick Dyer 				 const struct firmware *cfg)
220550a77c65SNick Dyer {
220650a77c65SNick Dyer 	struct device *dev = &data->client->dev;
220750a77c65SNick Dyer 	struct mxt_info *info = &data->info;
220850a77c65SNick Dyer 	int error;
220950a77c65SNick Dyer 
22107f3884f7SNick Dyer 	error = mxt_init_t7_power_cfg(data);
22117f3884f7SNick Dyer 	if (error) {
22127f3884f7SNick Dyer 		dev_err(dev, "Failed to initialize power cfg\n");
22137f3884f7SNick Dyer 		return error;
22147f3884f7SNick Dyer 	}
22157f3884f7SNick Dyer 
221650a77c65SNick Dyer 	if (cfg) {
221750a77c65SNick Dyer 		error = mxt_update_cfg(data, cfg);
221850a77c65SNick Dyer 		if (error)
221950a77c65SNick Dyer 			dev_warn(dev, "Error %d updating config\n", error);
222050a77c65SNick Dyer 	}
222150a77c65SNick Dyer 
2222b23157dcSNick Dyer 	if (data->multitouch) {
2223b23157dcSNick Dyer 		error = mxt_initialize_input_device(data);
222450a77c65SNick Dyer 		if (error)
222550a77c65SNick Dyer 			return error;
2226b23157dcSNick Dyer 	} else {
2227b23157dcSNick Dyer 		dev_warn(dev, "No touch object detected\n");
2228b23157dcSNick Dyer 	}
222950a77c65SNick Dyer 
2230*d6a39404SNick Dyer 	mxt_debug_init(data);
2231*d6a39404SNick Dyer 
223250a77c65SNick Dyer 	dev_info(dev,
223350a77c65SNick Dyer 		 "Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n",
223450a77c65SNick Dyer 		 info->family_id, info->variant_id, info->version >> 4,
223550a77c65SNick Dyer 		 info->version & 0xf, info->build, info->object_num);
223650a77c65SNick Dyer 
223750a77c65SNick Dyer 	return 0;
223850a77c65SNick Dyer }
223950a77c65SNick Dyer 
2240b19fc9ecSDaniel Kurtz /* Firmware Version is returned as Major.Minor.Build */
2241b19fc9ecSDaniel Kurtz static ssize_t mxt_fw_version_show(struct device *dev,
2242b19fc9ecSDaniel Kurtz 				   struct device_attribute *attr, char *buf)
2243b19fc9ecSDaniel Kurtz {
2244b19fc9ecSDaniel Kurtz 	struct mxt_data *data = dev_get_drvdata(dev);
2245b19fc9ecSDaniel Kurtz 	struct mxt_info *info = &data->info;
2246b19fc9ecSDaniel Kurtz 	return scnprintf(buf, PAGE_SIZE, "%u.%u.%02X\n",
2247b19fc9ecSDaniel Kurtz 			 info->version >> 4, info->version & 0xf, info->build);
2248b19fc9ecSDaniel Kurtz }
2249b19fc9ecSDaniel Kurtz 
2250b19fc9ecSDaniel Kurtz /* Hardware Version is returned as FamilyID.VariantID */
2251b19fc9ecSDaniel Kurtz static ssize_t mxt_hw_version_show(struct device *dev,
2252b19fc9ecSDaniel Kurtz 				   struct device_attribute *attr, char *buf)
2253b19fc9ecSDaniel Kurtz {
2254b19fc9ecSDaniel Kurtz 	struct mxt_data *data = dev_get_drvdata(dev);
2255b19fc9ecSDaniel Kurtz 	struct mxt_info *info = &data->info;
2256b19fc9ecSDaniel Kurtz 	return scnprintf(buf, PAGE_SIZE, "%u.%u\n",
2257b19fc9ecSDaniel Kurtz 			 info->family_id, info->variant_id);
2258b19fc9ecSDaniel Kurtz }
2259b19fc9ecSDaniel Kurtz 
2260794eb67eSDaniel Kurtz static ssize_t mxt_show_instance(char *buf, int count,
2261794eb67eSDaniel Kurtz 				 struct mxt_object *object, int instance,
2262794eb67eSDaniel Kurtz 				 const u8 *val)
2263794eb67eSDaniel Kurtz {
2264794eb67eSDaniel Kurtz 	int i;
2265794eb67eSDaniel Kurtz 
22661e0c0c5bSDaniel Kurtz 	if (mxt_obj_instances(object) > 1)
2267794eb67eSDaniel Kurtz 		count += scnprintf(buf + count, PAGE_SIZE - count,
2268794eb67eSDaniel Kurtz 				   "Instance %u\n", instance);
2269794eb67eSDaniel Kurtz 
22701e0c0c5bSDaniel Kurtz 	for (i = 0; i < mxt_obj_size(object); i++)
2271794eb67eSDaniel Kurtz 		count += scnprintf(buf + count, PAGE_SIZE - count,
2272794eb67eSDaniel Kurtz 				"\t[%2u]: %02x (%d)\n", i, val[i], val[i]);
2273794eb67eSDaniel Kurtz 	count += scnprintf(buf + count, PAGE_SIZE - count, "\n");
2274794eb67eSDaniel Kurtz 
2275794eb67eSDaniel Kurtz 	return count;
2276794eb67eSDaniel Kurtz }
2277794eb67eSDaniel Kurtz 
22787686b108SIiro Valkonen static ssize_t mxt_object_show(struct device *dev,
22794cf51c38SJoonyoung Shim 				    struct device_attribute *attr, char *buf)
22804cf51c38SJoonyoung Shim {
22817686b108SIiro Valkonen 	struct mxt_data *data = dev_get_drvdata(dev);
22827686b108SIiro Valkonen 	struct mxt_object *object;
22834cf51c38SJoonyoung Shim 	int count = 0;
22844cf51c38SJoonyoung Shim 	int i, j;
22854cf51c38SJoonyoung Shim 	int error;
228643a91d51SDaniel Kurtz 	u8 *obuf;
22874cf51c38SJoonyoung Shim 
228843a91d51SDaniel Kurtz 	/* Pre-allocate buffer large enough to hold max sized object. */
228943a91d51SDaniel Kurtz 	obuf = kmalloc(256, GFP_KERNEL);
229043a91d51SDaniel Kurtz 	if (!obuf)
229143a91d51SDaniel Kurtz 		return -ENOMEM;
229243a91d51SDaniel Kurtz 
229343a91d51SDaniel Kurtz 	error = 0;
22944cf51c38SJoonyoung Shim 	for (i = 0; i < data->info.object_num; i++) {
22954cf51c38SJoonyoung Shim 		object = data->object_table + i;
22964cf51c38SJoonyoung Shim 
229791630955SDaniel Kurtz 		if (!mxt_object_readable(object->type))
22984cf51c38SJoonyoung Shim 			continue;
22994cf51c38SJoonyoung Shim 
230091630955SDaniel Kurtz 		count += scnprintf(buf + count, PAGE_SIZE - count,
230191630955SDaniel Kurtz 				"T%u:\n", object->type);
23024cf51c38SJoonyoung Shim 
23031e0c0c5bSDaniel Kurtz 		for (j = 0; j < mxt_obj_instances(object); j++) {
23041e0c0c5bSDaniel Kurtz 			u16 size = mxt_obj_size(object);
2305794eb67eSDaniel Kurtz 			u16 addr = object->start_address + j * size;
2306794eb67eSDaniel Kurtz 
2307794eb67eSDaniel Kurtz 			error = __mxt_read_reg(data->client, addr, size, obuf);
23084cf51c38SJoonyoung Shim 			if (error)
2309794eb67eSDaniel Kurtz 				goto done;
23104cf51c38SJoonyoung Shim 
2311794eb67eSDaniel Kurtz 			count = mxt_show_instance(buf, count, object, j, obuf);
23124cf51c38SJoonyoung Shim 		}
23134cf51c38SJoonyoung Shim 	}
23144cf51c38SJoonyoung Shim 
2315794eb67eSDaniel Kurtz done:
231643a91d51SDaniel Kurtz 	kfree(obuf);
231743a91d51SDaniel Kurtz 	return error ?: count;
23184cf51c38SJoonyoung Shim }
23194cf51c38SJoonyoung Shim 
2320f2ac6cb9SNick Dyer static int mxt_check_firmware_format(struct device *dev,
2321f2ac6cb9SNick Dyer 				     const struct firmware *fw)
2322f2ac6cb9SNick Dyer {
2323f2ac6cb9SNick Dyer 	unsigned int pos = 0;
2324f2ac6cb9SNick Dyer 	char c;
2325f2ac6cb9SNick Dyer 
2326f2ac6cb9SNick Dyer 	while (pos < fw->size) {
2327f2ac6cb9SNick Dyer 		c = *(fw->data + pos);
2328f2ac6cb9SNick Dyer 
2329f2ac6cb9SNick Dyer 		if (c < '0' || (c > '9' && c < 'A') || c > 'F')
2330f2ac6cb9SNick Dyer 			return 0;
2331f2ac6cb9SNick Dyer 
2332f2ac6cb9SNick Dyer 		pos++;
2333f2ac6cb9SNick Dyer 	}
2334f2ac6cb9SNick Dyer 
2335f2ac6cb9SNick Dyer 	/*
2336f2ac6cb9SNick Dyer 	 * To convert file try:
2337f2ac6cb9SNick Dyer 	 * xxd -r -p mXTXXX__APP_VX-X-XX.enc > maxtouch.fw
2338f2ac6cb9SNick Dyer 	 */
2339f2ac6cb9SNick Dyer 	dev_err(dev, "Aborting: firmware file must be in binary format\n");
2340f2ac6cb9SNick Dyer 
2341f2ac6cb9SNick Dyer 	return -EINVAL;
2342f2ac6cb9SNick Dyer }
2343f2ac6cb9SNick Dyer 
23447686b108SIiro Valkonen static int mxt_load_fw(struct device *dev, const char *fn)
23454cf51c38SJoonyoung Shim {
23467686b108SIiro Valkonen 	struct mxt_data *data = dev_get_drvdata(dev);
23474cf51c38SJoonyoung Shim 	const struct firmware *fw = NULL;
23484cf51c38SJoonyoung Shim 	unsigned int frame_size;
23494cf51c38SJoonyoung Shim 	unsigned int pos = 0;
2350f943c74aSNick Dyer 	unsigned int retry = 0;
2351f477c758SNick Dyer 	unsigned int frame = 0;
23524cf51c38SJoonyoung Shim 	int ret;
23534cf51c38SJoonyoung Shim 
23544cf51c38SJoonyoung Shim 	ret = request_firmware(&fw, fn, dev);
23554cf51c38SJoonyoung Shim 	if (ret) {
23564cf51c38SJoonyoung Shim 		dev_err(dev, "Unable to open firmware %s\n", fn);
23574cf51c38SJoonyoung Shim 		return ret;
23584cf51c38SJoonyoung Shim 	}
23594cf51c38SJoonyoung Shim 
2360f2ac6cb9SNick Dyer 	/* Check for incorrect enc file */
2361f2ac6cb9SNick Dyer 	ret = mxt_check_firmware_format(dev, fw);
2362f2ac6cb9SNick Dyer 	if (ret)
2363f2ac6cb9SNick Dyer 		goto release_firmware;
2364f2ac6cb9SNick Dyer 
2365a9fdd1e6SNick Dyer 	if (!data->in_bootloader) {
23664cf51c38SJoonyoung Shim 		/* Change to the bootloader mode */
2367d79e7e47SBenson Leung 		data->in_bootloader = true;
2368d79e7e47SBenson Leung 
2369a9fdd1e6SNick Dyer 		ret = mxt_t6_command(data, MXT_COMMAND_RESET,
2370a9fdd1e6SNick Dyer 				     MXT_BOOT_VALUE, false);
2371a4a2ef46SIiro Valkonen 		if (ret)
2372a4a2ef46SIiro Valkonen 			goto release_firmware;
2373a4a2ef46SIiro Valkonen 
23747686b108SIiro Valkonen 		msleep(MXT_RESET_TIME);
23758efaa5e5SNick Dyer 
23768efaa5e5SNick Dyer 		/* Do not need to scan since we know family ID */
23778efaa5e5SNick Dyer 		ret = mxt_lookup_bootloader_address(data, 0);
23788efaa5e5SNick Dyer 		if (ret)
23798efaa5e5SNick Dyer 			goto release_firmware;
238058e4aeeeSStephen Warren 
238158e4aeeeSStephen Warren 		mxt_free_input_device(data);
238258e4aeeeSStephen Warren 		mxt_free_object_table(data);
23838efaa5e5SNick Dyer 	} else {
23848efaa5e5SNick Dyer 		enable_irq(data->irq);
2385a9fdd1e6SNick Dyer 	}
23864cf51c38SJoonyoung Shim 
2387d79e7e47SBenson Leung 	reinit_completion(&data->bl_completion);
2388d79e7e47SBenson Leung 
2389385deb96SNick Dyer 	ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD, false);
2390385deb96SNick Dyer 	if (ret) {
2391385deb96SNick Dyer 		/* Bootloader may still be unlocked from previous attempt */
2392385deb96SNick Dyer 		ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, false);
23934cf51c38SJoonyoung Shim 		if (ret)
2394d79e7e47SBenson Leung 			goto disable_irq;
2395385deb96SNick Dyer 	} else {
2396385deb96SNick Dyer 		dev_info(dev, "Unlocking bootloader\n");
23974cf51c38SJoonyoung Shim 
23984cf51c38SJoonyoung Shim 		/* Unlock bootloader */
23998efaa5e5SNick Dyer 		ret = mxt_send_bootloader_cmd(data, true);
2400385deb96SNick Dyer 		if (ret)
2401385deb96SNick Dyer 			goto disable_irq;
2402385deb96SNick Dyer 	}
24034cf51c38SJoonyoung Shim 
24044cf51c38SJoonyoung Shim 	while (pos < fw->size) {
2405385deb96SNick Dyer 		ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, true);
24064cf51c38SJoonyoung Shim 		if (ret)
2407d79e7e47SBenson Leung 			goto disable_irq;
24084cf51c38SJoonyoung Shim 
24094cf51c38SJoonyoung Shim 		frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1));
24104cf51c38SJoonyoung Shim 
2411f943c74aSNick Dyer 		/* Take account of CRC bytes */
24124cf51c38SJoonyoung Shim 		frame_size += 2;
24134cf51c38SJoonyoung Shim 
24144cf51c38SJoonyoung Shim 		/* Write one frame to device */
2415f28a842dSNick Dyer 		ret = mxt_bootloader_write(data, fw->data + pos, frame_size);
2416f28a842dSNick Dyer 		if (ret)
2417f28a842dSNick Dyer 			goto disable_irq;
24184cf51c38SJoonyoung Shim 
2419385deb96SNick Dyer 		ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS, true);
2420f943c74aSNick Dyer 		if (ret) {
2421f943c74aSNick Dyer 			retry++;
24224cf51c38SJoonyoung Shim 
2423f943c74aSNick Dyer 			/* Back off by 20ms per retry */
2424f943c74aSNick Dyer 			msleep(retry * 20);
2425f943c74aSNick Dyer 
2426f943c74aSNick Dyer 			if (retry > 20) {
2427f943c74aSNick Dyer 				dev_err(dev, "Retry count exceeded\n");
2428f943c74aSNick Dyer 				goto disable_irq;
2429f943c74aSNick Dyer 			}
2430f943c74aSNick Dyer 		} else {
2431f943c74aSNick Dyer 			retry = 0;
24324cf51c38SJoonyoung Shim 			pos += frame_size;
2433f477c758SNick Dyer 			frame++;
2434f943c74aSNick Dyer 		}
24354cf51c38SJoonyoung Shim 
2436f477c758SNick Dyer 		if (frame % 50 == 0)
2437f477c758SNick Dyer 			dev_dbg(dev, "Sent %d frames, %d/%zd bytes\n",
2438f477c758SNick Dyer 				frame, pos, fw->size);
24394cf51c38SJoonyoung Shim 	}
24404cf51c38SJoonyoung Shim 
2441a0434b75SBenson Leung 	/* Wait for flash. */
2442a4a2ef46SIiro Valkonen 	ret = mxt_wait_for_completion(data, &data->bl_completion,
2443a4a2ef46SIiro Valkonen 				      MXT_FW_RESET_TIME);
2444a0434b75SBenson Leung 	if (ret)
2445a0434b75SBenson Leung 		goto disable_irq;
2446a0434b75SBenson Leung 
2447f477c758SNick Dyer 	dev_dbg(dev, "Sent %d frames, %d bytes\n", frame, pos);
2448f477c758SNick Dyer 
2449a0434b75SBenson Leung 	/*
2450a0434b75SBenson Leung 	 * Wait for device to reset. Some bootloader versions do not assert
2451a0434b75SBenson Leung 	 * the CHG line after bootloading has finished, so ignore potential
2452a0434b75SBenson Leung 	 * errors.
2453a0434b75SBenson Leung 	 */
2454a4a2ef46SIiro Valkonen 	mxt_wait_for_completion(data, &data->bl_completion, MXT_FW_RESET_TIME);
2455a0434b75SBenson Leung 
2456d79e7e47SBenson Leung 	data->in_bootloader = false;
2457d79e7e47SBenson Leung 
2458d79e7e47SBenson Leung disable_irq:
2459d79e7e47SBenson Leung 	disable_irq(data->irq);
2460a4a2ef46SIiro Valkonen release_firmware:
24614cf51c38SJoonyoung Shim 	release_firmware(fw);
24624cf51c38SJoonyoung Shim 	return ret;
24634cf51c38SJoonyoung Shim }
24644cf51c38SJoonyoung Shim 
24657686b108SIiro Valkonen static ssize_t mxt_update_fw_store(struct device *dev,
24664cf51c38SJoonyoung Shim 					struct device_attribute *attr,
24674cf51c38SJoonyoung Shim 					const char *buf, size_t count)
24684cf51c38SJoonyoung Shim {
24697686b108SIiro Valkonen 	struct mxt_data *data = dev_get_drvdata(dev);
24704cf51c38SJoonyoung Shim 	int error;
24714cf51c38SJoonyoung Shim 
24727686b108SIiro Valkonen 	error = mxt_load_fw(dev, MXT_FW_NAME);
24734cf51c38SJoonyoung Shim 	if (error) {
24744cf51c38SJoonyoung Shim 		dev_err(dev, "The firmware update failed(%d)\n", error);
24754cf51c38SJoonyoung Shim 		count = error;
24764cf51c38SJoonyoung Shim 	} else {
24777bed6805SNick Dyer 		dev_info(dev, "The firmware update succeeded\n");
24787bed6805SNick Dyer 
2479dd24dcf5SNick Dyer 		error = mxt_initialize(data);
248008960a07SIiro Valkonen 		if (error)
248108960a07SIiro Valkonen 			return error;
2482d79e7e47SBenson Leung 	}
248308960a07SIiro Valkonen 
24844cf51c38SJoonyoung Shim 	return count;
24854cf51c38SJoonyoung Shim }
24864cf51c38SJoonyoung Shim 
2487b19fc9ecSDaniel Kurtz static DEVICE_ATTR(fw_version, S_IRUGO, mxt_fw_version_show, NULL);
2488b19fc9ecSDaniel Kurtz static DEVICE_ATTR(hw_version, S_IRUGO, mxt_hw_version_show, NULL);
248971b3e938SDaniel Kurtz static DEVICE_ATTR(object, S_IRUGO, mxt_object_show, NULL);
249071b3e938SDaniel Kurtz static DEVICE_ATTR(update_fw, S_IWUSR, NULL, mxt_update_fw_store);
24914cf51c38SJoonyoung Shim 
24927686b108SIiro Valkonen static struct attribute *mxt_attrs[] = {
2493b19fc9ecSDaniel Kurtz 	&dev_attr_fw_version.attr,
2494b19fc9ecSDaniel Kurtz 	&dev_attr_hw_version.attr,
24954cf51c38SJoonyoung Shim 	&dev_attr_object.attr,
24964cf51c38SJoonyoung Shim 	&dev_attr_update_fw.attr,
24974cf51c38SJoonyoung Shim 	NULL
24984cf51c38SJoonyoung Shim };
24994cf51c38SJoonyoung Shim 
25007686b108SIiro Valkonen static const struct attribute_group mxt_attr_group = {
25017686b108SIiro Valkonen 	.attrs = mxt_attrs,
25024cf51c38SJoonyoung Shim };
25034cf51c38SJoonyoung Shim 
25047686b108SIiro Valkonen static void mxt_start(struct mxt_data *data)
25054cf51c38SJoonyoung Shim {
25067f3884f7SNick Dyer 	switch (data->pdata->suspend_mode) {
25077f3884f7SNick Dyer 	case MXT_SUSPEND_T9_CTRL:
25087f3884f7SNick Dyer 		mxt_soft_reset(data);
25097f3884f7SNick Dyer 
25107f405483SLinus Torvalds 		/* Touch enable */
25117f3884f7SNick Dyer 		/* 0x83 = SCANEN | RPTEN | ENABLE */
25127f3884f7SNick Dyer 		mxt_write_object(data,
25137f3884f7SNick Dyer 				MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0x83);
25147f3884f7SNick Dyer 		break;
25157f3884f7SNick Dyer 
25167f3884f7SNick Dyer 	case MXT_SUSPEND_DEEP_SLEEP:
25177f3884f7SNick Dyer 	default:
25187f3884f7SNick Dyer 		mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN);
25197f3884f7SNick Dyer 
25207f3884f7SNick Dyer 		/* Recalibrate since chip has been in deep sleep */
25217f3884f7SNick Dyer 		mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false);
25227f3884f7SNick Dyer 		break;
25237f3884f7SNick Dyer 	}
25247f3884f7SNick Dyer 
25254cf51c38SJoonyoung Shim }
25264cf51c38SJoonyoung Shim 
25277686b108SIiro Valkonen static void mxt_stop(struct mxt_data *data)
25284cf51c38SJoonyoung Shim {
25297f3884f7SNick Dyer 	switch (data->pdata->suspend_mode) {
25307f3884f7SNick Dyer 	case MXT_SUSPEND_T9_CTRL:
25317f405483SLinus Torvalds 		/* Touch disable */
25327f3884f7SNick Dyer 		mxt_write_object(data,
25337f3884f7SNick Dyer 				MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0);
25347f3884f7SNick Dyer 		break;
25357f3884f7SNick Dyer 
25367f3884f7SNick Dyer 	case MXT_SUSPEND_DEEP_SLEEP:
25377f3884f7SNick Dyer 	default:
25387f3884f7SNick Dyer 		mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP);
25397f3884f7SNick Dyer 		break;
25407f3884f7SNick Dyer 	}
25414cf51c38SJoonyoung Shim }
25424cf51c38SJoonyoung Shim 
25437686b108SIiro Valkonen static int mxt_input_open(struct input_dev *dev)
25444cf51c38SJoonyoung Shim {
25457686b108SIiro Valkonen 	struct mxt_data *data = input_get_drvdata(dev);
25464cf51c38SJoonyoung Shim 
25477686b108SIiro Valkonen 	mxt_start(data);
25484cf51c38SJoonyoung Shim 
25494cf51c38SJoonyoung Shim 	return 0;
25504cf51c38SJoonyoung Shim }
25514cf51c38SJoonyoung Shim 
25527686b108SIiro Valkonen static void mxt_input_close(struct input_dev *dev)
25534cf51c38SJoonyoung Shim {
25547686b108SIiro Valkonen 	struct mxt_data *data = input_get_drvdata(dev);
25554cf51c38SJoonyoung Shim 
25567686b108SIiro Valkonen 	mxt_stop(data);
25574cf51c38SJoonyoung Shim }
25584cf51c38SJoonyoung Shim 
255978188be3SStephen Warren #ifdef CONFIG_OF
25604f8d8088SDmitry Torokhov static const struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client)
256178188be3SStephen Warren {
256278188be3SStephen Warren 	struct mxt_platform_data *pdata;
256320447664SNick Dyer 	struct device_node *np = client->dev.of_node;
256478188be3SStephen Warren 	u32 *keymap;
256520447664SNick Dyer 	int proplen, ret;
256678188be3SStephen Warren 
256720447664SNick Dyer 	if (!np)
25684f8d8088SDmitry Torokhov 		return ERR_PTR(-ENOENT);
256978188be3SStephen Warren 
257078188be3SStephen Warren 	pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
257178188be3SStephen Warren 	if (!pdata)
257278188be3SStephen Warren 		return ERR_PTR(-ENOMEM);
257378188be3SStephen Warren 
257420447664SNick Dyer 	if (of_find_property(np, "linux,gpio-keymap", &proplen)) {
257578188be3SStephen Warren 		pdata->t19_num_keys = proplen / sizeof(u32);
257678188be3SStephen Warren 
257778188be3SStephen Warren 		keymap = devm_kzalloc(&client->dev,
257878188be3SStephen Warren 				pdata->t19_num_keys * sizeof(keymap[0]),
257978188be3SStephen Warren 				GFP_KERNEL);
258078188be3SStephen Warren 		if (!keymap)
258178188be3SStephen Warren 			return ERR_PTR(-ENOMEM);
258278188be3SStephen Warren 
258320447664SNick Dyer 		ret = of_property_read_u32_array(np, "linux,gpio-keymap",
258420447664SNick Dyer 						 keymap, pdata->t19_num_keys);
258578188be3SStephen Warren 		if (ret)
258620447664SNick Dyer 			dev_warn(&client->dev,
258720447664SNick Dyer 				 "Couldn't read linux,gpio-keymap: %d\n", ret);
258878188be3SStephen Warren 
258978188be3SStephen Warren 		pdata->t19_keymap = keymap;
259078188be3SStephen Warren 	}
259178188be3SStephen Warren 
25927f3884f7SNick Dyer 	pdata->suspend_mode = MXT_SUSPEND_DEEP_SLEEP;
25937f3884f7SNick Dyer 
259478188be3SStephen Warren 	return pdata;
259578188be3SStephen Warren }
259678188be3SStephen Warren #else
25974f8d8088SDmitry Torokhov static const struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client)
259878188be3SStephen Warren {
25994f8d8088SDmitry Torokhov 	return ERR_PTR(-ENOENT);
260078188be3SStephen Warren }
260178188be3SStephen Warren #endif
260278188be3SStephen Warren 
26034f8d8088SDmitry Torokhov #ifdef CONFIG_ACPI
26044f8d8088SDmitry Torokhov 
26054f8d8088SDmitry Torokhov struct mxt_acpi_platform_data {
26064f8d8088SDmitry Torokhov 	const char *hid;
26074f8d8088SDmitry Torokhov 	struct mxt_platform_data pdata;
26084f8d8088SDmitry Torokhov };
26094f8d8088SDmitry Torokhov 
26104f8d8088SDmitry Torokhov static unsigned int samus_touchpad_buttons[] = {
26114f8d8088SDmitry Torokhov 	KEY_RESERVED,
26124f8d8088SDmitry Torokhov 	KEY_RESERVED,
26134f8d8088SDmitry Torokhov 	KEY_RESERVED,
26144f8d8088SDmitry Torokhov 	BTN_LEFT
26154f8d8088SDmitry Torokhov };
26164f8d8088SDmitry Torokhov 
26174f8d8088SDmitry Torokhov static struct mxt_acpi_platform_data samus_platform_data[] = {
26184f8d8088SDmitry Torokhov 	{
26194f8d8088SDmitry Torokhov 		/* Touchpad */
26204f8d8088SDmitry Torokhov 		.hid	= "ATML0000",
26214f8d8088SDmitry Torokhov 		.pdata	= {
26224f8d8088SDmitry Torokhov 			.t19_num_keys	= ARRAY_SIZE(samus_touchpad_buttons),
26234f8d8088SDmitry Torokhov 			.t19_keymap	= samus_touchpad_buttons,
26244f8d8088SDmitry Torokhov 		},
26254f8d8088SDmitry Torokhov 	},
26264f8d8088SDmitry Torokhov 	{
26274f8d8088SDmitry Torokhov 		/* Touchscreen */
26284f8d8088SDmitry Torokhov 		.hid	= "ATML0001",
26294f8d8088SDmitry Torokhov 	},
26304f8d8088SDmitry Torokhov 	{ }
26314f8d8088SDmitry Torokhov };
26324f8d8088SDmitry Torokhov 
2633c67566c6SDmitry Torokhov static unsigned int chromebook_tp_buttons[] = {
2634c67566c6SDmitry Torokhov 	KEY_RESERVED,
2635c67566c6SDmitry Torokhov 	KEY_RESERVED,
2636c67566c6SDmitry Torokhov 	KEY_RESERVED,
2637c67566c6SDmitry Torokhov 	KEY_RESERVED,
2638c67566c6SDmitry Torokhov 	KEY_RESERVED,
2639c67566c6SDmitry Torokhov 	BTN_LEFT
2640c67566c6SDmitry Torokhov };
2641c67566c6SDmitry Torokhov 
2642c67566c6SDmitry Torokhov static struct mxt_acpi_platform_data chromebook_platform_data[] = {
2643c67566c6SDmitry Torokhov 	{
2644c67566c6SDmitry Torokhov 		/* Touchpad */
2645c67566c6SDmitry Torokhov 		.hid	= "ATML0000",
2646c67566c6SDmitry Torokhov 		.pdata	= {
2647c67566c6SDmitry Torokhov 			.t19_num_keys	= ARRAY_SIZE(chromebook_tp_buttons),
2648c67566c6SDmitry Torokhov 			.t19_keymap	= chromebook_tp_buttons,
2649c67566c6SDmitry Torokhov 		},
2650c67566c6SDmitry Torokhov 	},
2651c67566c6SDmitry Torokhov 	{
2652c67566c6SDmitry Torokhov 		/* Touchscreen */
2653c67566c6SDmitry Torokhov 		.hid	= "ATML0001",
2654c67566c6SDmitry Torokhov 	},
2655c67566c6SDmitry Torokhov 	{ }
2656c67566c6SDmitry Torokhov };
2657c67566c6SDmitry Torokhov 
26584f8d8088SDmitry Torokhov static const struct dmi_system_id mxt_dmi_table[] = {
26594f8d8088SDmitry Torokhov 	{
26604f8d8088SDmitry Torokhov 		/* 2015 Google Pixel */
26614f8d8088SDmitry Torokhov 		.ident = "Chromebook Pixel 2",
26624f8d8088SDmitry Torokhov 		.matches = {
26634f8d8088SDmitry Torokhov 			DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
26644f8d8088SDmitry Torokhov 			DMI_MATCH(DMI_PRODUCT_NAME, "Samus"),
26654f8d8088SDmitry Torokhov 		},
26664f8d8088SDmitry Torokhov 		.driver_data = samus_platform_data,
26674f8d8088SDmitry Torokhov 	},
2668c67566c6SDmitry Torokhov 	{
2669c67566c6SDmitry Torokhov 		/* Other Google Chromebooks */
2670c67566c6SDmitry Torokhov 		.ident = "Chromebook",
2671c67566c6SDmitry Torokhov 		.matches = {
2672c67566c6SDmitry Torokhov 			DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
2673c67566c6SDmitry Torokhov 		},
2674c67566c6SDmitry Torokhov 		.driver_data = chromebook_platform_data,
2675c67566c6SDmitry Torokhov 	},
26764f8d8088SDmitry Torokhov 	{ }
26774f8d8088SDmitry Torokhov };
26784f8d8088SDmitry Torokhov 
26794f8d8088SDmitry Torokhov static const struct mxt_platform_data *mxt_parse_acpi(struct i2c_client *client)
26804f8d8088SDmitry Torokhov {
26814f8d8088SDmitry Torokhov 	struct acpi_device *adev;
26824f8d8088SDmitry Torokhov 	const struct dmi_system_id *system_id;
26834f8d8088SDmitry Torokhov 	const struct mxt_acpi_platform_data *acpi_pdata;
26844f8d8088SDmitry Torokhov 
26854f8d8088SDmitry Torokhov 	/*
26864f8d8088SDmitry Torokhov 	 * Ignore ACPI devices representing bootloader mode.
26874f8d8088SDmitry Torokhov 	 *
26884f8d8088SDmitry Torokhov 	 * This is a bit of a hack: Google Chromebook BIOS creates ACPI
26894f8d8088SDmitry Torokhov 	 * devices for both application and bootloader modes, but we are
26904f8d8088SDmitry Torokhov 	 * interested in application mode only (if device is in bootloader
26914f8d8088SDmitry Torokhov 	 * mode we'll end up switching into application anyway). So far
26924f8d8088SDmitry Torokhov 	 * application mode addresses were all above 0x40, so we'll use it
26934f8d8088SDmitry Torokhov 	 * as a threshold.
26944f8d8088SDmitry Torokhov 	 */
26954f8d8088SDmitry Torokhov 	if (client->addr < 0x40)
26964f8d8088SDmitry Torokhov 		return ERR_PTR(-ENXIO);
26974f8d8088SDmitry Torokhov 
26984f8d8088SDmitry Torokhov 	adev = ACPI_COMPANION(&client->dev);
26994f8d8088SDmitry Torokhov 	if (!adev)
27004f8d8088SDmitry Torokhov 		return ERR_PTR(-ENOENT);
27014f8d8088SDmitry Torokhov 
27024f8d8088SDmitry Torokhov 	system_id = dmi_first_match(mxt_dmi_table);
27034f8d8088SDmitry Torokhov 	if (!system_id)
27044f8d8088SDmitry Torokhov 		return ERR_PTR(-ENOENT);
27054f8d8088SDmitry Torokhov 
27064f8d8088SDmitry Torokhov 	acpi_pdata = system_id->driver_data;
27074f8d8088SDmitry Torokhov 	if (!acpi_pdata)
27084f8d8088SDmitry Torokhov 		return ERR_PTR(-ENOENT);
27094f8d8088SDmitry Torokhov 
27104f8d8088SDmitry Torokhov 	while (acpi_pdata->hid) {
27114f8d8088SDmitry Torokhov 		if (!strcmp(acpi_device_hid(adev), acpi_pdata->hid))
27124f8d8088SDmitry Torokhov 			return &acpi_pdata->pdata;
27134f8d8088SDmitry Torokhov 
27144f8d8088SDmitry Torokhov 		acpi_pdata++;
27154f8d8088SDmitry Torokhov 	}
27164f8d8088SDmitry Torokhov 
27174f8d8088SDmitry Torokhov 	return ERR_PTR(-ENOENT);
27184f8d8088SDmitry Torokhov }
27194f8d8088SDmitry Torokhov #else
27204f8d8088SDmitry Torokhov static const struct mxt_platform_data *mxt_parse_acpi(struct i2c_client *client)
27214f8d8088SDmitry Torokhov {
27224f8d8088SDmitry Torokhov 	return ERR_PTR(-ENOENT);
27234f8d8088SDmitry Torokhov }
27244f8d8088SDmitry Torokhov #endif
27254f8d8088SDmitry Torokhov 
27264f8d8088SDmitry Torokhov static const struct mxt_platform_data *
27274f8d8088SDmitry Torokhov mxt_get_platform_data(struct i2c_client *client)
27284f8d8088SDmitry Torokhov {
27294f8d8088SDmitry Torokhov 	const struct mxt_platform_data *pdata;
27304f8d8088SDmitry Torokhov 
27314f8d8088SDmitry Torokhov 	pdata = dev_get_platdata(&client->dev);
27324f8d8088SDmitry Torokhov 	if (pdata)
27334f8d8088SDmitry Torokhov 		return pdata;
27344f8d8088SDmitry Torokhov 
27354f8d8088SDmitry Torokhov 	pdata = mxt_parse_dt(client);
27364f8d8088SDmitry Torokhov 	if (!IS_ERR(pdata) || PTR_ERR(pdata) != -ENOENT)
27374f8d8088SDmitry Torokhov 		return pdata;
27384f8d8088SDmitry Torokhov 
27394f8d8088SDmitry Torokhov 	pdata = mxt_parse_acpi(client);
27404f8d8088SDmitry Torokhov 	if (!IS_ERR(pdata) || PTR_ERR(pdata) != -ENOENT)
27414f8d8088SDmitry Torokhov 		return pdata;
27424f8d8088SDmitry Torokhov 
27434f8d8088SDmitry Torokhov 	dev_err(&client->dev, "No platform data specified\n");
27444f8d8088SDmitry Torokhov 	return ERR_PTR(-EINVAL);
27454f8d8088SDmitry Torokhov }
27464f8d8088SDmitry Torokhov 
274778188be3SStephen Warren static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
27484cf51c38SJoonyoung Shim {
27497686b108SIiro Valkonen 	struct mxt_data *data;
275078188be3SStephen Warren 	const struct mxt_platform_data *pdata;
27514cf51c38SJoonyoung Shim 	int error;
27524cf51c38SJoonyoung Shim 
27534f8d8088SDmitry Torokhov 	pdata = mxt_get_platform_data(client);
275478188be3SStephen Warren 	if (IS_ERR(pdata))
275578188be3SStephen Warren 		return PTR_ERR(pdata);
27564cf51c38SJoonyoung Shim 
27577686b108SIiro Valkonen 	data = kzalloc(sizeof(struct mxt_data), GFP_KERNEL);
27587a53d609SNick Dyer 	if (!data) {
27594cf51c38SJoonyoung Shim 		dev_err(&client->dev, "Failed to allocate memory\n");
27607a53d609SNick Dyer 		return -ENOMEM;
27614cf51c38SJoonyoung Shim 	}
27624cf51c38SJoonyoung Shim 
2763ec02ac2bSDaniel Kurtz 	snprintf(data->phys, sizeof(data->phys), "i2c-%u-%04x/input0",
2764ec02ac2bSDaniel Kurtz 		 client->adapter->nr, client->addr);
276522dfab7fSDaniel Kurtz 
2766910d8051SJoonyoung Shim 	data->client = client;
2767910d8051SJoonyoung Shim 	data->pdata = pdata;
2768910d8051SJoonyoung Shim 	data->irq = client->irq;
27697a53d609SNick Dyer 	i2c_set_clientdata(client, data);
2770910d8051SJoonyoung Shim 
2771d79e7e47SBenson Leung 	init_completion(&data->bl_completion);
2772a4a2ef46SIiro Valkonen 	init_completion(&data->reset_completion);
2773c3f78043SNick Dyer 	init_completion(&data->crc_completion);
2774d79e7e47SBenson Leung 
2775dd24dcf5SNick Dyer 	error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
2776dd24dcf5SNick Dyer 				     pdata->irqflags | IRQF_ONESHOT,
2777dd24dcf5SNick Dyer 				     client->name, data);
2778dd24dcf5SNick Dyer 	if (error) {
2779dd24dcf5SNick Dyer 		dev_err(&client->dev, "Failed to register interrupt\n");
2780dd24dcf5SNick Dyer 		goto err_free_mem;
2781dd24dcf5SNick Dyer 	}
2782dd24dcf5SNick Dyer 
2783dd24dcf5SNick Dyer 	disable_irq(client->irq);
2784dd24dcf5SNick Dyer 
2785cb159115SDaniel Kurtz 	error = mxt_initialize(data);
2786cb159115SDaniel Kurtz 	if (error)
27877a53d609SNick Dyer 		goto err_free_irq;
27884cf51c38SJoonyoung Shim 
27897686b108SIiro Valkonen 	error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
27907bed6805SNick Dyer 	if (error) {
27917bed6805SNick Dyer 		dev_err(&client->dev, "Failure %d creating sysfs group\n",
27927bed6805SNick Dyer 			error);
27937a53d609SNick Dyer 		goto err_free_object;
27947bed6805SNick Dyer 	}
27954cf51c38SJoonyoung Shim 
27964cf51c38SJoonyoung Shim 	return 0;
27974cf51c38SJoonyoung Shim 
27984cf51c38SJoonyoung Shim err_free_object:
279958e4aeeeSStephen Warren 	mxt_free_input_device(data);
28005f3f9bc2SNick Dyer 	mxt_free_object_table(data);
2801dd24dcf5SNick Dyer err_free_irq:
2802dd24dcf5SNick Dyer 	free_irq(client->irq, data);
28034cf51c38SJoonyoung Shim err_free_mem:
28044cf51c38SJoonyoung Shim 	kfree(data);
28054cf51c38SJoonyoung Shim 	return error;
28064cf51c38SJoonyoung Shim }
28074cf51c38SJoonyoung Shim 
2808e2619cf7SBill Pemberton static int mxt_remove(struct i2c_client *client)
28094cf51c38SJoonyoung Shim {
28107686b108SIiro Valkonen 	struct mxt_data *data = i2c_get_clientdata(client);
28114cf51c38SJoonyoung Shim 
28127686b108SIiro Valkonen 	sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
28134cf51c38SJoonyoung Shim 	free_irq(data->irq, data);
281458e4aeeeSStephen Warren 	mxt_free_input_device(data);
28155f3f9bc2SNick Dyer 	mxt_free_object_table(data);
28164cf51c38SJoonyoung Shim 	kfree(data);
28174cf51c38SJoonyoung Shim 
28184cf51c38SJoonyoung Shim 	return 0;
28194cf51c38SJoonyoung Shim }
28204cf51c38SJoonyoung Shim 
282102b6a58bSJingoo Han static int __maybe_unused mxt_suspend(struct device *dev)
28224cf51c38SJoonyoung Shim {
28238b5fce06SDmitry Torokhov 	struct i2c_client *client = to_i2c_client(dev);
28247686b108SIiro Valkonen 	struct mxt_data *data = i2c_get_clientdata(client);
28254cf51c38SJoonyoung Shim 	struct input_dev *input_dev = data->input_dev;
28264cf51c38SJoonyoung Shim 
282750fabb02SPan Xinhui 	if (!input_dev)
282850fabb02SPan Xinhui 		return 0;
282950fabb02SPan Xinhui 
28304cf51c38SJoonyoung Shim 	mutex_lock(&input_dev->mutex);
28314cf51c38SJoonyoung Shim 
28324cf51c38SJoonyoung Shim 	if (input_dev->users)
28337686b108SIiro Valkonen 		mxt_stop(data);
28344cf51c38SJoonyoung Shim 
28354cf51c38SJoonyoung Shim 	mutex_unlock(&input_dev->mutex);
28364cf51c38SJoonyoung Shim 
28374cf51c38SJoonyoung Shim 	return 0;
28384cf51c38SJoonyoung Shim }
28394cf51c38SJoonyoung Shim 
284002b6a58bSJingoo Han static int __maybe_unused mxt_resume(struct device *dev)
28414cf51c38SJoonyoung Shim {
28428b5fce06SDmitry Torokhov 	struct i2c_client *client = to_i2c_client(dev);
28437686b108SIiro Valkonen 	struct mxt_data *data = i2c_get_clientdata(client);
28444cf51c38SJoonyoung Shim 	struct input_dev *input_dev = data->input_dev;
28454cf51c38SJoonyoung Shim 
284650fabb02SPan Xinhui 	if (!input_dev)
284750fabb02SPan Xinhui 		return 0;
284850fabb02SPan Xinhui 
28494cf51c38SJoonyoung Shim 	mutex_lock(&input_dev->mutex);
28504cf51c38SJoonyoung Shim 
28514cf51c38SJoonyoung Shim 	if (input_dev->users)
28527686b108SIiro Valkonen 		mxt_start(data);
28534cf51c38SJoonyoung Shim 
28544cf51c38SJoonyoung Shim 	mutex_unlock(&input_dev->mutex);
28554cf51c38SJoonyoung Shim 
28564cf51c38SJoonyoung Shim 	return 0;
28574cf51c38SJoonyoung Shim }
28584cf51c38SJoonyoung Shim 
28593a73c816SDaniel Kurtz static SIMPLE_DEV_PM_OPS(mxt_pm_ops, mxt_suspend, mxt_resume);
28603a73c816SDaniel Kurtz 
286178188be3SStephen Warren static const struct of_device_id mxt_of_match[] = {
286278188be3SStephen Warren 	{ .compatible = "atmel,maxtouch", },
286378188be3SStephen Warren 	{},
286478188be3SStephen Warren };
286578188be3SStephen Warren MODULE_DEVICE_TABLE(of, mxt_of_match);
286678188be3SStephen Warren 
28674f8d8088SDmitry Torokhov #ifdef CONFIG_ACPI
28684f8d8088SDmitry Torokhov static const struct acpi_device_id mxt_acpi_id[] = {
28694f8d8088SDmitry Torokhov 	{ "ATML0000", 0 },	/* Touchpad */
28704f8d8088SDmitry Torokhov 	{ "ATML0001", 0 },	/* Touchscreen */
28714f8d8088SDmitry Torokhov 	{ }
28724f8d8088SDmitry Torokhov };
28734f8d8088SDmitry Torokhov MODULE_DEVICE_TABLE(acpi, mxt_acpi_id);
28744f8d8088SDmitry Torokhov #endif
28754f8d8088SDmitry Torokhov 
28767686b108SIiro Valkonen static const struct i2c_device_id mxt_id[] = {
28774cf51c38SJoonyoung Shim 	{ "qt602240_ts", 0 },
28787686b108SIiro Valkonen 	{ "atmel_mxt_ts", 0 },
287922dfab7fSDaniel Kurtz 	{ "atmel_mxt_tp", 0 },
2880b7d21058SJavier Martinez Canillas 	{ "maxtouch", 0 },
288146ee2a05SChris Leech 	{ "mXT224", 0 },
28824cf51c38SJoonyoung Shim 	{ }
28834cf51c38SJoonyoung Shim };
28847686b108SIiro Valkonen MODULE_DEVICE_TABLE(i2c, mxt_id);
28854cf51c38SJoonyoung Shim 
28867686b108SIiro Valkonen static struct i2c_driver mxt_driver = {
28874cf51c38SJoonyoung Shim 	.driver = {
28887686b108SIiro Valkonen 		.name	= "atmel_mxt_ts",
288978188be3SStephen Warren 		.of_match_table = of_match_ptr(mxt_of_match),
28904f8d8088SDmitry Torokhov 		.acpi_match_table = ACPI_PTR(mxt_acpi_id),
28917686b108SIiro Valkonen 		.pm	= &mxt_pm_ops,
28924cf51c38SJoonyoung Shim 	},
28937686b108SIiro Valkonen 	.probe		= mxt_probe,
28941cb0aa88SBill Pemberton 	.remove		= mxt_remove,
28957686b108SIiro Valkonen 	.id_table	= mxt_id,
28964cf51c38SJoonyoung Shim };
28974cf51c38SJoonyoung Shim 
28981b92c1cfSAxel Lin module_i2c_driver(mxt_driver);
28994cf51c38SJoonyoung Shim 
29004cf51c38SJoonyoung Shim /* Module information */
29014cf51c38SJoonyoung Shim MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
29027686b108SIiro Valkonen MODULE_DESCRIPTION("Atmel maXTouch Touchscreen driver");
29034cf51c38SJoonyoung Shim MODULE_LICENSE("GPL");
2904