162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Azoteq IQS7222A/B/C/D Capacitive Touch Controller
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2022 Jeff LaBundy <jeff@labundy.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/bits.h>
962306a36Sopenharmony_ci#include <linux/delay.h>
1062306a36Sopenharmony_ci#include <linux/device.h>
1162306a36Sopenharmony_ci#include <linux/err.h>
1262306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
1362306a36Sopenharmony_ci#include <linux/i2c.h>
1462306a36Sopenharmony_ci#include <linux/input.h>
1562306a36Sopenharmony_ci#include <linux/input/touchscreen.h>
1662306a36Sopenharmony_ci#include <linux/interrupt.h>
1762306a36Sopenharmony_ci#include <linux/kernel.h>
1862306a36Sopenharmony_ci#include <linux/ktime.h>
1962306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
2062306a36Sopenharmony_ci#include <linux/module.h>
2162306a36Sopenharmony_ci#include <linux/property.h>
2262306a36Sopenharmony_ci#include <linux/slab.h>
2362306a36Sopenharmony_ci#include <asm/unaligned.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define IQS7222_PROD_NUM			0x00
2662306a36Sopenharmony_ci#define IQS7222_PROD_NUM_A			840
2762306a36Sopenharmony_ci#define IQS7222_PROD_NUM_B			698
2862306a36Sopenharmony_ci#define IQS7222_PROD_NUM_C			863
2962306a36Sopenharmony_ci#define IQS7222_PROD_NUM_D			1046
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define IQS7222_SYS_STATUS			0x10
3262306a36Sopenharmony_ci#define IQS7222_SYS_STATUS_RESET		BIT(3)
3362306a36Sopenharmony_ci#define IQS7222_SYS_STATUS_ATI_ERROR		BIT(1)
3462306a36Sopenharmony_ci#define IQS7222_SYS_STATUS_ATI_ACTIVE		BIT(0)
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define IQS7222_CHAN_SETUP_0_REF_MODE_MASK	GENMASK(15, 14)
3762306a36Sopenharmony_ci#define IQS7222_CHAN_SETUP_0_REF_MODE_FOLLOW	BIT(15)
3862306a36Sopenharmony_ci#define IQS7222_CHAN_SETUP_0_REF_MODE_REF	BIT(14)
3962306a36Sopenharmony_ci#define IQS7222_CHAN_SETUP_0_CHAN_EN		BIT(8)
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK	GENMASK(2, 0)
4262306a36Sopenharmony_ci#define IQS7222_SLDR_SETUP_2_RES_MASK		GENMASK(15, 8)
4362306a36Sopenharmony_ci#define IQS7222_SLDR_SETUP_2_RES_SHIFT		8
4462306a36Sopenharmony_ci#define IQS7222_SLDR_SETUP_2_TOP_SPEED_MASK	GENMASK(7, 0)
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define IQS7222_GPIO_SETUP_0_GPIO_EN		BIT(0)
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define IQS7222_SYS_SETUP			0xD0
4962306a36Sopenharmony_ci#define IQS7222_SYS_SETUP_INTF_MODE_MASK	GENMASK(7, 6)
5062306a36Sopenharmony_ci#define IQS7222_SYS_SETUP_INTF_MODE_TOUCH	BIT(7)
5162306a36Sopenharmony_ci#define IQS7222_SYS_SETUP_INTF_MODE_EVENT	BIT(6)
5262306a36Sopenharmony_ci#define IQS7222_SYS_SETUP_PWR_MODE_MASK		GENMASK(5, 4)
5362306a36Sopenharmony_ci#define IQS7222_SYS_SETUP_PWR_MODE_AUTO		IQS7222_SYS_SETUP_PWR_MODE_MASK
5462306a36Sopenharmony_ci#define IQS7222_SYS_SETUP_REDO_ATI		BIT(2)
5562306a36Sopenharmony_ci#define IQS7222_SYS_SETUP_ACK_RESET		BIT(0)
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define IQS7222_EVENT_MASK_ATI			BIT(12)
5862306a36Sopenharmony_ci#define IQS7222_EVENT_MASK_SLDR			BIT(10)
5962306a36Sopenharmony_ci#define IQS7222_EVENT_MASK_TPAD			IQS7222_EVENT_MASK_SLDR
6062306a36Sopenharmony_ci#define IQS7222_EVENT_MASK_TOUCH		BIT(1)
6162306a36Sopenharmony_ci#define IQS7222_EVENT_MASK_PROX			BIT(0)
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define IQS7222_COMMS_HOLD			BIT(0)
6462306a36Sopenharmony_ci#define IQS7222_COMMS_ERROR			0xEEEE
6562306a36Sopenharmony_ci#define IQS7222_COMMS_RETRY_MS			50
6662306a36Sopenharmony_ci#define IQS7222_COMMS_TIMEOUT_MS		100
6762306a36Sopenharmony_ci#define IQS7222_RESET_TIMEOUT_MS		250
6862306a36Sopenharmony_ci#define IQS7222_ATI_TIMEOUT_MS			2000
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#define IQS7222_MAX_COLS_STAT			8
7162306a36Sopenharmony_ci#define IQS7222_MAX_COLS_CYCLE			3
7262306a36Sopenharmony_ci#define IQS7222_MAX_COLS_GLBL			3
7362306a36Sopenharmony_ci#define IQS7222_MAX_COLS_BTN			3
7462306a36Sopenharmony_ci#define IQS7222_MAX_COLS_CHAN			6
7562306a36Sopenharmony_ci#define IQS7222_MAX_COLS_FILT			2
7662306a36Sopenharmony_ci#define IQS7222_MAX_COLS_SLDR			11
7762306a36Sopenharmony_ci#define IQS7222_MAX_COLS_TPAD			24
7862306a36Sopenharmony_ci#define IQS7222_MAX_COLS_GPIO			3
7962306a36Sopenharmony_ci#define IQS7222_MAX_COLS_SYS			13
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#define IQS7222_MAX_CHAN			20
8262306a36Sopenharmony_ci#define IQS7222_MAX_SLDR			2
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci#define IQS7222_NUM_RETRIES			5
8562306a36Sopenharmony_ci#define IQS7222_REG_OFFSET			0x100
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cienum iqs7222_reg_key_id {
8862306a36Sopenharmony_ci	IQS7222_REG_KEY_NONE,
8962306a36Sopenharmony_ci	IQS7222_REG_KEY_PROX,
9062306a36Sopenharmony_ci	IQS7222_REG_KEY_TOUCH,
9162306a36Sopenharmony_ci	IQS7222_REG_KEY_DEBOUNCE,
9262306a36Sopenharmony_ci	IQS7222_REG_KEY_TAP,
9362306a36Sopenharmony_ci	IQS7222_REG_KEY_TAP_LEGACY,
9462306a36Sopenharmony_ci	IQS7222_REG_KEY_AXIAL,
9562306a36Sopenharmony_ci	IQS7222_REG_KEY_AXIAL_LEGACY,
9662306a36Sopenharmony_ci	IQS7222_REG_KEY_WHEEL,
9762306a36Sopenharmony_ci	IQS7222_REG_KEY_NO_WHEEL,
9862306a36Sopenharmony_ci	IQS7222_REG_KEY_RESERVED
9962306a36Sopenharmony_ci};
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cienum iqs7222_reg_grp_id {
10262306a36Sopenharmony_ci	IQS7222_REG_GRP_STAT,
10362306a36Sopenharmony_ci	IQS7222_REG_GRP_FILT,
10462306a36Sopenharmony_ci	IQS7222_REG_GRP_CYCLE,
10562306a36Sopenharmony_ci	IQS7222_REG_GRP_GLBL,
10662306a36Sopenharmony_ci	IQS7222_REG_GRP_BTN,
10762306a36Sopenharmony_ci	IQS7222_REG_GRP_CHAN,
10862306a36Sopenharmony_ci	IQS7222_REG_GRP_SLDR,
10962306a36Sopenharmony_ci	IQS7222_REG_GRP_TPAD,
11062306a36Sopenharmony_ci	IQS7222_REG_GRP_GPIO,
11162306a36Sopenharmony_ci	IQS7222_REG_GRP_SYS,
11262306a36Sopenharmony_ci	IQS7222_NUM_REG_GRPS
11362306a36Sopenharmony_ci};
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic const char * const iqs7222_reg_grp_names[IQS7222_NUM_REG_GRPS] = {
11662306a36Sopenharmony_ci	[IQS7222_REG_GRP_CYCLE] = "cycle-%d",
11762306a36Sopenharmony_ci	[IQS7222_REG_GRP_CHAN] = "channel-%d",
11862306a36Sopenharmony_ci	[IQS7222_REG_GRP_SLDR] = "slider-%d",
11962306a36Sopenharmony_ci	[IQS7222_REG_GRP_TPAD] = "trackpad",
12062306a36Sopenharmony_ci	[IQS7222_REG_GRP_GPIO] = "gpio-%d",
12162306a36Sopenharmony_ci};
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic const unsigned int iqs7222_max_cols[IQS7222_NUM_REG_GRPS] = {
12462306a36Sopenharmony_ci	[IQS7222_REG_GRP_STAT] = IQS7222_MAX_COLS_STAT,
12562306a36Sopenharmony_ci	[IQS7222_REG_GRP_CYCLE] = IQS7222_MAX_COLS_CYCLE,
12662306a36Sopenharmony_ci	[IQS7222_REG_GRP_GLBL] = IQS7222_MAX_COLS_GLBL,
12762306a36Sopenharmony_ci	[IQS7222_REG_GRP_BTN] = IQS7222_MAX_COLS_BTN,
12862306a36Sopenharmony_ci	[IQS7222_REG_GRP_CHAN] = IQS7222_MAX_COLS_CHAN,
12962306a36Sopenharmony_ci	[IQS7222_REG_GRP_FILT] = IQS7222_MAX_COLS_FILT,
13062306a36Sopenharmony_ci	[IQS7222_REG_GRP_SLDR] = IQS7222_MAX_COLS_SLDR,
13162306a36Sopenharmony_ci	[IQS7222_REG_GRP_TPAD] = IQS7222_MAX_COLS_TPAD,
13262306a36Sopenharmony_ci	[IQS7222_REG_GRP_GPIO] = IQS7222_MAX_COLS_GPIO,
13362306a36Sopenharmony_ci	[IQS7222_REG_GRP_SYS] = IQS7222_MAX_COLS_SYS,
13462306a36Sopenharmony_ci};
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic const unsigned int iqs7222_gpio_links[] = { 2, 5, 6, };
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistruct iqs7222_event_desc {
13962306a36Sopenharmony_ci	const char *name;
14062306a36Sopenharmony_ci	u16 link;
14162306a36Sopenharmony_ci	u16 mask;
14262306a36Sopenharmony_ci	u16 val;
14362306a36Sopenharmony_ci	u16 strict;
14462306a36Sopenharmony_ci	u16 enable;
14562306a36Sopenharmony_ci	enum iqs7222_reg_key_id reg_key;
14662306a36Sopenharmony_ci};
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic const struct iqs7222_event_desc iqs7222_kp_events[] = {
14962306a36Sopenharmony_ci	{
15062306a36Sopenharmony_ci		.name = "event-prox",
15162306a36Sopenharmony_ci		.enable = IQS7222_EVENT_MASK_PROX,
15262306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_PROX,
15362306a36Sopenharmony_ci	},
15462306a36Sopenharmony_ci	{
15562306a36Sopenharmony_ci		.name = "event-touch",
15662306a36Sopenharmony_ci		.enable = IQS7222_EVENT_MASK_TOUCH,
15762306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_TOUCH,
15862306a36Sopenharmony_ci	},
15962306a36Sopenharmony_ci};
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic const struct iqs7222_event_desc iqs7222_sl_events[] = {
16262306a36Sopenharmony_ci	{ .name = "event-press", },
16362306a36Sopenharmony_ci	{
16462306a36Sopenharmony_ci		.name = "event-tap",
16562306a36Sopenharmony_ci		.mask = BIT(0),
16662306a36Sopenharmony_ci		.val = BIT(0),
16762306a36Sopenharmony_ci		.enable = BIT(0),
16862306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_TAP,
16962306a36Sopenharmony_ci	},
17062306a36Sopenharmony_ci	{
17162306a36Sopenharmony_ci		.name = "event-swipe-pos",
17262306a36Sopenharmony_ci		.mask = BIT(5) | BIT(1),
17362306a36Sopenharmony_ci		.val = BIT(1),
17462306a36Sopenharmony_ci		.enable = BIT(1),
17562306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_AXIAL,
17662306a36Sopenharmony_ci	},
17762306a36Sopenharmony_ci	{
17862306a36Sopenharmony_ci		.name = "event-swipe-neg",
17962306a36Sopenharmony_ci		.mask = BIT(5) | BIT(1),
18062306a36Sopenharmony_ci		.val = BIT(5) | BIT(1),
18162306a36Sopenharmony_ci		.enable = BIT(1),
18262306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_AXIAL,
18362306a36Sopenharmony_ci	},
18462306a36Sopenharmony_ci	{
18562306a36Sopenharmony_ci		.name = "event-flick-pos",
18662306a36Sopenharmony_ci		.mask = BIT(5) | BIT(2),
18762306a36Sopenharmony_ci		.val = BIT(2),
18862306a36Sopenharmony_ci		.enable = BIT(2),
18962306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_AXIAL,
19062306a36Sopenharmony_ci	},
19162306a36Sopenharmony_ci	{
19262306a36Sopenharmony_ci		.name = "event-flick-neg",
19362306a36Sopenharmony_ci		.mask = BIT(5) | BIT(2),
19462306a36Sopenharmony_ci		.val = BIT(5) | BIT(2),
19562306a36Sopenharmony_ci		.enable = BIT(2),
19662306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_AXIAL,
19762306a36Sopenharmony_ci	},
19862306a36Sopenharmony_ci};
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic const struct iqs7222_event_desc iqs7222_tp_events[] = {
20162306a36Sopenharmony_ci	{
20262306a36Sopenharmony_ci		.name = "event-press",
20362306a36Sopenharmony_ci		.link = BIT(7),
20462306a36Sopenharmony_ci	},
20562306a36Sopenharmony_ci	{
20662306a36Sopenharmony_ci		.name = "event-tap",
20762306a36Sopenharmony_ci		.link = BIT(0),
20862306a36Sopenharmony_ci		.mask = BIT(0),
20962306a36Sopenharmony_ci		.val = BIT(0),
21062306a36Sopenharmony_ci		.enable = BIT(0),
21162306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_TAP,
21262306a36Sopenharmony_ci	},
21362306a36Sopenharmony_ci	{
21462306a36Sopenharmony_ci		.name = "event-swipe-x-pos",
21562306a36Sopenharmony_ci		.link = BIT(2),
21662306a36Sopenharmony_ci		.mask = BIT(2) | BIT(1),
21762306a36Sopenharmony_ci		.val = BIT(2),
21862306a36Sopenharmony_ci		.strict = BIT(4),
21962306a36Sopenharmony_ci		.enable = BIT(1),
22062306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_AXIAL,
22162306a36Sopenharmony_ci	},
22262306a36Sopenharmony_ci	{
22362306a36Sopenharmony_ci		.name = "event-swipe-y-pos",
22462306a36Sopenharmony_ci		.link = BIT(3),
22562306a36Sopenharmony_ci		.mask = BIT(3) | BIT(1),
22662306a36Sopenharmony_ci		.val = BIT(3),
22762306a36Sopenharmony_ci		.strict = BIT(3),
22862306a36Sopenharmony_ci		.enable = BIT(1),
22962306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_AXIAL,
23062306a36Sopenharmony_ci	},
23162306a36Sopenharmony_ci	{
23262306a36Sopenharmony_ci		.name = "event-swipe-x-neg",
23362306a36Sopenharmony_ci		.link = BIT(4),
23462306a36Sopenharmony_ci		.mask = BIT(4) | BIT(1),
23562306a36Sopenharmony_ci		.val = BIT(4),
23662306a36Sopenharmony_ci		.strict = BIT(4),
23762306a36Sopenharmony_ci		.enable = BIT(1),
23862306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_AXIAL,
23962306a36Sopenharmony_ci	},
24062306a36Sopenharmony_ci	{
24162306a36Sopenharmony_ci		.name = "event-swipe-y-neg",
24262306a36Sopenharmony_ci		.link = BIT(5),
24362306a36Sopenharmony_ci		.mask = BIT(5) | BIT(1),
24462306a36Sopenharmony_ci		.val = BIT(5),
24562306a36Sopenharmony_ci		.strict = BIT(3),
24662306a36Sopenharmony_ci		.enable = BIT(1),
24762306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_AXIAL,
24862306a36Sopenharmony_ci	},
24962306a36Sopenharmony_ci	{
25062306a36Sopenharmony_ci		.name = "event-flick-x-pos",
25162306a36Sopenharmony_ci		.link = BIT(2),
25262306a36Sopenharmony_ci		.mask = BIT(2) | BIT(1),
25362306a36Sopenharmony_ci		.val = BIT(2) | BIT(1),
25462306a36Sopenharmony_ci		.strict = BIT(4),
25562306a36Sopenharmony_ci		.enable = BIT(2),
25662306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_AXIAL,
25762306a36Sopenharmony_ci	},
25862306a36Sopenharmony_ci	{
25962306a36Sopenharmony_ci		.name = "event-flick-y-pos",
26062306a36Sopenharmony_ci		.link = BIT(3),
26162306a36Sopenharmony_ci		.mask = BIT(3) | BIT(1),
26262306a36Sopenharmony_ci		.val = BIT(3) | BIT(1),
26362306a36Sopenharmony_ci		.strict = BIT(3),
26462306a36Sopenharmony_ci		.enable = BIT(2),
26562306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_AXIAL,
26662306a36Sopenharmony_ci	},
26762306a36Sopenharmony_ci	{
26862306a36Sopenharmony_ci		.name = "event-flick-x-neg",
26962306a36Sopenharmony_ci		.link = BIT(4),
27062306a36Sopenharmony_ci		.mask = BIT(4) | BIT(1),
27162306a36Sopenharmony_ci		.val = BIT(4) | BIT(1),
27262306a36Sopenharmony_ci		.strict = BIT(4),
27362306a36Sopenharmony_ci		.enable = BIT(2),
27462306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_AXIAL,
27562306a36Sopenharmony_ci	},
27662306a36Sopenharmony_ci	{
27762306a36Sopenharmony_ci		.name = "event-flick-y-neg",
27862306a36Sopenharmony_ci		.link = BIT(5),
27962306a36Sopenharmony_ci		.mask = BIT(5) | BIT(1),
28062306a36Sopenharmony_ci		.val = BIT(5) | BIT(1),
28162306a36Sopenharmony_ci		.strict = BIT(3),
28262306a36Sopenharmony_ci		.enable = BIT(2),
28362306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_AXIAL,
28462306a36Sopenharmony_ci	},
28562306a36Sopenharmony_ci};
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistruct iqs7222_reg_grp_desc {
28862306a36Sopenharmony_ci	u16 base;
28962306a36Sopenharmony_ci	int num_row;
29062306a36Sopenharmony_ci	int num_col;
29162306a36Sopenharmony_ci};
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistruct iqs7222_dev_desc {
29462306a36Sopenharmony_ci	u16 prod_num;
29562306a36Sopenharmony_ci	u16 fw_major;
29662306a36Sopenharmony_ci	u16 fw_minor;
29762306a36Sopenharmony_ci	u16 sldr_res;
29862306a36Sopenharmony_ci	u16 touch_link;
29962306a36Sopenharmony_ci	u16 wheel_enable;
30062306a36Sopenharmony_ci	int allow_offset;
30162306a36Sopenharmony_ci	int event_offset;
30262306a36Sopenharmony_ci	int comms_offset;
30362306a36Sopenharmony_ci	bool legacy_gesture;
30462306a36Sopenharmony_ci	struct iqs7222_reg_grp_desc reg_grps[IQS7222_NUM_REG_GRPS];
30562306a36Sopenharmony_ci};
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_cistatic const struct iqs7222_dev_desc iqs7222_devs[] = {
30862306a36Sopenharmony_ci	{
30962306a36Sopenharmony_ci		.prod_num = IQS7222_PROD_NUM_A,
31062306a36Sopenharmony_ci		.fw_major = 1,
31162306a36Sopenharmony_ci		.fw_minor = 13,
31262306a36Sopenharmony_ci		.sldr_res = U8_MAX * 16,
31362306a36Sopenharmony_ci		.touch_link = 1768,
31462306a36Sopenharmony_ci		.allow_offset = 9,
31562306a36Sopenharmony_ci		.event_offset = 10,
31662306a36Sopenharmony_ci		.comms_offset = 12,
31762306a36Sopenharmony_ci		.reg_grps = {
31862306a36Sopenharmony_ci			[IQS7222_REG_GRP_STAT] = {
31962306a36Sopenharmony_ci				.base = IQS7222_SYS_STATUS,
32062306a36Sopenharmony_ci				.num_row = 1,
32162306a36Sopenharmony_ci				.num_col = 8,
32262306a36Sopenharmony_ci			},
32362306a36Sopenharmony_ci			[IQS7222_REG_GRP_CYCLE] = {
32462306a36Sopenharmony_ci				.base = 0x8000,
32562306a36Sopenharmony_ci				.num_row = 7,
32662306a36Sopenharmony_ci				.num_col = 3,
32762306a36Sopenharmony_ci			},
32862306a36Sopenharmony_ci			[IQS7222_REG_GRP_GLBL] = {
32962306a36Sopenharmony_ci				.base = 0x8700,
33062306a36Sopenharmony_ci				.num_row = 1,
33162306a36Sopenharmony_ci				.num_col = 3,
33262306a36Sopenharmony_ci			},
33362306a36Sopenharmony_ci			[IQS7222_REG_GRP_BTN] = {
33462306a36Sopenharmony_ci				.base = 0x9000,
33562306a36Sopenharmony_ci				.num_row = 12,
33662306a36Sopenharmony_ci				.num_col = 3,
33762306a36Sopenharmony_ci			},
33862306a36Sopenharmony_ci			[IQS7222_REG_GRP_CHAN] = {
33962306a36Sopenharmony_ci				.base = 0xA000,
34062306a36Sopenharmony_ci				.num_row = 12,
34162306a36Sopenharmony_ci				.num_col = 6,
34262306a36Sopenharmony_ci			},
34362306a36Sopenharmony_ci			[IQS7222_REG_GRP_FILT] = {
34462306a36Sopenharmony_ci				.base = 0xAC00,
34562306a36Sopenharmony_ci				.num_row = 1,
34662306a36Sopenharmony_ci				.num_col = 2,
34762306a36Sopenharmony_ci			},
34862306a36Sopenharmony_ci			[IQS7222_REG_GRP_SLDR] = {
34962306a36Sopenharmony_ci				.base = 0xB000,
35062306a36Sopenharmony_ci				.num_row = 2,
35162306a36Sopenharmony_ci				.num_col = 11,
35262306a36Sopenharmony_ci			},
35362306a36Sopenharmony_ci			[IQS7222_REG_GRP_GPIO] = {
35462306a36Sopenharmony_ci				.base = 0xC000,
35562306a36Sopenharmony_ci				.num_row = 1,
35662306a36Sopenharmony_ci				.num_col = 3,
35762306a36Sopenharmony_ci			},
35862306a36Sopenharmony_ci			[IQS7222_REG_GRP_SYS] = {
35962306a36Sopenharmony_ci				.base = IQS7222_SYS_SETUP,
36062306a36Sopenharmony_ci				.num_row = 1,
36162306a36Sopenharmony_ci				.num_col = 13,
36262306a36Sopenharmony_ci			},
36362306a36Sopenharmony_ci		},
36462306a36Sopenharmony_ci	},
36562306a36Sopenharmony_ci	{
36662306a36Sopenharmony_ci		.prod_num = IQS7222_PROD_NUM_A,
36762306a36Sopenharmony_ci		.fw_major = 1,
36862306a36Sopenharmony_ci		.fw_minor = 12,
36962306a36Sopenharmony_ci		.sldr_res = U8_MAX * 16,
37062306a36Sopenharmony_ci		.touch_link = 1768,
37162306a36Sopenharmony_ci		.allow_offset = 9,
37262306a36Sopenharmony_ci		.event_offset = 10,
37362306a36Sopenharmony_ci		.comms_offset = 12,
37462306a36Sopenharmony_ci		.legacy_gesture = true,
37562306a36Sopenharmony_ci		.reg_grps = {
37662306a36Sopenharmony_ci			[IQS7222_REG_GRP_STAT] = {
37762306a36Sopenharmony_ci				.base = IQS7222_SYS_STATUS,
37862306a36Sopenharmony_ci				.num_row = 1,
37962306a36Sopenharmony_ci				.num_col = 8,
38062306a36Sopenharmony_ci			},
38162306a36Sopenharmony_ci			[IQS7222_REG_GRP_CYCLE] = {
38262306a36Sopenharmony_ci				.base = 0x8000,
38362306a36Sopenharmony_ci				.num_row = 7,
38462306a36Sopenharmony_ci				.num_col = 3,
38562306a36Sopenharmony_ci			},
38662306a36Sopenharmony_ci			[IQS7222_REG_GRP_GLBL] = {
38762306a36Sopenharmony_ci				.base = 0x8700,
38862306a36Sopenharmony_ci				.num_row = 1,
38962306a36Sopenharmony_ci				.num_col = 3,
39062306a36Sopenharmony_ci			},
39162306a36Sopenharmony_ci			[IQS7222_REG_GRP_BTN] = {
39262306a36Sopenharmony_ci				.base = 0x9000,
39362306a36Sopenharmony_ci				.num_row = 12,
39462306a36Sopenharmony_ci				.num_col = 3,
39562306a36Sopenharmony_ci			},
39662306a36Sopenharmony_ci			[IQS7222_REG_GRP_CHAN] = {
39762306a36Sopenharmony_ci				.base = 0xA000,
39862306a36Sopenharmony_ci				.num_row = 12,
39962306a36Sopenharmony_ci				.num_col = 6,
40062306a36Sopenharmony_ci			},
40162306a36Sopenharmony_ci			[IQS7222_REG_GRP_FILT] = {
40262306a36Sopenharmony_ci				.base = 0xAC00,
40362306a36Sopenharmony_ci				.num_row = 1,
40462306a36Sopenharmony_ci				.num_col = 2,
40562306a36Sopenharmony_ci			},
40662306a36Sopenharmony_ci			[IQS7222_REG_GRP_SLDR] = {
40762306a36Sopenharmony_ci				.base = 0xB000,
40862306a36Sopenharmony_ci				.num_row = 2,
40962306a36Sopenharmony_ci				.num_col = 11,
41062306a36Sopenharmony_ci			},
41162306a36Sopenharmony_ci			[IQS7222_REG_GRP_GPIO] = {
41262306a36Sopenharmony_ci				.base = 0xC000,
41362306a36Sopenharmony_ci				.num_row = 1,
41462306a36Sopenharmony_ci				.num_col = 3,
41562306a36Sopenharmony_ci			},
41662306a36Sopenharmony_ci			[IQS7222_REG_GRP_SYS] = {
41762306a36Sopenharmony_ci				.base = IQS7222_SYS_SETUP,
41862306a36Sopenharmony_ci				.num_row = 1,
41962306a36Sopenharmony_ci				.num_col = 13,
42062306a36Sopenharmony_ci			},
42162306a36Sopenharmony_ci		},
42262306a36Sopenharmony_ci	},
42362306a36Sopenharmony_ci	{
42462306a36Sopenharmony_ci		.prod_num = IQS7222_PROD_NUM_B,
42562306a36Sopenharmony_ci		.fw_major = 1,
42662306a36Sopenharmony_ci		.fw_minor = 43,
42762306a36Sopenharmony_ci		.event_offset = 10,
42862306a36Sopenharmony_ci		.comms_offset = 11,
42962306a36Sopenharmony_ci		.reg_grps = {
43062306a36Sopenharmony_ci			[IQS7222_REG_GRP_STAT] = {
43162306a36Sopenharmony_ci				.base = IQS7222_SYS_STATUS,
43262306a36Sopenharmony_ci				.num_row = 1,
43362306a36Sopenharmony_ci				.num_col = 6,
43462306a36Sopenharmony_ci			},
43562306a36Sopenharmony_ci			[IQS7222_REG_GRP_CYCLE] = {
43662306a36Sopenharmony_ci				.base = 0x8000,
43762306a36Sopenharmony_ci				.num_row = 10,
43862306a36Sopenharmony_ci				.num_col = 2,
43962306a36Sopenharmony_ci			},
44062306a36Sopenharmony_ci			[IQS7222_REG_GRP_GLBL] = {
44162306a36Sopenharmony_ci				.base = 0x8A00,
44262306a36Sopenharmony_ci				.num_row = 1,
44362306a36Sopenharmony_ci				.num_col = 3,
44462306a36Sopenharmony_ci			},
44562306a36Sopenharmony_ci			[IQS7222_REG_GRP_BTN] = {
44662306a36Sopenharmony_ci				.base = 0x9000,
44762306a36Sopenharmony_ci				.num_row = 20,
44862306a36Sopenharmony_ci				.num_col = 2,
44962306a36Sopenharmony_ci			},
45062306a36Sopenharmony_ci			[IQS7222_REG_GRP_CHAN] = {
45162306a36Sopenharmony_ci				.base = 0xB000,
45262306a36Sopenharmony_ci				.num_row = 20,
45362306a36Sopenharmony_ci				.num_col = 4,
45462306a36Sopenharmony_ci			},
45562306a36Sopenharmony_ci			[IQS7222_REG_GRP_FILT] = {
45662306a36Sopenharmony_ci				.base = 0xC400,
45762306a36Sopenharmony_ci				.num_row = 1,
45862306a36Sopenharmony_ci				.num_col = 2,
45962306a36Sopenharmony_ci			},
46062306a36Sopenharmony_ci			[IQS7222_REG_GRP_SYS] = {
46162306a36Sopenharmony_ci				.base = IQS7222_SYS_SETUP,
46262306a36Sopenharmony_ci				.num_row = 1,
46362306a36Sopenharmony_ci				.num_col = 13,
46462306a36Sopenharmony_ci			},
46562306a36Sopenharmony_ci		},
46662306a36Sopenharmony_ci	},
46762306a36Sopenharmony_ci	{
46862306a36Sopenharmony_ci		.prod_num = IQS7222_PROD_NUM_B,
46962306a36Sopenharmony_ci		.fw_major = 1,
47062306a36Sopenharmony_ci		.fw_minor = 27,
47162306a36Sopenharmony_ci		.reg_grps = {
47262306a36Sopenharmony_ci			[IQS7222_REG_GRP_STAT] = {
47362306a36Sopenharmony_ci				.base = IQS7222_SYS_STATUS,
47462306a36Sopenharmony_ci				.num_row = 1,
47562306a36Sopenharmony_ci				.num_col = 6,
47662306a36Sopenharmony_ci			},
47762306a36Sopenharmony_ci			[IQS7222_REG_GRP_CYCLE] = {
47862306a36Sopenharmony_ci				.base = 0x8000,
47962306a36Sopenharmony_ci				.num_row = 10,
48062306a36Sopenharmony_ci				.num_col = 2,
48162306a36Sopenharmony_ci			},
48262306a36Sopenharmony_ci			[IQS7222_REG_GRP_GLBL] = {
48362306a36Sopenharmony_ci				.base = 0x8A00,
48462306a36Sopenharmony_ci				.num_row = 1,
48562306a36Sopenharmony_ci				.num_col = 3,
48662306a36Sopenharmony_ci			},
48762306a36Sopenharmony_ci			[IQS7222_REG_GRP_BTN] = {
48862306a36Sopenharmony_ci				.base = 0x9000,
48962306a36Sopenharmony_ci				.num_row = 20,
49062306a36Sopenharmony_ci				.num_col = 2,
49162306a36Sopenharmony_ci			},
49262306a36Sopenharmony_ci			[IQS7222_REG_GRP_CHAN] = {
49362306a36Sopenharmony_ci				.base = 0xB000,
49462306a36Sopenharmony_ci				.num_row = 20,
49562306a36Sopenharmony_ci				.num_col = 4,
49662306a36Sopenharmony_ci			},
49762306a36Sopenharmony_ci			[IQS7222_REG_GRP_FILT] = {
49862306a36Sopenharmony_ci				.base = 0xC400,
49962306a36Sopenharmony_ci				.num_row = 1,
50062306a36Sopenharmony_ci				.num_col = 2,
50162306a36Sopenharmony_ci			},
50262306a36Sopenharmony_ci			[IQS7222_REG_GRP_SYS] = {
50362306a36Sopenharmony_ci				.base = IQS7222_SYS_SETUP,
50462306a36Sopenharmony_ci				.num_row = 1,
50562306a36Sopenharmony_ci				.num_col = 10,
50662306a36Sopenharmony_ci			},
50762306a36Sopenharmony_ci		},
50862306a36Sopenharmony_ci	},
50962306a36Sopenharmony_ci	{
51062306a36Sopenharmony_ci		.prod_num = IQS7222_PROD_NUM_C,
51162306a36Sopenharmony_ci		.fw_major = 2,
51262306a36Sopenharmony_ci		.fw_minor = 6,
51362306a36Sopenharmony_ci		.sldr_res = U16_MAX,
51462306a36Sopenharmony_ci		.touch_link = 1686,
51562306a36Sopenharmony_ci		.wheel_enable = BIT(3),
51662306a36Sopenharmony_ci		.event_offset = 9,
51762306a36Sopenharmony_ci		.comms_offset = 10,
51862306a36Sopenharmony_ci		.reg_grps = {
51962306a36Sopenharmony_ci			[IQS7222_REG_GRP_STAT] = {
52062306a36Sopenharmony_ci				.base = IQS7222_SYS_STATUS,
52162306a36Sopenharmony_ci				.num_row = 1,
52262306a36Sopenharmony_ci				.num_col = 6,
52362306a36Sopenharmony_ci			},
52462306a36Sopenharmony_ci			[IQS7222_REG_GRP_CYCLE] = {
52562306a36Sopenharmony_ci				.base = 0x8000,
52662306a36Sopenharmony_ci				.num_row = 5,
52762306a36Sopenharmony_ci				.num_col = 3,
52862306a36Sopenharmony_ci			},
52962306a36Sopenharmony_ci			[IQS7222_REG_GRP_GLBL] = {
53062306a36Sopenharmony_ci				.base = 0x8500,
53162306a36Sopenharmony_ci				.num_row = 1,
53262306a36Sopenharmony_ci				.num_col = 3,
53362306a36Sopenharmony_ci			},
53462306a36Sopenharmony_ci			[IQS7222_REG_GRP_BTN] = {
53562306a36Sopenharmony_ci				.base = 0x9000,
53662306a36Sopenharmony_ci				.num_row = 10,
53762306a36Sopenharmony_ci				.num_col = 3,
53862306a36Sopenharmony_ci			},
53962306a36Sopenharmony_ci			[IQS7222_REG_GRP_CHAN] = {
54062306a36Sopenharmony_ci				.base = 0xA000,
54162306a36Sopenharmony_ci				.num_row = 10,
54262306a36Sopenharmony_ci				.num_col = 6,
54362306a36Sopenharmony_ci			},
54462306a36Sopenharmony_ci			[IQS7222_REG_GRP_FILT] = {
54562306a36Sopenharmony_ci				.base = 0xAA00,
54662306a36Sopenharmony_ci				.num_row = 1,
54762306a36Sopenharmony_ci				.num_col = 2,
54862306a36Sopenharmony_ci			},
54962306a36Sopenharmony_ci			[IQS7222_REG_GRP_SLDR] = {
55062306a36Sopenharmony_ci				.base = 0xB000,
55162306a36Sopenharmony_ci				.num_row = 2,
55262306a36Sopenharmony_ci				.num_col = 10,
55362306a36Sopenharmony_ci			},
55462306a36Sopenharmony_ci			[IQS7222_REG_GRP_GPIO] = {
55562306a36Sopenharmony_ci				.base = 0xC000,
55662306a36Sopenharmony_ci				.num_row = 3,
55762306a36Sopenharmony_ci				.num_col = 3,
55862306a36Sopenharmony_ci			},
55962306a36Sopenharmony_ci			[IQS7222_REG_GRP_SYS] = {
56062306a36Sopenharmony_ci				.base = IQS7222_SYS_SETUP,
56162306a36Sopenharmony_ci				.num_row = 1,
56262306a36Sopenharmony_ci				.num_col = 12,
56362306a36Sopenharmony_ci			},
56462306a36Sopenharmony_ci		},
56562306a36Sopenharmony_ci	},
56662306a36Sopenharmony_ci	{
56762306a36Sopenharmony_ci		.prod_num = IQS7222_PROD_NUM_C,
56862306a36Sopenharmony_ci		.fw_major = 1,
56962306a36Sopenharmony_ci		.fw_minor = 13,
57062306a36Sopenharmony_ci		.sldr_res = U16_MAX,
57162306a36Sopenharmony_ci		.touch_link = 1674,
57262306a36Sopenharmony_ci		.wheel_enable = BIT(3),
57362306a36Sopenharmony_ci		.event_offset = 9,
57462306a36Sopenharmony_ci		.comms_offset = 10,
57562306a36Sopenharmony_ci		.reg_grps = {
57662306a36Sopenharmony_ci			[IQS7222_REG_GRP_STAT] = {
57762306a36Sopenharmony_ci				.base = IQS7222_SYS_STATUS,
57862306a36Sopenharmony_ci				.num_row = 1,
57962306a36Sopenharmony_ci				.num_col = 6,
58062306a36Sopenharmony_ci			},
58162306a36Sopenharmony_ci			[IQS7222_REG_GRP_CYCLE] = {
58262306a36Sopenharmony_ci				.base = 0x8000,
58362306a36Sopenharmony_ci				.num_row = 5,
58462306a36Sopenharmony_ci				.num_col = 3,
58562306a36Sopenharmony_ci			},
58662306a36Sopenharmony_ci			[IQS7222_REG_GRP_GLBL] = {
58762306a36Sopenharmony_ci				.base = 0x8500,
58862306a36Sopenharmony_ci				.num_row = 1,
58962306a36Sopenharmony_ci				.num_col = 3,
59062306a36Sopenharmony_ci			},
59162306a36Sopenharmony_ci			[IQS7222_REG_GRP_BTN] = {
59262306a36Sopenharmony_ci				.base = 0x9000,
59362306a36Sopenharmony_ci				.num_row = 10,
59462306a36Sopenharmony_ci				.num_col = 3,
59562306a36Sopenharmony_ci			},
59662306a36Sopenharmony_ci			[IQS7222_REG_GRP_CHAN] = {
59762306a36Sopenharmony_ci				.base = 0xA000,
59862306a36Sopenharmony_ci				.num_row = 10,
59962306a36Sopenharmony_ci				.num_col = 6,
60062306a36Sopenharmony_ci			},
60162306a36Sopenharmony_ci			[IQS7222_REG_GRP_FILT] = {
60262306a36Sopenharmony_ci				.base = 0xAA00,
60362306a36Sopenharmony_ci				.num_row = 1,
60462306a36Sopenharmony_ci				.num_col = 2,
60562306a36Sopenharmony_ci			},
60662306a36Sopenharmony_ci			[IQS7222_REG_GRP_SLDR] = {
60762306a36Sopenharmony_ci				.base = 0xB000,
60862306a36Sopenharmony_ci				.num_row = 2,
60962306a36Sopenharmony_ci				.num_col = 10,
61062306a36Sopenharmony_ci			},
61162306a36Sopenharmony_ci			[IQS7222_REG_GRP_GPIO] = {
61262306a36Sopenharmony_ci				.base = 0xC000,
61362306a36Sopenharmony_ci				.num_row = 1,
61462306a36Sopenharmony_ci				.num_col = 3,
61562306a36Sopenharmony_ci			},
61662306a36Sopenharmony_ci			[IQS7222_REG_GRP_SYS] = {
61762306a36Sopenharmony_ci				.base = IQS7222_SYS_SETUP,
61862306a36Sopenharmony_ci				.num_row = 1,
61962306a36Sopenharmony_ci				.num_col = 11,
62062306a36Sopenharmony_ci			},
62162306a36Sopenharmony_ci		},
62262306a36Sopenharmony_ci	},
62362306a36Sopenharmony_ci	{
62462306a36Sopenharmony_ci		.prod_num = IQS7222_PROD_NUM_D,
62562306a36Sopenharmony_ci		.fw_major = 1,
62662306a36Sopenharmony_ci		.fw_minor = 2,
62762306a36Sopenharmony_ci		.touch_link = 1770,
62862306a36Sopenharmony_ci		.allow_offset = 9,
62962306a36Sopenharmony_ci		.event_offset = 10,
63062306a36Sopenharmony_ci		.comms_offset = 11,
63162306a36Sopenharmony_ci		.reg_grps = {
63262306a36Sopenharmony_ci			[IQS7222_REG_GRP_STAT] = {
63362306a36Sopenharmony_ci				.base = IQS7222_SYS_STATUS,
63462306a36Sopenharmony_ci				.num_row = 1,
63562306a36Sopenharmony_ci				.num_col = 7,
63662306a36Sopenharmony_ci			},
63762306a36Sopenharmony_ci			[IQS7222_REG_GRP_CYCLE] = {
63862306a36Sopenharmony_ci				.base = 0x8000,
63962306a36Sopenharmony_ci				.num_row = 7,
64062306a36Sopenharmony_ci				.num_col = 2,
64162306a36Sopenharmony_ci			},
64262306a36Sopenharmony_ci			[IQS7222_REG_GRP_GLBL] = {
64362306a36Sopenharmony_ci				.base = 0x8700,
64462306a36Sopenharmony_ci				.num_row = 1,
64562306a36Sopenharmony_ci				.num_col = 3,
64662306a36Sopenharmony_ci			},
64762306a36Sopenharmony_ci			[IQS7222_REG_GRP_BTN] = {
64862306a36Sopenharmony_ci				.base = 0x9000,
64962306a36Sopenharmony_ci				.num_row = 14,
65062306a36Sopenharmony_ci				.num_col = 3,
65162306a36Sopenharmony_ci			},
65262306a36Sopenharmony_ci			[IQS7222_REG_GRP_CHAN] = {
65362306a36Sopenharmony_ci				.base = 0xA000,
65462306a36Sopenharmony_ci				.num_row = 14,
65562306a36Sopenharmony_ci				.num_col = 4,
65662306a36Sopenharmony_ci			},
65762306a36Sopenharmony_ci			[IQS7222_REG_GRP_FILT] = {
65862306a36Sopenharmony_ci				.base = 0xAE00,
65962306a36Sopenharmony_ci				.num_row = 1,
66062306a36Sopenharmony_ci				.num_col = 2,
66162306a36Sopenharmony_ci			},
66262306a36Sopenharmony_ci			[IQS7222_REG_GRP_TPAD] = {
66362306a36Sopenharmony_ci				.base = 0xB000,
66462306a36Sopenharmony_ci				.num_row = 1,
66562306a36Sopenharmony_ci				.num_col = 24,
66662306a36Sopenharmony_ci			},
66762306a36Sopenharmony_ci			[IQS7222_REG_GRP_GPIO] = {
66862306a36Sopenharmony_ci				.base = 0xC000,
66962306a36Sopenharmony_ci				.num_row = 3,
67062306a36Sopenharmony_ci				.num_col = 3,
67162306a36Sopenharmony_ci			},
67262306a36Sopenharmony_ci			[IQS7222_REG_GRP_SYS] = {
67362306a36Sopenharmony_ci				.base = IQS7222_SYS_SETUP,
67462306a36Sopenharmony_ci				.num_row = 1,
67562306a36Sopenharmony_ci				.num_col = 12,
67662306a36Sopenharmony_ci			},
67762306a36Sopenharmony_ci		},
67862306a36Sopenharmony_ci	},
67962306a36Sopenharmony_ci	{
68062306a36Sopenharmony_ci		.prod_num = IQS7222_PROD_NUM_D,
68162306a36Sopenharmony_ci		.fw_major = 1,
68262306a36Sopenharmony_ci		.fw_minor = 1,
68362306a36Sopenharmony_ci		.touch_link = 1774,
68462306a36Sopenharmony_ci		.allow_offset = 9,
68562306a36Sopenharmony_ci		.event_offset = 10,
68662306a36Sopenharmony_ci		.comms_offset = 11,
68762306a36Sopenharmony_ci		.reg_grps = {
68862306a36Sopenharmony_ci			[IQS7222_REG_GRP_STAT] = {
68962306a36Sopenharmony_ci				.base = IQS7222_SYS_STATUS,
69062306a36Sopenharmony_ci				.num_row = 1,
69162306a36Sopenharmony_ci				.num_col = 7,
69262306a36Sopenharmony_ci			},
69362306a36Sopenharmony_ci			[IQS7222_REG_GRP_CYCLE] = {
69462306a36Sopenharmony_ci				.base = 0x8000,
69562306a36Sopenharmony_ci				.num_row = 7,
69662306a36Sopenharmony_ci				.num_col = 2,
69762306a36Sopenharmony_ci			},
69862306a36Sopenharmony_ci			[IQS7222_REG_GRP_GLBL] = {
69962306a36Sopenharmony_ci				.base = 0x8700,
70062306a36Sopenharmony_ci				.num_row = 1,
70162306a36Sopenharmony_ci				.num_col = 3,
70262306a36Sopenharmony_ci			},
70362306a36Sopenharmony_ci			[IQS7222_REG_GRP_BTN] = {
70462306a36Sopenharmony_ci				.base = 0x9000,
70562306a36Sopenharmony_ci				.num_row = 14,
70662306a36Sopenharmony_ci				.num_col = 3,
70762306a36Sopenharmony_ci			},
70862306a36Sopenharmony_ci			[IQS7222_REG_GRP_CHAN] = {
70962306a36Sopenharmony_ci				.base = 0xA000,
71062306a36Sopenharmony_ci				.num_row = 14,
71162306a36Sopenharmony_ci				.num_col = 4,
71262306a36Sopenharmony_ci			},
71362306a36Sopenharmony_ci			[IQS7222_REG_GRP_FILT] = {
71462306a36Sopenharmony_ci				.base = 0xAE00,
71562306a36Sopenharmony_ci				.num_row = 1,
71662306a36Sopenharmony_ci				.num_col = 2,
71762306a36Sopenharmony_ci			},
71862306a36Sopenharmony_ci			[IQS7222_REG_GRP_TPAD] = {
71962306a36Sopenharmony_ci				.base = 0xB000,
72062306a36Sopenharmony_ci				.num_row = 1,
72162306a36Sopenharmony_ci				.num_col = 24,
72262306a36Sopenharmony_ci			},
72362306a36Sopenharmony_ci			[IQS7222_REG_GRP_GPIO] = {
72462306a36Sopenharmony_ci				.base = 0xC000,
72562306a36Sopenharmony_ci				.num_row = 3,
72662306a36Sopenharmony_ci				.num_col = 3,
72762306a36Sopenharmony_ci			},
72862306a36Sopenharmony_ci			[IQS7222_REG_GRP_SYS] = {
72962306a36Sopenharmony_ci				.base = IQS7222_SYS_SETUP,
73062306a36Sopenharmony_ci				.num_row = 1,
73162306a36Sopenharmony_ci				.num_col = 12,
73262306a36Sopenharmony_ci			},
73362306a36Sopenharmony_ci		},
73462306a36Sopenharmony_ci	},
73562306a36Sopenharmony_ci	{
73662306a36Sopenharmony_ci		.prod_num = IQS7222_PROD_NUM_D,
73762306a36Sopenharmony_ci		.fw_major = 0,
73862306a36Sopenharmony_ci		.fw_minor = 37,
73962306a36Sopenharmony_ci		.touch_link = 1770,
74062306a36Sopenharmony_ci		.allow_offset = 9,
74162306a36Sopenharmony_ci		.event_offset = 10,
74262306a36Sopenharmony_ci		.comms_offset = 11,
74362306a36Sopenharmony_ci		.reg_grps = {
74462306a36Sopenharmony_ci			[IQS7222_REG_GRP_STAT] = {
74562306a36Sopenharmony_ci				.base = IQS7222_SYS_STATUS,
74662306a36Sopenharmony_ci				.num_row = 1,
74762306a36Sopenharmony_ci				.num_col = 7,
74862306a36Sopenharmony_ci			},
74962306a36Sopenharmony_ci			[IQS7222_REG_GRP_CYCLE] = {
75062306a36Sopenharmony_ci				.base = 0x8000,
75162306a36Sopenharmony_ci				.num_row = 7,
75262306a36Sopenharmony_ci				.num_col = 2,
75362306a36Sopenharmony_ci			},
75462306a36Sopenharmony_ci			[IQS7222_REG_GRP_GLBL] = {
75562306a36Sopenharmony_ci				.base = 0x8700,
75662306a36Sopenharmony_ci				.num_row = 1,
75762306a36Sopenharmony_ci				.num_col = 3,
75862306a36Sopenharmony_ci			},
75962306a36Sopenharmony_ci			[IQS7222_REG_GRP_BTN] = {
76062306a36Sopenharmony_ci				.base = 0x9000,
76162306a36Sopenharmony_ci				.num_row = 14,
76262306a36Sopenharmony_ci				.num_col = 3,
76362306a36Sopenharmony_ci			},
76462306a36Sopenharmony_ci			[IQS7222_REG_GRP_CHAN] = {
76562306a36Sopenharmony_ci				.base = 0xA000,
76662306a36Sopenharmony_ci				.num_row = 14,
76762306a36Sopenharmony_ci				.num_col = 4,
76862306a36Sopenharmony_ci			},
76962306a36Sopenharmony_ci			[IQS7222_REG_GRP_FILT] = {
77062306a36Sopenharmony_ci				.base = 0xAE00,
77162306a36Sopenharmony_ci				.num_row = 1,
77262306a36Sopenharmony_ci				.num_col = 2,
77362306a36Sopenharmony_ci			},
77462306a36Sopenharmony_ci			[IQS7222_REG_GRP_TPAD] = {
77562306a36Sopenharmony_ci				.base = 0xB000,
77662306a36Sopenharmony_ci				.num_row = 1,
77762306a36Sopenharmony_ci				.num_col = 24,
77862306a36Sopenharmony_ci			},
77962306a36Sopenharmony_ci			[IQS7222_REG_GRP_GPIO] = {
78062306a36Sopenharmony_ci				.base = 0xC000,
78162306a36Sopenharmony_ci				.num_row = 3,
78262306a36Sopenharmony_ci				.num_col = 3,
78362306a36Sopenharmony_ci			},
78462306a36Sopenharmony_ci			[IQS7222_REG_GRP_SYS] = {
78562306a36Sopenharmony_ci				.base = IQS7222_SYS_SETUP,
78662306a36Sopenharmony_ci				.num_row = 1,
78762306a36Sopenharmony_ci				.num_col = 12,
78862306a36Sopenharmony_ci			},
78962306a36Sopenharmony_ci		},
79062306a36Sopenharmony_ci	},
79162306a36Sopenharmony_ci};
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_cistruct iqs7222_prop_desc {
79462306a36Sopenharmony_ci	const char *name;
79562306a36Sopenharmony_ci	enum iqs7222_reg_grp_id reg_grp;
79662306a36Sopenharmony_ci	enum iqs7222_reg_key_id reg_key;
79762306a36Sopenharmony_ci	int reg_offset;
79862306a36Sopenharmony_ci	int reg_shift;
79962306a36Sopenharmony_ci	int reg_width;
80062306a36Sopenharmony_ci	int val_pitch;
80162306a36Sopenharmony_ci	int val_min;
80262306a36Sopenharmony_ci	int val_max;
80362306a36Sopenharmony_ci	bool invert;
80462306a36Sopenharmony_ci	const char *label;
80562306a36Sopenharmony_ci};
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_cistatic const struct iqs7222_prop_desc iqs7222_props[] = {
80862306a36Sopenharmony_ci	{
80962306a36Sopenharmony_ci		.name = "azoteq,conv-period",
81062306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CYCLE,
81162306a36Sopenharmony_ci		.reg_offset = 0,
81262306a36Sopenharmony_ci		.reg_shift = 8,
81362306a36Sopenharmony_ci		.reg_width = 8,
81462306a36Sopenharmony_ci		.label = "conversion period",
81562306a36Sopenharmony_ci	},
81662306a36Sopenharmony_ci	{
81762306a36Sopenharmony_ci		.name = "azoteq,conv-frac",
81862306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CYCLE,
81962306a36Sopenharmony_ci		.reg_offset = 0,
82062306a36Sopenharmony_ci		.reg_shift = 0,
82162306a36Sopenharmony_ci		.reg_width = 8,
82262306a36Sopenharmony_ci		.label = "conversion frequency fractional divider",
82362306a36Sopenharmony_ci	},
82462306a36Sopenharmony_ci	{
82562306a36Sopenharmony_ci		.name = "azoteq,rx-float-inactive",
82662306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CYCLE,
82762306a36Sopenharmony_ci		.reg_offset = 1,
82862306a36Sopenharmony_ci		.reg_shift = 6,
82962306a36Sopenharmony_ci		.reg_width = 1,
83062306a36Sopenharmony_ci		.invert = true,
83162306a36Sopenharmony_ci	},
83262306a36Sopenharmony_ci	{
83362306a36Sopenharmony_ci		.name = "azoteq,dead-time-enable",
83462306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CYCLE,
83562306a36Sopenharmony_ci		.reg_offset = 1,
83662306a36Sopenharmony_ci		.reg_shift = 5,
83762306a36Sopenharmony_ci		.reg_width = 1,
83862306a36Sopenharmony_ci	},
83962306a36Sopenharmony_ci	{
84062306a36Sopenharmony_ci		.name = "azoteq,tx-freq-fosc",
84162306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CYCLE,
84262306a36Sopenharmony_ci		.reg_offset = 1,
84362306a36Sopenharmony_ci		.reg_shift = 4,
84462306a36Sopenharmony_ci		.reg_width = 1,
84562306a36Sopenharmony_ci	},
84662306a36Sopenharmony_ci	{
84762306a36Sopenharmony_ci		.name = "azoteq,vbias-enable",
84862306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CYCLE,
84962306a36Sopenharmony_ci		.reg_offset = 1,
85062306a36Sopenharmony_ci		.reg_shift = 3,
85162306a36Sopenharmony_ci		.reg_width = 1,
85262306a36Sopenharmony_ci	},
85362306a36Sopenharmony_ci	{
85462306a36Sopenharmony_ci		.name = "azoteq,sense-mode",
85562306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CYCLE,
85662306a36Sopenharmony_ci		.reg_offset = 1,
85762306a36Sopenharmony_ci		.reg_shift = 0,
85862306a36Sopenharmony_ci		.reg_width = 3,
85962306a36Sopenharmony_ci		.val_max = 3,
86062306a36Sopenharmony_ci		.label = "sensing mode",
86162306a36Sopenharmony_ci	},
86262306a36Sopenharmony_ci	{
86362306a36Sopenharmony_ci		.name = "azoteq,iref-enable",
86462306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CYCLE,
86562306a36Sopenharmony_ci		.reg_offset = 2,
86662306a36Sopenharmony_ci		.reg_shift = 10,
86762306a36Sopenharmony_ci		.reg_width = 1,
86862306a36Sopenharmony_ci	},
86962306a36Sopenharmony_ci	{
87062306a36Sopenharmony_ci		.name = "azoteq,iref-level",
87162306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CYCLE,
87262306a36Sopenharmony_ci		.reg_offset = 2,
87362306a36Sopenharmony_ci		.reg_shift = 4,
87462306a36Sopenharmony_ci		.reg_width = 4,
87562306a36Sopenharmony_ci		.label = "current reference level",
87662306a36Sopenharmony_ci	},
87762306a36Sopenharmony_ci	{
87862306a36Sopenharmony_ci		.name = "azoteq,iref-trim",
87962306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CYCLE,
88062306a36Sopenharmony_ci		.reg_offset = 2,
88162306a36Sopenharmony_ci		.reg_shift = 0,
88262306a36Sopenharmony_ci		.reg_width = 4,
88362306a36Sopenharmony_ci		.label = "current reference trim",
88462306a36Sopenharmony_ci	},
88562306a36Sopenharmony_ci	{
88662306a36Sopenharmony_ci		.name = "azoteq,max-counts",
88762306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_GLBL,
88862306a36Sopenharmony_ci		.reg_offset = 0,
88962306a36Sopenharmony_ci		.reg_shift = 13,
89062306a36Sopenharmony_ci		.reg_width = 2,
89162306a36Sopenharmony_ci		.label = "maximum counts",
89262306a36Sopenharmony_ci	},
89362306a36Sopenharmony_ci	{
89462306a36Sopenharmony_ci		.name = "azoteq,auto-mode",
89562306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_GLBL,
89662306a36Sopenharmony_ci		.reg_offset = 0,
89762306a36Sopenharmony_ci		.reg_shift = 2,
89862306a36Sopenharmony_ci		.reg_width = 2,
89962306a36Sopenharmony_ci		.label = "number of conversions",
90062306a36Sopenharmony_ci	},
90162306a36Sopenharmony_ci	{
90262306a36Sopenharmony_ci		.name = "azoteq,ati-frac-div-fine",
90362306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_GLBL,
90462306a36Sopenharmony_ci		.reg_offset = 1,
90562306a36Sopenharmony_ci		.reg_shift = 9,
90662306a36Sopenharmony_ci		.reg_width = 5,
90762306a36Sopenharmony_ci		.label = "ATI fine fractional divider",
90862306a36Sopenharmony_ci	},
90962306a36Sopenharmony_ci	{
91062306a36Sopenharmony_ci		.name = "azoteq,ati-frac-div-coarse",
91162306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_GLBL,
91262306a36Sopenharmony_ci		.reg_offset = 1,
91362306a36Sopenharmony_ci		.reg_shift = 0,
91462306a36Sopenharmony_ci		.reg_width = 5,
91562306a36Sopenharmony_ci		.label = "ATI coarse fractional divider",
91662306a36Sopenharmony_ci	},
91762306a36Sopenharmony_ci	{
91862306a36Sopenharmony_ci		.name = "azoteq,ati-comp-select",
91962306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_GLBL,
92062306a36Sopenharmony_ci		.reg_offset = 2,
92162306a36Sopenharmony_ci		.reg_shift = 0,
92262306a36Sopenharmony_ci		.reg_width = 10,
92362306a36Sopenharmony_ci		.label = "ATI compensation selection",
92462306a36Sopenharmony_ci	},
92562306a36Sopenharmony_ci	{
92662306a36Sopenharmony_ci		.name = "azoteq,ati-band",
92762306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CHAN,
92862306a36Sopenharmony_ci		.reg_offset = 0,
92962306a36Sopenharmony_ci		.reg_shift = 12,
93062306a36Sopenharmony_ci		.reg_width = 2,
93162306a36Sopenharmony_ci		.label = "ATI band",
93262306a36Sopenharmony_ci	},
93362306a36Sopenharmony_ci	{
93462306a36Sopenharmony_ci		.name = "azoteq,global-halt",
93562306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CHAN,
93662306a36Sopenharmony_ci		.reg_offset = 0,
93762306a36Sopenharmony_ci		.reg_shift = 11,
93862306a36Sopenharmony_ci		.reg_width = 1,
93962306a36Sopenharmony_ci	},
94062306a36Sopenharmony_ci	{
94162306a36Sopenharmony_ci		.name = "azoteq,invert-enable",
94262306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CHAN,
94362306a36Sopenharmony_ci		.reg_offset = 0,
94462306a36Sopenharmony_ci		.reg_shift = 10,
94562306a36Sopenharmony_ci		.reg_width = 1,
94662306a36Sopenharmony_ci	},
94762306a36Sopenharmony_ci	{
94862306a36Sopenharmony_ci		.name = "azoteq,dual-direction",
94962306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CHAN,
95062306a36Sopenharmony_ci		.reg_offset = 0,
95162306a36Sopenharmony_ci		.reg_shift = 9,
95262306a36Sopenharmony_ci		.reg_width = 1,
95362306a36Sopenharmony_ci	},
95462306a36Sopenharmony_ci	{
95562306a36Sopenharmony_ci		.name = "azoteq,samp-cap-double",
95662306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CHAN,
95762306a36Sopenharmony_ci		.reg_offset = 0,
95862306a36Sopenharmony_ci		.reg_shift = 3,
95962306a36Sopenharmony_ci		.reg_width = 1,
96062306a36Sopenharmony_ci	},
96162306a36Sopenharmony_ci	{
96262306a36Sopenharmony_ci		.name = "azoteq,vref-half",
96362306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CHAN,
96462306a36Sopenharmony_ci		.reg_offset = 0,
96562306a36Sopenharmony_ci		.reg_shift = 2,
96662306a36Sopenharmony_ci		.reg_width = 1,
96762306a36Sopenharmony_ci	},
96862306a36Sopenharmony_ci	{
96962306a36Sopenharmony_ci		.name = "azoteq,proj-bias",
97062306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CHAN,
97162306a36Sopenharmony_ci		.reg_offset = 0,
97262306a36Sopenharmony_ci		.reg_shift = 0,
97362306a36Sopenharmony_ci		.reg_width = 2,
97462306a36Sopenharmony_ci		.label = "projected bias current",
97562306a36Sopenharmony_ci	},
97662306a36Sopenharmony_ci	{
97762306a36Sopenharmony_ci		.name = "azoteq,ati-target",
97862306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CHAN,
97962306a36Sopenharmony_ci		.reg_offset = 1,
98062306a36Sopenharmony_ci		.reg_shift = 8,
98162306a36Sopenharmony_ci		.reg_width = 8,
98262306a36Sopenharmony_ci		.val_pitch = 8,
98362306a36Sopenharmony_ci		.label = "ATI target",
98462306a36Sopenharmony_ci	},
98562306a36Sopenharmony_ci	{
98662306a36Sopenharmony_ci		.name = "azoteq,ati-base",
98762306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CHAN,
98862306a36Sopenharmony_ci		.reg_offset = 1,
98962306a36Sopenharmony_ci		.reg_shift = 3,
99062306a36Sopenharmony_ci		.reg_width = 5,
99162306a36Sopenharmony_ci		.val_pitch = 16,
99262306a36Sopenharmony_ci		.label = "ATI base",
99362306a36Sopenharmony_ci	},
99462306a36Sopenharmony_ci	{
99562306a36Sopenharmony_ci		.name = "azoteq,ati-mode",
99662306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CHAN,
99762306a36Sopenharmony_ci		.reg_offset = 1,
99862306a36Sopenharmony_ci		.reg_shift = 0,
99962306a36Sopenharmony_ci		.reg_width = 3,
100062306a36Sopenharmony_ci		.val_max = 5,
100162306a36Sopenharmony_ci		.label = "ATI mode",
100262306a36Sopenharmony_ci	},
100362306a36Sopenharmony_ci	{
100462306a36Sopenharmony_ci		.name = "azoteq,ati-frac-div-fine",
100562306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CHAN,
100662306a36Sopenharmony_ci		.reg_offset = 2,
100762306a36Sopenharmony_ci		.reg_shift = 9,
100862306a36Sopenharmony_ci		.reg_width = 5,
100962306a36Sopenharmony_ci		.label = "ATI fine fractional divider",
101062306a36Sopenharmony_ci	},
101162306a36Sopenharmony_ci	{
101262306a36Sopenharmony_ci		.name = "azoteq,ati-frac-mult-coarse",
101362306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CHAN,
101462306a36Sopenharmony_ci		.reg_offset = 2,
101562306a36Sopenharmony_ci		.reg_shift = 5,
101662306a36Sopenharmony_ci		.reg_width = 4,
101762306a36Sopenharmony_ci		.label = "ATI coarse fractional multiplier",
101862306a36Sopenharmony_ci	},
101962306a36Sopenharmony_ci	{
102062306a36Sopenharmony_ci		.name = "azoteq,ati-frac-div-coarse",
102162306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CHAN,
102262306a36Sopenharmony_ci		.reg_offset = 2,
102362306a36Sopenharmony_ci		.reg_shift = 0,
102462306a36Sopenharmony_ci		.reg_width = 5,
102562306a36Sopenharmony_ci		.label = "ATI coarse fractional divider",
102662306a36Sopenharmony_ci	},
102762306a36Sopenharmony_ci	{
102862306a36Sopenharmony_ci		.name = "azoteq,ati-comp-div",
102962306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CHAN,
103062306a36Sopenharmony_ci		.reg_offset = 3,
103162306a36Sopenharmony_ci		.reg_shift = 11,
103262306a36Sopenharmony_ci		.reg_width = 5,
103362306a36Sopenharmony_ci		.label = "ATI compensation divider",
103462306a36Sopenharmony_ci	},
103562306a36Sopenharmony_ci	{
103662306a36Sopenharmony_ci		.name = "azoteq,ati-comp-select",
103762306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_CHAN,
103862306a36Sopenharmony_ci		.reg_offset = 3,
103962306a36Sopenharmony_ci		.reg_shift = 0,
104062306a36Sopenharmony_ci		.reg_width = 10,
104162306a36Sopenharmony_ci		.label = "ATI compensation selection",
104262306a36Sopenharmony_ci	},
104362306a36Sopenharmony_ci	{
104462306a36Sopenharmony_ci		.name = "azoteq,debounce-exit",
104562306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_BTN,
104662306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_DEBOUNCE,
104762306a36Sopenharmony_ci		.reg_offset = 0,
104862306a36Sopenharmony_ci		.reg_shift = 12,
104962306a36Sopenharmony_ci		.reg_width = 4,
105062306a36Sopenharmony_ci		.label = "debounce exit factor",
105162306a36Sopenharmony_ci	},
105262306a36Sopenharmony_ci	{
105362306a36Sopenharmony_ci		.name = "azoteq,debounce-enter",
105462306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_BTN,
105562306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_DEBOUNCE,
105662306a36Sopenharmony_ci		.reg_offset = 0,
105762306a36Sopenharmony_ci		.reg_shift = 8,
105862306a36Sopenharmony_ci		.reg_width = 4,
105962306a36Sopenharmony_ci		.label = "debounce entrance factor",
106062306a36Sopenharmony_ci	},
106162306a36Sopenharmony_ci	{
106262306a36Sopenharmony_ci		.name = "azoteq,thresh",
106362306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_BTN,
106462306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_PROX,
106562306a36Sopenharmony_ci		.reg_offset = 0,
106662306a36Sopenharmony_ci		.reg_shift = 0,
106762306a36Sopenharmony_ci		.reg_width = 8,
106862306a36Sopenharmony_ci		.val_max = 127,
106962306a36Sopenharmony_ci		.label = "threshold",
107062306a36Sopenharmony_ci	},
107162306a36Sopenharmony_ci	{
107262306a36Sopenharmony_ci		.name = "azoteq,thresh",
107362306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_BTN,
107462306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_TOUCH,
107562306a36Sopenharmony_ci		.reg_offset = 1,
107662306a36Sopenharmony_ci		.reg_shift = 0,
107762306a36Sopenharmony_ci		.reg_width = 8,
107862306a36Sopenharmony_ci		.label = "threshold",
107962306a36Sopenharmony_ci	},
108062306a36Sopenharmony_ci	{
108162306a36Sopenharmony_ci		.name = "azoteq,hyst",
108262306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_BTN,
108362306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_TOUCH,
108462306a36Sopenharmony_ci		.reg_offset = 1,
108562306a36Sopenharmony_ci		.reg_shift = 8,
108662306a36Sopenharmony_ci		.reg_width = 8,
108762306a36Sopenharmony_ci		.label = "hysteresis",
108862306a36Sopenharmony_ci	},
108962306a36Sopenharmony_ci	{
109062306a36Sopenharmony_ci		.name = "azoteq,lta-beta-lp",
109162306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_FILT,
109262306a36Sopenharmony_ci		.reg_offset = 0,
109362306a36Sopenharmony_ci		.reg_shift = 12,
109462306a36Sopenharmony_ci		.reg_width = 4,
109562306a36Sopenharmony_ci		.label = "low-power mode long-term average beta",
109662306a36Sopenharmony_ci	},
109762306a36Sopenharmony_ci	{
109862306a36Sopenharmony_ci		.name = "azoteq,lta-beta-np",
109962306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_FILT,
110062306a36Sopenharmony_ci		.reg_offset = 0,
110162306a36Sopenharmony_ci		.reg_shift = 8,
110262306a36Sopenharmony_ci		.reg_width = 4,
110362306a36Sopenharmony_ci		.label = "normal-power mode long-term average beta",
110462306a36Sopenharmony_ci	},
110562306a36Sopenharmony_ci	{
110662306a36Sopenharmony_ci		.name = "azoteq,counts-beta-lp",
110762306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_FILT,
110862306a36Sopenharmony_ci		.reg_offset = 0,
110962306a36Sopenharmony_ci		.reg_shift = 4,
111062306a36Sopenharmony_ci		.reg_width = 4,
111162306a36Sopenharmony_ci		.label = "low-power mode counts beta",
111262306a36Sopenharmony_ci	},
111362306a36Sopenharmony_ci	{
111462306a36Sopenharmony_ci		.name = "azoteq,counts-beta-np",
111562306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_FILT,
111662306a36Sopenharmony_ci		.reg_offset = 0,
111762306a36Sopenharmony_ci		.reg_shift = 0,
111862306a36Sopenharmony_ci		.reg_width = 4,
111962306a36Sopenharmony_ci		.label = "normal-power mode counts beta",
112062306a36Sopenharmony_ci	},
112162306a36Sopenharmony_ci	{
112262306a36Sopenharmony_ci		.name = "azoteq,lta-fast-beta-lp",
112362306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_FILT,
112462306a36Sopenharmony_ci		.reg_offset = 1,
112562306a36Sopenharmony_ci		.reg_shift = 4,
112662306a36Sopenharmony_ci		.reg_width = 4,
112762306a36Sopenharmony_ci		.label = "low-power mode long-term average fast beta",
112862306a36Sopenharmony_ci	},
112962306a36Sopenharmony_ci	{
113062306a36Sopenharmony_ci		.name = "azoteq,lta-fast-beta-np",
113162306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_FILT,
113262306a36Sopenharmony_ci		.reg_offset = 1,
113362306a36Sopenharmony_ci		.reg_shift = 0,
113462306a36Sopenharmony_ci		.reg_width = 4,
113562306a36Sopenharmony_ci		.label = "normal-power mode long-term average fast beta",
113662306a36Sopenharmony_ci	},
113762306a36Sopenharmony_ci	{
113862306a36Sopenharmony_ci		.name = "azoteq,lower-cal",
113962306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SLDR,
114062306a36Sopenharmony_ci		.reg_offset = 0,
114162306a36Sopenharmony_ci		.reg_shift = 8,
114262306a36Sopenharmony_ci		.reg_width = 8,
114362306a36Sopenharmony_ci		.label = "lower calibration",
114462306a36Sopenharmony_ci	},
114562306a36Sopenharmony_ci	{
114662306a36Sopenharmony_ci		.name = "azoteq,static-beta",
114762306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SLDR,
114862306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_NO_WHEEL,
114962306a36Sopenharmony_ci		.reg_offset = 0,
115062306a36Sopenharmony_ci		.reg_shift = 6,
115162306a36Sopenharmony_ci		.reg_width = 1,
115262306a36Sopenharmony_ci	},
115362306a36Sopenharmony_ci	{
115462306a36Sopenharmony_ci		.name = "azoteq,bottom-beta",
115562306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SLDR,
115662306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_NO_WHEEL,
115762306a36Sopenharmony_ci		.reg_offset = 0,
115862306a36Sopenharmony_ci		.reg_shift = 3,
115962306a36Sopenharmony_ci		.reg_width = 3,
116062306a36Sopenharmony_ci		.label = "bottom beta",
116162306a36Sopenharmony_ci	},
116262306a36Sopenharmony_ci	{
116362306a36Sopenharmony_ci		.name = "azoteq,static-beta",
116462306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SLDR,
116562306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_WHEEL,
116662306a36Sopenharmony_ci		.reg_offset = 0,
116762306a36Sopenharmony_ci		.reg_shift = 7,
116862306a36Sopenharmony_ci		.reg_width = 1,
116962306a36Sopenharmony_ci	},
117062306a36Sopenharmony_ci	{
117162306a36Sopenharmony_ci		.name = "azoteq,bottom-beta",
117262306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SLDR,
117362306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_WHEEL,
117462306a36Sopenharmony_ci		.reg_offset = 0,
117562306a36Sopenharmony_ci		.reg_shift = 4,
117662306a36Sopenharmony_ci		.reg_width = 3,
117762306a36Sopenharmony_ci		.label = "bottom beta",
117862306a36Sopenharmony_ci	},
117962306a36Sopenharmony_ci	{
118062306a36Sopenharmony_ci		.name = "azoteq,bottom-speed",
118162306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SLDR,
118262306a36Sopenharmony_ci		.reg_offset = 1,
118362306a36Sopenharmony_ci		.reg_shift = 8,
118462306a36Sopenharmony_ci		.reg_width = 8,
118562306a36Sopenharmony_ci		.label = "bottom speed",
118662306a36Sopenharmony_ci	},
118762306a36Sopenharmony_ci	{
118862306a36Sopenharmony_ci		.name = "azoteq,upper-cal",
118962306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SLDR,
119062306a36Sopenharmony_ci		.reg_offset = 1,
119162306a36Sopenharmony_ci		.reg_shift = 0,
119262306a36Sopenharmony_ci		.reg_width = 8,
119362306a36Sopenharmony_ci		.label = "upper calibration",
119462306a36Sopenharmony_ci	},
119562306a36Sopenharmony_ci	{
119662306a36Sopenharmony_ci		.name = "azoteq,gesture-max-ms",
119762306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SLDR,
119862306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_TAP,
119962306a36Sopenharmony_ci		.reg_offset = 9,
120062306a36Sopenharmony_ci		.reg_shift = 8,
120162306a36Sopenharmony_ci		.reg_width = 8,
120262306a36Sopenharmony_ci		.val_pitch = 16,
120362306a36Sopenharmony_ci		.label = "maximum gesture time",
120462306a36Sopenharmony_ci	},
120562306a36Sopenharmony_ci	{
120662306a36Sopenharmony_ci		.name = "azoteq,gesture-max-ms",
120762306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SLDR,
120862306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_TAP_LEGACY,
120962306a36Sopenharmony_ci		.reg_offset = 9,
121062306a36Sopenharmony_ci		.reg_shift = 8,
121162306a36Sopenharmony_ci		.reg_width = 8,
121262306a36Sopenharmony_ci		.val_pitch = 4,
121362306a36Sopenharmony_ci		.label = "maximum gesture time",
121462306a36Sopenharmony_ci	},
121562306a36Sopenharmony_ci	{
121662306a36Sopenharmony_ci		.name = "azoteq,gesture-min-ms",
121762306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SLDR,
121862306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_TAP,
121962306a36Sopenharmony_ci		.reg_offset = 9,
122062306a36Sopenharmony_ci		.reg_shift = 3,
122162306a36Sopenharmony_ci		.reg_width = 5,
122262306a36Sopenharmony_ci		.val_pitch = 16,
122362306a36Sopenharmony_ci		.label = "minimum gesture time",
122462306a36Sopenharmony_ci	},
122562306a36Sopenharmony_ci	{
122662306a36Sopenharmony_ci		.name = "azoteq,gesture-min-ms",
122762306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SLDR,
122862306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_TAP_LEGACY,
122962306a36Sopenharmony_ci		.reg_offset = 9,
123062306a36Sopenharmony_ci		.reg_shift = 3,
123162306a36Sopenharmony_ci		.reg_width = 5,
123262306a36Sopenharmony_ci		.val_pitch = 4,
123362306a36Sopenharmony_ci		.label = "minimum gesture time",
123462306a36Sopenharmony_ci	},
123562306a36Sopenharmony_ci	{
123662306a36Sopenharmony_ci		.name = "azoteq,gesture-dist",
123762306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SLDR,
123862306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_AXIAL,
123962306a36Sopenharmony_ci		.reg_offset = 10,
124062306a36Sopenharmony_ci		.reg_shift = 8,
124162306a36Sopenharmony_ci		.reg_width = 8,
124262306a36Sopenharmony_ci		.val_pitch = 16,
124362306a36Sopenharmony_ci		.label = "gesture distance",
124462306a36Sopenharmony_ci	},
124562306a36Sopenharmony_ci	{
124662306a36Sopenharmony_ci		.name = "azoteq,gesture-dist",
124762306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SLDR,
124862306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_AXIAL_LEGACY,
124962306a36Sopenharmony_ci		.reg_offset = 10,
125062306a36Sopenharmony_ci		.reg_shift = 8,
125162306a36Sopenharmony_ci		.reg_width = 8,
125262306a36Sopenharmony_ci		.val_pitch = 16,
125362306a36Sopenharmony_ci		.label = "gesture distance",
125462306a36Sopenharmony_ci	},
125562306a36Sopenharmony_ci	{
125662306a36Sopenharmony_ci		.name = "azoteq,gesture-max-ms",
125762306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SLDR,
125862306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_AXIAL,
125962306a36Sopenharmony_ci		.reg_offset = 10,
126062306a36Sopenharmony_ci		.reg_shift = 0,
126162306a36Sopenharmony_ci		.reg_width = 8,
126262306a36Sopenharmony_ci		.val_pitch = 16,
126362306a36Sopenharmony_ci		.label = "maximum gesture time",
126462306a36Sopenharmony_ci	},
126562306a36Sopenharmony_ci	{
126662306a36Sopenharmony_ci		.name = "azoteq,gesture-max-ms",
126762306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SLDR,
126862306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_AXIAL_LEGACY,
126962306a36Sopenharmony_ci		.reg_offset = 10,
127062306a36Sopenharmony_ci		.reg_shift = 0,
127162306a36Sopenharmony_ci		.reg_width = 8,
127262306a36Sopenharmony_ci		.val_pitch = 4,
127362306a36Sopenharmony_ci		.label = "maximum gesture time",
127462306a36Sopenharmony_ci	},
127562306a36Sopenharmony_ci	{
127662306a36Sopenharmony_ci		.name = "azoteq,num-rows",
127762306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_TPAD,
127862306a36Sopenharmony_ci		.reg_offset = 0,
127962306a36Sopenharmony_ci		.reg_shift = 4,
128062306a36Sopenharmony_ci		.reg_width = 4,
128162306a36Sopenharmony_ci		.val_min = 1,
128262306a36Sopenharmony_ci		.val_max = 12,
128362306a36Sopenharmony_ci		.label = "number of rows",
128462306a36Sopenharmony_ci	},
128562306a36Sopenharmony_ci	{
128662306a36Sopenharmony_ci		.name = "azoteq,num-cols",
128762306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_TPAD,
128862306a36Sopenharmony_ci		.reg_offset = 0,
128962306a36Sopenharmony_ci		.reg_shift = 0,
129062306a36Sopenharmony_ci		.reg_width = 4,
129162306a36Sopenharmony_ci		.val_min = 1,
129262306a36Sopenharmony_ci		.val_max = 12,
129362306a36Sopenharmony_ci		.label = "number of columns",
129462306a36Sopenharmony_ci	},
129562306a36Sopenharmony_ci	{
129662306a36Sopenharmony_ci		.name = "azoteq,lower-cal-y",
129762306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_TPAD,
129862306a36Sopenharmony_ci		.reg_offset = 1,
129962306a36Sopenharmony_ci		.reg_shift = 8,
130062306a36Sopenharmony_ci		.reg_width = 8,
130162306a36Sopenharmony_ci		.label = "lower vertical calibration",
130262306a36Sopenharmony_ci	},
130362306a36Sopenharmony_ci	{
130462306a36Sopenharmony_ci		.name = "azoteq,lower-cal-x",
130562306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_TPAD,
130662306a36Sopenharmony_ci		.reg_offset = 1,
130762306a36Sopenharmony_ci		.reg_shift = 0,
130862306a36Sopenharmony_ci		.reg_width = 8,
130962306a36Sopenharmony_ci		.label = "lower horizontal calibration",
131062306a36Sopenharmony_ci	},
131162306a36Sopenharmony_ci	{
131262306a36Sopenharmony_ci		.name = "azoteq,upper-cal-y",
131362306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_TPAD,
131462306a36Sopenharmony_ci		.reg_offset = 2,
131562306a36Sopenharmony_ci		.reg_shift = 8,
131662306a36Sopenharmony_ci		.reg_width = 8,
131762306a36Sopenharmony_ci		.label = "upper vertical calibration",
131862306a36Sopenharmony_ci	},
131962306a36Sopenharmony_ci	{
132062306a36Sopenharmony_ci		.name = "azoteq,upper-cal-x",
132162306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_TPAD,
132262306a36Sopenharmony_ci		.reg_offset = 2,
132362306a36Sopenharmony_ci		.reg_shift = 0,
132462306a36Sopenharmony_ci		.reg_width = 8,
132562306a36Sopenharmony_ci		.label = "upper horizontal calibration",
132662306a36Sopenharmony_ci	},
132762306a36Sopenharmony_ci	{
132862306a36Sopenharmony_ci		.name = "azoteq,top-speed",
132962306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_TPAD,
133062306a36Sopenharmony_ci		.reg_offset = 3,
133162306a36Sopenharmony_ci		.reg_shift = 8,
133262306a36Sopenharmony_ci		.reg_width = 8,
133362306a36Sopenharmony_ci		.val_pitch = 4,
133462306a36Sopenharmony_ci		.label = "top speed",
133562306a36Sopenharmony_ci	},
133662306a36Sopenharmony_ci	{
133762306a36Sopenharmony_ci		.name = "azoteq,bottom-speed",
133862306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_TPAD,
133962306a36Sopenharmony_ci		.reg_offset = 3,
134062306a36Sopenharmony_ci		.reg_shift = 0,
134162306a36Sopenharmony_ci		.reg_width = 8,
134262306a36Sopenharmony_ci		.label = "bottom speed",
134362306a36Sopenharmony_ci	},
134462306a36Sopenharmony_ci	{
134562306a36Sopenharmony_ci		.name = "azoteq,gesture-min-ms",
134662306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_TPAD,
134762306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_TAP,
134862306a36Sopenharmony_ci		.reg_offset = 20,
134962306a36Sopenharmony_ci		.reg_shift = 8,
135062306a36Sopenharmony_ci		.reg_width = 8,
135162306a36Sopenharmony_ci		.val_pitch = 16,
135262306a36Sopenharmony_ci		.label = "minimum gesture time",
135362306a36Sopenharmony_ci	},
135462306a36Sopenharmony_ci	{
135562306a36Sopenharmony_ci		.name = "azoteq,gesture-max-ms",
135662306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_TPAD,
135762306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_AXIAL,
135862306a36Sopenharmony_ci		.reg_offset = 21,
135962306a36Sopenharmony_ci		.reg_shift = 8,
136062306a36Sopenharmony_ci		.reg_width = 8,
136162306a36Sopenharmony_ci		.val_pitch = 16,
136262306a36Sopenharmony_ci		.label = "maximum gesture time",
136362306a36Sopenharmony_ci	},
136462306a36Sopenharmony_ci	{
136562306a36Sopenharmony_ci		.name = "azoteq,gesture-max-ms",
136662306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_TPAD,
136762306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_TAP,
136862306a36Sopenharmony_ci		.reg_offset = 21,
136962306a36Sopenharmony_ci		.reg_shift = 0,
137062306a36Sopenharmony_ci		.reg_width = 8,
137162306a36Sopenharmony_ci		.val_pitch = 16,
137262306a36Sopenharmony_ci		.label = "maximum gesture time",
137362306a36Sopenharmony_ci	},
137462306a36Sopenharmony_ci	{
137562306a36Sopenharmony_ci		.name = "azoteq,gesture-dist",
137662306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_TPAD,
137762306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_TAP,
137862306a36Sopenharmony_ci		.reg_offset = 22,
137962306a36Sopenharmony_ci		.reg_shift = 0,
138062306a36Sopenharmony_ci		.reg_width = 16,
138162306a36Sopenharmony_ci		.label = "gesture distance",
138262306a36Sopenharmony_ci	},
138362306a36Sopenharmony_ci	{
138462306a36Sopenharmony_ci		.name = "azoteq,gesture-dist",
138562306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_TPAD,
138662306a36Sopenharmony_ci		.reg_key = IQS7222_REG_KEY_AXIAL,
138762306a36Sopenharmony_ci		.reg_offset = 23,
138862306a36Sopenharmony_ci		.reg_shift = 0,
138962306a36Sopenharmony_ci		.reg_width = 16,
139062306a36Sopenharmony_ci		.label = "gesture distance",
139162306a36Sopenharmony_ci	},
139262306a36Sopenharmony_ci	{
139362306a36Sopenharmony_ci		.name = "drive-open-drain",
139462306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_GPIO,
139562306a36Sopenharmony_ci		.reg_offset = 0,
139662306a36Sopenharmony_ci		.reg_shift = 1,
139762306a36Sopenharmony_ci		.reg_width = 1,
139862306a36Sopenharmony_ci	},
139962306a36Sopenharmony_ci	{
140062306a36Sopenharmony_ci		.name = "azoteq,timeout-ati-ms",
140162306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SYS,
140262306a36Sopenharmony_ci		.reg_offset = 1,
140362306a36Sopenharmony_ci		.reg_shift = 0,
140462306a36Sopenharmony_ci		.reg_width = 16,
140562306a36Sopenharmony_ci		.val_pitch = 500,
140662306a36Sopenharmony_ci		.label = "ATI error timeout",
140762306a36Sopenharmony_ci	},
140862306a36Sopenharmony_ci	{
140962306a36Sopenharmony_ci		.name = "azoteq,rate-ati-ms",
141062306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SYS,
141162306a36Sopenharmony_ci		.reg_offset = 2,
141262306a36Sopenharmony_ci		.reg_shift = 0,
141362306a36Sopenharmony_ci		.reg_width = 16,
141462306a36Sopenharmony_ci		.label = "ATI report rate",
141562306a36Sopenharmony_ci	},
141662306a36Sopenharmony_ci	{
141762306a36Sopenharmony_ci		.name = "azoteq,timeout-np-ms",
141862306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SYS,
141962306a36Sopenharmony_ci		.reg_offset = 3,
142062306a36Sopenharmony_ci		.reg_shift = 0,
142162306a36Sopenharmony_ci		.reg_width = 16,
142262306a36Sopenharmony_ci		.label = "normal-power mode timeout",
142362306a36Sopenharmony_ci	},
142462306a36Sopenharmony_ci	{
142562306a36Sopenharmony_ci		.name = "azoteq,rate-np-ms",
142662306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SYS,
142762306a36Sopenharmony_ci		.reg_offset = 4,
142862306a36Sopenharmony_ci		.reg_shift = 0,
142962306a36Sopenharmony_ci		.reg_width = 16,
143062306a36Sopenharmony_ci		.val_max = 3000,
143162306a36Sopenharmony_ci		.label = "normal-power mode report rate",
143262306a36Sopenharmony_ci	},
143362306a36Sopenharmony_ci	{
143462306a36Sopenharmony_ci		.name = "azoteq,timeout-lp-ms",
143562306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SYS,
143662306a36Sopenharmony_ci		.reg_offset = 5,
143762306a36Sopenharmony_ci		.reg_shift = 0,
143862306a36Sopenharmony_ci		.reg_width = 16,
143962306a36Sopenharmony_ci		.label = "low-power mode timeout",
144062306a36Sopenharmony_ci	},
144162306a36Sopenharmony_ci	{
144262306a36Sopenharmony_ci		.name = "azoteq,rate-lp-ms",
144362306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SYS,
144462306a36Sopenharmony_ci		.reg_offset = 6,
144562306a36Sopenharmony_ci		.reg_shift = 0,
144662306a36Sopenharmony_ci		.reg_width = 16,
144762306a36Sopenharmony_ci		.val_max = 3000,
144862306a36Sopenharmony_ci		.label = "low-power mode report rate",
144962306a36Sopenharmony_ci	},
145062306a36Sopenharmony_ci	{
145162306a36Sopenharmony_ci		.name = "azoteq,timeout-ulp-ms",
145262306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SYS,
145362306a36Sopenharmony_ci		.reg_offset = 7,
145462306a36Sopenharmony_ci		.reg_shift = 0,
145562306a36Sopenharmony_ci		.reg_width = 16,
145662306a36Sopenharmony_ci		.label = "ultra-low-power mode timeout",
145762306a36Sopenharmony_ci	},
145862306a36Sopenharmony_ci	{
145962306a36Sopenharmony_ci		.name = "azoteq,rate-ulp-ms",
146062306a36Sopenharmony_ci		.reg_grp = IQS7222_REG_GRP_SYS,
146162306a36Sopenharmony_ci		.reg_offset = 8,
146262306a36Sopenharmony_ci		.reg_shift = 0,
146362306a36Sopenharmony_ci		.reg_width = 16,
146462306a36Sopenharmony_ci		.val_max = 3000,
146562306a36Sopenharmony_ci		.label = "ultra-low-power mode report rate",
146662306a36Sopenharmony_ci	},
146762306a36Sopenharmony_ci};
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_cistruct iqs7222_private {
147062306a36Sopenharmony_ci	const struct iqs7222_dev_desc *dev_desc;
147162306a36Sopenharmony_ci	struct gpio_desc *reset_gpio;
147262306a36Sopenharmony_ci	struct gpio_desc *irq_gpio;
147362306a36Sopenharmony_ci	struct i2c_client *client;
147462306a36Sopenharmony_ci	struct input_dev *keypad;
147562306a36Sopenharmony_ci	struct touchscreen_properties prop;
147662306a36Sopenharmony_ci	unsigned int kp_type[IQS7222_MAX_CHAN][ARRAY_SIZE(iqs7222_kp_events)];
147762306a36Sopenharmony_ci	unsigned int kp_code[IQS7222_MAX_CHAN][ARRAY_SIZE(iqs7222_kp_events)];
147862306a36Sopenharmony_ci	unsigned int sl_code[IQS7222_MAX_SLDR][ARRAY_SIZE(iqs7222_sl_events)];
147962306a36Sopenharmony_ci	unsigned int sl_axis[IQS7222_MAX_SLDR];
148062306a36Sopenharmony_ci	unsigned int tp_code[ARRAY_SIZE(iqs7222_tp_events)];
148162306a36Sopenharmony_ci	u16 cycle_setup[IQS7222_MAX_CHAN / 2][IQS7222_MAX_COLS_CYCLE];
148262306a36Sopenharmony_ci	u16 glbl_setup[IQS7222_MAX_COLS_GLBL];
148362306a36Sopenharmony_ci	u16 btn_setup[IQS7222_MAX_CHAN][IQS7222_MAX_COLS_BTN];
148462306a36Sopenharmony_ci	u16 chan_setup[IQS7222_MAX_CHAN][IQS7222_MAX_COLS_CHAN];
148562306a36Sopenharmony_ci	u16 filt_setup[IQS7222_MAX_COLS_FILT];
148662306a36Sopenharmony_ci	u16 sldr_setup[IQS7222_MAX_SLDR][IQS7222_MAX_COLS_SLDR];
148762306a36Sopenharmony_ci	u16 tpad_setup[IQS7222_MAX_COLS_TPAD];
148862306a36Sopenharmony_ci	u16 gpio_setup[ARRAY_SIZE(iqs7222_gpio_links)][IQS7222_MAX_COLS_GPIO];
148962306a36Sopenharmony_ci	u16 sys_setup[IQS7222_MAX_COLS_SYS];
149062306a36Sopenharmony_ci};
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_cistatic u16 *iqs7222_setup(struct iqs7222_private *iqs7222,
149362306a36Sopenharmony_ci			  enum iqs7222_reg_grp_id reg_grp, int row)
149462306a36Sopenharmony_ci{
149562306a36Sopenharmony_ci	switch (reg_grp) {
149662306a36Sopenharmony_ci	case IQS7222_REG_GRP_CYCLE:
149762306a36Sopenharmony_ci		return iqs7222->cycle_setup[row];
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	case IQS7222_REG_GRP_GLBL:
150062306a36Sopenharmony_ci		return iqs7222->glbl_setup;
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	case IQS7222_REG_GRP_BTN:
150362306a36Sopenharmony_ci		return iqs7222->btn_setup[row];
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	case IQS7222_REG_GRP_CHAN:
150662306a36Sopenharmony_ci		return iqs7222->chan_setup[row];
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	case IQS7222_REG_GRP_FILT:
150962306a36Sopenharmony_ci		return iqs7222->filt_setup;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	case IQS7222_REG_GRP_SLDR:
151262306a36Sopenharmony_ci		return iqs7222->sldr_setup[row];
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	case IQS7222_REG_GRP_TPAD:
151562306a36Sopenharmony_ci		return iqs7222->tpad_setup;
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	case IQS7222_REG_GRP_GPIO:
151862306a36Sopenharmony_ci		return iqs7222->gpio_setup[row];
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	case IQS7222_REG_GRP_SYS:
152162306a36Sopenharmony_ci		return iqs7222->sys_setup;
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	default:
152462306a36Sopenharmony_ci		return NULL;
152562306a36Sopenharmony_ci	}
152662306a36Sopenharmony_ci}
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_cistatic int iqs7222_irq_poll(struct iqs7222_private *iqs7222, u16 timeout_ms)
152962306a36Sopenharmony_ci{
153062306a36Sopenharmony_ci	ktime_t irq_timeout = ktime_add_ms(ktime_get(), timeout_ms);
153162306a36Sopenharmony_ci	int ret;
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	do {
153462306a36Sopenharmony_ci		usleep_range(1000, 1100);
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci		ret = gpiod_get_value_cansleep(iqs7222->irq_gpio);
153762306a36Sopenharmony_ci		if (ret < 0)
153862306a36Sopenharmony_ci			return ret;
153962306a36Sopenharmony_ci		else if (ret > 0)
154062306a36Sopenharmony_ci			return 0;
154162306a36Sopenharmony_ci	} while (ktime_compare(ktime_get(), irq_timeout) < 0);
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	return -EBUSY;
154462306a36Sopenharmony_ci}
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_cistatic int iqs7222_hard_reset(struct iqs7222_private *iqs7222)
154762306a36Sopenharmony_ci{
154862306a36Sopenharmony_ci	struct i2c_client *client = iqs7222->client;
154962306a36Sopenharmony_ci	int error;
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	if (!iqs7222->reset_gpio)
155262306a36Sopenharmony_ci		return 0;
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	gpiod_set_value_cansleep(iqs7222->reset_gpio, 1);
155562306a36Sopenharmony_ci	usleep_range(1000, 1100);
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	gpiod_set_value_cansleep(iqs7222->reset_gpio, 0);
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	error = iqs7222_irq_poll(iqs7222, IQS7222_RESET_TIMEOUT_MS);
156062306a36Sopenharmony_ci	if (error)
156162306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to reset device: %d\n", error);
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	return error;
156462306a36Sopenharmony_ci}
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_cistatic int iqs7222_force_comms(struct iqs7222_private *iqs7222)
156762306a36Sopenharmony_ci{
156862306a36Sopenharmony_ci	u8 msg_buf[] = { 0xFF, };
156962306a36Sopenharmony_ci	int ret;
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	/*
157262306a36Sopenharmony_ci	 * The device cannot communicate until it asserts its interrupt (RDY)
157362306a36Sopenharmony_ci	 * pin. Attempts to do so while RDY is deasserted return an ACK; how-
157462306a36Sopenharmony_ci	 * ever all write data is ignored, and all read data returns 0xEE.
157562306a36Sopenharmony_ci	 *
157662306a36Sopenharmony_ci	 * Unsolicited communication must be preceded by a special force com-
157762306a36Sopenharmony_ci	 * munication command, after which the device eventually asserts its
157862306a36Sopenharmony_ci	 * RDY pin and agrees to communicate.
157962306a36Sopenharmony_ci	 *
158062306a36Sopenharmony_ci	 * Regardless of whether communication is forced or the result of an
158162306a36Sopenharmony_ci	 * interrupt, the device automatically deasserts its RDY pin once it
158262306a36Sopenharmony_ci	 * detects an I2C stop condition, or a timeout expires.
158362306a36Sopenharmony_ci	 */
158462306a36Sopenharmony_ci	ret = gpiod_get_value_cansleep(iqs7222->irq_gpio);
158562306a36Sopenharmony_ci	if (ret < 0)
158662306a36Sopenharmony_ci		return ret;
158762306a36Sopenharmony_ci	else if (ret > 0)
158862306a36Sopenharmony_ci		return 0;
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	ret = i2c_master_send(iqs7222->client, msg_buf, sizeof(msg_buf));
159162306a36Sopenharmony_ci	if (ret < (int)sizeof(msg_buf)) {
159262306a36Sopenharmony_ci		if (ret >= 0)
159362306a36Sopenharmony_ci			ret = -EIO;
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci		/*
159662306a36Sopenharmony_ci		 * The datasheet states that the host must wait to retry any
159762306a36Sopenharmony_ci		 * failed attempt to communicate over I2C.
159862306a36Sopenharmony_ci		 */
159962306a36Sopenharmony_ci		msleep(IQS7222_COMMS_RETRY_MS);
160062306a36Sopenharmony_ci		return ret;
160162306a36Sopenharmony_ci	}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	return iqs7222_irq_poll(iqs7222, IQS7222_COMMS_TIMEOUT_MS);
160462306a36Sopenharmony_ci}
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_cistatic int iqs7222_read_burst(struct iqs7222_private *iqs7222,
160762306a36Sopenharmony_ci			      u16 reg, void *val, u16 num_val)
160862306a36Sopenharmony_ci{
160962306a36Sopenharmony_ci	u8 reg_buf[sizeof(__be16)];
161062306a36Sopenharmony_ci	int ret, i;
161162306a36Sopenharmony_ci	struct i2c_client *client = iqs7222->client;
161262306a36Sopenharmony_ci	struct i2c_msg msg[] = {
161362306a36Sopenharmony_ci		{
161462306a36Sopenharmony_ci			.addr = client->addr,
161562306a36Sopenharmony_ci			.flags = 0,
161662306a36Sopenharmony_ci			.len = reg > U8_MAX ? sizeof(reg) : sizeof(u8),
161762306a36Sopenharmony_ci			.buf = reg_buf,
161862306a36Sopenharmony_ci		},
161962306a36Sopenharmony_ci		{
162062306a36Sopenharmony_ci			.addr = client->addr,
162162306a36Sopenharmony_ci			.flags = I2C_M_RD,
162262306a36Sopenharmony_ci			.len = num_val * sizeof(__le16),
162362306a36Sopenharmony_ci			.buf = (u8 *)val,
162462306a36Sopenharmony_ci		},
162562306a36Sopenharmony_ci	};
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	if (reg > U8_MAX)
162862306a36Sopenharmony_ci		put_unaligned_be16(reg, reg_buf);
162962306a36Sopenharmony_ci	else
163062306a36Sopenharmony_ci		*reg_buf = (u8)reg;
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	/*
163362306a36Sopenharmony_ci	 * The following loop protects against an edge case in which the RDY
163462306a36Sopenharmony_ci	 * pin is automatically deasserted just as the read is initiated. In
163562306a36Sopenharmony_ci	 * that case, the read must be retried using forced communication.
163662306a36Sopenharmony_ci	 */
163762306a36Sopenharmony_ci	for (i = 0; i < IQS7222_NUM_RETRIES; i++) {
163862306a36Sopenharmony_ci		ret = iqs7222_force_comms(iqs7222);
163962306a36Sopenharmony_ci		if (ret < 0)
164062306a36Sopenharmony_ci			continue;
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci		ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
164362306a36Sopenharmony_ci		if (ret < (int)ARRAY_SIZE(msg)) {
164462306a36Sopenharmony_ci			if (ret >= 0)
164562306a36Sopenharmony_ci				ret = -EIO;
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci			msleep(IQS7222_COMMS_RETRY_MS);
164862306a36Sopenharmony_ci			continue;
164962306a36Sopenharmony_ci		}
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci		if (get_unaligned_le16(msg[1].buf) == IQS7222_COMMS_ERROR) {
165262306a36Sopenharmony_ci			ret = -ENODATA;
165362306a36Sopenharmony_ci			continue;
165462306a36Sopenharmony_ci		}
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci		ret = 0;
165762306a36Sopenharmony_ci		break;
165862306a36Sopenharmony_ci	}
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci	/*
166162306a36Sopenharmony_ci	 * The following delay ensures the device has deasserted the RDY pin
166262306a36Sopenharmony_ci	 * following the I2C stop condition.
166362306a36Sopenharmony_ci	 */
166462306a36Sopenharmony_ci	usleep_range(50, 100);
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	if (ret < 0)
166762306a36Sopenharmony_ci		dev_err(&client->dev,
166862306a36Sopenharmony_ci			"Failed to read from address 0x%04X: %d\n", reg, ret);
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	return ret;
167162306a36Sopenharmony_ci}
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_cistatic int iqs7222_read_word(struct iqs7222_private *iqs7222, u16 reg, u16 *val)
167462306a36Sopenharmony_ci{
167562306a36Sopenharmony_ci	__le16 val_buf;
167662306a36Sopenharmony_ci	int error;
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	error = iqs7222_read_burst(iqs7222, reg, &val_buf, 1);
167962306a36Sopenharmony_ci	if (error)
168062306a36Sopenharmony_ci		return error;
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	*val = le16_to_cpu(val_buf);
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	return 0;
168562306a36Sopenharmony_ci}
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_cistatic int iqs7222_write_burst(struct iqs7222_private *iqs7222,
168862306a36Sopenharmony_ci			       u16 reg, const void *val, u16 num_val)
168962306a36Sopenharmony_ci{
169062306a36Sopenharmony_ci	int reg_len = reg > U8_MAX ? sizeof(reg) : sizeof(u8);
169162306a36Sopenharmony_ci	int val_len = num_val * sizeof(__le16);
169262306a36Sopenharmony_ci	int msg_len = reg_len + val_len;
169362306a36Sopenharmony_ci	int ret, i;
169462306a36Sopenharmony_ci	struct i2c_client *client = iqs7222->client;
169562306a36Sopenharmony_ci	u8 *msg_buf;
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci	msg_buf = kzalloc(msg_len, GFP_KERNEL);
169862306a36Sopenharmony_ci	if (!msg_buf)
169962306a36Sopenharmony_ci		return -ENOMEM;
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	if (reg > U8_MAX)
170262306a36Sopenharmony_ci		put_unaligned_be16(reg, msg_buf);
170362306a36Sopenharmony_ci	else
170462306a36Sopenharmony_ci		*msg_buf = (u8)reg;
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	memcpy(msg_buf + reg_len, val, val_len);
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	/*
170962306a36Sopenharmony_ci	 * The following loop protects against an edge case in which the RDY
171062306a36Sopenharmony_ci	 * pin is automatically asserted just before the force communication
171162306a36Sopenharmony_ci	 * command is sent.
171262306a36Sopenharmony_ci	 *
171362306a36Sopenharmony_ci	 * In that case, the subsequent I2C stop condition tricks the device
171462306a36Sopenharmony_ci	 * into preemptively deasserting the RDY pin and the command must be
171562306a36Sopenharmony_ci	 * sent again.
171662306a36Sopenharmony_ci	 */
171762306a36Sopenharmony_ci	for (i = 0; i < IQS7222_NUM_RETRIES; i++) {
171862306a36Sopenharmony_ci		ret = iqs7222_force_comms(iqs7222);
171962306a36Sopenharmony_ci		if (ret < 0)
172062306a36Sopenharmony_ci			continue;
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci		ret = i2c_master_send(client, msg_buf, msg_len);
172362306a36Sopenharmony_ci		if (ret < msg_len) {
172462306a36Sopenharmony_ci			if (ret >= 0)
172562306a36Sopenharmony_ci				ret = -EIO;
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci			msleep(IQS7222_COMMS_RETRY_MS);
172862306a36Sopenharmony_ci			continue;
172962306a36Sopenharmony_ci		}
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci		ret = 0;
173262306a36Sopenharmony_ci		break;
173362306a36Sopenharmony_ci	}
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci	kfree(msg_buf);
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci	usleep_range(50, 100);
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	if (ret < 0)
174062306a36Sopenharmony_ci		dev_err(&client->dev,
174162306a36Sopenharmony_ci			"Failed to write to address 0x%04X: %d\n", reg, ret);
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	return ret;
174462306a36Sopenharmony_ci}
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_cistatic int iqs7222_write_word(struct iqs7222_private *iqs7222, u16 reg, u16 val)
174762306a36Sopenharmony_ci{
174862306a36Sopenharmony_ci	__le16 val_buf = cpu_to_le16(val);
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	return iqs7222_write_burst(iqs7222, reg, &val_buf, 1);
175162306a36Sopenharmony_ci}
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_cistatic int iqs7222_ati_trigger(struct iqs7222_private *iqs7222)
175462306a36Sopenharmony_ci{
175562306a36Sopenharmony_ci	struct i2c_client *client = iqs7222->client;
175662306a36Sopenharmony_ci	ktime_t ati_timeout;
175762306a36Sopenharmony_ci	u16 sys_status = 0;
175862306a36Sopenharmony_ci	u16 sys_setup;
175962306a36Sopenharmony_ci	int error, i;
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	/*
176262306a36Sopenharmony_ci	 * The reserved fields of the system setup register may have changed
176362306a36Sopenharmony_ci	 * as a result of other registers having been written. As such, read
176462306a36Sopenharmony_ci	 * the register's latest value to avoid unexpected behavior when the
176562306a36Sopenharmony_ci	 * register is written in the loop that follows.
176662306a36Sopenharmony_ci	 */
176762306a36Sopenharmony_ci	error = iqs7222_read_word(iqs7222, IQS7222_SYS_SETUP, &sys_setup);
176862306a36Sopenharmony_ci	if (error)
176962306a36Sopenharmony_ci		return error;
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	for (i = 0; i < IQS7222_NUM_RETRIES; i++) {
177262306a36Sopenharmony_ci		/*
177362306a36Sopenharmony_ci		 * Trigger ATI from streaming and normal-power modes so that
177462306a36Sopenharmony_ci		 * the RDY pin continues to be asserted during ATI.
177562306a36Sopenharmony_ci		 */
177662306a36Sopenharmony_ci		error = iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP,
177762306a36Sopenharmony_ci					   sys_setup |
177862306a36Sopenharmony_ci					   IQS7222_SYS_SETUP_REDO_ATI);
177962306a36Sopenharmony_ci		if (error)
178062306a36Sopenharmony_ci			return error;
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci		ati_timeout = ktime_add_ms(ktime_get(), IQS7222_ATI_TIMEOUT_MS);
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci		do {
178562306a36Sopenharmony_ci			error = iqs7222_irq_poll(iqs7222,
178662306a36Sopenharmony_ci						 IQS7222_COMMS_TIMEOUT_MS);
178762306a36Sopenharmony_ci			if (error)
178862306a36Sopenharmony_ci				continue;
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci			error = iqs7222_read_word(iqs7222, IQS7222_SYS_STATUS,
179162306a36Sopenharmony_ci						  &sys_status);
179262306a36Sopenharmony_ci			if (error)
179362306a36Sopenharmony_ci				return error;
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci			if (sys_status & IQS7222_SYS_STATUS_RESET)
179662306a36Sopenharmony_ci				return 0;
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci			if (sys_status & IQS7222_SYS_STATUS_ATI_ERROR)
179962306a36Sopenharmony_ci				break;
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci			if (sys_status & IQS7222_SYS_STATUS_ATI_ACTIVE)
180262306a36Sopenharmony_ci				continue;
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci			/*
180562306a36Sopenharmony_ci			 * Use stream-in-touch mode if either slider reports
180662306a36Sopenharmony_ci			 * absolute position.
180762306a36Sopenharmony_ci			 */
180862306a36Sopenharmony_ci			sys_setup |= test_bit(EV_ABS, iqs7222->keypad->evbit)
180962306a36Sopenharmony_ci				   ? IQS7222_SYS_SETUP_INTF_MODE_TOUCH
181062306a36Sopenharmony_ci				   : IQS7222_SYS_SETUP_INTF_MODE_EVENT;
181162306a36Sopenharmony_ci			sys_setup |= IQS7222_SYS_SETUP_PWR_MODE_AUTO;
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci			return iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP,
181462306a36Sopenharmony_ci						  sys_setup);
181562306a36Sopenharmony_ci		} while (ktime_compare(ktime_get(), ati_timeout) < 0);
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci		dev_err(&client->dev,
181862306a36Sopenharmony_ci			"ATI attempt %d of %d failed with status 0x%02X, %s\n",
181962306a36Sopenharmony_ci			i + 1, IQS7222_NUM_RETRIES, (u8)sys_status,
182062306a36Sopenharmony_ci			i + 1 < IQS7222_NUM_RETRIES ? "retrying" : "stopping");
182162306a36Sopenharmony_ci	}
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	return -ETIMEDOUT;
182462306a36Sopenharmony_ci}
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_cistatic int iqs7222_dev_init(struct iqs7222_private *iqs7222, int dir)
182762306a36Sopenharmony_ci{
182862306a36Sopenharmony_ci	const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
182962306a36Sopenharmony_ci	int comms_offset = dev_desc->comms_offset;
183062306a36Sopenharmony_ci	int error, i, j, k;
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	/*
183362306a36Sopenharmony_ci	 * Acknowledge reset before writing any registers in case the device
183462306a36Sopenharmony_ci	 * suffers a spurious reset during initialization. Because this step
183562306a36Sopenharmony_ci	 * may change the reserved fields of the second filter beta register,
183662306a36Sopenharmony_ci	 * its cache must be updated.
183762306a36Sopenharmony_ci	 *
183862306a36Sopenharmony_ci	 * Writing the second filter beta register, in turn, may clobber the
183962306a36Sopenharmony_ci	 * system status register. As such, the filter beta register pair is
184062306a36Sopenharmony_ci	 * written first to protect against this hazard.
184162306a36Sopenharmony_ci	 */
184262306a36Sopenharmony_ci	if (dir == WRITE) {
184362306a36Sopenharmony_ci		u16 reg = dev_desc->reg_grps[IQS7222_REG_GRP_FILT].base + 1;
184462306a36Sopenharmony_ci		u16 filt_setup;
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci		error = iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP,
184762306a36Sopenharmony_ci					   iqs7222->sys_setup[0] |
184862306a36Sopenharmony_ci					   IQS7222_SYS_SETUP_ACK_RESET);
184962306a36Sopenharmony_ci		if (error)
185062306a36Sopenharmony_ci			return error;
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci		error = iqs7222_read_word(iqs7222, reg, &filt_setup);
185362306a36Sopenharmony_ci		if (error)
185462306a36Sopenharmony_ci			return error;
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci		iqs7222->filt_setup[1] &= GENMASK(7, 0);
185762306a36Sopenharmony_ci		iqs7222->filt_setup[1] |= (filt_setup & ~GENMASK(7, 0));
185862306a36Sopenharmony_ci	}
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci	/*
186162306a36Sopenharmony_ci	 * Take advantage of the stop-bit disable function, if available, to
186262306a36Sopenharmony_ci	 * save the trouble of having to reopen a communication window after
186362306a36Sopenharmony_ci	 * each burst read or write.
186462306a36Sopenharmony_ci	 */
186562306a36Sopenharmony_ci	if (comms_offset) {
186662306a36Sopenharmony_ci		u16 comms_setup;
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci		error = iqs7222_read_word(iqs7222,
186962306a36Sopenharmony_ci					  IQS7222_SYS_SETUP + comms_offset,
187062306a36Sopenharmony_ci					  &comms_setup);
187162306a36Sopenharmony_ci		if (error)
187262306a36Sopenharmony_ci			return error;
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci		error = iqs7222_write_word(iqs7222,
187562306a36Sopenharmony_ci					   IQS7222_SYS_SETUP + comms_offset,
187662306a36Sopenharmony_ci					   comms_setup | IQS7222_COMMS_HOLD);
187762306a36Sopenharmony_ci		if (error)
187862306a36Sopenharmony_ci			return error;
187962306a36Sopenharmony_ci	}
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	for (i = 0; i < IQS7222_NUM_REG_GRPS; i++) {
188262306a36Sopenharmony_ci		int num_row = dev_desc->reg_grps[i].num_row;
188362306a36Sopenharmony_ci		int num_col = dev_desc->reg_grps[i].num_col;
188462306a36Sopenharmony_ci		u16 reg = dev_desc->reg_grps[i].base;
188562306a36Sopenharmony_ci		__le16 *val_buf;
188662306a36Sopenharmony_ci		u16 *val;
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci		if (!num_col)
188962306a36Sopenharmony_ci			continue;
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci		val = iqs7222_setup(iqs7222, i, 0);
189262306a36Sopenharmony_ci		if (!val)
189362306a36Sopenharmony_ci			continue;
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci		val_buf = kcalloc(num_col, sizeof(__le16), GFP_KERNEL);
189662306a36Sopenharmony_ci		if (!val_buf)
189762306a36Sopenharmony_ci			return -ENOMEM;
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci		for (j = 0; j < num_row; j++) {
190062306a36Sopenharmony_ci			switch (dir) {
190162306a36Sopenharmony_ci			case READ:
190262306a36Sopenharmony_ci				error = iqs7222_read_burst(iqs7222, reg,
190362306a36Sopenharmony_ci							   val_buf, num_col);
190462306a36Sopenharmony_ci				for (k = 0; k < num_col; k++)
190562306a36Sopenharmony_ci					val[k] = le16_to_cpu(val_buf[k]);
190662306a36Sopenharmony_ci				break;
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci			case WRITE:
190962306a36Sopenharmony_ci				for (k = 0; k < num_col; k++)
191062306a36Sopenharmony_ci					val_buf[k] = cpu_to_le16(val[k]);
191162306a36Sopenharmony_ci				error = iqs7222_write_burst(iqs7222, reg,
191262306a36Sopenharmony_ci							    val_buf, num_col);
191362306a36Sopenharmony_ci				break;
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci			default:
191662306a36Sopenharmony_ci				error = -EINVAL;
191762306a36Sopenharmony_ci			}
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci			if (error)
192062306a36Sopenharmony_ci				break;
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci			reg += IQS7222_REG_OFFSET;
192362306a36Sopenharmony_ci			val += iqs7222_max_cols[i];
192462306a36Sopenharmony_ci		}
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci		kfree(val_buf);
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ci		if (error)
192962306a36Sopenharmony_ci			return error;
193062306a36Sopenharmony_ci	}
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	if (comms_offset) {
193362306a36Sopenharmony_ci		u16 comms_setup;
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci		error = iqs7222_read_word(iqs7222,
193662306a36Sopenharmony_ci					  IQS7222_SYS_SETUP + comms_offset,
193762306a36Sopenharmony_ci					  &comms_setup);
193862306a36Sopenharmony_ci		if (error)
193962306a36Sopenharmony_ci			return error;
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci		error = iqs7222_write_word(iqs7222,
194262306a36Sopenharmony_ci					   IQS7222_SYS_SETUP + comms_offset,
194362306a36Sopenharmony_ci					   comms_setup & ~IQS7222_COMMS_HOLD);
194462306a36Sopenharmony_ci		if (error)
194562306a36Sopenharmony_ci			return error;
194662306a36Sopenharmony_ci	}
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci	if (dir == READ) {
194962306a36Sopenharmony_ci		iqs7222->sys_setup[0] &= ~IQS7222_SYS_SETUP_INTF_MODE_MASK;
195062306a36Sopenharmony_ci		iqs7222->sys_setup[0] &= ~IQS7222_SYS_SETUP_PWR_MODE_MASK;
195162306a36Sopenharmony_ci		return 0;
195262306a36Sopenharmony_ci	}
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci	return iqs7222_ati_trigger(iqs7222);
195562306a36Sopenharmony_ci}
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_cistatic int iqs7222_dev_info(struct iqs7222_private *iqs7222)
195862306a36Sopenharmony_ci{
195962306a36Sopenharmony_ci	struct i2c_client *client = iqs7222->client;
196062306a36Sopenharmony_ci	bool prod_num_valid = false;
196162306a36Sopenharmony_ci	__le16 dev_id[3];
196262306a36Sopenharmony_ci	int error, i;
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	error = iqs7222_read_burst(iqs7222, IQS7222_PROD_NUM, dev_id,
196562306a36Sopenharmony_ci				   ARRAY_SIZE(dev_id));
196662306a36Sopenharmony_ci	if (error)
196762306a36Sopenharmony_ci		return error;
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(iqs7222_devs); i++) {
197062306a36Sopenharmony_ci		if (le16_to_cpu(dev_id[0]) != iqs7222_devs[i].prod_num)
197162306a36Sopenharmony_ci			continue;
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci		prod_num_valid = true;
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci		if (le16_to_cpu(dev_id[1]) < iqs7222_devs[i].fw_major)
197662306a36Sopenharmony_ci			continue;
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci		if (le16_to_cpu(dev_id[2]) < iqs7222_devs[i].fw_minor)
197962306a36Sopenharmony_ci			continue;
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci		iqs7222->dev_desc = &iqs7222_devs[i];
198262306a36Sopenharmony_ci		return 0;
198362306a36Sopenharmony_ci	}
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	if (prod_num_valid)
198662306a36Sopenharmony_ci		dev_err(&client->dev, "Unsupported firmware revision: %u.%u\n",
198762306a36Sopenharmony_ci			le16_to_cpu(dev_id[1]), le16_to_cpu(dev_id[2]));
198862306a36Sopenharmony_ci	else
198962306a36Sopenharmony_ci		dev_err(&client->dev, "Unrecognized product number: %u\n",
199062306a36Sopenharmony_ci			le16_to_cpu(dev_id[0]));
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	return -EINVAL;
199362306a36Sopenharmony_ci}
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_cistatic int iqs7222_gpio_select(struct iqs7222_private *iqs7222,
199662306a36Sopenharmony_ci			       struct fwnode_handle *child_node,
199762306a36Sopenharmony_ci			       int child_enable, u16 child_link)
199862306a36Sopenharmony_ci{
199962306a36Sopenharmony_ci	const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
200062306a36Sopenharmony_ci	struct i2c_client *client = iqs7222->client;
200162306a36Sopenharmony_ci	int num_gpio = dev_desc->reg_grps[IQS7222_REG_GRP_GPIO].num_row;
200262306a36Sopenharmony_ci	int error, count, i;
200362306a36Sopenharmony_ci	unsigned int gpio_sel[ARRAY_SIZE(iqs7222_gpio_links)];
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci	if (!num_gpio)
200662306a36Sopenharmony_ci		return 0;
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ci	if (!fwnode_property_present(child_node, "azoteq,gpio-select"))
200962306a36Sopenharmony_ci		return 0;
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci	count = fwnode_property_count_u32(child_node, "azoteq,gpio-select");
201262306a36Sopenharmony_ci	if (count > num_gpio) {
201362306a36Sopenharmony_ci		dev_err(&client->dev, "Invalid number of %s GPIOs\n",
201462306a36Sopenharmony_ci			fwnode_get_name(child_node));
201562306a36Sopenharmony_ci		return -EINVAL;
201662306a36Sopenharmony_ci	} else if (count < 0) {
201762306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to count %s GPIOs: %d\n",
201862306a36Sopenharmony_ci			fwnode_get_name(child_node), count);
201962306a36Sopenharmony_ci		return count;
202062306a36Sopenharmony_ci	}
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_ci	error = fwnode_property_read_u32_array(child_node,
202362306a36Sopenharmony_ci					       "azoteq,gpio-select",
202462306a36Sopenharmony_ci					       gpio_sel, count);
202562306a36Sopenharmony_ci	if (error) {
202662306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to read %s GPIOs: %d\n",
202762306a36Sopenharmony_ci			fwnode_get_name(child_node), error);
202862306a36Sopenharmony_ci		return error;
202962306a36Sopenharmony_ci	}
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
203262306a36Sopenharmony_ci		u16 *gpio_setup;
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci		if (gpio_sel[i] >= num_gpio) {
203562306a36Sopenharmony_ci			dev_err(&client->dev, "Invalid %s GPIO: %u\n",
203662306a36Sopenharmony_ci				fwnode_get_name(child_node), gpio_sel[i]);
203762306a36Sopenharmony_ci			return -EINVAL;
203862306a36Sopenharmony_ci		}
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci		gpio_setup = iqs7222->gpio_setup[gpio_sel[i]];
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci		if (gpio_setup[2] && child_link != gpio_setup[2]) {
204362306a36Sopenharmony_ci			dev_err(&client->dev,
204462306a36Sopenharmony_ci				"Conflicting GPIO %u event types\n",
204562306a36Sopenharmony_ci				gpio_sel[i]);
204662306a36Sopenharmony_ci			return -EINVAL;
204762306a36Sopenharmony_ci		}
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci		gpio_setup[0] |= IQS7222_GPIO_SETUP_0_GPIO_EN;
205062306a36Sopenharmony_ci		gpio_setup[1] |= child_enable;
205162306a36Sopenharmony_ci		gpio_setup[2] = child_link;
205262306a36Sopenharmony_ci	}
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ci	return 0;
205562306a36Sopenharmony_ci}
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_cistatic int iqs7222_parse_props(struct iqs7222_private *iqs7222,
205862306a36Sopenharmony_ci			       struct fwnode_handle *reg_grp_node,
205962306a36Sopenharmony_ci			       int reg_grp_index,
206062306a36Sopenharmony_ci			       enum iqs7222_reg_grp_id reg_grp,
206162306a36Sopenharmony_ci			       enum iqs7222_reg_key_id reg_key)
206262306a36Sopenharmony_ci{
206362306a36Sopenharmony_ci	u16 *setup = iqs7222_setup(iqs7222, reg_grp, reg_grp_index);
206462306a36Sopenharmony_ci	struct i2c_client *client = iqs7222->client;
206562306a36Sopenharmony_ci	int i;
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci	if (!setup)
206862306a36Sopenharmony_ci		return 0;
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(iqs7222_props); i++) {
207162306a36Sopenharmony_ci		const char *name = iqs7222_props[i].name;
207262306a36Sopenharmony_ci		int reg_offset = iqs7222_props[i].reg_offset;
207362306a36Sopenharmony_ci		int reg_shift = iqs7222_props[i].reg_shift;
207462306a36Sopenharmony_ci		int reg_width = iqs7222_props[i].reg_width;
207562306a36Sopenharmony_ci		int val_pitch = iqs7222_props[i].val_pitch ? : 1;
207662306a36Sopenharmony_ci		int val_min = iqs7222_props[i].val_min;
207762306a36Sopenharmony_ci		int val_max = iqs7222_props[i].val_max;
207862306a36Sopenharmony_ci		bool invert = iqs7222_props[i].invert;
207962306a36Sopenharmony_ci		const char *label = iqs7222_props[i].label ? : name;
208062306a36Sopenharmony_ci		unsigned int val;
208162306a36Sopenharmony_ci		int error;
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci		if (iqs7222_props[i].reg_grp != reg_grp ||
208462306a36Sopenharmony_ci		    iqs7222_props[i].reg_key != reg_key)
208562306a36Sopenharmony_ci			continue;
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci		/*
208862306a36Sopenharmony_ci		 * Boolean register fields are one bit wide; they are forcibly
208962306a36Sopenharmony_ci		 * reset to provide a means to undo changes by a bootloader if
209062306a36Sopenharmony_ci		 * necessary.
209162306a36Sopenharmony_ci		 *
209262306a36Sopenharmony_ci		 * Scalar fields, on the other hand, are left untouched unless
209362306a36Sopenharmony_ci		 * their corresponding properties are present.
209462306a36Sopenharmony_ci		 */
209562306a36Sopenharmony_ci		if (reg_width == 1) {
209662306a36Sopenharmony_ci			if (invert)
209762306a36Sopenharmony_ci				setup[reg_offset] |= BIT(reg_shift);
209862306a36Sopenharmony_ci			else
209962306a36Sopenharmony_ci				setup[reg_offset] &= ~BIT(reg_shift);
210062306a36Sopenharmony_ci		}
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci		if (!fwnode_property_present(reg_grp_node, name))
210362306a36Sopenharmony_ci			continue;
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci		if (reg_width == 1) {
210662306a36Sopenharmony_ci			if (invert)
210762306a36Sopenharmony_ci				setup[reg_offset] &= ~BIT(reg_shift);
210862306a36Sopenharmony_ci			else
210962306a36Sopenharmony_ci				setup[reg_offset] |= BIT(reg_shift);
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci			continue;
211262306a36Sopenharmony_ci		}
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci		error = fwnode_property_read_u32(reg_grp_node, name, &val);
211562306a36Sopenharmony_ci		if (error) {
211662306a36Sopenharmony_ci			dev_err(&client->dev, "Failed to read %s %s: %d\n",
211762306a36Sopenharmony_ci				fwnode_get_name(reg_grp_node), label, error);
211862306a36Sopenharmony_ci			return error;
211962306a36Sopenharmony_ci		}
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci		if (!val_max)
212262306a36Sopenharmony_ci			val_max = GENMASK(reg_width - 1, 0) * val_pitch;
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci		if (val < val_min || val > val_max) {
212562306a36Sopenharmony_ci			dev_err(&client->dev, "Invalid %s %s: %u\n",
212662306a36Sopenharmony_ci				fwnode_get_name(reg_grp_node), label, val);
212762306a36Sopenharmony_ci			return -EINVAL;
212862306a36Sopenharmony_ci		}
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci		setup[reg_offset] &= ~GENMASK(reg_shift + reg_width - 1,
213162306a36Sopenharmony_ci					      reg_shift);
213262306a36Sopenharmony_ci		setup[reg_offset] |= (val / val_pitch << reg_shift);
213362306a36Sopenharmony_ci	}
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci	return 0;
213662306a36Sopenharmony_ci}
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_cistatic int iqs7222_parse_event(struct iqs7222_private *iqs7222,
213962306a36Sopenharmony_ci			       struct fwnode_handle *event_node,
214062306a36Sopenharmony_ci			       int reg_grp_index,
214162306a36Sopenharmony_ci			       enum iqs7222_reg_grp_id reg_grp,
214262306a36Sopenharmony_ci			       enum iqs7222_reg_key_id reg_key,
214362306a36Sopenharmony_ci			       u16 event_enable, u16 event_link,
214462306a36Sopenharmony_ci			       unsigned int *event_type,
214562306a36Sopenharmony_ci			       unsigned int *event_code)
214662306a36Sopenharmony_ci{
214762306a36Sopenharmony_ci	struct i2c_client *client = iqs7222->client;
214862306a36Sopenharmony_ci	int error;
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	error = iqs7222_parse_props(iqs7222, event_node, reg_grp_index,
215162306a36Sopenharmony_ci				    reg_grp, reg_key);
215262306a36Sopenharmony_ci	if (error)
215362306a36Sopenharmony_ci		return error;
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci	error = iqs7222_gpio_select(iqs7222, event_node, event_enable,
215662306a36Sopenharmony_ci				    event_link);
215762306a36Sopenharmony_ci	if (error)
215862306a36Sopenharmony_ci		return error;
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_ci	error = fwnode_property_read_u32(event_node, "linux,code", event_code);
216162306a36Sopenharmony_ci	if (error == -EINVAL) {
216262306a36Sopenharmony_ci		return 0;
216362306a36Sopenharmony_ci	} else if (error) {
216462306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to read %s code: %d\n",
216562306a36Sopenharmony_ci			fwnode_get_name(event_node), error);
216662306a36Sopenharmony_ci		return error;
216762306a36Sopenharmony_ci	}
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci	if (!event_type) {
217062306a36Sopenharmony_ci		input_set_capability(iqs7222->keypad, EV_KEY, *event_code);
217162306a36Sopenharmony_ci		return 0;
217262306a36Sopenharmony_ci	}
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_ci	error = fwnode_property_read_u32(event_node, "linux,input-type",
217562306a36Sopenharmony_ci					 event_type);
217662306a36Sopenharmony_ci	if (error == -EINVAL) {
217762306a36Sopenharmony_ci		*event_type = EV_KEY;
217862306a36Sopenharmony_ci	} else if (error) {
217962306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to read %s input type: %d\n",
218062306a36Sopenharmony_ci			fwnode_get_name(event_node), error);
218162306a36Sopenharmony_ci		return error;
218262306a36Sopenharmony_ci	} else if (*event_type != EV_KEY && *event_type != EV_SW) {
218362306a36Sopenharmony_ci		dev_err(&client->dev, "Invalid %s input type: %d\n",
218462306a36Sopenharmony_ci			fwnode_get_name(event_node), *event_type);
218562306a36Sopenharmony_ci		return -EINVAL;
218662306a36Sopenharmony_ci	}
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci	input_set_capability(iqs7222->keypad, *event_type, *event_code);
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	return 0;
219162306a36Sopenharmony_ci}
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_cistatic int iqs7222_parse_cycle(struct iqs7222_private *iqs7222,
219462306a36Sopenharmony_ci			       struct fwnode_handle *cycle_node, int cycle_index)
219562306a36Sopenharmony_ci{
219662306a36Sopenharmony_ci	u16 *cycle_setup = iqs7222->cycle_setup[cycle_index];
219762306a36Sopenharmony_ci	struct i2c_client *client = iqs7222->client;
219862306a36Sopenharmony_ci	unsigned int pins[9];
219962306a36Sopenharmony_ci	int error, count, i;
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_ci	/*
220262306a36Sopenharmony_ci	 * Each channel shares a cycle with one other channel; the mapping of
220362306a36Sopenharmony_ci	 * channels to cycles is fixed. Properties defined for a cycle impact
220462306a36Sopenharmony_ci	 * both channels tied to the cycle.
220562306a36Sopenharmony_ci	 *
220662306a36Sopenharmony_ci	 * Unlike channels which are restricted to a select range of CRx pins
220762306a36Sopenharmony_ci	 * based on channel number, any cycle can claim any of the device's 9
220862306a36Sopenharmony_ci	 * CTx pins (CTx0-8).
220962306a36Sopenharmony_ci	 */
221062306a36Sopenharmony_ci	if (!fwnode_property_present(cycle_node, "azoteq,tx-enable"))
221162306a36Sopenharmony_ci		return 0;
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci	count = fwnode_property_count_u32(cycle_node, "azoteq,tx-enable");
221462306a36Sopenharmony_ci	if (count < 0) {
221562306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to count %s CTx pins: %d\n",
221662306a36Sopenharmony_ci			fwnode_get_name(cycle_node), count);
221762306a36Sopenharmony_ci		return count;
221862306a36Sopenharmony_ci	} else if (count > ARRAY_SIZE(pins)) {
221962306a36Sopenharmony_ci		dev_err(&client->dev, "Invalid number of %s CTx pins\n",
222062306a36Sopenharmony_ci			fwnode_get_name(cycle_node));
222162306a36Sopenharmony_ci		return -EINVAL;
222262306a36Sopenharmony_ci	}
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_ci	error = fwnode_property_read_u32_array(cycle_node, "azoteq,tx-enable",
222562306a36Sopenharmony_ci					       pins, count);
222662306a36Sopenharmony_ci	if (error) {
222762306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to read %s CTx pins: %d\n",
222862306a36Sopenharmony_ci			fwnode_get_name(cycle_node), error);
222962306a36Sopenharmony_ci		return error;
223062306a36Sopenharmony_ci	}
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_ci	cycle_setup[1] &= ~GENMASK(7 + ARRAY_SIZE(pins) - 1, 7);
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
223562306a36Sopenharmony_ci		if (pins[i] > 8) {
223662306a36Sopenharmony_ci			dev_err(&client->dev, "Invalid %s CTx pin: %u\n",
223762306a36Sopenharmony_ci				fwnode_get_name(cycle_node), pins[i]);
223862306a36Sopenharmony_ci			return -EINVAL;
223962306a36Sopenharmony_ci		}
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_ci		cycle_setup[1] |= BIT(pins[i] + 7);
224262306a36Sopenharmony_ci	}
224362306a36Sopenharmony_ci
224462306a36Sopenharmony_ci	return 0;
224562306a36Sopenharmony_ci}
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_cistatic int iqs7222_parse_chan(struct iqs7222_private *iqs7222,
224862306a36Sopenharmony_ci			      struct fwnode_handle *chan_node, int chan_index)
224962306a36Sopenharmony_ci{
225062306a36Sopenharmony_ci	const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
225162306a36Sopenharmony_ci	struct i2c_client *client = iqs7222->client;
225262306a36Sopenharmony_ci	int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
225362306a36Sopenharmony_ci	int ext_chan = rounddown(num_chan, 10);
225462306a36Sopenharmony_ci	int error, i;
225562306a36Sopenharmony_ci	u16 *chan_setup = iqs7222->chan_setup[chan_index];
225662306a36Sopenharmony_ci	u16 *sys_setup = iqs7222->sys_setup;
225762306a36Sopenharmony_ci	unsigned int val;
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci	if (dev_desc->allow_offset &&
226062306a36Sopenharmony_ci	    fwnode_property_present(chan_node, "azoteq,ulp-allow"))
226162306a36Sopenharmony_ci		sys_setup[dev_desc->allow_offset] &= ~BIT(chan_index);
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci	chan_setup[0] |= IQS7222_CHAN_SETUP_0_CHAN_EN;
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci	/*
226662306a36Sopenharmony_ci	 * The reference channel function allows for differential measurements
226762306a36Sopenharmony_ci	 * and is only available in the case of IQS7222A or IQS7222C.
226862306a36Sopenharmony_ci	 */
226962306a36Sopenharmony_ci	if (dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_col > 4 &&
227062306a36Sopenharmony_ci	    fwnode_property_present(chan_node, "azoteq,ref-select")) {
227162306a36Sopenharmony_ci		u16 *ref_setup;
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci		error = fwnode_property_read_u32(chan_node, "azoteq,ref-select",
227462306a36Sopenharmony_ci						 &val);
227562306a36Sopenharmony_ci		if (error) {
227662306a36Sopenharmony_ci			dev_err(&client->dev,
227762306a36Sopenharmony_ci				"Failed to read %s reference channel: %d\n",
227862306a36Sopenharmony_ci				fwnode_get_name(chan_node), error);
227962306a36Sopenharmony_ci			return error;
228062306a36Sopenharmony_ci		}
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci		if (val >= ext_chan) {
228362306a36Sopenharmony_ci			dev_err(&client->dev,
228462306a36Sopenharmony_ci				"Invalid %s reference channel: %u\n",
228562306a36Sopenharmony_ci				fwnode_get_name(chan_node), val);
228662306a36Sopenharmony_ci			return -EINVAL;
228762306a36Sopenharmony_ci		}
228862306a36Sopenharmony_ci
228962306a36Sopenharmony_ci		ref_setup = iqs7222->chan_setup[val];
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci		/*
229262306a36Sopenharmony_ci		 * Configure the current channel as a follower of the selected
229362306a36Sopenharmony_ci		 * reference channel.
229462306a36Sopenharmony_ci		 */
229562306a36Sopenharmony_ci		chan_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_FOLLOW;
229662306a36Sopenharmony_ci		chan_setup[4] = val * 42 + 1048;
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci		error = fwnode_property_read_u32(chan_node, "azoteq,ref-weight",
229962306a36Sopenharmony_ci						 &val);
230062306a36Sopenharmony_ci		if (!error) {
230162306a36Sopenharmony_ci			if (val > U16_MAX) {
230262306a36Sopenharmony_ci				dev_err(&client->dev,
230362306a36Sopenharmony_ci					"Invalid %s reference weight: %u\n",
230462306a36Sopenharmony_ci					fwnode_get_name(chan_node), val);
230562306a36Sopenharmony_ci				return -EINVAL;
230662306a36Sopenharmony_ci			}
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_ci			chan_setup[5] = val;
230962306a36Sopenharmony_ci		} else if (error != -EINVAL) {
231062306a36Sopenharmony_ci			dev_err(&client->dev,
231162306a36Sopenharmony_ci				"Failed to read %s reference weight: %d\n",
231262306a36Sopenharmony_ci				fwnode_get_name(chan_node), error);
231362306a36Sopenharmony_ci			return error;
231462306a36Sopenharmony_ci		}
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci		/*
231762306a36Sopenharmony_ci		 * Configure the selected channel as a reference channel which
231862306a36Sopenharmony_ci		 * serves the current channel.
231962306a36Sopenharmony_ci		 */
232062306a36Sopenharmony_ci		ref_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_REF;
232162306a36Sopenharmony_ci		ref_setup[5] |= BIT(chan_index);
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_ci		ref_setup[4] = dev_desc->touch_link;
232462306a36Sopenharmony_ci		if (fwnode_property_present(chan_node, "azoteq,use-prox"))
232562306a36Sopenharmony_ci			ref_setup[4] -= 2;
232662306a36Sopenharmony_ci	} else if (dev_desc->reg_grps[IQS7222_REG_GRP_TPAD].num_row &&
232762306a36Sopenharmony_ci		   fwnode_property_present(chan_node,
232862306a36Sopenharmony_ci					   "azoteq,counts-filt-enable")) {
232962306a36Sopenharmony_ci		/*
233062306a36Sopenharmony_ci		 * In the case of IQS7222D, however, the reference mode field
233162306a36Sopenharmony_ci		 * is partially repurposed as a counts filter enable control.
233262306a36Sopenharmony_ci		 */
233362306a36Sopenharmony_ci		chan_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_REF;
233462306a36Sopenharmony_ci	}
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_ci	if (fwnode_property_present(chan_node, "azoteq,rx-enable")) {
233762306a36Sopenharmony_ci		/*
233862306a36Sopenharmony_ci		 * Each channel can claim up to 4 CRx pins. The first half of
233962306a36Sopenharmony_ci		 * the channels can use CRx0-3, while the second half can use
234062306a36Sopenharmony_ci		 * CRx4-7.
234162306a36Sopenharmony_ci		 */
234262306a36Sopenharmony_ci		unsigned int pins[4];
234362306a36Sopenharmony_ci		int count;
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ci		count = fwnode_property_count_u32(chan_node,
234662306a36Sopenharmony_ci						  "azoteq,rx-enable");
234762306a36Sopenharmony_ci		if (count < 0) {
234862306a36Sopenharmony_ci			dev_err(&client->dev,
234962306a36Sopenharmony_ci				"Failed to count %s CRx pins: %d\n",
235062306a36Sopenharmony_ci				fwnode_get_name(chan_node), count);
235162306a36Sopenharmony_ci			return count;
235262306a36Sopenharmony_ci		} else if (count > ARRAY_SIZE(pins)) {
235362306a36Sopenharmony_ci			dev_err(&client->dev,
235462306a36Sopenharmony_ci				"Invalid number of %s CRx pins\n",
235562306a36Sopenharmony_ci				fwnode_get_name(chan_node));
235662306a36Sopenharmony_ci			return -EINVAL;
235762306a36Sopenharmony_ci		}
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci		error = fwnode_property_read_u32_array(chan_node,
236062306a36Sopenharmony_ci						       "azoteq,rx-enable",
236162306a36Sopenharmony_ci						       pins, count);
236262306a36Sopenharmony_ci		if (error) {
236362306a36Sopenharmony_ci			dev_err(&client->dev,
236462306a36Sopenharmony_ci				"Failed to read %s CRx pins: %d\n",
236562306a36Sopenharmony_ci				fwnode_get_name(chan_node), error);
236662306a36Sopenharmony_ci			return error;
236762306a36Sopenharmony_ci		}
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci		chan_setup[0] &= ~GENMASK(4 + ARRAY_SIZE(pins) - 1, 4);
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci		for (i = 0; i < count; i++) {
237262306a36Sopenharmony_ci			int min_crx = chan_index < ext_chan / 2 ? 0 : 4;
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci			if (pins[i] < min_crx || pins[i] > min_crx + 3) {
237562306a36Sopenharmony_ci				dev_err(&client->dev,
237662306a36Sopenharmony_ci					"Invalid %s CRx pin: %u\n",
237762306a36Sopenharmony_ci					fwnode_get_name(chan_node), pins[i]);
237862306a36Sopenharmony_ci				return -EINVAL;
237962306a36Sopenharmony_ci			}
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci			chan_setup[0] |= BIT(pins[i] + 4 - min_crx);
238262306a36Sopenharmony_ci		}
238362306a36Sopenharmony_ci	}
238462306a36Sopenharmony_ci
238562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(iqs7222_kp_events); i++) {
238662306a36Sopenharmony_ci		const char *event_name = iqs7222_kp_events[i].name;
238762306a36Sopenharmony_ci		u16 event_enable = iqs7222_kp_events[i].enable;
238862306a36Sopenharmony_ci		struct fwnode_handle *event_node;
238962306a36Sopenharmony_ci
239062306a36Sopenharmony_ci		event_node = fwnode_get_named_child_node(chan_node, event_name);
239162306a36Sopenharmony_ci		if (!event_node)
239262306a36Sopenharmony_ci			continue;
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_ci		error = fwnode_property_read_u32(event_node,
239562306a36Sopenharmony_ci						 "azoteq,timeout-press-ms",
239662306a36Sopenharmony_ci						 &val);
239762306a36Sopenharmony_ci		if (!error) {
239862306a36Sopenharmony_ci			/*
239962306a36Sopenharmony_ci			 * The IQS7222B employs a global pair of press timeout
240062306a36Sopenharmony_ci			 * registers as opposed to channel-specific registers.
240162306a36Sopenharmony_ci			 */
240262306a36Sopenharmony_ci			u16 *setup = dev_desc->reg_grps
240362306a36Sopenharmony_ci				     [IQS7222_REG_GRP_BTN].num_col > 2 ?
240462306a36Sopenharmony_ci				     &iqs7222->btn_setup[chan_index][2] :
240562306a36Sopenharmony_ci				     &sys_setup[9];
240662306a36Sopenharmony_ci
240762306a36Sopenharmony_ci			if (val > U8_MAX * 500) {
240862306a36Sopenharmony_ci				dev_err(&client->dev,
240962306a36Sopenharmony_ci					"Invalid %s press timeout: %u\n",
241062306a36Sopenharmony_ci					fwnode_get_name(event_node), val);
241162306a36Sopenharmony_ci				fwnode_handle_put(event_node);
241262306a36Sopenharmony_ci				return -EINVAL;
241362306a36Sopenharmony_ci			}
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci			*setup &= ~(U8_MAX << i * 8);
241662306a36Sopenharmony_ci			*setup |= (val / 500 << i * 8);
241762306a36Sopenharmony_ci		} else if (error != -EINVAL) {
241862306a36Sopenharmony_ci			dev_err(&client->dev,
241962306a36Sopenharmony_ci				"Failed to read %s press timeout: %d\n",
242062306a36Sopenharmony_ci				fwnode_get_name(event_node), error);
242162306a36Sopenharmony_ci			fwnode_handle_put(event_node);
242262306a36Sopenharmony_ci			return error;
242362306a36Sopenharmony_ci		}
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_ci		error = iqs7222_parse_event(iqs7222, event_node, chan_index,
242662306a36Sopenharmony_ci					    IQS7222_REG_GRP_BTN,
242762306a36Sopenharmony_ci					    iqs7222_kp_events[i].reg_key,
242862306a36Sopenharmony_ci					    BIT(chan_index),
242962306a36Sopenharmony_ci					    dev_desc->touch_link - (i ? 0 : 2),
243062306a36Sopenharmony_ci					    &iqs7222->kp_type[chan_index][i],
243162306a36Sopenharmony_ci					    &iqs7222->kp_code[chan_index][i]);
243262306a36Sopenharmony_ci		fwnode_handle_put(event_node);
243362306a36Sopenharmony_ci		if (error)
243462306a36Sopenharmony_ci			return error;
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci		if (!dev_desc->event_offset)
243762306a36Sopenharmony_ci			continue;
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_ci		sys_setup[dev_desc->event_offset] |= event_enable;
244062306a36Sopenharmony_ci	}
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci	/*
244362306a36Sopenharmony_ci	 * The following call handles a special pair of properties that apply
244462306a36Sopenharmony_ci	 * to a channel node, but reside within the button (event) group.
244562306a36Sopenharmony_ci	 */
244662306a36Sopenharmony_ci	return iqs7222_parse_props(iqs7222, chan_node, chan_index,
244762306a36Sopenharmony_ci				   IQS7222_REG_GRP_BTN,
244862306a36Sopenharmony_ci				   IQS7222_REG_KEY_DEBOUNCE);
244962306a36Sopenharmony_ci}
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_cistatic int iqs7222_parse_sldr(struct iqs7222_private *iqs7222,
245262306a36Sopenharmony_ci			      struct fwnode_handle *sldr_node, int sldr_index)
245362306a36Sopenharmony_ci{
245462306a36Sopenharmony_ci	const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
245562306a36Sopenharmony_ci	struct i2c_client *client = iqs7222->client;
245662306a36Sopenharmony_ci	int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
245762306a36Sopenharmony_ci	int ext_chan = rounddown(num_chan, 10);
245862306a36Sopenharmony_ci	int count, error, reg_offset, i;
245962306a36Sopenharmony_ci	u16 *event_mask = &iqs7222->sys_setup[dev_desc->event_offset];
246062306a36Sopenharmony_ci	u16 *sldr_setup = iqs7222->sldr_setup[sldr_index];
246162306a36Sopenharmony_ci	unsigned int chan_sel[4], val;
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci	/*
246462306a36Sopenharmony_ci	 * Each slider can be spread across 3 to 4 channels. It is possible to
246562306a36Sopenharmony_ci	 * select only 2 channels, but doing so prevents the slider from using
246662306a36Sopenharmony_ci	 * the specified resolution.
246762306a36Sopenharmony_ci	 */
246862306a36Sopenharmony_ci	count = fwnode_property_count_u32(sldr_node, "azoteq,channel-select");
246962306a36Sopenharmony_ci	if (count < 0) {
247062306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to count %s channels: %d\n",
247162306a36Sopenharmony_ci			fwnode_get_name(sldr_node), count);
247262306a36Sopenharmony_ci		return count;
247362306a36Sopenharmony_ci	} else if (count < 3 || count > ARRAY_SIZE(chan_sel)) {
247462306a36Sopenharmony_ci		dev_err(&client->dev, "Invalid number of %s channels\n",
247562306a36Sopenharmony_ci			fwnode_get_name(sldr_node));
247662306a36Sopenharmony_ci		return -EINVAL;
247762306a36Sopenharmony_ci	}
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci	error = fwnode_property_read_u32_array(sldr_node,
248062306a36Sopenharmony_ci					       "azoteq,channel-select",
248162306a36Sopenharmony_ci					       chan_sel, count);
248262306a36Sopenharmony_ci	if (error) {
248362306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to read %s channels: %d\n",
248462306a36Sopenharmony_ci			fwnode_get_name(sldr_node), error);
248562306a36Sopenharmony_ci		return error;
248662306a36Sopenharmony_ci	}
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_ci	/*
248962306a36Sopenharmony_ci	 * Resolution and top speed, if small enough, are packed into a single
249062306a36Sopenharmony_ci	 * register. Otherwise, each occupies its own register and the rest of
249162306a36Sopenharmony_ci	 * the slider-related register addresses are offset by one.
249262306a36Sopenharmony_ci	 */
249362306a36Sopenharmony_ci	reg_offset = dev_desc->sldr_res < U16_MAX ? 0 : 1;
249462306a36Sopenharmony_ci
249562306a36Sopenharmony_ci	sldr_setup[0] |= count;
249662306a36Sopenharmony_ci	sldr_setup[3 + reg_offset] &= ~GENMASK(ext_chan - 1, 0);
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(chan_sel); i++) {
249962306a36Sopenharmony_ci		sldr_setup[5 + reg_offset + i] = 0;
250062306a36Sopenharmony_ci		if (i >= count)
250162306a36Sopenharmony_ci			continue;
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_ci		if (chan_sel[i] >= ext_chan) {
250462306a36Sopenharmony_ci			dev_err(&client->dev, "Invalid %s channel: %u\n",
250562306a36Sopenharmony_ci				fwnode_get_name(sldr_node), chan_sel[i]);
250662306a36Sopenharmony_ci			return -EINVAL;
250762306a36Sopenharmony_ci		}
250862306a36Sopenharmony_ci
250962306a36Sopenharmony_ci		/*
251062306a36Sopenharmony_ci		 * The following fields indicate which channels participate in
251162306a36Sopenharmony_ci		 * the slider, as well as each channel's relative placement.
251262306a36Sopenharmony_ci		 */
251362306a36Sopenharmony_ci		sldr_setup[3 + reg_offset] |= BIT(chan_sel[i]);
251462306a36Sopenharmony_ci		sldr_setup[5 + reg_offset + i] = chan_sel[i] * 42 + 1080;
251562306a36Sopenharmony_ci	}
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ci	sldr_setup[4 + reg_offset] = dev_desc->touch_link;
251862306a36Sopenharmony_ci	if (fwnode_property_present(sldr_node, "azoteq,use-prox"))
251962306a36Sopenharmony_ci		sldr_setup[4 + reg_offset] -= 2;
252062306a36Sopenharmony_ci
252162306a36Sopenharmony_ci	error = fwnode_property_read_u32(sldr_node, "azoteq,slider-size", &val);
252262306a36Sopenharmony_ci	if (!error) {
252362306a36Sopenharmony_ci		if (val > dev_desc->sldr_res) {
252462306a36Sopenharmony_ci			dev_err(&client->dev, "Invalid %s size: %u\n",
252562306a36Sopenharmony_ci				fwnode_get_name(sldr_node), val);
252662306a36Sopenharmony_ci			return -EINVAL;
252762306a36Sopenharmony_ci		}
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_ci		if (reg_offset) {
253062306a36Sopenharmony_ci			sldr_setup[3] = val;
253162306a36Sopenharmony_ci		} else {
253262306a36Sopenharmony_ci			sldr_setup[2] &= ~IQS7222_SLDR_SETUP_2_RES_MASK;
253362306a36Sopenharmony_ci			sldr_setup[2] |= (val / 16 <<
253462306a36Sopenharmony_ci					  IQS7222_SLDR_SETUP_2_RES_SHIFT);
253562306a36Sopenharmony_ci		}
253662306a36Sopenharmony_ci	} else if (error != -EINVAL) {
253762306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to read %s size: %d\n",
253862306a36Sopenharmony_ci			fwnode_get_name(sldr_node), error);
253962306a36Sopenharmony_ci		return error;
254062306a36Sopenharmony_ci	}
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci	if (!(reg_offset ? sldr_setup[3]
254362306a36Sopenharmony_ci			 : sldr_setup[2] & IQS7222_SLDR_SETUP_2_RES_MASK)) {
254462306a36Sopenharmony_ci		dev_err(&client->dev, "Undefined %s size\n",
254562306a36Sopenharmony_ci			fwnode_get_name(sldr_node));
254662306a36Sopenharmony_ci		return -EINVAL;
254762306a36Sopenharmony_ci	}
254862306a36Sopenharmony_ci
254962306a36Sopenharmony_ci	error = fwnode_property_read_u32(sldr_node, "azoteq,top-speed", &val);
255062306a36Sopenharmony_ci	if (!error) {
255162306a36Sopenharmony_ci		if (val > (reg_offset ? U16_MAX : U8_MAX * 4)) {
255262306a36Sopenharmony_ci			dev_err(&client->dev, "Invalid %s top speed: %u\n",
255362306a36Sopenharmony_ci				fwnode_get_name(sldr_node), val);
255462306a36Sopenharmony_ci			return -EINVAL;
255562306a36Sopenharmony_ci		}
255662306a36Sopenharmony_ci
255762306a36Sopenharmony_ci		if (reg_offset) {
255862306a36Sopenharmony_ci			sldr_setup[2] = val;
255962306a36Sopenharmony_ci		} else {
256062306a36Sopenharmony_ci			sldr_setup[2] &= ~IQS7222_SLDR_SETUP_2_TOP_SPEED_MASK;
256162306a36Sopenharmony_ci			sldr_setup[2] |= (val / 4);
256262306a36Sopenharmony_ci		}
256362306a36Sopenharmony_ci	} else if (error != -EINVAL) {
256462306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to read %s top speed: %d\n",
256562306a36Sopenharmony_ci			fwnode_get_name(sldr_node), error);
256662306a36Sopenharmony_ci		return error;
256762306a36Sopenharmony_ci	}
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci	error = fwnode_property_read_u32(sldr_node, "linux,axis", &val);
257062306a36Sopenharmony_ci	if (!error) {
257162306a36Sopenharmony_ci		u16 sldr_max = sldr_setup[3] - 1;
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci		if (!reg_offset) {
257462306a36Sopenharmony_ci			sldr_max = sldr_setup[2];
257562306a36Sopenharmony_ci
257662306a36Sopenharmony_ci			sldr_max &= IQS7222_SLDR_SETUP_2_RES_MASK;
257762306a36Sopenharmony_ci			sldr_max >>= IQS7222_SLDR_SETUP_2_RES_SHIFT;
257862306a36Sopenharmony_ci
257962306a36Sopenharmony_ci			sldr_max = sldr_max * 16 - 1;
258062306a36Sopenharmony_ci		}
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_ci		input_set_abs_params(iqs7222->keypad, val, 0, sldr_max, 0, 0);
258362306a36Sopenharmony_ci		iqs7222->sl_axis[sldr_index] = val;
258462306a36Sopenharmony_ci	} else if (error != -EINVAL) {
258562306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to read %s axis: %d\n",
258662306a36Sopenharmony_ci			fwnode_get_name(sldr_node), error);
258762306a36Sopenharmony_ci		return error;
258862306a36Sopenharmony_ci	}
258962306a36Sopenharmony_ci
259062306a36Sopenharmony_ci	if (dev_desc->wheel_enable) {
259162306a36Sopenharmony_ci		sldr_setup[0] &= ~dev_desc->wheel_enable;
259262306a36Sopenharmony_ci		if (iqs7222->sl_axis[sldr_index] == ABS_WHEEL)
259362306a36Sopenharmony_ci			sldr_setup[0] |= dev_desc->wheel_enable;
259462306a36Sopenharmony_ci	}
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_ci	/*
259762306a36Sopenharmony_ci	 * The absence of a register offset makes it safe to assume the device
259862306a36Sopenharmony_ci	 * supports gestures, each of which is first disabled until explicitly
259962306a36Sopenharmony_ci	 * enabled.
260062306a36Sopenharmony_ci	 */
260162306a36Sopenharmony_ci	if (!reg_offset)
260262306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(iqs7222_sl_events); i++)
260362306a36Sopenharmony_ci			sldr_setup[9] &= ~iqs7222_sl_events[i].enable;
260462306a36Sopenharmony_ci
260562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(iqs7222_sl_events); i++) {
260662306a36Sopenharmony_ci		const char *event_name = iqs7222_sl_events[i].name;
260762306a36Sopenharmony_ci		struct fwnode_handle *event_node;
260862306a36Sopenharmony_ci		enum iqs7222_reg_key_id reg_key;
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_ci		event_node = fwnode_get_named_child_node(sldr_node, event_name);
261162306a36Sopenharmony_ci		if (!event_node)
261262306a36Sopenharmony_ci			continue;
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci		/*
261562306a36Sopenharmony_ci		 * Depending on the device, gestures are either offered using
261662306a36Sopenharmony_ci		 * one of two timing resolutions, or are not supported at all.
261762306a36Sopenharmony_ci		 */
261862306a36Sopenharmony_ci		if (reg_offset)
261962306a36Sopenharmony_ci			reg_key = IQS7222_REG_KEY_RESERVED;
262062306a36Sopenharmony_ci		else if (dev_desc->legacy_gesture &&
262162306a36Sopenharmony_ci			 iqs7222_sl_events[i].reg_key == IQS7222_REG_KEY_TAP)
262262306a36Sopenharmony_ci			reg_key = IQS7222_REG_KEY_TAP_LEGACY;
262362306a36Sopenharmony_ci		else if (dev_desc->legacy_gesture &&
262462306a36Sopenharmony_ci			 iqs7222_sl_events[i].reg_key == IQS7222_REG_KEY_AXIAL)
262562306a36Sopenharmony_ci			reg_key = IQS7222_REG_KEY_AXIAL_LEGACY;
262662306a36Sopenharmony_ci		else
262762306a36Sopenharmony_ci			reg_key = iqs7222_sl_events[i].reg_key;
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci		/*
263062306a36Sopenharmony_ci		 * The press/release event does not expose a direct GPIO link,
263162306a36Sopenharmony_ci		 * but one can be emulated by tying each of the participating
263262306a36Sopenharmony_ci		 * channels to the same GPIO.
263362306a36Sopenharmony_ci		 */
263462306a36Sopenharmony_ci		error = iqs7222_parse_event(iqs7222, event_node, sldr_index,
263562306a36Sopenharmony_ci					    IQS7222_REG_GRP_SLDR, reg_key,
263662306a36Sopenharmony_ci					    i ? iqs7222_sl_events[i].enable
263762306a36Sopenharmony_ci					      : sldr_setup[3 + reg_offset],
263862306a36Sopenharmony_ci					    i ? 1568 + sldr_index * 30
263962306a36Sopenharmony_ci					      : sldr_setup[4 + reg_offset],
264062306a36Sopenharmony_ci					    NULL,
264162306a36Sopenharmony_ci					    &iqs7222->sl_code[sldr_index][i]);
264262306a36Sopenharmony_ci		fwnode_handle_put(event_node);
264362306a36Sopenharmony_ci		if (error)
264462306a36Sopenharmony_ci			return error;
264562306a36Sopenharmony_ci
264662306a36Sopenharmony_ci		if (!reg_offset)
264762306a36Sopenharmony_ci			sldr_setup[9] |= iqs7222_sl_events[i].enable;
264862306a36Sopenharmony_ci
264962306a36Sopenharmony_ci		if (!dev_desc->event_offset)
265062306a36Sopenharmony_ci			continue;
265162306a36Sopenharmony_ci
265262306a36Sopenharmony_ci		/*
265362306a36Sopenharmony_ci		 * The press/release event is determined based on whether the
265462306a36Sopenharmony_ci		 * coordinate field reports 0xFFFF and solely relies on touch
265562306a36Sopenharmony_ci		 * or proximity interrupts to be unmasked.
265662306a36Sopenharmony_ci		 */
265762306a36Sopenharmony_ci		if (i && !reg_offset)
265862306a36Sopenharmony_ci			*event_mask |= (IQS7222_EVENT_MASK_SLDR << sldr_index);
265962306a36Sopenharmony_ci		else if (sldr_setup[4 + reg_offset] == dev_desc->touch_link)
266062306a36Sopenharmony_ci			*event_mask |= IQS7222_EVENT_MASK_TOUCH;
266162306a36Sopenharmony_ci		else
266262306a36Sopenharmony_ci			*event_mask |= IQS7222_EVENT_MASK_PROX;
266362306a36Sopenharmony_ci	}
266462306a36Sopenharmony_ci
266562306a36Sopenharmony_ci	/*
266662306a36Sopenharmony_ci	 * The following call handles a special pair of properties that shift
266762306a36Sopenharmony_ci	 * to make room for a wheel enable control in the case of IQS7222C.
266862306a36Sopenharmony_ci	 */
266962306a36Sopenharmony_ci	return iqs7222_parse_props(iqs7222, sldr_node, sldr_index,
267062306a36Sopenharmony_ci				   IQS7222_REG_GRP_SLDR,
267162306a36Sopenharmony_ci				   dev_desc->wheel_enable ?
267262306a36Sopenharmony_ci				   IQS7222_REG_KEY_WHEEL :
267362306a36Sopenharmony_ci				   IQS7222_REG_KEY_NO_WHEEL);
267462306a36Sopenharmony_ci}
267562306a36Sopenharmony_ci
267662306a36Sopenharmony_cistatic int iqs7222_parse_tpad(struct iqs7222_private *iqs7222,
267762306a36Sopenharmony_ci			      struct fwnode_handle *tpad_node, int tpad_index)
267862306a36Sopenharmony_ci{
267962306a36Sopenharmony_ci	const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
268062306a36Sopenharmony_ci	struct touchscreen_properties *prop = &iqs7222->prop;
268162306a36Sopenharmony_ci	struct i2c_client *client = iqs7222->client;
268262306a36Sopenharmony_ci	int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
268362306a36Sopenharmony_ci	int count, error, i;
268462306a36Sopenharmony_ci	u16 *event_mask = &iqs7222->sys_setup[dev_desc->event_offset];
268562306a36Sopenharmony_ci	u16 *tpad_setup = iqs7222->tpad_setup;
268662306a36Sopenharmony_ci	unsigned int chan_sel[12];
268762306a36Sopenharmony_ci
268862306a36Sopenharmony_ci	error = iqs7222_parse_props(iqs7222, tpad_node, tpad_index,
268962306a36Sopenharmony_ci				    IQS7222_REG_GRP_TPAD,
269062306a36Sopenharmony_ci				    IQS7222_REG_KEY_NONE);
269162306a36Sopenharmony_ci	if (error)
269262306a36Sopenharmony_ci		return error;
269362306a36Sopenharmony_ci
269462306a36Sopenharmony_ci	count = fwnode_property_count_u32(tpad_node, "azoteq,channel-select");
269562306a36Sopenharmony_ci	if (count < 0) {
269662306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to count %s channels: %d\n",
269762306a36Sopenharmony_ci			fwnode_get_name(tpad_node), count);
269862306a36Sopenharmony_ci		return count;
269962306a36Sopenharmony_ci	} else if (!count || count > ARRAY_SIZE(chan_sel)) {
270062306a36Sopenharmony_ci		dev_err(&client->dev, "Invalid number of %s channels\n",
270162306a36Sopenharmony_ci			fwnode_get_name(tpad_node));
270262306a36Sopenharmony_ci		return -EINVAL;
270362306a36Sopenharmony_ci	}
270462306a36Sopenharmony_ci
270562306a36Sopenharmony_ci	error = fwnode_property_read_u32_array(tpad_node,
270662306a36Sopenharmony_ci					       "azoteq,channel-select",
270762306a36Sopenharmony_ci					       chan_sel, count);
270862306a36Sopenharmony_ci	if (error) {
270962306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to read %s channels: %d\n",
271062306a36Sopenharmony_ci			fwnode_get_name(tpad_node), error);
271162306a36Sopenharmony_ci		return error;
271262306a36Sopenharmony_ci	}
271362306a36Sopenharmony_ci
271462306a36Sopenharmony_ci	tpad_setup[6] &= ~GENMASK(num_chan - 1, 0);
271562306a36Sopenharmony_ci
271662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(chan_sel); i++) {
271762306a36Sopenharmony_ci		tpad_setup[8 + i] = 0;
271862306a36Sopenharmony_ci		if (i >= count || chan_sel[i] == U8_MAX)
271962306a36Sopenharmony_ci			continue;
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ci		if (chan_sel[i] >= num_chan) {
272262306a36Sopenharmony_ci			dev_err(&client->dev, "Invalid %s channel: %u\n",
272362306a36Sopenharmony_ci				fwnode_get_name(tpad_node), chan_sel[i]);
272462306a36Sopenharmony_ci			return -EINVAL;
272562306a36Sopenharmony_ci		}
272662306a36Sopenharmony_ci
272762306a36Sopenharmony_ci		/*
272862306a36Sopenharmony_ci		 * The following fields indicate which channels participate in
272962306a36Sopenharmony_ci		 * the trackpad, as well as each channel's relative placement.
273062306a36Sopenharmony_ci		 */
273162306a36Sopenharmony_ci		tpad_setup[6] |= BIT(chan_sel[i]);
273262306a36Sopenharmony_ci		tpad_setup[8 + i] = chan_sel[i] * 34 + 1072;
273362306a36Sopenharmony_ci	}
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci	tpad_setup[7] = dev_desc->touch_link;
273662306a36Sopenharmony_ci	if (fwnode_property_present(tpad_node, "azoteq,use-prox"))
273762306a36Sopenharmony_ci		tpad_setup[7] -= 2;
273862306a36Sopenharmony_ci
273962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(iqs7222_tp_events); i++)
274062306a36Sopenharmony_ci		tpad_setup[20] &= ~(iqs7222_tp_events[i].strict |
274162306a36Sopenharmony_ci				    iqs7222_tp_events[i].enable);
274262306a36Sopenharmony_ci
274362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(iqs7222_tp_events); i++) {
274462306a36Sopenharmony_ci		const char *event_name = iqs7222_tp_events[i].name;
274562306a36Sopenharmony_ci		struct fwnode_handle *event_node;
274662306a36Sopenharmony_ci
274762306a36Sopenharmony_ci		event_node = fwnode_get_named_child_node(tpad_node, event_name);
274862306a36Sopenharmony_ci		if (!event_node)
274962306a36Sopenharmony_ci			continue;
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci		if (fwnode_property_present(event_node,
275262306a36Sopenharmony_ci					    "azoteq,gesture-angle-tighten"))
275362306a36Sopenharmony_ci			tpad_setup[20] |= iqs7222_tp_events[i].strict;
275462306a36Sopenharmony_ci
275562306a36Sopenharmony_ci		tpad_setup[20] |= iqs7222_tp_events[i].enable;
275662306a36Sopenharmony_ci
275762306a36Sopenharmony_ci		error = iqs7222_parse_event(iqs7222, event_node, tpad_index,
275862306a36Sopenharmony_ci					    IQS7222_REG_GRP_TPAD,
275962306a36Sopenharmony_ci					    iqs7222_tp_events[i].reg_key,
276062306a36Sopenharmony_ci					    iqs7222_tp_events[i].link, 1566,
276162306a36Sopenharmony_ci					    NULL,
276262306a36Sopenharmony_ci					    &iqs7222->tp_code[i]);
276362306a36Sopenharmony_ci		fwnode_handle_put(event_node);
276462306a36Sopenharmony_ci		if (error)
276562306a36Sopenharmony_ci			return error;
276662306a36Sopenharmony_ci
276762306a36Sopenharmony_ci		if (!dev_desc->event_offset)
276862306a36Sopenharmony_ci			continue;
276962306a36Sopenharmony_ci
277062306a36Sopenharmony_ci		/*
277162306a36Sopenharmony_ci		 * The press/release event is determined based on whether the
277262306a36Sopenharmony_ci		 * coordinate fields report 0xFFFF and solely relies on touch
277362306a36Sopenharmony_ci		 * or proximity interrupts to be unmasked.
277462306a36Sopenharmony_ci		 */
277562306a36Sopenharmony_ci		if (i)
277662306a36Sopenharmony_ci			*event_mask |= IQS7222_EVENT_MASK_TPAD;
277762306a36Sopenharmony_ci		else if (tpad_setup[7] == dev_desc->touch_link)
277862306a36Sopenharmony_ci			*event_mask |= IQS7222_EVENT_MASK_TOUCH;
277962306a36Sopenharmony_ci		else
278062306a36Sopenharmony_ci			*event_mask |= IQS7222_EVENT_MASK_PROX;
278162306a36Sopenharmony_ci	}
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci	if (!iqs7222->tp_code[0])
278462306a36Sopenharmony_ci		return 0;
278562306a36Sopenharmony_ci
278662306a36Sopenharmony_ci	input_set_abs_params(iqs7222->keypad, ABS_X,
278762306a36Sopenharmony_ci			     0, (tpad_setup[4] ? : 1) - 1, 0, 0);
278862306a36Sopenharmony_ci
278962306a36Sopenharmony_ci	input_set_abs_params(iqs7222->keypad, ABS_Y,
279062306a36Sopenharmony_ci			     0, (tpad_setup[5] ? : 1) - 1, 0, 0);
279162306a36Sopenharmony_ci
279262306a36Sopenharmony_ci	touchscreen_parse_properties(iqs7222->keypad, false, prop);
279362306a36Sopenharmony_ci
279462306a36Sopenharmony_ci	if (prop->max_x >= U16_MAX || prop->max_y >= U16_MAX) {
279562306a36Sopenharmony_ci		dev_err(&client->dev, "Invalid trackpad size: %u*%u\n",
279662306a36Sopenharmony_ci			prop->max_x, prop->max_y);
279762306a36Sopenharmony_ci		return -EINVAL;
279862306a36Sopenharmony_ci	}
279962306a36Sopenharmony_ci
280062306a36Sopenharmony_ci	tpad_setup[4] = prop->max_x + 1;
280162306a36Sopenharmony_ci	tpad_setup[5] = prop->max_y + 1;
280262306a36Sopenharmony_ci
280362306a36Sopenharmony_ci	return 0;
280462306a36Sopenharmony_ci}
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_cistatic int (*iqs7222_parse_extra[IQS7222_NUM_REG_GRPS])
280762306a36Sopenharmony_ci				(struct iqs7222_private *iqs7222,
280862306a36Sopenharmony_ci				 struct fwnode_handle *reg_grp_node,
280962306a36Sopenharmony_ci				 int reg_grp_index) = {
281062306a36Sopenharmony_ci	[IQS7222_REG_GRP_CYCLE] = iqs7222_parse_cycle,
281162306a36Sopenharmony_ci	[IQS7222_REG_GRP_CHAN] = iqs7222_parse_chan,
281262306a36Sopenharmony_ci	[IQS7222_REG_GRP_SLDR] = iqs7222_parse_sldr,
281362306a36Sopenharmony_ci	[IQS7222_REG_GRP_TPAD] = iqs7222_parse_tpad,
281462306a36Sopenharmony_ci};
281562306a36Sopenharmony_ci
281662306a36Sopenharmony_cistatic int iqs7222_parse_reg_grp(struct iqs7222_private *iqs7222,
281762306a36Sopenharmony_ci				 enum iqs7222_reg_grp_id reg_grp,
281862306a36Sopenharmony_ci				 int reg_grp_index)
281962306a36Sopenharmony_ci{
282062306a36Sopenharmony_ci	struct i2c_client *client = iqs7222->client;
282162306a36Sopenharmony_ci	struct fwnode_handle *reg_grp_node;
282262306a36Sopenharmony_ci	int error;
282362306a36Sopenharmony_ci
282462306a36Sopenharmony_ci	if (iqs7222_reg_grp_names[reg_grp]) {
282562306a36Sopenharmony_ci		char reg_grp_name[16];
282662306a36Sopenharmony_ci
282762306a36Sopenharmony_ci		snprintf(reg_grp_name, sizeof(reg_grp_name),
282862306a36Sopenharmony_ci			 iqs7222_reg_grp_names[reg_grp], reg_grp_index);
282962306a36Sopenharmony_ci
283062306a36Sopenharmony_ci		reg_grp_node = device_get_named_child_node(&client->dev,
283162306a36Sopenharmony_ci							   reg_grp_name);
283262306a36Sopenharmony_ci	} else {
283362306a36Sopenharmony_ci		reg_grp_node = fwnode_handle_get(dev_fwnode(&client->dev));
283462306a36Sopenharmony_ci	}
283562306a36Sopenharmony_ci
283662306a36Sopenharmony_ci	if (!reg_grp_node)
283762306a36Sopenharmony_ci		return 0;
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_ci	error = iqs7222_parse_props(iqs7222, reg_grp_node, reg_grp_index,
284062306a36Sopenharmony_ci				    reg_grp, IQS7222_REG_KEY_NONE);
284162306a36Sopenharmony_ci
284262306a36Sopenharmony_ci	if (!error && iqs7222_parse_extra[reg_grp])
284362306a36Sopenharmony_ci		error = iqs7222_parse_extra[reg_grp](iqs7222, reg_grp_node,
284462306a36Sopenharmony_ci						     reg_grp_index);
284562306a36Sopenharmony_ci
284662306a36Sopenharmony_ci	fwnode_handle_put(reg_grp_node);
284762306a36Sopenharmony_ci
284862306a36Sopenharmony_ci	return error;
284962306a36Sopenharmony_ci}
285062306a36Sopenharmony_ci
285162306a36Sopenharmony_cistatic int iqs7222_parse_all(struct iqs7222_private *iqs7222)
285262306a36Sopenharmony_ci{
285362306a36Sopenharmony_ci	const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
285462306a36Sopenharmony_ci	const struct iqs7222_reg_grp_desc *reg_grps = dev_desc->reg_grps;
285562306a36Sopenharmony_ci	u16 *sys_setup = iqs7222->sys_setup;
285662306a36Sopenharmony_ci	int error, i, j;
285762306a36Sopenharmony_ci
285862306a36Sopenharmony_ci	if (dev_desc->allow_offset)
285962306a36Sopenharmony_ci		sys_setup[dev_desc->allow_offset] = U16_MAX;
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_ci	if (dev_desc->event_offset)
286262306a36Sopenharmony_ci		sys_setup[dev_desc->event_offset] = IQS7222_EVENT_MASK_ATI;
286362306a36Sopenharmony_ci
286462306a36Sopenharmony_ci	for (i = 0; i < reg_grps[IQS7222_REG_GRP_GPIO].num_row; i++) {
286562306a36Sopenharmony_ci		u16 *gpio_setup = iqs7222->gpio_setup[i];
286662306a36Sopenharmony_ci
286762306a36Sopenharmony_ci		gpio_setup[0] &= ~IQS7222_GPIO_SETUP_0_GPIO_EN;
286862306a36Sopenharmony_ci		gpio_setup[1] = 0;
286962306a36Sopenharmony_ci		gpio_setup[2] = 0;
287062306a36Sopenharmony_ci
287162306a36Sopenharmony_ci		if (reg_grps[IQS7222_REG_GRP_GPIO].num_row == 1)
287262306a36Sopenharmony_ci			continue;
287362306a36Sopenharmony_ci
287462306a36Sopenharmony_ci		/*
287562306a36Sopenharmony_ci		 * The IQS7222C and IQS7222D expose multiple GPIO and must be
287662306a36Sopenharmony_ci		 * informed as to which GPIO this group represents.
287762306a36Sopenharmony_ci		 */
287862306a36Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(iqs7222_gpio_links); j++)
287962306a36Sopenharmony_ci			gpio_setup[0] &= ~BIT(iqs7222_gpio_links[j]);
288062306a36Sopenharmony_ci
288162306a36Sopenharmony_ci		gpio_setup[0] |= BIT(iqs7222_gpio_links[i]);
288262306a36Sopenharmony_ci	}
288362306a36Sopenharmony_ci
288462306a36Sopenharmony_ci	for (i = 0; i < reg_grps[IQS7222_REG_GRP_CHAN].num_row; i++) {
288562306a36Sopenharmony_ci		u16 *chan_setup = iqs7222->chan_setup[i];
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_ci		chan_setup[0] &= ~IQS7222_CHAN_SETUP_0_REF_MODE_MASK;
288862306a36Sopenharmony_ci		chan_setup[0] &= ~IQS7222_CHAN_SETUP_0_CHAN_EN;
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_ci		chan_setup[5] = 0;
289162306a36Sopenharmony_ci	}
289262306a36Sopenharmony_ci
289362306a36Sopenharmony_ci	for (i = 0; i < reg_grps[IQS7222_REG_GRP_SLDR].num_row; i++) {
289462306a36Sopenharmony_ci		u16 *sldr_setup = iqs7222->sldr_setup[i];
289562306a36Sopenharmony_ci
289662306a36Sopenharmony_ci		sldr_setup[0] &= ~IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK;
289762306a36Sopenharmony_ci	}
289862306a36Sopenharmony_ci
289962306a36Sopenharmony_ci	for (i = 0; i < IQS7222_NUM_REG_GRPS; i++) {
290062306a36Sopenharmony_ci		for (j = 0; j < reg_grps[i].num_row; j++) {
290162306a36Sopenharmony_ci			error = iqs7222_parse_reg_grp(iqs7222, i, j);
290262306a36Sopenharmony_ci			if (error)
290362306a36Sopenharmony_ci				return error;
290462306a36Sopenharmony_ci		}
290562306a36Sopenharmony_ci	}
290662306a36Sopenharmony_ci
290762306a36Sopenharmony_ci	return 0;
290862306a36Sopenharmony_ci}
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_cistatic int iqs7222_report(struct iqs7222_private *iqs7222)
291162306a36Sopenharmony_ci{
291262306a36Sopenharmony_ci	const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
291362306a36Sopenharmony_ci	struct i2c_client *client = iqs7222->client;
291462306a36Sopenharmony_ci	int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
291562306a36Sopenharmony_ci	int num_stat = dev_desc->reg_grps[IQS7222_REG_GRP_STAT].num_col;
291662306a36Sopenharmony_ci	int error, i, j;
291762306a36Sopenharmony_ci	__le16 status[IQS7222_MAX_COLS_STAT];
291862306a36Sopenharmony_ci
291962306a36Sopenharmony_ci	error = iqs7222_read_burst(iqs7222, IQS7222_SYS_STATUS, status,
292062306a36Sopenharmony_ci				   num_stat);
292162306a36Sopenharmony_ci	if (error)
292262306a36Sopenharmony_ci		return error;
292362306a36Sopenharmony_ci
292462306a36Sopenharmony_ci	if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_RESET) {
292562306a36Sopenharmony_ci		dev_err(&client->dev, "Unexpected device reset\n");
292662306a36Sopenharmony_ci		return iqs7222_dev_init(iqs7222, WRITE);
292762306a36Sopenharmony_ci	}
292862306a36Sopenharmony_ci
292962306a36Sopenharmony_ci	if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_ATI_ERROR) {
293062306a36Sopenharmony_ci		dev_err(&client->dev, "Unexpected ATI error\n");
293162306a36Sopenharmony_ci		return iqs7222_ati_trigger(iqs7222);
293262306a36Sopenharmony_ci	}
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_ci	if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_ATI_ACTIVE)
293562306a36Sopenharmony_ci		return 0;
293662306a36Sopenharmony_ci
293762306a36Sopenharmony_ci	for (i = 0; i < num_chan; i++) {
293862306a36Sopenharmony_ci		u16 *chan_setup = iqs7222->chan_setup[i];
293962306a36Sopenharmony_ci
294062306a36Sopenharmony_ci		if (!(chan_setup[0] & IQS7222_CHAN_SETUP_0_CHAN_EN))
294162306a36Sopenharmony_ci			continue;
294262306a36Sopenharmony_ci
294362306a36Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(iqs7222_kp_events); j++) {
294462306a36Sopenharmony_ci			/*
294562306a36Sopenharmony_ci			 * Proximity state begins at offset 2 and spills into
294662306a36Sopenharmony_ci			 * offset 3 for devices with more than 16 channels.
294762306a36Sopenharmony_ci			 *
294862306a36Sopenharmony_ci			 * Touch state begins at the first offset immediately
294962306a36Sopenharmony_ci			 * following proximity state.
295062306a36Sopenharmony_ci			 */
295162306a36Sopenharmony_ci			int k = 2 + j * (num_chan > 16 ? 2 : 1);
295262306a36Sopenharmony_ci			u16 state = le16_to_cpu(status[k + i / 16]);
295362306a36Sopenharmony_ci
295462306a36Sopenharmony_ci			if (!iqs7222->kp_type[i][j])
295562306a36Sopenharmony_ci				continue;
295662306a36Sopenharmony_ci
295762306a36Sopenharmony_ci			input_event(iqs7222->keypad,
295862306a36Sopenharmony_ci				    iqs7222->kp_type[i][j],
295962306a36Sopenharmony_ci				    iqs7222->kp_code[i][j],
296062306a36Sopenharmony_ci				    !!(state & BIT(i % 16)));
296162306a36Sopenharmony_ci		}
296262306a36Sopenharmony_ci	}
296362306a36Sopenharmony_ci
296462306a36Sopenharmony_ci	for (i = 0; i < dev_desc->reg_grps[IQS7222_REG_GRP_SLDR].num_row; i++) {
296562306a36Sopenharmony_ci		u16 *sldr_setup = iqs7222->sldr_setup[i];
296662306a36Sopenharmony_ci		u16 sldr_pos = le16_to_cpu(status[4 + i]);
296762306a36Sopenharmony_ci		u16 state = le16_to_cpu(status[6 + i]);
296862306a36Sopenharmony_ci
296962306a36Sopenharmony_ci		if (!(sldr_setup[0] & IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK))
297062306a36Sopenharmony_ci			continue;
297162306a36Sopenharmony_ci
297262306a36Sopenharmony_ci		if (sldr_pos < dev_desc->sldr_res)
297362306a36Sopenharmony_ci			input_report_abs(iqs7222->keypad, iqs7222->sl_axis[i],
297462306a36Sopenharmony_ci					 sldr_pos);
297562306a36Sopenharmony_ci
297662306a36Sopenharmony_ci		input_report_key(iqs7222->keypad, iqs7222->sl_code[i][0],
297762306a36Sopenharmony_ci				 sldr_pos < dev_desc->sldr_res);
297862306a36Sopenharmony_ci
297962306a36Sopenharmony_ci		/*
298062306a36Sopenharmony_ci		 * A maximum resolution indicates the device does not support
298162306a36Sopenharmony_ci		 * gestures, in which case the remaining fields are ignored.
298262306a36Sopenharmony_ci		 */
298362306a36Sopenharmony_ci		if (dev_desc->sldr_res == U16_MAX)
298462306a36Sopenharmony_ci			continue;
298562306a36Sopenharmony_ci
298662306a36Sopenharmony_ci		if (!(le16_to_cpu(status[1]) & IQS7222_EVENT_MASK_SLDR << i))
298762306a36Sopenharmony_ci			continue;
298862306a36Sopenharmony_ci
298962306a36Sopenharmony_ci		/*
299062306a36Sopenharmony_ci		 * Skip the press/release event, as it does not have separate
299162306a36Sopenharmony_ci		 * status fields and is handled separately.
299262306a36Sopenharmony_ci		 */
299362306a36Sopenharmony_ci		for (j = 1; j < ARRAY_SIZE(iqs7222_sl_events); j++) {
299462306a36Sopenharmony_ci			u16 mask = iqs7222_sl_events[j].mask;
299562306a36Sopenharmony_ci			u16 val = iqs7222_sl_events[j].val;
299662306a36Sopenharmony_ci
299762306a36Sopenharmony_ci			input_report_key(iqs7222->keypad,
299862306a36Sopenharmony_ci					 iqs7222->sl_code[i][j],
299962306a36Sopenharmony_ci					 (state & mask) == val);
300062306a36Sopenharmony_ci		}
300162306a36Sopenharmony_ci
300262306a36Sopenharmony_ci		input_sync(iqs7222->keypad);
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_ci		for (j = 1; j < ARRAY_SIZE(iqs7222_sl_events); j++)
300562306a36Sopenharmony_ci			input_report_key(iqs7222->keypad,
300662306a36Sopenharmony_ci					 iqs7222->sl_code[i][j], 0);
300762306a36Sopenharmony_ci	}
300862306a36Sopenharmony_ci
300962306a36Sopenharmony_ci	for (i = 0; i < dev_desc->reg_grps[IQS7222_REG_GRP_TPAD].num_row; i++) {
301062306a36Sopenharmony_ci		u16 tpad_pos_x = le16_to_cpu(status[4]);
301162306a36Sopenharmony_ci		u16 tpad_pos_y = le16_to_cpu(status[5]);
301262306a36Sopenharmony_ci		u16 state = le16_to_cpu(status[6]);
301362306a36Sopenharmony_ci
301462306a36Sopenharmony_ci		input_report_key(iqs7222->keypad, iqs7222->tp_code[0],
301562306a36Sopenharmony_ci				 tpad_pos_x < U16_MAX);
301662306a36Sopenharmony_ci
301762306a36Sopenharmony_ci		if (tpad_pos_x < U16_MAX)
301862306a36Sopenharmony_ci			touchscreen_report_pos(iqs7222->keypad, &iqs7222->prop,
301962306a36Sopenharmony_ci					       tpad_pos_x, tpad_pos_y, false);
302062306a36Sopenharmony_ci
302162306a36Sopenharmony_ci		if (!(le16_to_cpu(status[1]) & IQS7222_EVENT_MASK_TPAD))
302262306a36Sopenharmony_ci			continue;
302362306a36Sopenharmony_ci
302462306a36Sopenharmony_ci		/*
302562306a36Sopenharmony_ci		 * Skip the press/release event, as it does not have separate
302662306a36Sopenharmony_ci		 * status fields and is handled separately.
302762306a36Sopenharmony_ci		 */
302862306a36Sopenharmony_ci		for (j = 1; j < ARRAY_SIZE(iqs7222_tp_events); j++) {
302962306a36Sopenharmony_ci			u16 mask = iqs7222_tp_events[j].mask;
303062306a36Sopenharmony_ci			u16 val = iqs7222_tp_events[j].val;
303162306a36Sopenharmony_ci
303262306a36Sopenharmony_ci			input_report_key(iqs7222->keypad,
303362306a36Sopenharmony_ci					 iqs7222->tp_code[j],
303462306a36Sopenharmony_ci					 (state & mask) == val);
303562306a36Sopenharmony_ci		}
303662306a36Sopenharmony_ci
303762306a36Sopenharmony_ci		input_sync(iqs7222->keypad);
303862306a36Sopenharmony_ci
303962306a36Sopenharmony_ci		for (j = 1; j < ARRAY_SIZE(iqs7222_tp_events); j++)
304062306a36Sopenharmony_ci			input_report_key(iqs7222->keypad,
304162306a36Sopenharmony_ci					 iqs7222->tp_code[j], 0);
304262306a36Sopenharmony_ci	}
304362306a36Sopenharmony_ci
304462306a36Sopenharmony_ci	input_sync(iqs7222->keypad);
304562306a36Sopenharmony_ci
304662306a36Sopenharmony_ci	return 0;
304762306a36Sopenharmony_ci}
304862306a36Sopenharmony_ci
304962306a36Sopenharmony_cistatic irqreturn_t iqs7222_irq(int irq, void *context)
305062306a36Sopenharmony_ci{
305162306a36Sopenharmony_ci	struct iqs7222_private *iqs7222 = context;
305262306a36Sopenharmony_ci
305362306a36Sopenharmony_ci	return iqs7222_report(iqs7222) ? IRQ_NONE : IRQ_HANDLED;
305462306a36Sopenharmony_ci}
305562306a36Sopenharmony_ci
305662306a36Sopenharmony_cistatic int iqs7222_probe(struct i2c_client *client)
305762306a36Sopenharmony_ci{
305862306a36Sopenharmony_ci	struct iqs7222_private *iqs7222;
305962306a36Sopenharmony_ci	unsigned long irq_flags;
306062306a36Sopenharmony_ci	int error, irq;
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci	iqs7222 = devm_kzalloc(&client->dev, sizeof(*iqs7222), GFP_KERNEL);
306362306a36Sopenharmony_ci	if (!iqs7222)
306462306a36Sopenharmony_ci		return -ENOMEM;
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_ci	i2c_set_clientdata(client, iqs7222);
306762306a36Sopenharmony_ci	iqs7222->client = client;
306862306a36Sopenharmony_ci
306962306a36Sopenharmony_ci	iqs7222->keypad = devm_input_allocate_device(&client->dev);
307062306a36Sopenharmony_ci	if (!iqs7222->keypad)
307162306a36Sopenharmony_ci		return -ENOMEM;
307262306a36Sopenharmony_ci
307362306a36Sopenharmony_ci	iqs7222->keypad->name = client->name;
307462306a36Sopenharmony_ci	iqs7222->keypad->id.bustype = BUS_I2C;
307562306a36Sopenharmony_ci
307662306a36Sopenharmony_ci	/*
307762306a36Sopenharmony_ci	 * The RDY pin behaves as an interrupt, but must also be polled ahead
307862306a36Sopenharmony_ci	 * of unsolicited I2C communication. As such, it is first opened as a
307962306a36Sopenharmony_ci	 * GPIO and then passed to gpiod_to_irq() to register the interrupt.
308062306a36Sopenharmony_ci	 */
308162306a36Sopenharmony_ci	iqs7222->irq_gpio = devm_gpiod_get(&client->dev, "irq", GPIOD_IN);
308262306a36Sopenharmony_ci	if (IS_ERR(iqs7222->irq_gpio)) {
308362306a36Sopenharmony_ci		error = PTR_ERR(iqs7222->irq_gpio);
308462306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to request IRQ GPIO: %d\n",
308562306a36Sopenharmony_ci			error);
308662306a36Sopenharmony_ci		return error;
308762306a36Sopenharmony_ci	}
308862306a36Sopenharmony_ci
308962306a36Sopenharmony_ci	iqs7222->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
309062306a36Sopenharmony_ci						      GPIOD_OUT_HIGH);
309162306a36Sopenharmony_ci	if (IS_ERR(iqs7222->reset_gpio)) {
309262306a36Sopenharmony_ci		error = PTR_ERR(iqs7222->reset_gpio);
309362306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to request reset GPIO: %d\n",
309462306a36Sopenharmony_ci			error);
309562306a36Sopenharmony_ci		return error;
309662306a36Sopenharmony_ci	}
309762306a36Sopenharmony_ci
309862306a36Sopenharmony_ci	error = iqs7222_hard_reset(iqs7222);
309962306a36Sopenharmony_ci	if (error)
310062306a36Sopenharmony_ci		return error;
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_ci	error = iqs7222_dev_info(iqs7222);
310362306a36Sopenharmony_ci	if (error)
310462306a36Sopenharmony_ci		return error;
310562306a36Sopenharmony_ci
310662306a36Sopenharmony_ci	error = iqs7222_dev_init(iqs7222, READ);
310762306a36Sopenharmony_ci	if (error)
310862306a36Sopenharmony_ci		return error;
310962306a36Sopenharmony_ci
311062306a36Sopenharmony_ci	error = iqs7222_parse_all(iqs7222);
311162306a36Sopenharmony_ci	if (error)
311262306a36Sopenharmony_ci		return error;
311362306a36Sopenharmony_ci
311462306a36Sopenharmony_ci	error = iqs7222_dev_init(iqs7222, WRITE);
311562306a36Sopenharmony_ci	if (error)
311662306a36Sopenharmony_ci		return error;
311762306a36Sopenharmony_ci
311862306a36Sopenharmony_ci	error = iqs7222_report(iqs7222);
311962306a36Sopenharmony_ci	if (error)
312062306a36Sopenharmony_ci		return error;
312162306a36Sopenharmony_ci
312262306a36Sopenharmony_ci	error = input_register_device(iqs7222->keypad);
312362306a36Sopenharmony_ci	if (error) {
312462306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to register device: %d\n", error);
312562306a36Sopenharmony_ci		return error;
312662306a36Sopenharmony_ci	}
312762306a36Sopenharmony_ci
312862306a36Sopenharmony_ci	irq = gpiod_to_irq(iqs7222->irq_gpio);
312962306a36Sopenharmony_ci	if (irq < 0)
313062306a36Sopenharmony_ci		return irq;
313162306a36Sopenharmony_ci
313262306a36Sopenharmony_ci	irq_flags = gpiod_is_active_low(iqs7222->irq_gpio) ? IRQF_TRIGGER_LOW
313362306a36Sopenharmony_ci							   : IRQF_TRIGGER_HIGH;
313462306a36Sopenharmony_ci	irq_flags |= IRQF_ONESHOT;
313562306a36Sopenharmony_ci
313662306a36Sopenharmony_ci	error = devm_request_threaded_irq(&client->dev, irq, NULL, iqs7222_irq,
313762306a36Sopenharmony_ci					  irq_flags, client->name, iqs7222);
313862306a36Sopenharmony_ci	if (error)
313962306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to request IRQ: %d\n", error);
314062306a36Sopenharmony_ci
314162306a36Sopenharmony_ci	return error;
314262306a36Sopenharmony_ci}
314362306a36Sopenharmony_ci
314462306a36Sopenharmony_cistatic const struct of_device_id iqs7222_of_match[] = {
314562306a36Sopenharmony_ci	{ .compatible = "azoteq,iqs7222a" },
314662306a36Sopenharmony_ci	{ .compatible = "azoteq,iqs7222b" },
314762306a36Sopenharmony_ci	{ .compatible = "azoteq,iqs7222c" },
314862306a36Sopenharmony_ci	{ .compatible = "azoteq,iqs7222d" },
314962306a36Sopenharmony_ci	{ }
315062306a36Sopenharmony_ci};
315162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, iqs7222_of_match);
315262306a36Sopenharmony_ci
315362306a36Sopenharmony_cistatic struct i2c_driver iqs7222_i2c_driver = {
315462306a36Sopenharmony_ci	.driver = {
315562306a36Sopenharmony_ci		.name = "iqs7222",
315662306a36Sopenharmony_ci		.of_match_table = iqs7222_of_match,
315762306a36Sopenharmony_ci	},
315862306a36Sopenharmony_ci	.probe = iqs7222_probe,
315962306a36Sopenharmony_ci};
316062306a36Sopenharmony_cimodule_i2c_driver(iqs7222_i2c_driver);
316162306a36Sopenharmony_ci
316262306a36Sopenharmony_ciMODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
316362306a36Sopenharmony_ciMODULE_DESCRIPTION("Azoteq IQS7222A/B/C/D Capacitive Touch Controller");
316462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
3165