Contributors: 1
Author Tokens Token Proportion Commits Commit Proportion
Jeff LaBundy 11450 100.00% 2 100.00%
Total 11450 2


// 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 <asm/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 = &reg,
		},
		{
			.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(&reg_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 scnprintf(buf, PAGE_SIZE, "%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");