| // SPDX-License-Identifier: GPL-2.0-or-later | 
 | /* | 
 |  * Azoteq IQS7210A/7211A/E Trackpad/Touchscreen Controller | 
 |  * | 
 |  * Copyright (C) 2023 Jeff LaBundy <jeff@labundy.com> | 
 |  */ | 
 |  | 
 | #include <linux/bits.h> | 
 | #include <linux/delay.h> | 
 | #include <linux/device.h> | 
 | #include <linux/err.h> | 
 | #include <linux/gpio/consumer.h> | 
 | #include <linux/i2c.h> | 
 | #include <linux/input.h> | 
 | #include <linux/input/mt.h> | 
 | #include <linux/input/touchscreen.h> | 
 | #include <linux/interrupt.h> | 
 | #include <linux/iopoll.h> | 
 | #include <linux/kernel.h> | 
 | #include <linux/list.h> | 
 | #include <linux/module.h> | 
 | #include <linux/of_device.h> | 
 | #include <linux/property.h> | 
 | #include <linux/slab.h> | 
 | #include <linux/unaligned.h> | 
 |  | 
 | #define IQS7211_PROD_NUM			0x00 | 
 |  | 
 | #define IQS7211_EVENT_MASK_ALL			GENMASK(14, 8) | 
 | #define IQS7211_EVENT_MASK_ALP			BIT(13) | 
 | #define IQS7211_EVENT_MASK_BTN			BIT(12) | 
 | #define IQS7211_EVENT_MASK_ATI			BIT(11) | 
 | #define IQS7211_EVENT_MASK_MOVE			BIT(10) | 
 | #define IQS7211_EVENT_MASK_GSTR			BIT(9) | 
 | #define IQS7211_EVENT_MODE			BIT(8) | 
 |  | 
 | #define IQS7211_COMMS_ERROR			0xEEEE | 
 | #define IQS7211_COMMS_RETRY_MS			50 | 
 | #define IQS7211_COMMS_SLEEP_US			100 | 
 | #define IQS7211_COMMS_TIMEOUT_US		(100 * USEC_PER_MSEC) | 
 | #define IQS7211_RESET_TIMEOUT_MS		150 | 
 | #define IQS7211_START_TIMEOUT_US		(1 * USEC_PER_SEC) | 
 |  | 
 | #define IQS7211_NUM_RETRIES			5 | 
 | #define IQS7211_NUM_CRX				8 | 
 | #define IQS7211_MAX_CTX				13 | 
 |  | 
 | #define IQS7211_MAX_CONTACTS			2 | 
 | #define IQS7211_MAX_CYCLES			21 | 
 |  | 
 | /* | 
 |  * The following delay is used during instances that must wait for the open- | 
 |  * drain RDY pin to settle. Its value is calculated as 5*R*C, where R and C | 
 |  * represent typical datasheet values of 4.7k and 100 nF, respectively. | 
 |  */ | 
 | #define iqs7211_irq_wait()			usleep_range(2500, 2600) | 
 |  | 
 | enum iqs7211_dev_id { | 
 | 	IQS7210A, | 
 | 	IQS7211A, | 
 | 	IQS7211E, | 
 | }; | 
 |  | 
 | enum iqs7211_comms_mode { | 
 | 	IQS7211_COMMS_MODE_WAIT, | 
 | 	IQS7211_COMMS_MODE_FREE, | 
 | 	IQS7211_COMMS_MODE_FORCE, | 
 | }; | 
 |  | 
 | struct iqs7211_reg_field_desc { | 
 | 	struct list_head list; | 
 | 	u8 addr; | 
 | 	u16 mask; | 
 | 	u16 val; | 
 | }; | 
 |  | 
 | enum iqs7211_reg_key_id { | 
 | 	IQS7211_REG_KEY_NONE, | 
 | 	IQS7211_REG_KEY_PROX, | 
 | 	IQS7211_REG_KEY_TOUCH, | 
 | 	IQS7211_REG_KEY_TAP, | 
 | 	IQS7211_REG_KEY_HOLD, | 
 | 	IQS7211_REG_KEY_PALM, | 
 | 	IQS7211_REG_KEY_AXIAL_X, | 
 | 	IQS7211_REG_KEY_AXIAL_Y, | 
 | 	IQS7211_REG_KEY_RESERVED | 
 | }; | 
 |  | 
 | enum iqs7211_reg_grp_id { | 
 | 	IQS7211_REG_GRP_TP, | 
 | 	IQS7211_REG_GRP_BTN, | 
 | 	IQS7211_REG_GRP_ALP, | 
 | 	IQS7211_REG_GRP_SYS, | 
 | 	IQS7211_NUM_REG_GRPS | 
 | }; | 
 |  | 
 | static const char * const iqs7211_reg_grp_names[IQS7211_NUM_REG_GRPS] = { | 
 | 	[IQS7211_REG_GRP_TP] = "trackpad", | 
 | 	[IQS7211_REG_GRP_BTN] = "button", | 
 | 	[IQS7211_REG_GRP_ALP] = "alp", | 
 | }; | 
 |  | 
 | static const u16 iqs7211_reg_grp_masks[IQS7211_NUM_REG_GRPS] = { | 
 | 	[IQS7211_REG_GRP_TP] = IQS7211_EVENT_MASK_GSTR, | 
 | 	[IQS7211_REG_GRP_BTN] = IQS7211_EVENT_MASK_BTN, | 
 | 	[IQS7211_REG_GRP_ALP] = IQS7211_EVENT_MASK_ALP, | 
 | }; | 
 |  | 
 | struct iqs7211_event_desc { | 
 | 	const char *name; | 
 | 	u16 mask; | 
 | 	u16 enable; | 
 | 	enum iqs7211_reg_grp_id reg_grp; | 
 | 	enum iqs7211_reg_key_id reg_key; | 
 | }; | 
 |  | 
 | static const struct iqs7211_event_desc iqs7210a_kp_events[] = { | 
 | 	{ | 
 | 		.mask = BIT(10), | 
 | 		.enable = BIT(13) | BIT(12), | 
 | 		.reg_grp = IQS7211_REG_GRP_ALP, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-prox", | 
 | 		.mask = BIT(2), | 
 | 		.enable = BIT(5) | BIT(4), | 
 | 		.reg_grp = IQS7211_REG_GRP_BTN, | 
 | 		.reg_key = IQS7211_REG_KEY_PROX, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-touch", | 
 | 		.mask = BIT(3), | 
 | 		.enable = BIT(5) | BIT(4), | 
 | 		.reg_grp = IQS7211_REG_GRP_BTN, | 
 | 		.reg_key = IQS7211_REG_KEY_TOUCH, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-tap", | 
 | 		.mask = BIT(0), | 
 | 		.enable = BIT(0), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_TAP, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-hold", | 
 | 		.mask = BIT(1), | 
 | 		.enable = BIT(1), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_HOLD, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-swipe-x-neg", | 
 | 		.mask = BIT(2), | 
 | 		.enable = BIT(2), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_AXIAL_X, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-swipe-x-pos", | 
 | 		.mask = BIT(3), | 
 | 		.enable = BIT(3), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_AXIAL_X, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-swipe-y-pos", | 
 | 		.mask = BIT(4), | 
 | 		.enable = BIT(4), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_AXIAL_Y, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-swipe-y-neg", | 
 | 		.mask = BIT(5), | 
 | 		.enable = BIT(5), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_AXIAL_Y, | 
 | 	}, | 
 | }; | 
 |  | 
 | static const struct iqs7211_event_desc iqs7211a_kp_events[] = { | 
 | 	{ | 
 | 		.mask = BIT(14), | 
 | 		.reg_grp = IQS7211_REG_GRP_ALP, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-tap", | 
 | 		.mask = BIT(0), | 
 | 		.enable = BIT(0), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_TAP, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-hold", | 
 | 		.mask = BIT(1), | 
 | 		.enable = BIT(1), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_HOLD, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-swipe-x-neg", | 
 | 		.mask = BIT(2), | 
 | 		.enable = BIT(2), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_AXIAL_X, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-swipe-x-pos", | 
 | 		.mask = BIT(3), | 
 | 		.enable = BIT(3), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_AXIAL_X, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-swipe-y-pos", | 
 | 		.mask = BIT(4), | 
 | 		.enable = BIT(4), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_AXIAL_Y, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-swipe-y-neg", | 
 | 		.mask = BIT(5), | 
 | 		.enable = BIT(5), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_AXIAL_Y, | 
 | 	}, | 
 | }; | 
 |  | 
 | static const struct iqs7211_event_desc iqs7211e_kp_events[] = { | 
 | 	{ | 
 | 		.mask = BIT(14), | 
 | 		.reg_grp = IQS7211_REG_GRP_ALP, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-tap", | 
 | 		.mask = BIT(0), | 
 | 		.enable = BIT(0), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_TAP, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-tap-double", | 
 | 		.mask = BIT(1), | 
 | 		.enable = BIT(1), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_TAP, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-tap-triple", | 
 | 		.mask = BIT(2), | 
 | 		.enable = BIT(2), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_TAP, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-hold", | 
 | 		.mask = BIT(3), | 
 | 		.enable = BIT(3), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_HOLD, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-palm", | 
 | 		.mask = BIT(4), | 
 | 		.enable = BIT(4), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_PALM, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-swipe-x-pos", | 
 | 		.mask = BIT(8), | 
 | 		.enable = BIT(8), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_AXIAL_X, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-swipe-x-neg", | 
 | 		.mask = BIT(9), | 
 | 		.enable = BIT(9), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_AXIAL_X, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-swipe-y-pos", | 
 | 		.mask = BIT(10), | 
 | 		.enable = BIT(10), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_AXIAL_Y, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-swipe-y-neg", | 
 | 		.mask = BIT(11), | 
 | 		.enable = BIT(11), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_AXIAL_Y, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-swipe-x-pos-hold", | 
 | 		.mask = BIT(12), | 
 | 		.enable = BIT(12), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_HOLD, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-swipe-x-neg-hold", | 
 | 		.mask = BIT(13), | 
 | 		.enable = BIT(13), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_HOLD, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-swipe-y-pos-hold", | 
 | 		.mask = BIT(14), | 
 | 		.enable = BIT(14), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_HOLD, | 
 | 	}, | 
 | 	{ | 
 | 		.name = "event-swipe-y-neg-hold", | 
 | 		.mask = BIT(15), | 
 | 		.enable = BIT(15), | 
 | 		.reg_grp = IQS7211_REG_GRP_TP, | 
 | 		.reg_key = IQS7211_REG_KEY_HOLD, | 
 | 	}, | 
 | }; | 
 |  | 
 | struct iqs7211_dev_desc { | 
 | 	const char *tp_name; | 
 | 	const char *kp_name; | 
 | 	u16 prod_num; | 
 | 	u16 show_reset; | 
 | 	u16 ati_error[IQS7211_NUM_REG_GRPS]; | 
 | 	u16 ati_start[IQS7211_NUM_REG_GRPS]; | 
 | 	u16 suspend; | 
 | 	u16 ack_reset; | 
 | 	u16 comms_end; | 
 | 	u16 comms_req; | 
 | 	int charge_shift; | 
 | 	int info_offs; | 
 | 	int gesture_offs; | 
 | 	int contact_offs; | 
 | 	u8 sys_stat; | 
 | 	u8 sys_ctrl; | 
 | 	u8 alp_config; | 
 | 	u8 tp_config; | 
 | 	u8 exp_file; | 
 | 	u8 kp_enable[IQS7211_NUM_REG_GRPS]; | 
 | 	u8 gesture_angle; | 
 | 	u8 rx_tx_map; | 
 | 	u8 cycle_alloc[2]; | 
 | 	u8 cycle_limit[2]; | 
 | 	const struct iqs7211_event_desc *kp_events; | 
 | 	int num_kp_events; | 
 | 	int min_crx_alp; | 
 | 	int num_ctx; | 
 | }; | 
 |  | 
 | static const struct iqs7211_dev_desc iqs7211_devs[] = { | 
 | 	[IQS7210A] = { | 
 | 		.tp_name = "iqs7210a_trackpad", | 
 | 		.kp_name = "iqs7210a_keys", | 
 | 		.prod_num = 944, | 
 | 		.show_reset = BIT(15), | 
 | 		.ati_error = { | 
 | 			[IQS7211_REG_GRP_TP] = BIT(12), | 
 | 			[IQS7211_REG_GRP_BTN] = BIT(0), | 
 | 			[IQS7211_REG_GRP_ALP] = BIT(8), | 
 | 		}, | 
 | 		.ati_start = { | 
 | 			[IQS7211_REG_GRP_TP] = BIT(13), | 
 | 			[IQS7211_REG_GRP_BTN] = BIT(1), | 
 | 			[IQS7211_REG_GRP_ALP] = BIT(9), | 
 | 		}, | 
 | 		.suspend = BIT(11), | 
 | 		.ack_reset = BIT(7), | 
 | 		.comms_end = BIT(2), | 
 | 		.comms_req = BIT(1), | 
 | 		.charge_shift = 4, | 
 | 		.info_offs = 0, | 
 | 		.gesture_offs = 1, | 
 | 		.contact_offs = 4, | 
 | 		.sys_stat = 0x0A, | 
 | 		.sys_ctrl = 0x35, | 
 | 		.alp_config = 0x39, | 
 | 		.tp_config = 0x4E, | 
 | 		.exp_file = 0x57, | 
 | 		.kp_enable = { | 
 | 			[IQS7211_REG_GRP_TP] = 0x58, | 
 | 			[IQS7211_REG_GRP_BTN] = 0x37, | 
 | 			[IQS7211_REG_GRP_ALP] = 0x37, | 
 | 		}, | 
 | 		.gesture_angle = 0x5F, | 
 | 		.rx_tx_map = 0x60, | 
 | 		.cycle_alloc = { 0x66, 0x75, }, | 
 | 		.cycle_limit = { 10, 6, }, | 
 | 		.kp_events = iqs7210a_kp_events, | 
 | 		.num_kp_events = ARRAY_SIZE(iqs7210a_kp_events), | 
 | 		.min_crx_alp = 4, | 
 | 		.num_ctx = IQS7211_MAX_CTX - 1, | 
 | 	}, | 
 | 	[IQS7211A] = { | 
 | 		.tp_name = "iqs7211a_trackpad", | 
 | 		.kp_name = "iqs7211a_keys", | 
 | 		.prod_num = 763, | 
 | 		.show_reset = BIT(7), | 
 | 		.ati_error = { | 
 | 			[IQS7211_REG_GRP_TP] = BIT(3), | 
 | 			[IQS7211_REG_GRP_ALP] = BIT(5), | 
 | 		}, | 
 | 		.ati_start = { | 
 | 			[IQS7211_REG_GRP_TP] = BIT(5), | 
 | 			[IQS7211_REG_GRP_ALP] = BIT(6), | 
 | 		}, | 
 | 		.ack_reset = BIT(7), | 
 | 		.comms_req = BIT(4), | 
 | 		.charge_shift = 0, | 
 | 		.info_offs = 0, | 
 | 		.gesture_offs = 1, | 
 | 		.contact_offs = 4, | 
 | 		.sys_stat = 0x10, | 
 | 		.sys_ctrl = 0x50, | 
 | 		.tp_config = 0x60, | 
 | 		.alp_config = 0x72, | 
 | 		.exp_file = 0x74, | 
 | 		.kp_enable = { | 
 | 			[IQS7211_REG_GRP_TP] = 0x80, | 
 | 		}, | 
 | 		.gesture_angle = 0x87, | 
 | 		.rx_tx_map = 0x90, | 
 | 		.cycle_alloc = { 0xA0, 0xB0, }, | 
 | 		.cycle_limit = { 10, 8, }, | 
 | 		.kp_events = iqs7211a_kp_events, | 
 | 		.num_kp_events = ARRAY_SIZE(iqs7211a_kp_events), | 
 | 		.num_ctx = IQS7211_MAX_CTX - 1, | 
 | 	}, | 
 | 	[IQS7211E] = { | 
 | 		.tp_name = "iqs7211e_trackpad", | 
 | 		.kp_name = "iqs7211e_keys", | 
 | 		.prod_num = 1112, | 
 | 		.show_reset = BIT(7), | 
 | 		.ati_error = { | 
 | 			[IQS7211_REG_GRP_TP] = BIT(3), | 
 | 			[IQS7211_REG_GRP_ALP] = BIT(5), | 
 | 		}, | 
 | 		.ati_start = { | 
 | 			[IQS7211_REG_GRP_TP] = BIT(5), | 
 | 			[IQS7211_REG_GRP_ALP] = BIT(6), | 
 | 		}, | 
 | 		.suspend = BIT(11), | 
 | 		.ack_reset = BIT(7), | 
 | 		.comms_end = BIT(6), | 
 | 		.comms_req = BIT(4), | 
 | 		.charge_shift = 0, | 
 | 		.info_offs = 1, | 
 | 		.gesture_offs = 0, | 
 | 		.contact_offs = 2, | 
 | 		.sys_stat = 0x0E, | 
 | 		.sys_ctrl = 0x33, | 
 | 		.tp_config = 0x41, | 
 | 		.alp_config = 0x36, | 
 | 		.exp_file = 0x4A, | 
 | 		.kp_enable = { | 
 | 			[IQS7211_REG_GRP_TP] = 0x4B, | 
 | 		}, | 
 | 		.gesture_angle = 0x55, | 
 | 		.rx_tx_map = 0x56, | 
 | 		.cycle_alloc = { 0x5D, 0x6C, }, | 
 | 		.cycle_limit = { 10, 11, }, | 
 | 		.kp_events = iqs7211e_kp_events, | 
 | 		.num_kp_events = ARRAY_SIZE(iqs7211e_kp_events), | 
 | 		.num_ctx = IQS7211_MAX_CTX, | 
 | 	}, | 
 | }; | 
 |  | 
 | struct iqs7211_prop_desc { | 
 | 	const char *name; | 
 | 	enum iqs7211_reg_key_id reg_key; | 
 | 	u8 reg_addr[IQS7211_NUM_REG_GRPS][ARRAY_SIZE(iqs7211_devs)]; | 
 | 	int reg_shift; | 
 | 	int reg_width; | 
 | 	int val_pitch; | 
 | 	int val_min; | 
 | 	int val_max; | 
 | 	const char *label; | 
 | }; | 
 |  | 
 | static const struct iqs7211_prop_desc iqs7211_props[] = { | 
 | 	{ | 
 | 		.name = "azoteq,ati-frac-div-fine", | 
 | 		.reg_addr = { | 
 | 			[IQS7211_REG_GRP_TP] = { | 
 | 				[IQS7210A] = 0x1E, | 
 | 				[IQS7211A] = 0x30, | 
 | 				[IQS7211E] = 0x21, | 
 | 			}, | 
 | 			[IQS7211_REG_GRP_BTN] = { | 
 | 				[IQS7210A] = 0x22, | 
 | 			}, | 
 | 			[IQS7211_REG_GRP_ALP] = { | 
 | 				[IQS7210A] = 0x23, | 
 | 				[IQS7211A] = 0x36, | 
 | 				[IQS7211E] = 0x25, | 
 | 			}, | 
 | 		}, | 
 | 		.reg_shift = 9, | 
 | 		.reg_width = 5, | 
 | 		.label = "ATI fine fractional divider", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,ati-frac-mult-coarse", | 
 | 		.reg_addr = { | 
 | 			[IQS7211_REG_GRP_TP] = { | 
 | 				[IQS7210A] = 0x1E, | 
 | 				[IQS7211A] = 0x30, | 
 | 				[IQS7211E] = 0x21, | 
 | 			}, | 
 | 			[IQS7211_REG_GRP_BTN] = { | 
 | 				[IQS7210A] = 0x22, | 
 | 			}, | 
 | 			[IQS7211_REG_GRP_ALP] = { | 
 | 				[IQS7210A] = 0x23, | 
 | 				[IQS7211A] = 0x36, | 
 | 				[IQS7211E] = 0x25, | 
 | 			}, | 
 | 		}, | 
 | 		.reg_shift = 5, | 
 | 		.reg_width = 4, | 
 | 		.label = "ATI coarse fractional multiplier", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,ati-frac-div-coarse", | 
 | 		.reg_addr = { | 
 | 			[IQS7211_REG_GRP_TP] = { | 
 | 				[IQS7210A] = 0x1E, | 
 | 				[IQS7211A] = 0x30, | 
 | 				[IQS7211E] = 0x21, | 
 | 			}, | 
 | 			[IQS7211_REG_GRP_BTN] = { | 
 | 				[IQS7210A] = 0x22, | 
 | 			}, | 
 | 			[IQS7211_REG_GRP_ALP] = { | 
 | 				[IQS7210A] = 0x23, | 
 | 				[IQS7211A] = 0x36, | 
 | 				[IQS7211E] = 0x25, | 
 | 			}, | 
 | 		}, | 
 | 		.reg_shift = 0, | 
 | 		.reg_width = 5, | 
 | 		.label = "ATI coarse fractional divider", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,ati-comp-div", | 
 | 		.reg_addr = { | 
 | 			[IQS7211_REG_GRP_TP] = { | 
 | 				[IQS7210A] = 0x1F, | 
 | 				[IQS7211E] = 0x22, | 
 | 			}, | 
 | 			[IQS7211_REG_GRP_BTN] = { | 
 | 				[IQS7210A] = 0x24, | 
 | 			}, | 
 | 			[IQS7211_REG_GRP_ALP] = { | 
 | 				[IQS7211E] = 0x26, | 
 | 			}, | 
 | 		}, | 
 | 		.reg_shift = 0, | 
 | 		.reg_width = 8, | 
 | 		.val_max = 31, | 
 | 		.label = "ATI compensation divider", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,ati-comp-div", | 
 | 		.reg_addr = { | 
 | 			[IQS7211_REG_GRP_ALP] = { | 
 | 				[IQS7210A] = 0x24, | 
 | 			}, | 
 | 		}, | 
 | 		.reg_shift = 8, | 
 | 		.reg_width = 8, | 
 | 		.val_max = 31, | 
 | 		.label = "ATI compensation divider", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,ati-comp-div", | 
 | 		.reg_addr = { | 
 | 			[IQS7211_REG_GRP_TP] = { | 
 | 				[IQS7211A] = 0x31, | 
 | 			}, | 
 | 			[IQS7211_REG_GRP_ALP] = { | 
 | 				[IQS7211A] = 0x37, | 
 | 			}, | 
 | 		}, | 
 | 		.val_max = 31, | 
 | 		.label = "ATI compensation divider", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,ati-target", | 
 | 		.reg_addr = { | 
 | 			[IQS7211_REG_GRP_TP] = { | 
 | 				[IQS7210A] = 0x20, | 
 | 				[IQS7211A] = 0x32, | 
 | 				[IQS7211E] = 0x23, | 
 | 			}, | 
 | 			[IQS7211_REG_GRP_BTN] = { | 
 | 				[IQS7210A] = 0x27, | 
 | 			}, | 
 | 			[IQS7211_REG_GRP_ALP] = { | 
 | 				[IQS7210A] = 0x28, | 
 | 				[IQS7211A] = 0x38, | 
 | 				[IQS7211E] = 0x27, | 
 | 			}, | 
 | 		}, | 
 | 		.label = "ATI target", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,ati-base", | 
 | 		.reg_addr[IQS7211_REG_GRP_ALP] = { | 
 | 			[IQS7210A] = 0x26, | 
 | 		}, | 
 | 		.reg_shift = 8, | 
 | 		.reg_width = 8, | 
 | 		.val_pitch = 8, | 
 | 		.label = "ATI base", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,ati-base", | 
 | 		.reg_addr[IQS7211_REG_GRP_BTN] = { | 
 | 			[IQS7210A] = 0x26, | 
 | 		}, | 
 | 		.reg_shift = 0, | 
 | 		.reg_width = 8, | 
 | 		.val_pitch = 8, | 
 | 		.label = "ATI base", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,rate-active-ms", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7210A] = 0x29, | 
 | 			[IQS7211A] = 0x40, | 
 | 			[IQS7211E] = 0x28, | 
 | 		}, | 
 | 		.label = "active mode report rate", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,rate-touch-ms", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7210A] = 0x2A, | 
 | 			[IQS7211A] = 0x41, | 
 | 			[IQS7211E] = 0x29, | 
 | 		}, | 
 | 		.label = "idle-touch mode report rate", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,rate-idle-ms", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7210A] = 0x2B, | 
 | 			[IQS7211A] = 0x42, | 
 | 			[IQS7211E] = 0x2A, | 
 | 		}, | 
 | 		.label = "idle mode report rate", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,rate-lp1-ms", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7210A] = 0x2C, | 
 | 			[IQS7211A] = 0x43, | 
 | 			[IQS7211E] = 0x2B, | 
 | 		}, | 
 | 		.label = "low-power mode 1 report rate", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,rate-lp2-ms", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7210A] = 0x2D, | 
 | 			[IQS7211A] = 0x44, | 
 | 			[IQS7211E] = 0x2C, | 
 | 		}, | 
 | 		.label = "low-power mode 2 report rate", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,timeout-active-ms", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7210A] = 0x2E, | 
 | 			[IQS7211A] = 0x45, | 
 | 			[IQS7211E] = 0x2D, | 
 | 		}, | 
 | 		.val_pitch = 1000, | 
 | 		.label = "active mode timeout", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,timeout-touch-ms", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7210A] = 0x2F, | 
 | 			[IQS7211A] = 0x46, | 
 | 			[IQS7211E] = 0x2E, | 
 | 		}, | 
 | 		.val_pitch = 1000, | 
 | 		.label = "idle-touch mode timeout", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,timeout-idle-ms", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7210A] = 0x30, | 
 | 			[IQS7211A] = 0x47, | 
 | 			[IQS7211E] = 0x2F, | 
 | 		}, | 
 | 		.val_pitch = 1000, | 
 | 		.label = "idle mode timeout", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,timeout-lp1-ms", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7210A] = 0x31, | 
 | 			[IQS7211A] = 0x48, | 
 | 			[IQS7211E] = 0x30, | 
 | 		}, | 
 | 		.val_pitch = 1000, | 
 | 		.label = "low-power mode 1 timeout", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,timeout-lp2-ms", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7210A] = 0x32, | 
 | 			[IQS7211E] = 0x31, | 
 | 		}, | 
 | 		.reg_shift = 8, | 
 | 		.reg_width = 8, | 
 | 		.val_pitch = 1000, | 
 | 		.val_max = 60000, | 
 | 		.label = "trackpad reference value update rate", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,timeout-lp2-ms", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7211A] = 0x49, | 
 | 		}, | 
 | 		.val_pitch = 1000, | 
 | 		.val_max = 60000, | 
 | 		.label = "trackpad reference value update rate", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,timeout-ati-ms", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7210A] = 0x32, | 
 | 			[IQS7211E] = 0x31, | 
 | 		}, | 
 | 		.reg_width = 8, | 
 | 		.val_pitch = 1000, | 
 | 		.val_max = 60000, | 
 | 		.label = "ATI error timeout", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,timeout-ati-ms", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7211A] = 0x35, | 
 | 		}, | 
 | 		.val_pitch = 1000, | 
 | 		.val_max = 60000, | 
 | 		.label = "ATI error timeout", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,timeout-comms-ms", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7210A] = 0x33, | 
 | 			[IQS7211A] = 0x4A, | 
 | 			[IQS7211E] = 0x32, | 
 | 		}, | 
 | 		.label = "communication timeout", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,timeout-press-ms", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7210A] = 0x34, | 
 | 		}, | 
 | 		.reg_width = 8, | 
 | 		.val_pitch = 1000, | 
 | 		.val_max = 60000, | 
 | 		.label = "press timeout", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,ati-mode", | 
 | 		.reg_addr[IQS7211_REG_GRP_ALP] = { | 
 | 			[IQS7210A] = 0x37, | 
 | 		}, | 
 | 		.reg_shift = 15, | 
 | 		.reg_width = 1, | 
 | 		.label = "ATI mode", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,ati-mode", | 
 | 		.reg_addr[IQS7211_REG_GRP_BTN] = { | 
 | 			[IQS7210A] = 0x37, | 
 | 		}, | 
 | 		.reg_shift = 7, | 
 | 		.reg_width = 1, | 
 | 		.label = "ATI mode", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,sense-mode", | 
 | 		.reg_addr[IQS7211_REG_GRP_ALP] = { | 
 | 			[IQS7210A] = 0x37, | 
 | 			[IQS7211A] = 0x72, | 
 | 			[IQS7211E] = 0x36, | 
 | 		}, | 
 | 		.reg_shift = 8, | 
 | 		.reg_width = 1, | 
 | 		.label = "sensing mode", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,sense-mode", | 
 | 		.reg_addr[IQS7211_REG_GRP_BTN] = { | 
 | 			[IQS7210A] = 0x37, | 
 | 		}, | 
 | 		.reg_shift = 0, | 
 | 		.reg_width = 2, | 
 | 		.val_max = 2, | 
 | 		.label = "sensing mode", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,fosc-freq", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7210A] = 0x38, | 
 | 			[IQS7211A] = 0x52, | 
 | 			[IQS7211E] = 0x35, | 
 | 		}, | 
 | 		.reg_shift = 4, | 
 | 		.reg_width = 1, | 
 | 		.label = "core clock frequency selection", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,fosc-trim", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7210A] = 0x38, | 
 | 			[IQS7211A] = 0x52, | 
 | 			[IQS7211E] = 0x35, | 
 | 		}, | 
 | 		.reg_shift = 0, | 
 | 		.reg_width = 4, | 
 | 		.label = "core clock frequency trim", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,touch-exit", | 
 | 		.reg_addr = { | 
 | 			[IQS7211_REG_GRP_TP] = { | 
 | 				[IQS7210A] = 0x3B, | 
 | 				[IQS7211A] = 0x53, | 
 | 				[IQS7211E] = 0x38, | 
 | 			}, | 
 | 			[IQS7211_REG_GRP_BTN] = { | 
 | 				[IQS7210A] = 0x3E, | 
 | 			}, | 
 | 		}, | 
 | 		.reg_shift = 8, | 
 | 		.reg_width = 8, | 
 | 		.label = "touch exit factor", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,touch-enter", | 
 | 		.reg_addr = { | 
 | 			[IQS7211_REG_GRP_TP] = { | 
 | 				[IQS7210A] = 0x3B, | 
 | 				[IQS7211A] = 0x53, | 
 | 				[IQS7211E] = 0x38, | 
 | 			}, | 
 | 			[IQS7211_REG_GRP_BTN] = { | 
 | 				[IQS7210A] = 0x3E, | 
 | 			}, | 
 | 		}, | 
 | 		.reg_shift = 0, | 
 | 		.reg_width = 8, | 
 | 		.label = "touch entrance factor", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,thresh", | 
 | 		.reg_addr = { | 
 | 			[IQS7211_REG_GRP_BTN] = { | 
 | 				[IQS7210A] = 0x3C, | 
 | 			}, | 
 | 			[IQS7211_REG_GRP_ALP] = { | 
 | 				[IQS7210A] = 0x3D, | 
 | 				[IQS7211A] = 0x54, | 
 | 				[IQS7211E] = 0x39, | 
 | 			}, | 
 | 		}, | 
 | 		.label = "threshold", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,debounce-exit", | 
 | 		.reg_addr = { | 
 | 			[IQS7211_REG_GRP_BTN] = { | 
 | 				[IQS7210A] = 0x3F, | 
 | 			}, | 
 | 			[IQS7211_REG_GRP_ALP] = { | 
 | 				[IQS7210A] = 0x40, | 
 | 				[IQS7211A] = 0x56, | 
 | 				[IQS7211E] = 0x3A, | 
 | 			}, | 
 | 		}, | 
 | 		.reg_shift = 8, | 
 | 		.reg_width = 8, | 
 | 		.label = "debounce exit factor", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,debounce-enter", | 
 | 		.reg_addr = { | 
 | 			[IQS7211_REG_GRP_BTN] = { | 
 | 				[IQS7210A] = 0x3F, | 
 | 			}, | 
 | 			[IQS7211_REG_GRP_ALP] = { | 
 | 				[IQS7210A] = 0x40, | 
 | 				[IQS7211A] = 0x56, | 
 | 				[IQS7211E] = 0x3A, | 
 | 			}, | 
 | 		}, | 
 | 		.reg_shift = 0, | 
 | 		.reg_width = 8, | 
 | 		.label = "debounce entrance factor", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,conv-frac", | 
 | 		.reg_addr = { | 
 | 			[IQS7211_REG_GRP_TP] = { | 
 | 				[IQS7210A] = 0x48, | 
 | 				[IQS7211A] = 0x58, | 
 | 				[IQS7211E] = 0x3D, | 
 | 			}, | 
 | 			[IQS7211_REG_GRP_BTN] = { | 
 | 				[IQS7210A] = 0x49, | 
 | 			}, | 
 | 			[IQS7211_REG_GRP_ALP] = { | 
 | 				[IQS7210A] = 0x4A, | 
 | 				[IQS7211A] = 0x59, | 
 | 				[IQS7211E] = 0x3E, | 
 | 			}, | 
 | 		}, | 
 | 		.reg_shift = 8, | 
 | 		.reg_width = 8, | 
 | 		.label = "conversion frequency fractional divider", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,conv-period", | 
 | 		.reg_addr = { | 
 | 			[IQS7211_REG_GRP_TP] = { | 
 | 				[IQS7210A] = 0x48, | 
 | 				[IQS7211A] = 0x58, | 
 | 				[IQS7211E] = 0x3D, | 
 | 			}, | 
 | 			[IQS7211_REG_GRP_BTN] = { | 
 | 				[IQS7210A] = 0x49, | 
 | 			}, | 
 | 			[IQS7211_REG_GRP_ALP] = { | 
 | 				[IQS7210A] = 0x4A, | 
 | 				[IQS7211A] = 0x59, | 
 | 				[IQS7211E] = 0x3E, | 
 | 			}, | 
 | 		}, | 
 | 		.reg_shift = 0, | 
 | 		.reg_width = 8, | 
 | 		.label = "conversion period", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,thresh", | 
 | 		.reg_addr[IQS7211_REG_GRP_TP] = { | 
 | 			[IQS7210A] = 0x55, | 
 | 			[IQS7211A] = 0x67, | 
 | 			[IQS7211E] = 0x48, | 
 | 		}, | 
 | 		.reg_shift = 0, | 
 | 		.reg_width = 8, | 
 | 		.label = "threshold", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,contact-split", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7210A] = 0x55, | 
 | 			[IQS7211A] = 0x67, | 
 | 			[IQS7211E] = 0x48, | 
 | 		}, | 
 | 		.reg_shift = 8, | 
 | 		.reg_width = 8, | 
 | 		.label = "contact split factor", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,trim-x", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7210A] = 0x56, | 
 | 			[IQS7211E] = 0x49, | 
 | 		}, | 
 | 		.reg_shift = 0, | 
 | 		.reg_width = 8, | 
 | 		.label = "horizontal trim width", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,trim-x", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7211A] = 0x68, | 
 | 		}, | 
 | 		.label = "horizontal trim width", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,trim-y", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7210A] = 0x56, | 
 | 			[IQS7211E] = 0x49, | 
 | 		}, | 
 | 		.reg_shift = 8, | 
 | 		.reg_width = 8, | 
 | 		.label = "vertical trim height", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,trim-y", | 
 | 		.reg_addr[IQS7211_REG_GRP_SYS] = { | 
 | 			[IQS7211A] = 0x69, | 
 | 		}, | 
 | 		.label = "vertical trim height", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,gesture-max-ms", | 
 | 		.reg_key = IQS7211_REG_KEY_TAP, | 
 | 		.reg_addr[IQS7211_REG_GRP_TP] = { | 
 | 			[IQS7210A] = 0x59, | 
 | 			[IQS7211A] = 0x81, | 
 | 			[IQS7211E] = 0x4C, | 
 | 		}, | 
 | 		.label = "maximum gesture time", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,gesture-mid-ms", | 
 | 		.reg_key = IQS7211_REG_KEY_TAP, | 
 | 		.reg_addr[IQS7211_REG_GRP_TP] = { | 
 | 			[IQS7211E] = 0x4D, | 
 | 		}, | 
 | 		.label = "repeated gesture time", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,gesture-dist", | 
 | 		.reg_key = IQS7211_REG_KEY_TAP, | 
 | 		.reg_addr[IQS7211_REG_GRP_TP] = { | 
 | 			[IQS7210A] = 0x5A, | 
 | 			[IQS7211A] = 0x82, | 
 | 			[IQS7211E] = 0x4E, | 
 | 		}, | 
 | 		.label = "gesture distance", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,gesture-dist", | 
 | 		.reg_key = IQS7211_REG_KEY_HOLD, | 
 | 		.reg_addr[IQS7211_REG_GRP_TP] = { | 
 | 			[IQS7210A] = 0x5A, | 
 | 			[IQS7211A] = 0x82, | 
 | 			[IQS7211E] = 0x4E, | 
 | 		}, | 
 | 		.label = "gesture distance", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,gesture-min-ms", | 
 | 		.reg_key = IQS7211_REG_KEY_HOLD, | 
 | 		.reg_addr[IQS7211_REG_GRP_TP] = { | 
 | 			[IQS7210A] = 0x5B, | 
 | 			[IQS7211A] = 0x83, | 
 | 			[IQS7211E] = 0x4F, | 
 | 		}, | 
 | 		.label = "minimum gesture time", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,gesture-max-ms", | 
 | 		.reg_key = IQS7211_REG_KEY_AXIAL_X, | 
 | 		.reg_addr[IQS7211_REG_GRP_TP] = { | 
 | 			[IQS7210A] = 0x5C, | 
 | 			[IQS7211A] = 0x84, | 
 | 			[IQS7211E] = 0x50, | 
 | 		}, | 
 | 		.label = "maximum gesture time", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,gesture-max-ms", | 
 | 		.reg_key = IQS7211_REG_KEY_AXIAL_Y, | 
 | 		.reg_addr[IQS7211_REG_GRP_TP] = { | 
 | 			[IQS7210A] = 0x5C, | 
 | 			[IQS7211A] = 0x84, | 
 | 			[IQS7211E] = 0x50, | 
 | 		}, | 
 | 		.label = "maximum gesture time", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,gesture-dist", | 
 | 		.reg_key = IQS7211_REG_KEY_AXIAL_X, | 
 | 		.reg_addr[IQS7211_REG_GRP_TP] = { | 
 | 			[IQS7210A] = 0x5D, | 
 | 			[IQS7211A] = 0x85, | 
 | 			[IQS7211E] = 0x51, | 
 | 		}, | 
 | 		.label = "gesture distance", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,gesture-dist", | 
 | 		.reg_key = IQS7211_REG_KEY_AXIAL_Y, | 
 | 		.reg_addr[IQS7211_REG_GRP_TP] = { | 
 | 			[IQS7210A] = 0x5E, | 
 | 			[IQS7211A] = 0x86, | 
 | 			[IQS7211E] = 0x52, | 
 | 		}, | 
 | 		.label = "gesture distance", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,gesture-dist-rep", | 
 | 		.reg_key = IQS7211_REG_KEY_AXIAL_X, | 
 | 		.reg_addr[IQS7211_REG_GRP_TP] = { | 
 | 			[IQS7211E] = 0x53, | 
 | 		}, | 
 | 		.label = "repeated gesture distance", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,gesture-dist-rep", | 
 | 		.reg_key = IQS7211_REG_KEY_AXIAL_Y, | 
 | 		.reg_addr[IQS7211_REG_GRP_TP] = { | 
 | 			[IQS7211E] = 0x54, | 
 | 		}, | 
 | 		.label = "repeated gesture distance", | 
 | 	}, | 
 | 	{ | 
 | 		.name = "azoteq,thresh", | 
 | 		.reg_key = IQS7211_REG_KEY_PALM, | 
 | 		.reg_addr[IQS7211_REG_GRP_TP] = { | 
 | 			[IQS7211E] = 0x55, | 
 | 		}, | 
 | 		.reg_shift = 8, | 
 | 		.reg_width = 8, | 
 | 		.val_max = 42, | 
 | 		.label = "threshold", | 
 | 	}, | 
 | }; | 
 |  | 
 | static const u8 iqs7211_gesture_angle[] = { | 
 | 	0x00, 0x01, 0x02, 0x03, | 
 | 	0x04, 0x06, 0x07, 0x08, | 
 | 	0x09, 0x0A, 0x0B, 0x0C, | 
 | 	0x0E, 0x0F, 0x10, 0x11, | 
 | 	0x12, 0x14, 0x15, 0x16, | 
 | 	0x17, 0x19, 0x1A, 0x1B, | 
 | 	0x1C, 0x1E, 0x1F, 0x21, | 
 | 	0x22, 0x23, 0x25, 0x26, | 
 | 	0x28, 0x2A, 0x2B, 0x2D, | 
 | 	0x2E, 0x30, 0x32, 0x34, | 
 | 	0x36, 0x38, 0x3A, 0x3C, | 
 | 	0x3E, 0x40, 0x42, 0x45, | 
 | 	0x47, 0x4A, 0x4C, 0x4F, | 
 | 	0x52, 0x55, 0x58, 0x5B, | 
 | 	0x5F, 0x63, 0x66, 0x6B, | 
 | 	0x6F, 0x73, 0x78, 0x7E, | 
 | 	0x83, 0x89, 0x90, 0x97, | 
 | 	0x9E, 0xA7, 0xB0, 0xBA, | 
 | 	0xC5, 0xD1, 0xDF, 0xEF, | 
 | }; | 
 |  | 
 | struct iqs7211_ver_info { | 
 | 	__le16 prod_num; | 
 | 	__le16 major; | 
 | 	__le16 minor; | 
 | 	__le32 patch; | 
 | } __packed; | 
 |  | 
 | struct iqs7211_touch_data { | 
 | 	__le16 abs_x; | 
 | 	__le16 abs_y; | 
 | 	__le16 pressure; | 
 | 	__le16 area; | 
 | } __packed; | 
 |  | 
 | struct iqs7211_tp_config { | 
 | 	u8 tp_settings; | 
 | 	u8 total_rx; | 
 | 	u8 total_tx; | 
 | 	u8 num_contacts; | 
 | 	__le16 max_x; | 
 | 	__le16 max_y; | 
 | } __packed; | 
 |  | 
 | struct iqs7211_private { | 
 | 	const struct iqs7211_dev_desc *dev_desc; | 
 | 	struct gpio_desc *reset_gpio; | 
 | 	struct gpio_desc *irq_gpio; | 
 | 	struct i2c_client *client; | 
 | 	struct input_dev *tp_idev; | 
 | 	struct input_dev *kp_idev; | 
 | 	struct iqs7211_ver_info ver_info; | 
 | 	struct iqs7211_tp_config tp_config; | 
 | 	struct touchscreen_properties prop; | 
 | 	struct list_head reg_field_head; | 
 | 	enum iqs7211_comms_mode comms_init; | 
 | 	enum iqs7211_comms_mode comms_mode; | 
 | 	unsigned int num_contacts; | 
 | 	unsigned int kp_code[ARRAY_SIZE(iqs7211e_kp_events)]; | 
 | 	u8 rx_tx_map[IQS7211_MAX_CTX + 1]; | 
 | 	u8 cycle_alloc[2][33]; | 
 | 	u8 exp_file[2]; | 
 | 	u16 event_mask; | 
 | 	u16 ati_start; | 
 | 	u16 gesture_cache; | 
 | }; | 
 |  | 
 | static int iqs7211_irq_poll(struct iqs7211_private *iqs7211, u64 timeout_us) | 
 | { | 
 | 	int error, val; | 
 |  | 
 | 	error = readx_poll_timeout(gpiod_get_value_cansleep, iqs7211->irq_gpio, | 
 | 				   val, val, IQS7211_COMMS_SLEEP_US, timeout_us); | 
 |  | 
 | 	return val < 0 ? val : error; | 
 | } | 
 |  | 
 | static int iqs7211_hard_reset(struct iqs7211_private *iqs7211) | 
 | { | 
 | 	if (!iqs7211->reset_gpio) | 
 | 		return 0; | 
 |  | 
 | 	gpiod_set_value_cansleep(iqs7211->reset_gpio, 1); | 
 |  | 
 | 	/* | 
 | 	 * The following delay ensures the shared RDY/MCLR pin is sampled in | 
 | 	 * between periodic assertions by the device and assumes the default | 
 | 	 * communication timeout has not been overwritten in OTP memory. | 
 | 	 */ | 
 | 	if (iqs7211->reset_gpio == iqs7211->irq_gpio) | 
 | 		msleep(IQS7211_RESET_TIMEOUT_MS); | 
 | 	else | 
 | 		usleep_range(1000, 1100); | 
 |  | 
 | 	gpiod_set_value_cansleep(iqs7211->reset_gpio, 0); | 
 | 	if (iqs7211->reset_gpio == iqs7211->irq_gpio) | 
 | 		iqs7211_irq_wait(); | 
 |  | 
 | 	return iqs7211_irq_poll(iqs7211, IQS7211_START_TIMEOUT_US); | 
 | } | 
 |  | 
 | static int iqs7211_force_comms(struct iqs7211_private *iqs7211) | 
 | { | 
 | 	u8 msg_buf[] = { 0xFF, }; | 
 | 	int ret; | 
 |  | 
 | 	switch (iqs7211->comms_mode) { | 
 | 	case IQS7211_COMMS_MODE_WAIT: | 
 | 		return iqs7211_irq_poll(iqs7211, IQS7211_START_TIMEOUT_US); | 
 |  | 
 | 	case IQS7211_COMMS_MODE_FREE: | 
 | 		return 0; | 
 |  | 
 | 	case IQS7211_COMMS_MODE_FORCE: | 
 | 		break; | 
 |  | 
 | 	default: | 
 | 		return -EINVAL; | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * The device cannot communicate until it asserts its interrupt (RDY) | 
 | 	 * pin. Attempts to do so while RDY is deasserted return an ACK; how- | 
 | 	 * ever all write data is ignored, and all read data returns 0xEE. | 
 | 	 * | 
 | 	 * Unsolicited communication must be preceded by a special force com- | 
 | 	 * munication command, after which the device eventually asserts its | 
 | 	 * RDY pin and agrees to communicate. | 
 | 	 * | 
 | 	 * Regardless of whether communication is forced or the result of an | 
 | 	 * interrupt, the device automatically deasserts its RDY pin once it | 
 | 	 * detects an I2C stop condition, or a timeout expires. | 
 | 	 */ | 
 | 	ret = gpiod_get_value_cansleep(iqs7211->irq_gpio); | 
 | 	if (ret < 0) | 
 | 		return ret; | 
 | 	else if (ret > 0) | 
 | 		return 0; | 
 |  | 
 | 	ret = i2c_master_send(iqs7211->client, msg_buf, sizeof(msg_buf)); | 
 | 	if (ret < (int)sizeof(msg_buf)) { | 
 | 		if (ret >= 0) | 
 | 			ret = -EIO; | 
 |  | 
 | 		msleep(IQS7211_COMMS_RETRY_MS); | 
 | 		return ret; | 
 | 	} | 
 |  | 
 | 	iqs7211_irq_wait(); | 
 |  | 
 | 	return iqs7211_irq_poll(iqs7211, IQS7211_COMMS_TIMEOUT_US); | 
 | } | 
 |  | 
 | static int iqs7211_read_burst(struct iqs7211_private *iqs7211, | 
 | 			      u8 reg, void *val, u16 val_len) | 
 | { | 
 | 	int ret, i; | 
 | 	struct i2c_client *client = iqs7211->client; | 
 | 	struct i2c_msg msg[] = { | 
 | 		{ | 
 | 			.addr = client->addr, | 
 | 			.flags = 0, | 
 | 			.len = sizeof(reg), | 
 | 			.buf = ®, | 
 | 		}, | 
 | 		{ | 
 | 			.addr = client->addr, | 
 | 			.flags = I2C_M_RD, | 
 | 			.len = val_len, | 
 | 			.buf = (u8 *)val, | 
 | 		}, | 
 | 	}; | 
 |  | 
 | 	/* | 
 | 	 * The following loop protects against an edge case in which the RDY | 
 | 	 * pin is automatically deasserted just as the read is initiated. In | 
 | 	 * that case, the read must be retried using forced communication. | 
 | 	 */ | 
 | 	for (i = 0; i < IQS7211_NUM_RETRIES; i++) { | 
 | 		ret = iqs7211_force_comms(iqs7211); | 
 | 		if (ret < 0) | 
 | 			continue; | 
 |  | 
 | 		ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); | 
 | 		if (ret < (int)ARRAY_SIZE(msg)) { | 
 | 			if (ret >= 0) | 
 | 				ret = -EIO; | 
 |  | 
 | 			msleep(IQS7211_COMMS_RETRY_MS); | 
 | 			continue; | 
 | 		} | 
 |  | 
 | 		if (get_unaligned_le16(msg[1].buf) == IQS7211_COMMS_ERROR) { | 
 | 			ret = -ENODATA; | 
 | 			continue; | 
 | 		} | 
 |  | 
 | 		ret = 0; | 
 | 		break; | 
 | 	} | 
 |  | 
 | 	iqs7211_irq_wait(); | 
 |  | 
 | 	if (ret < 0) | 
 | 		dev_err(&client->dev, | 
 | 			"Failed to read from address 0x%02X: %d\n", reg, ret); | 
 |  | 
 | 	return ret; | 
 | } | 
 |  | 
 | static int iqs7211_read_word(struct iqs7211_private *iqs7211, u8 reg, u16 *val) | 
 | { | 
 | 	__le16 val_buf; | 
 | 	int error; | 
 |  | 
 | 	error = iqs7211_read_burst(iqs7211, reg, &val_buf, sizeof(val_buf)); | 
 | 	if (error) | 
 | 		return error; | 
 |  | 
 | 	*val = le16_to_cpu(val_buf); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int iqs7211_write_burst(struct iqs7211_private *iqs7211, | 
 | 			       u8 reg, const void *val, u16 val_len) | 
 | { | 
 | 	int msg_len = sizeof(reg) + val_len; | 
 | 	int ret, i; | 
 | 	struct i2c_client *client = iqs7211->client; | 
 | 	u8 *msg_buf; | 
 |  | 
 | 	msg_buf = kzalloc(msg_len, GFP_KERNEL); | 
 | 	if (!msg_buf) | 
 | 		return -ENOMEM; | 
 |  | 
 | 	*msg_buf = reg; | 
 | 	memcpy(msg_buf + sizeof(reg), val, val_len); | 
 |  | 
 | 	/* | 
 | 	 * The following loop protects against an edge case in which the RDY | 
 | 	 * pin is automatically asserted just before the force communication | 
 | 	 * command is sent. | 
 | 	 * | 
 | 	 * In that case, the subsequent I2C stop condition tricks the device | 
 | 	 * into preemptively deasserting the RDY pin and the command must be | 
 | 	 * sent again. | 
 | 	 */ | 
 | 	for (i = 0; i < IQS7211_NUM_RETRIES; i++) { | 
 | 		ret = iqs7211_force_comms(iqs7211); | 
 | 		if (ret < 0) | 
 | 			continue; | 
 |  | 
 | 		ret = i2c_master_send(client, msg_buf, msg_len); | 
 | 		if (ret < msg_len) { | 
 | 			if (ret >= 0) | 
 | 				ret = -EIO; | 
 |  | 
 | 			msleep(IQS7211_COMMS_RETRY_MS); | 
 | 			continue; | 
 | 		} | 
 |  | 
 | 		ret = 0; | 
 | 		break; | 
 | 	} | 
 |  | 
 | 	kfree(msg_buf); | 
 |  | 
 | 	iqs7211_irq_wait(); | 
 |  | 
 | 	if (ret < 0) | 
 | 		dev_err(&client->dev, | 
 | 			"Failed to write to address 0x%02X: %d\n", reg, ret); | 
 |  | 
 | 	return ret; | 
 | } | 
 |  | 
 | static int iqs7211_write_word(struct iqs7211_private *iqs7211, u8 reg, u16 val) | 
 | { | 
 | 	__le16 val_buf = cpu_to_le16(val); | 
 |  | 
 | 	return iqs7211_write_burst(iqs7211, reg, &val_buf, sizeof(val_buf)); | 
 | } | 
 |  | 
 | static int iqs7211_start_comms(struct iqs7211_private *iqs7211) | 
 | { | 
 | 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; | 
 | 	struct i2c_client *client = iqs7211->client; | 
 | 	bool forced_comms; | 
 | 	unsigned int val; | 
 | 	u16 comms_setup; | 
 | 	int error; | 
 |  | 
 | 	/* | 
 | 	 * Until forced communication can be enabled, the host must wait for a | 
 | 	 * communication window each time it intends to elicit a response from | 
 | 	 * the device. | 
 | 	 * | 
 | 	 * Forced communication is not necessary, however, if the host adapter | 
 | 	 * can support clock stretching. In that case, the device freely clock | 
 | 	 * stretches until all pending conversions are complete. | 
 | 	 */ | 
 | 	forced_comms = device_property_present(&client->dev, | 
 | 					       "azoteq,forced-comms"); | 
 |  | 
 | 	error = device_property_read_u32(&client->dev, | 
 | 					 "azoteq,forced-comms-default", &val); | 
 | 	if (error == -EINVAL) { | 
 | 		iqs7211->comms_init = IQS7211_COMMS_MODE_WAIT; | 
 | 	} else if (error) { | 
 | 		dev_err(&client->dev, | 
 | 			"Failed to read default communication mode: %d\n", | 
 | 			error); | 
 | 		return error; | 
 | 	} else if (val) { | 
 | 		iqs7211->comms_init = forced_comms ? IQS7211_COMMS_MODE_FORCE | 
 | 						   : IQS7211_COMMS_MODE_WAIT; | 
 | 	} else { | 
 | 		iqs7211->comms_init = forced_comms ? IQS7211_COMMS_MODE_WAIT | 
 | 						   : IQS7211_COMMS_MODE_FREE; | 
 | 	} | 
 |  | 
 | 	iqs7211->comms_mode = iqs7211->comms_init; | 
 |  | 
 | 	error = iqs7211_hard_reset(iqs7211); | 
 | 	if (error) { | 
 | 		dev_err(&client->dev, "Failed to reset device: %d\n", error); | 
 | 		return error; | 
 | 	} | 
 |  | 
 | 	error = iqs7211_read_burst(iqs7211, IQS7211_PROD_NUM, | 
 | 				   &iqs7211->ver_info, | 
 | 				   sizeof(iqs7211->ver_info)); | 
 | 	if (error) | 
 | 		return error; | 
 |  | 
 | 	if (le16_to_cpu(iqs7211->ver_info.prod_num) != dev_desc->prod_num) { | 
 | 		dev_err(&client->dev, "Invalid product number: %u\n", | 
 | 			le16_to_cpu(iqs7211->ver_info.prod_num)); | 
 | 		return -EINVAL; | 
 | 	} | 
 |  | 
 | 	error = iqs7211_read_word(iqs7211, dev_desc->sys_ctrl + 1, | 
 | 				  &comms_setup); | 
 | 	if (error) | 
 | 		return error; | 
 |  | 
 | 	if (forced_comms) | 
 | 		comms_setup |= dev_desc->comms_req; | 
 | 	else | 
 | 		comms_setup &= ~dev_desc->comms_req; | 
 |  | 
 | 	error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl + 1, | 
 | 				   comms_setup | dev_desc->comms_end); | 
 | 	if (error) | 
 | 		return error; | 
 |  | 
 | 	if (forced_comms) | 
 | 		iqs7211->comms_mode = IQS7211_COMMS_MODE_FORCE; | 
 | 	else | 
 | 		iqs7211->comms_mode = IQS7211_COMMS_MODE_FREE; | 
 |  | 
 | 	error = iqs7211_read_burst(iqs7211, dev_desc->exp_file, | 
 | 				   iqs7211->exp_file, | 
 | 				   sizeof(iqs7211->exp_file)); | 
 | 	if (error) | 
 | 		return error; | 
 |  | 
 | 	error = iqs7211_read_burst(iqs7211, dev_desc->tp_config, | 
 | 				   &iqs7211->tp_config, | 
 | 				   sizeof(iqs7211->tp_config)); | 
 | 	if (error) | 
 | 		return error; | 
 |  | 
 | 	error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl + 1, | 
 | 				   comms_setup); | 
 | 	if (error) | 
 | 		return error; | 
 |  | 
 | 	iqs7211->event_mask = comms_setup & ~IQS7211_EVENT_MASK_ALL; | 
 | 	iqs7211->event_mask |= (IQS7211_EVENT_MASK_ATI | IQS7211_EVENT_MODE); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int iqs7211_init_device(struct iqs7211_private *iqs7211) | 
 | { | 
 | 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; | 
 | 	struct iqs7211_reg_field_desc *reg_field; | 
 | 	__le16 sys_ctrl[] = { | 
 | 		cpu_to_le16(dev_desc->ack_reset), | 
 | 		cpu_to_le16(iqs7211->event_mask), | 
 | 	}; | 
 | 	int error, i; | 
 |  | 
 | 	/* | 
 | 	 * Acknowledge reset before writing any registers in case the device | 
 | 	 * suffers a spurious reset during initialization. The communication | 
 | 	 * mode is configured at this time as well. | 
 | 	 */ | 
 | 	error = iqs7211_write_burst(iqs7211, dev_desc->sys_ctrl, sys_ctrl, | 
 | 				    sizeof(sys_ctrl)); | 
 | 	if (error) | 
 | 		return error; | 
 |  | 
 | 	if (iqs7211->event_mask & dev_desc->comms_req) | 
 | 		iqs7211->comms_mode = IQS7211_COMMS_MODE_FORCE; | 
 | 	else | 
 | 		iqs7211->comms_mode = IQS7211_COMMS_MODE_FREE; | 
 |  | 
 | 	/* | 
 | 	 * Take advantage of the stop-bit disable function, if available, to | 
 | 	 * save the trouble of having to reopen a communication window after | 
 | 	 * each read or write. | 
 | 	 */ | 
 | 	error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl + 1, | 
 | 				   iqs7211->event_mask | dev_desc->comms_end); | 
 | 	if (error) | 
 | 		return error; | 
 |  | 
 | 	list_for_each_entry(reg_field, &iqs7211->reg_field_head, list) { | 
 | 		u16 new_val = reg_field->val; | 
 |  | 
 | 		if (reg_field->mask < U16_MAX) { | 
 | 			u16 old_val; | 
 |  | 
 | 			error = iqs7211_read_word(iqs7211, reg_field->addr, | 
 | 						  &old_val); | 
 | 			if (error) | 
 | 				return error; | 
 |  | 
 | 			new_val = old_val & ~reg_field->mask; | 
 | 			new_val |= reg_field->val; | 
 |  | 
 | 			if (new_val == old_val) | 
 | 				continue; | 
 | 		} | 
 |  | 
 | 		error = iqs7211_write_word(iqs7211, reg_field->addr, new_val); | 
 | 		if (error) | 
 | 			return error; | 
 | 	} | 
 |  | 
 | 	error = iqs7211_write_burst(iqs7211, dev_desc->tp_config, | 
 | 				    &iqs7211->tp_config, | 
 | 				    sizeof(iqs7211->tp_config)); | 
 | 	if (error) | 
 | 		return error; | 
 |  | 
 | 	if (**iqs7211->cycle_alloc) { | 
 | 		error = iqs7211_write_burst(iqs7211, dev_desc->rx_tx_map, | 
 | 					    &iqs7211->rx_tx_map, | 
 | 					    dev_desc->num_ctx); | 
 | 		if (error) | 
 | 			return error; | 
 |  | 
 | 		for (i = 0; i < sizeof(dev_desc->cycle_limit); i++) { | 
 | 			error = iqs7211_write_burst(iqs7211, | 
 | 						    dev_desc->cycle_alloc[i], | 
 | 						    iqs7211->cycle_alloc[i], | 
 | 						    dev_desc->cycle_limit[i] * 3); | 
 | 			if (error) | 
 | 				return error; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	*sys_ctrl = cpu_to_le16(iqs7211->ati_start); | 
 |  | 
 | 	return iqs7211_write_burst(iqs7211, dev_desc->sys_ctrl, sys_ctrl, | 
 | 				   sizeof(sys_ctrl)); | 
 | } | 
 |  | 
 | static int iqs7211_add_field(struct iqs7211_private *iqs7211, | 
 | 			     struct iqs7211_reg_field_desc new_field) | 
 | { | 
 | 	struct i2c_client *client = iqs7211->client; | 
 | 	struct iqs7211_reg_field_desc *reg_field; | 
 |  | 
 | 	if (!new_field.addr) | 
 | 		return 0; | 
 |  | 
 | 	list_for_each_entry(reg_field, &iqs7211->reg_field_head, list) { | 
 | 		if (reg_field->addr != new_field.addr) | 
 | 			continue; | 
 |  | 
 | 		reg_field->mask |= new_field.mask; | 
 | 		reg_field->val |= new_field.val; | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	reg_field = devm_kzalloc(&client->dev, sizeof(*reg_field), GFP_KERNEL); | 
 | 	if (!reg_field) | 
 | 		return -ENOMEM; | 
 |  | 
 | 	reg_field->addr = new_field.addr; | 
 | 	reg_field->mask = new_field.mask; | 
 | 	reg_field->val = new_field.val; | 
 |  | 
 | 	list_add(®_field->list, &iqs7211->reg_field_head); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int iqs7211_parse_props(struct iqs7211_private *iqs7211, | 
 | 			       struct fwnode_handle *reg_grp_node, | 
 | 			       enum iqs7211_reg_grp_id reg_grp, | 
 | 			       enum iqs7211_reg_key_id reg_key) | 
 | { | 
 | 	struct i2c_client *client = iqs7211->client; | 
 | 	int i; | 
 |  | 
 | 	for (i = 0; i < ARRAY_SIZE(iqs7211_props); i++) { | 
 | 		const char *name = iqs7211_props[i].name; | 
 | 		u8 reg_addr = iqs7211_props[i].reg_addr[reg_grp] | 
 | 						       [iqs7211->dev_desc - | 
 | 							iqs7211_devs]; | 
 | 		int reg_shift = iqs7211_props[i].reg_shift; | 
 | 		int reg_width = iqs7211_props[i].reg_width ? : 16; | 
 | 		int val_pitch = iqs7211_props[i].val_pitch ? : 1; | 
 | 		int val_min = iqs7211_props[i].val_min; | 
 | 		int val_max = iqs7211_props[i].val_max; | 
 | 		const char *label = iqs7211_props[i].label ? : name; | 
 | 		struct iqs7211_reg_field_desc reg_field; | 
 | 		unsigned int val; | 
 | 		int error; | 
 |  | 
 | 		if (iqs7211_props[i].reg_key != reg_key) | 
 | 			continue; | 
 |  | 
 | 		if (!reg_addr) | 
 | 			continue; | 
 |  | 
 | 		error = fwnode_property_read_u32(reg_grp_node, name, &val); | 
 | 		if (error == -EINVAL) { | 
 | 			continue; | 
 | 		} else if (error) { | 
 | 			dev_err(&client->dev, "Failed to read %s %s: %d\n", | 
 | 				fwnode_get_name(reg_grp_node), label, error); | 
 | 			return error; | 
 | 		} | 
 |  | 
 | 		if (!val_max) | 
 | 			val_max = GENMASK(reg_width - 1, 0) * val_pitch; | 
 |  | 
 | 		if (val < val_min || val > val_max) { | 
 | 			dev_err(&client->dev, "Invalid %s: %u\n", label, val); | 
 | 			return -EINVAL; | 
 | 		} | 
 |  | 
 | 		reg_field.addr = reg_addr; | 
 | 		reg_field.mask = GENMASK(reg_shift + reg_width - 1, reg_shift); | 
 | 		reg_field.val = val / val_pitch << reg_shift; | 
 |  | 
 | 		error = iqs7211_add_field(iqs7211, reg_field); | 
 | 		if (error) | 
 | 			return error; | 
 | 	} | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int iqs7211_parse_event(struct iqs7211_private *iqs7211, | 
 | 			       struct fwnode_handle *event_node, | 
 | 			       enum iqs7211_reg_grp_id reg_grp, | 
 | 			       enum iqs7211_reg_key_id reg_key, | 
 | 			       unsigned int *event_code) | 
 | { | 
 | 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; | 
 | 	struct i2c_client *client = iqs7211->client; | 
 | 	struct iqs7211_reg_field_desc reg_field; | 
 | 	unsigned int val; | 
 | 	int error; | 
 |  | 
 | 	error = iqs7211_parse_props(iqs7211, event_node, reg_grp, reg_key); | 
 | 	if (error) | 
 | 		return error; | 
 |  | 
 | 	if (reg_key == IQS7211_REG_KEY_AXIAL_X || | 
 | 	    reg_key == IQS7211_REG_KEY_AXIAL_Y) { | 
 | 		error = fwnode_property_read_u32(event_node, | 
 | 						 "azoteq,gesture-angle", &val); | 
 | 		if (!error) { | 
 | 			if (val >= ARRAY_SIZE(iqs7211_gesture_angle)) { | 
 | 				dev_err(&client->dev, | 
 | 					"Invalid %s gesture angle: %u\n", | 
 | 					fwnode_get_name(event_node), val); | 
 | 				return -EINVAL; | 
 | 			} | 
 |  | 
 | 			reg_field.addr = dev_desc->gesture_angle; | 
 | 			reg_field.mask = U8_MAX; | 
 | 			reg_field.val = iqs7211_gesture_angle[val]; | 
 |  | 
 | 			error = iqs7211_add_field(iqs7211, reg_field); | 
 | 			if (error) | 
 | 				return error; | 
 | 		} else if (error != -EINVAL) { | 
 | 			dev_err(&client->dev, | 
 | 				"Failed to read %s gesture angle: %d\n", | 
 | 				fwnode_get_name(event_node), error); | 
 | 			return error; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	error = fwnode_property_read_u32(event_node, "linux,code", event_code); | 
 | 	if (error == -EINVAL) | 
 | 		error = 0; | 
 | 	else if (error) | 
 | 		dev_err(&client->dev, "Failed to read %s code: %d\n", | 
 | 			fwnode_get_name(event_node), error); | 
 |  | 
 | 	return error; | 
 | } | 
 |  | 
 | static int iqs7211_parse_cycles(struct iqs7211_private *iqs7211, | 
 | 				struct fwnode_handle *tp_node) | 
 | { | 
 | 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; | 
 | 	struct i2c_client *client = iqs7211->client; | 
 | 	int num_cycles = dev_desc->cycle_limit[0] + dev_desc->cycle_limit[1]; | 
 | 	int error, count, i, j, k, cycle_start; | 
 | 	unsigned int cycle_alloc[IQS7211_MAX_CYCLES][2]; | 
 | 	u8 total_rx = iqs7211->tp_config.total_rx; | 
 | 	u8 total_tx = iqs7211->tp_config.total_tx; | 
 |  | 
 | 	for (i = 0; i < IQS7211_MAX_CYCLES * 2; i++) | 
 | 		*(cycle_alloc[0] + i) = U8_MAX; | 
 |  | 
 | 	count = fwnode_property_count_u32(tp_node, "azoteq,channel-select"); | 
 | 	if (count == -EINVAL) { | 
 | 		/* | 
 | 		 * Assign each sensing cycle's slots (0 and 1) to a channel, | 
 | 		 * defined as the intersection between two CRx and CTx pins. | 
 | 		 * A channel assignment of 255 means the slot is unused. | 
 | 		 */ | 
 | 		for (i = 0, cycle_start = 0; i < total_tx; i++) { | 
 | 			int cycle_stop = 0; | 
 |  | 
 | 			for (j = 0; j < total_rx; j++) { | 
 | 				/* | 
 | 				 * Channels formed by CRx0-3 and CRx4-7 are | 
 | 				 * bound to slots 0 and 1, respectively. | 
 | 				 */ | 
 | 				int slot = iqs7211->rx_tx_map[j] < 4 ? 0 : 1; | 
 | 				int chan = i * total_rx + j; | 
 |  | 
 | 				for (k = cycle_start; k < num_cycles; k++) { | 
 | 					if (cycle_alloc[k][slot] < U8_MAX) | 
 | 						continue; | 
 |  | 
 | 					cycle_alloc[k][slot] = chan; | 
 | 					break; | 
 | 				} | 
 |  | 
 | 				if (k < num_cycles) { | 
 | 					cycle_stop = max(k, cycle_stop); | 
 | 					continue; | 
 | 				} | 
 |  | 
 | 				dev_err(&client->dev, | 
 | 					"Insufficient number of cycles\n"); | 
 | 				return -EINVAL; | 
 | 			} | 
 |  | 
 | 			/* | 
 | 			 * Sensing cycles cannot straddle more than one CTx | 
 | 			 * pin. As such, the next row's starting cycle must | 
 | 			 * be greater than the previous row's highest cycle. | 
 | 			 */ | 
 | 			cycle_start = cycle_stop + 1; | 
 | 		} | 
 | 	} else if (count < 0) { | 
 | 		dev_err(&client->dev, "Failed to count channels: %d\n", count); | 
 | 		return count; | 
 | 	} else if (count > num_cycles * 2) { | 
 | 		dev_err(&client->dev, "Insufficient number of cycles\n"); | 
 | 		return -EINVAL; | 
 | 	} else if (count > 0) { | 
 | 		error = fwnode_property_read_u32_array(tp_node, | 
 | 						       "azoteq,channel-select", | 
 | 						       cycle_alloc[0], count); | 
 | 		if (error) { | 
 | 			dev_err(&client->dev, "Failed to read channels: %d\n", | 
 | 				error); | 
 | 			return error; | 
 | 		} | 
 |  | 
 | 		for (i = 0; i < count; i++) { | 
 | 			int chan = *(cycle_alloc[0] + i); | 
 |  | 
 | 			if (chan == U8_MAX) | 
 | 				continue; | 
 |  | 
 | 			if (chan >= total_rx * total_tx) { | 
 | 				dev_err(&client->dev, "Invalid channel: %d\n", | 
 | 					chan); | 
 | 				return -EINVAL; | 
 | 			} | 
 |  | 
 | 			for (j = 0; j < count; j++) { | 
 | 				if (j == i || *(cycle_alloc[0] + j) != chan) | 
 | 					continue; | 
 |  | 
 | 				dev_err(&client->dev, "Duplicate channel: %d\n", | 
 | 					chan); | 
 | 				return -EINVAL; | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * Once the raw channel assignments have been derived, they must be | 
 | 	 * packed according to the device's register map. | 
 | 	 */ | 
 | 	for (i = 0, cycle_start = 0; i < sizeof(dev_desc->cycle_limit); i++) { | 
 | 		int offs = 0; | 
 |  | 
 | 		for (j = cycle_start; | 
 | 		     j < cycle_start + dev_desc->cycle_limit[i]; j++) { | 
 | 			iqs7211->cycle_alloc[i][offs++] = 0x05; | 
 | 			iqs7211->cycle_alloc[i][offs++] = cycle_alloc[j][0]; | 
 | 			iqs7211->cycle_alloc[i][offs++] = cycle_alloc[j][1]; | 
 | 		} | 
 |  | 
 | 		cycle_start += dev_desc->cycle_limit[i]; | 
 | 	} | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int iqs7211_parse_tp(struct iqs7211_private *iqs7211, | 
 | 			    struct fwnode_handle *tp_node) | 
 | { | 
 | 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; | 
 | 	struct i2c_client *client = iqs7211->client; | 
 | 	unsigned int pins[IQS7211_MAX_CTX]; | 
 | 	int error, count, i, j; | 
 |  | 
 | 	count = fwnode_property_count_u32(tp_node, "azoteq,rx-enable"); | 
 | 	if (count == -EINVAL) { | 
 | 		return 0; | 
 | 	} else if (count < 0) { | 
 | 		dev_err(&client->dev, "Failed to count CRx pins: %d\n", count); | 
 | 		return count; | 
 | 	} else if (count > IQS7211_NUM_CRX) { | 
 | 		dev_err(&client->dev, "Invalid number of CRx pins\n"); | 
 | 		return -EINVAL; | 
 | 	} | 
 |  | 
 | 	error = fwnode_property_read_u32_array(tp_node, "azoteq,rx-enable", | 
 | 					       pins, count); | 
 | 	if (error) { | 
 | 		dev_err(&client->dev, "Failed to read CRx pins: %d\n", error); | 
 | 		return error; | 
 | 	} | 
 |  | 
 | 	for (i = 0; i < count; i++) { | 
 | 		if (pins[i] >= IQS7211_NUM_CRX) { | 
 | 			dev_err(&client->dev, "Invalid CRx pin: %u\n", pins[i]); | 
 | 			return -EINVAL; | 
 | 		} | 
 |  | 
 | 		iqs7211->rx_tx_map[i] = pins[i]; | 
 | 	} | 
 |  | 
 | 	iqs7211->tp_config.total_rx = count; | 
 |  | 
 | 	count = fwnode_property_count_u32(tp_node, "azoteq,tx-enable"); | 
 | 	if (count < 0) { | 
 | 		dev_err(&client->dev, "Failed to count CTx pins: %d\n", count); | 
 | 		return count; | 
 | 	} else if (count > dev_desc->num_ctx) { | 
 | 		dev_err(&client->dev, "Invalid number of CTx pins\n"); | 
 | 		return -EINVAL; | 
 | 	} | 
 |  | 
 | 	error = fwnode_property_read_u32_array(tp_node, "azoteq,tx-enable", | 
 | 					       pins, count); | 
 | 	if (error) { | 
 | 		dev_err(&client->dev, "Failed to read CTx pins: %d\n", error); | 
 | 		return error; | 
 | 	} | 
 |  | 
 | 	for (i = 0; i < count; i++) { | 
 | 		if (pins[i] >= dev_desc->num_ctx) { | 
 | 			dev_err(&client->dev, "Invalid CTx pin: %u\n", pins[i]); | 
 | 			return -EINVAL; | 
 | 		} | 
 |  | 
 | 		for (j = 0; j < iqs7211->tp_config.total_rx; j++) { | 
 | 			if (iqs7211->rx_tx_map[j] != pins[i]) | 
 | 				continue; | 
 |  | 
 | 			dev_err(&client->dev, "Conflicting CTx pin: %u\n", | 
 | 				pins[i]); | 
 | 			return -EINVAL; | 
 | 		} | 
 |  | 
 | 		iqs7211->rx_tx_map[iqs7211->tp_config.total_rx + i] = pins[i]; | 
 | 	} | 
 |  | 
 | 	iqs7211->tp_config.total_tx = count; | 
 |  | 
 | 	return iqs7211_parse_cycles(iqs7211, tp_node); | 
 | } | 
 |  | 
 | static int iqs7211_parse_alp(struct iqs7211_private *iqs7211, | 
 | 			     struct fwnode_handle *alp_node) | 
 | { | 
 | 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; | 
 | 	struct i2c_client *client = iqs7211->client; | 
 | 	struct iqs7211_reg_field_desc reg_field; | 
 | 	int error, count, i; | 
 |  | 
 | 	count = fwnode_property_count_u32(alp_node, "azoteq,rx-enable"); | 
 | 	if (count < 0 && count != -EINVAL) { | 
 | 		dev_err(&client->dev, "Failed to count CRx pins: %d\n", count); | 
 | 		return count; | 
 | 	} else if (count > IQS7211_NUM_CRX) { | 
 | 		dev_err(&client->dev, "Invalid number of CRx pins\n"); | 
 | 		return -EINVAL; | 
 | 	} else if (count >= 0) { | 
 | 		unsigned int pins[IQS7211_NUM_CRX]; | 
 |  | 
 | 		error = fwnode_property_read_u32_array(alp_node, | 
 | 						       "azoteq,rx-enable", | 
 | 						       pins, count); | 
 | 		if (error) { | 
 | 			dev_err(&client->dev, "Failed to read CRx pins: %d\n", | 
 | 				error); | 
 | 			return error; | 
 | 		} | 
 |  | 
 | 		reg_field.addr = dev_desc->alp_config; | 
 | 		reg_field.mask = GENMASK(IQS7211_NUM_CRX - 1, 0); | 
 | 		reg_field.val = 0; | 
 |  | 
 | 		for (i = 0; i < count; i++) { | 
 | 			if (pins[i] < dev_desc->min_crx_alp || | 
 | 			    pins[i] >= IQS7211_NUM_CRX) { | 
 | 				dev_err(&client->dev, "Invalid CRx pin: %u\n", | 
 | 					pins[i]); | 
 | 				return -EINVAL; | 
 | 			} | 
 |  | 
 | 			reg_field.val |= BIT(pins[i]); | 
 | 		} | 
 |  | 
 | 		error = iqs7211_add_field(iqs7211, reg_field); | 
 | 		if (error) | 
 | 			return error; | 
 | 	} | 
 |  | 
 | 	count = fwnode_property_count_u32(alp_node, "azoteq,tx-enable"); | 
 | 	if (count < 0 && count != -EINVAL) { | 
 | 		dev_err(&client->dev, "Failed to count CTx pins: %d\n", count); | 
 | 		return count; | 
 | 	} else if (count > dev_desc->num_ctx) { | 
 | 		dev_err(&client->dev, "Invalid number of CTx pins\n"); | 
 | 		return -EINVAL; | 
 | 	} else if (count >= 0) { | 
 | 		unsigned int pins[IQS7211_MAX_CTX]; | 
 |  | 
 | 		error = fwnode_property_read_u32_array(alp_node, | 
 | 						       "azoteq,tx-enable", | 
 | 						       pins, count); | 
 | 		if (error) { | 
 | 			dev_err(&client->dev, "Failed to read CTx pins: %d\n", | 
 | 				error); | 
 | 			return error; | 
 | 		} | 
 |  | 
 | 		reg_field.addr = dev_desc->alp_config + 1; | 
 | 		reg_field.mask = GENMASK(dev_desc->num_ctx - 1, 0); | 
 | 		reg_field.val = 0; | 
 |  | 
 | 		for (i = 0; i < count; i++) { | 
 | 			if (pins[i] >= dev_desc->num_ctx) { | 
 | 				dev_err(&client->dev, "Invalid CTx pin: %u\n", | 
 | 					pins[i]); | 
 | 				return -EINVAL; | 
 | 			} | 
 |  | 
 | 			reg_field.val |= BIT(pins[i]); | 
 | 		} | 
 |  | 
 | 		error = iqs7211_add_field(iqs7211, reg_field); | 
 | 		if (error) | 
 | 			return error; | 
 | 	} | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int (*iqs7211_parse_extra[IQS7211_NUM_REG_GRPS]) | 
 | 				(struct iqs7211_private *iqs7211, | 
 | 				 struct fwnode_handle *reg_grp_node) = { | 
 | 	[IQS7211_REG_GRP_TP] = iqs7211_parse_tp, | 
 | 	[IQS7211_REG_GRP_ALP] = iqs7211_parse_alp, | 
 | }; | 
 |  | 
 | static int iqs7211_parse_reg_grp(struct iqs7211_private *iqs7211, | 
 | 				 struct fwnode_handle *reg_grp_node, | 
 | 				 enum iqs7211_reg_grp_id reg_grp) | 
 | { | 
 | 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; | 
 | 	struct iqs7211_reg_field_desc reg_field; | 
 | 	int error, i; | 
 |  | 
 | 	error = iqs7211_parse_props(iqs7211, reg_grp_node, reg_grp, | 
 | 				    IQS7211_REG_KEY_NONE); | 
 | 	if (error) | 
 | 		return error; | 
 |  | 
 | 	if (iqs7211_parse_extra[reg_grp]) { | 
 | 		error = iqs7211_parse_extra[reg_grp](iqs7211, reg_grp_node); | 
 | 		if (error) | 
 | 			return error; | 
 | 	} | 
 |  | 
 | 	iqs7211->ati_start |= dev_desc->ati_start[reg_grp]; | 
 |  | 
 | 	reg_field.addr = dev_desc->kp_enable[reg_grp]; | 
 | 	reg_field.mask = 0; | 
 | 	reg_field.val = 0; | 
 |  | 
 | 	for (i = 0; i < dev_desc->num_kp_events; i++) { | 
 | 		const char *event_name = dev_desc->kp_events[i].name; | 
 | 		struct fwnode_handle *event_node; | 
 |  | 
 | 		if (dev_desc->kp_events[i].reg_grp != reg_grp) | 
 | 			continue; | 
 |  | 
 | 		reg_field.mask |= dev_desc->kp_events[i].enable; | 
 |  | 
 | 		if (event_name) | 
 | 			event_node = fwnode_get_named_child_node(reg_grp_node, | 
 | 								 event_name); | 
 | 		else | 
 | 			event_node = fwnode_handle_get(reg_grp_node); | 
 |  | 
 | 		if (!event_node) | 
 | 			continue; | 
 |  | 
 | 		error = iqs7211_parse_event(iqs7211, event_node, | 
 | 					    dev_desc->kp_events[i].reg_grp, | 
 | 					    dev_desc->kp_events[i].reg_key, | 
 | 					    &iqs7211->kp_code[i]); | 
 | 		fwnode_handle_put(event_node); | 
 | 		if (error) | 
 | 			return error; | 
 |  | 
 | 		reg_field.val |= dev_desc->kp_events[i].enable; | 
 |  | 
 | 		iqs7211->event_mask |= iqs7211_reg_grp_masks[reg_grp]; | 
 | 	} | 
 |  | 
 | 	return iqs7211_add_field(iqs7211, reg_field); | 
 | } | 
 |  | 
 | static int iqs7211_register_kp(struct iqs7211_private *iqs7211) | 
 | { | 
 | 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; | 
 | 	struct input_dev *kp_idev = iqs7211->kp_idev; | 
 | 	struct i2c_client *client = iqs7211->client; | 
 | 	int error, i; | 
 |  | 
 | 	for (i = 0; i < dev_desc->num_kp_events; i++) | 
 | 		if (iqs7211->kp_code[i]) | 
 | 			break; | 
 |  | 
 | 	if (i == dev_desc->num_kp_events) | 
 | 		return 0; | 
 |  | 
 | 	kp_idev = devm_input_allocate_device(&client->dev); | 
 | 	if (!kp_idev) | 
 | 		return -ENOMEM; | 
 |  | 
 | 	iqs7211->kp_idev = kp_idev; | 
 |  | 
 | 	kp_idev->name = dev_desc->kp_name; | 
 | 	kp_idev->id.bustype = BUS_I2C; | 
 |  | 
 | 	for (i = 0; i < dev_desc->num_kp_events; i++) | 
 | 		if (iqs7211->kp_code[i]) | 
 | 			input_set_capability(iqs7211->kp_idev, EV_KEY, | 
 | 					     iqs7211->kp_code[i]); | 
 |  | 
 | 	error = input_register_device(kp_idev); | 
 | 	if (error) | 
 | 		dev_err(&client->dev, "Failed to register %s: %d\n", | 
 | 			kp_idev->name, error); | 
 |  | 
 | 	return error; | 
 | } | 
 |  | 
 | static int iqs7211_register_tp(struct iqs7211_private *iqs7211) | 
 | { | 
 | 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; | 
 | 	struct touchscreen_properties *prop = &iqs7211->prop; | 
 | 	struct input_dev *tp_idev = iqs7211->tp_idev; | 
 | 	struct i2c_client *client = iqs7211->client; | 
 | 	int error; | 
 |  | 
 | 	error = device_property_read_u32(&client->dev, "azoteq,num-contacts", | 
 | 					 &iqs7211->num_contacts); | 
 | 	if (error == -EINVAL) { | 
 | 		return 0; | 
 | 	} else if (error) { | 
 | 		dev_err(&client->dev, "Failed to read number of contacts: %d\n", | 
 | 			error); | 
 | 		return error; | 
 | 	} else if (iqs7211->num_contacts > IQS7211_MAX_CONTACTS) { | 
 | 		dev_err(&client->dev, "Invalid number of contacts: %u\n", | 
 | 			iqs7211->num_contacts); | 
 | 		return -EINVAL; | 
 | 	} | 
 |  | 
 | 	iqs7211->tp_config.num_contacts = iqs7211->num_contacts ? : 1; | 
 |  | 
 | 	if (!iqs7211->num_contacts) | 
 | 		return 0; | 
 |  | 
 | 	iqs7211->event_mask |= IQS7211_EVENT_MASK_MOVE; | 
 |  | 
 | 	tp_idev = devm_input_allocate_device(&client->dev); | 
 | 	if (!tp_idev) | 
 | 		return -ENOMEM; | 
 |  | 
 | 	iqs7211->tp_idev = tp_idev; | 
 |  | 
 | 	tp_idev->name = dev_desc->tp_name; | 
 | 	tp_idev->id.bustype = BUS_I2C; | 
 |  | 
 | 	input_set_abs_params(tp_idev, ABS_MT_POSITION_X, | 
 | 			     0, le16_to_cpu(iqs7211->tp_config.max_x), 0, 0); | 
 |  | 
 | 	input_set_abs_params(tp_idev, ABS_MT_POSITION_Y, | 
 | 			     0, le16_to_cpu(iqs7211->tp_config.max_y), 0, 0); | 
 |  | 
 | 	input_set_abs_params(tp_idev, ABS_MT_PRESSURE, 0, U16_MAX, 0, 0); | 
 |  | 
 | 	touchscreen_parse_properties(tp_idev, true, prop); | 
 |  | 
 | 	/* | 
 | 	 * The device reserves 0xFFFF for coordinates that correspond to slots | 
 | 	 * which are not in a state of touch. | 
 | 	 */ | 
 | 	if (prop->max_x >= U16_MAX || prop->max_y >= U16_MAX) { | 
 | 		dev_err(&client->dev, "Invalid trackpad size: %u*%u\n", | 
 | 			prop->max_x, prop->max_y); | 
 | 		return -EINVAL; | 
 | 	} | 
 |  | 
 | 	iqs7211->tp_config.max_x = cpu_to_le16(prop->max_x); | 
 | 	iqs7211->tp_config.max_y = cpu_to_le16(prop->max_y); | 
 |  | 
 | 	error = input_mt_init_slots(tp_idev, iqs7211->num_contacts, | 
 | 				    INPUT_MT_DIRECT); | 
 | 	if (error) { | 
 | 		dev_err(&client->dev, "Failed to initialize slots: %d\n", | 
 | 			error); | 
 | 		return error; | 
 | 	} | 
 |  | 
 | 	error = input_register_device(tp_idev); | 
 | 	if (error) | 
 | 		dev_err(&client->dev, "Failed to register %s: %d\n", | 
 | 			tp_idev->name, error); | 
 |  | 
 | 	return error; | 
 | } | 
 |  | 
 | static int iqs7211_report(struct iqs7211_private *iqs7211) | 
 | { | 
 | 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; | 
 | 	struct i2c_client *client = iqs7211->client; | 
 | 	struct iqs7211_touch_data *touch_data; | 
 | 	u16 info_flags, charge_mode, gesture_flags; | 
 | 	__le16 status[12]; | 
 | 	int error, i; | 
 |  | 
 | 	error = iqs7211_read_burst(iqs7211, dev_desc->sys_stat, status, | 
 | 				   dev_desc->contact_offs * sizeof(__le16) + | 
 | 				   iqs7211->num_contacts * sizeof(*touch_data)); | 
 | 	if (error) | 
 | 		return error; | 
 |  | 
 | 	info_flags = le16_to_cpu(status[dev_desc->info_offs]); | 
 |  | 
 | 	if (info_flags & dev_desc->show_reset) { | 
 | 		dev_err(&client->dev, "Unexpected device reset\n"); | 
 |  | 
 | 		/* | 
 | 		 * The device may or may not expect forced communication after | 
 | 		 * it exits hardware reset, so the corresponding state machine | 
 | 		 * must be reset as well. | 
 | 		 */ | 
 | 		iqs7211->comms_mode = iqs7211->comms_init; | 
 |  | 
 | 		return iqs7211_init_device(iqs7211); | 
 | 	} | 
 |  | 
 | 	for (i = 0; i < ARRAY_SIZE(dev_desc->ati_error); i++) { | 
 | 		if (!(info_flags & dev_desc->ati_error[i])) | 
 | 			continue; | 
 |  | 
 | 		dev_err(&client->dev, "Unexpected %s ATI error\n", | 
 | 			iqs7211_reg_grp_names[i]); | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	for (i = 0; i < iqs7211->num_contacts; i++) { | 
 | 		u16 pressure; | 
 |  | 
 | 		touch_data = (struct iqs7211_touch_data *) | 
 | 			     &status[dev_desc->contact_offs] + i; | 
 | 		pressure = le16_to_cpu(touch_data->pressure); | 
 |  | 
 | 		input_mt_slot(iqs7211->tp_idev, i); | 
 | 		if (input_mt_report_slot_state(iqs7211->tp_idev, MT_TOOL_FINGER, | 
 | 					       pressure != 0)) { | 
 | 			touchscreen_report_pos(iqs7211->tp_idev, &iqs7211->prop, | 
 | 					       le16_to_cpu(touch_data->abs_x), | 
 | 					       le16_to_cpu(touch_data->abs_y), | 
 | 					       true); | 
 | 			input_report_abs(iqs7211->tp_idev, ABS_MT_PRESSURE, | 
 | 					 pressure); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if (iqs7211->num_contacts) { | 
 | 		input_mt_sync_frame(iqs7211->tp_idev); | 
 | 		input_sync(iqs7211->tp_idev); | 
 | 	} | 
 |  | 
 | 	if (!iqs7211->kp_idev) | 
 | 		return 0; | 
 |  | 
 | 	charge_mode = info_flags & GENMASK(dev_desc->charge_shift + 2, | 
 | 					   dev_desc->charge_shift); | 
 | 	charge_mode >>= dev_desc->charge_shift; | 
 |  | 
 | 	/* | 
 | 	 * A charging mode higher than 2 (idle mode) indicates the device last | 
 | 	 * operated in low-power mode and intends to express an ALP event. | 
 | 	 */ | 
 | 	if (info_flags & dev_desc->kp_events->mask && charge_mode > 2) { | 
 | 		input_report_key(iqs7211->kp_idev, *iqs7211->kp_code, 1); | 
 | 		input_sync(iqs7211->kp_idev); | 
 |  | 
 | 		input_report_key(iqs7211->kp_idev, *iqs7211->kp_code, 0); | 
 | 	} | 
 |  | 
 | 	for (i = 0; i < dev_desc->num_kp_events; i++) { | 
 | 		if (dev_desc->kp_events[i].reg_grp != IQS7211_REG_GRP_BTN) | 
 | 			continue; | 
 |  | 
 | 		input_report_key(iqs7211->kp_idev, iqs7211->kp_code[i], | 
 | 				 info_flags & dev_desc->kp_events[i].mask); | 
 | 	} | 
 |  | 
 | 	gesture_flags = le16_to_cpu(status[dev_desc->gesture_offs]); | 
 |  | 
 | 	for (i = 0; i < dev_desc->num_kp_events; i++) { | 
 | 		enum iqs7211_reg_key_id reg_key = dev_desc->kp_events[i].reg_key; | 
 | 		u16 mask = dev_desc->kp_events[i].mask; | 
 |  | 
 | 		if (dev_desc->kp_events[i].reg_grp != IQS7211_REG_GRP_TP) | 
 | 			continue; | 
 |  | 
 | 		if ((gesture_flags ^ iqs7211->gesture_cache) & mask) | 
 | 			input_report_key(iqs7211->kp_idev, iqs7211->kp_code[i], | 
 | 					 gesture_flags & mask); | 
 |  | 
 | 		iqs7211->gesture_cache &= ~mask; | 
 |  | 
 | 		/* | 
 | 		 * Hold and palm gestures persist while the contact remains in | 
 | 		 * place; all others are momentary and hence are followed by a | 
 | 		 * complementary release event. | 
 | 		 */ | 
 | 		if (reg_key == IQS7211_REG_KEY_HOLD || | 
 | 		    reg_key == IQS7211_REG_KEY_PALM) { | 
 | 			iqs7211->gesture_cache |= gesture_flags & mask; | 
 | 			gesture_flags &= ~mask; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if (gesture_flags) { | 
 | 		input_sync(iqs7211->kp_idev); | 
 |  | 
 | 		for (i = 0; i < dev_desc->num_kp_events; i++) | 
 | 			if (dev_desc->kp_events[i].reg_grp == IQS7211_REG_GRP_TP && | 
 | 			    gesture_flags & dev_desc->kp_events[i].mask) | 
 | 				input_report_key(iqs7211->kp_idev, | 
 | 						 iqs7211->kp_code[i], 0); | 
 | 	} | 
 |  | 
 | 	input_sync(iqs7211->kp_idev); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static irqreturn_t iqs7211_irq(int irq, void *context) | 
 | { | 
 | 	struct iqs7211_private *iqs7211 = context; | 
 |  | 
 | 	return iqs7211_report(iqs7211) ? IRQ_NONE : IRQ_HANDLED; | 
 | } | 
 |  | 
 | static int iqs7211_suspend(struct device *dev) | 
 | { | 
 | 	struct iqs7211_private *iqs7211 = dev_get_drvdata(dev); | 
 | 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; | 
 | 	int error; | 
 |  | 
 | 	if (!dev_desc->suspend || device_may_wakeup(dev)) | 
 | 		return 0; | 
 |  | 
 | 	/* | 
 | 	 * I2C communication prompts the device to assert its RDY pin if it is | 
 | 	 * not already asserted. As such, the interrupt must be disabled so as | 
 | 	 * to prevent reentrant interrupts. | 
 | 	 */ | 
 | 	disable_irq(gpiod_to_irq(iqs7211->irq_gpio)); | 
 |  | 
 | 	error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl, | 
 | 				   dev_desc->suspend); | 
 |  | 
 | 	enable_irq(gpiod_to_irq(iqs7211->irq_gpio)); | 
 |  | 
 | 	return error; | 
 | } | 
 |  | 
 | static int iqs7211_resume(struct device *dev) | 
 | { | 
 | 	struct iqs7211_private *iqs7211 = dev_get_drvdata(dev); | 
 | 	const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; | 
 | 	__le16 sys_ctrl[] = { | 
 | 		0, | 
 | 		cpu_to_le16(iqs7211->event_mask), | 
 | 	}; | 
 | 	int error; | 
 |  | 
 | 	if (!dev_desc->suspend || device_may_wakeup(dev)) | 
 | 		return 0; | 
 |  | 
 | 	disable_irq(gpiod_to_irq(iqs7211->irq_gpio)); | 
 |  | 
 | 	/* | 
 | 	 * Forced communication, if in use, must be explicitly enabled as part | 
 | 	 * of the wake-up command. | 
 | 	 */ | 
 | 	error = iqs7211_write_burst(iqs7211, dev_desc->sys_ctrl, sys_ctrl, | 
 | 				    sizeof(sys_ctrl)); | 
 |  | 
 | 	enable_irq(gpiod_to_irq(iqs7211->irq_gpio)); | 
 |  | 
 | 	return error; | 
 | } | 
 |  | 
 | static DEFINE_SIMPLE_DEV_PM_OPS(iqs7211_pm, iqs7211_suspend, iqs7211_resume); | 
 |  | 
 | static ssize_t fw_info_show(struct device *dev, | 
 | 			    struct device_attribute *attr, char *buf) | 
 | { | 
 | 	struct iqs7211_private *iqs7211 = dev_get_drvdata(dev); | 
 |  | 
 | 	return sysfs_emit(buf, "%u.%u.%u.%u:%u.%u\n", | 
 | 			  le16_to_cpu(iqs7211->ver_info.prod_num), | 
 | 			  le32_to_cpu(iqs7211->ver_info.patch), | 
 | 			  le16_to_cpu(iqs7211->ver_info.major), | 
 | 			  le16_to_cpu(iqs7211->ver_info.minor), | 
 | 			  iqs7211->exp_file[1], iqs7211->exp_file[0]); | 
 | } | 
 |  | 
 | static DEVICE_ATTR_RO(fw_info); | 
 |  | 
 | static struct attribute *iqs7211_attrs[] = { | 
 | 	&dev_attr_fw_info.attr, | 
 | 	NULL | 
 | }; | 
 | ATTRIBUTE_GROUPS(iqs7211); | 
 |  | 
 | static const struct of_device_id iqs7211_of_match[] = { | 
 | 	{ | 
 | 		.compatible = "azoteq,iqs7210a", | 
 | 		.data = &iqs7211_devs[IQS7210A], | 
 | 	}, | 
 | 	{ | 
 | 		.compatible = "azoteq,iqs7211a", | 
 | 		.data = &iqs7211_devs[IQS7211A], | 
 | 	}, | 
 | 	{ | 
 | 		.compatible = "azoteq,iqs7211e", | 
 | 		.data = &iqs7211_devs[IQS7211E], | 
 | 	}, | 
 | 	{ } | 
 | }; | 
 | MODULE_DEVICE_TABLE(of, iqs7211_of_match); | 
 |  | 
 | static int iqs7211_probe(struct i2c_client *client) | 
 | { | 
 | 	struct iqs7211_private *iqs7211; | 
 | 	enum iqs7211_reg_grp_id reg_grp; | 
 | 	unsigned long irq_flags; | 
 | 	bool shared_irq; | 
 | 	int error, irq; | 
 |  | 
 | 	iqs7211 = devm_kzalloc(&client->dev, sizeof(*iqs7211), GFP_KERNEL); | 
 | 	if (!iqs7211) | 
 | 		return -ENOMEM; | 
 |  | 
 | 	i2c_set_clientdata(client, iqs7211); | 
 | 	iqs7211->client = client; | 
 |  | 
 | 	INIT_LIST_HEAD(&iqs7211->reg_field_head); | 
 |  | 
 | 	iqs7211->dev_desc = device_get_match_data(&client->dev); | 
 | 	if (!iqs7211->dev_desc) | 
 | 		return -ENODEV; | 
 |  | 
 | 	shared_irq = iqs7211->dev_desc->num_ctx == IQS7211_MAX_CTX; | 
 |  | 
 | 	/* | 
 | 	 * The RDY pin behaves as an interrupt, but must also be polled ahead | 
 | 	 * of unsolicited I2C communication. As such, it is first opened as a | 
 | 	 * GPIO and then passed to gpiod_to_irq() to register the interrupt. | 
 | 	 * | 
 | 	 * If an extra CTx pin is present, the RDY and MCLR pins are combined | 
 | 	 * into a single bidirectional pin. In that case, the platform's GPIO | 
 | 	 * must be configured as an open-drain output. | 
 | 	 */ | 
 | 	iqs7211->irq_gpio = devm_gpiod_get(&client->dev, "irq", | 
 | 					   shared_irq ? GPIOD_OUT_LOW | 
 | 						      : GPIOD_IN); | 
 | 	if (IS_ERR(iqs7211->irq_gpio)) { | 
 | 		error = PTR_ERR(iqs7211->irq_gpio); | 
 | 		dev_err(&client->dev, "Failed to request IRQ GPIO: %d\n", | 
 | 			error); | 
 | 		return error; | 
 | 	} | 
 |  | 
 | 	if (shared_irq) { | 
 | 		iqs7211->reset_gpio = iqs7211->irq_gpio; | 
 | 	} else { | 
 | 		iqs7211->reset_gpio = devm_gpiod_get_optional(&client->dev, | 
 | 							      "reset", | 
 | 							      GPIOD_OUT_HIGH); | 
 | 		if (IS_ERR(iqs7211->reset_gpio)) { | 
 | 			error = PTR_ERR(iqs7211->reset_gpio); | 
 | 			dev_err(&client->dev, | 
 | 				"Failed to request reset GPIO: %d\n", error); | 
 | 			return error; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	error = iqs7211_start_comms(iqs7211); | 
 | 	if (error) | 
 | 		return error; | 
 |  | 
 | 	for (reg_grp = 0; reg_grp < IQS7211_NUM_REG_GRPS; reg_grp++) { | 
 | 		const char *reg_grp_name = iqs7211_reg_grp_names[reg_grp]; | 
 | 		struct fwnode_handle *reg_grp_node; | 
 |  | 
 | 		if (reg_grp_name) | 
 | 			reg_grp_node = device_get_named_child_node(&client->dev, | 
 | 								   reg_grp_name); | 
 | 		else | 
 | 			reg_grp_node = fwnode_handle_get(dev_fwnode(&client->dev)); | 
 |  | 
 | 		if (!reg_grp_node) | 
 | 			continue; | 
 |  | 
 | 		error = iqs7211_parse_reg_grp(iqs7211, reg_grp_node, reg_grp); | 
 | 		fwnode_handle_put(reg_grp_node); | 
 | 		if (error) | 
 | 			return error; | 
 | 	} | 
 |  | 
 | 	error = iqs7211_register_kp(iqs7211); | 
 | 	if (error) | 
 | 		return error; | 
 |  | 
 | 	error = iqs7211_register_tp(iqs7211); | 
 | 	if (error) | 
 | 		return error; | 
 |  | 
 | 	error = iqs7211_init_device(iqs7211); | 
 | 	if (error) | 
 | 		return error; | 
 |  | 
 | 	irq = gpiod_to_irq(iqs7211->irq_gpio); | 
 | 	if (irq < 0) | 
 | 		return irq; | 
 |  | 
 | 	irq_flags = gpiod_is_active_low(iqs7211->irq_gpio) ? IRQF_TRIGGER_LOW | 
 | 							   : IRQF_TRIGGER_HIGH; | 
 | 	irq_flags |= IRQF_ONESHOT; | 
 |  | 
 | 	error = devm_request_threaded_irq(&client->dev, irq, NULL, iqs7211_irq, | 
 | 					  irq_flags, client->name, iqs7211); | 
 | 	if (error) | 
 | 		dev_err(&client->dev, "Failed to request IRQ: %d\n", error); | 
 |  | 
 | 	return error; | 
 | } | 
 |  | 
 | static struct i2c_driver iqs7211_i2c_driver = { | 
 | 	.probe = iqs7211_probe, | 
 | 	.driver = { | 
 | 		.name = "iqs7211", | 
 | 		.of_match_table = iqs7211_of_match, | 
 | 		.dev_groups = iqs7211_groups, | 
 | 		.pm = pm_sleep_ptr(&iqs7211_pm), | 
 | 	}, | 
 | }; | 
 | module_i2c_driver(iqs7211_i2c_driver); | 
 |  | 
 | MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>"); | 
 | MODULE_DESCRIPTION("Azoteq IQS7210A/7211A/E Trackpad/Touchscreen Controller"); | 
 | MODULE_LICENSE("GPL"); |