xref: /openbmc/linux/drivers/input/misc/iqs269a.c (revision 6f49c4f5)
104e49867SJeff LaBundy // SPDX-License-Identifier: GPL-2.0+
204e49867SJeff LaBundy /*
304e49867SJeff LaBundy  * Azoteq IQS269A Capacitive Touch Controller
404e49867SJeff LaBundy  *
504e49867SJeff LaBundy  * Copyright (C) 2020 Jeff LaBundy <jeff@labundy.com>
604e49867SJeff LaBundy  *
704e49867SJeff LaBundy  * This driver registers up to 3 input devices: one representing capacitive or
804e49867SJeff LaBundy  * inductive keys as well as Hall-effect switches, and one for each of the two
904e49867SJeff LaBundy  * axial sliders presented by the device.
1004e49867SJeff LaBundy  */
1104e49867SJeff LaBundy 
1204e49867SJeff LaBundy #include <linux/delay.h>
1304e49867SJeff LaBundy #include <linux/device.h>
1404e49867SJeff LaBundy #include <linux/err.h>
1504e49867SJeff LaBundy #include <linux/i2c.h>
1604e49867SJeff LaBundy #include <linux/input.h>
1704e49867SJeff LaBundy #include <linux/interrupt.h>
1804e49867SJeff LaBundy #include <linux/kernel.h>
1904e49867SJeff LaBundy #include <linux/module.h>
2004e49867SJeff LaBundy #include <linux/mutex.h>
2104e49867SJeff LaBundy #include <linux/of_device.h>
2204e49867SJeff LaBundy #include <linux/property.h>
2304e49867SJeff LaBundy #include <linux/regmap.h>
2404e49867SJeff LaBundy #include <linux/slab.h>
2504e49867SJeff LaBundy 
2604e49867SJeff LaBundy #define IQS269_VER_INFO				0x00
2704e49867SJeff LaBundy #define IQS269_VER_INFO_PROD_NUM		0x4F
2804e49867SJeff LaBundy 
2904e49867SJeff LaBundy #define IQS269_SYS_FLAGS			0x02
3004e49867SJeff LaBundy #define IQS269_SYS_FLAGS_SHOW_RESET		BIT(15)
3104e49867SJeff LaBundy #define IQS269_SYS_FLAGS_PWR_MODE_MASK		GENMASK(12, 11)
3204e49867SJeff LaBundy #define IQS269_SYS_FLAGS_PWR_MODE_SHIFT		11
3304e49867SJeff LaBundy #define IQS269_SYS_FLAGS_IN_ATI			BIT(10)
3404e49867SJeff LaBundy 
3504e49867SJeff LaBundy #define IQS269_CHx_COUNTS			0x08
3604e49867SJeff LaBundy 
3704e49867SJeff LaBundy #define IQS269_SLIDER_X				0x30
3804e49867SJeff LaBundy 
3904e49867SJeff LaBundy #define IQS269_CAL_DATA_A			0x35
4004e49867SJeff LaBundy #define IQS269_CAL_DATA_A_HALL_BIN_L_MASK	GENMASK(15, 12)
4104e49867SJeff LaBundy #define IQS269_CAL_DATA_A_HALL_BIN_L_SHIFT	12
4204e49867SJeff LaBundy #define IQS269_CAL_DATA_A_HALL_BIN_R_MASK	GENMASK(11, 8)
4304e49867SJeff LaBundy #define IQS269_CAL_DATA_A_HALL_BIN_R_SHIFT	8
4404e49867SJeff LaBundy 
4504e49867SJeff LaBundy #define IQS269_SYS_SETTINGS			0x80
4604e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_CLK_DIV		BIT(15)
4704e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_ULP_AUTO		BIT(14)
4804e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_DIS_AUTO		BIT(13)
4904e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_PWR_MODE_MASK	GENMASK(12, 11)
5004e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_PWR_MODE_SHIFT	11
5104e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_PWR_MODE_MAX	3
5204e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_ULP_UPDATE_MASK	GENMASK(10, 8)
5304e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_ULP_UPDATE_SHIFT	8
5404e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_ULP_UPDATE_MAX	7
5504e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_RESEED_OFFSET	BIT(6)
5604e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_EVENT_MODE		BIT(5)
5704e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_EVENT_MODE_LP	BIT(4)
5804e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_REDO_ATI		BIT(2)
5904e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_ACK_RESET		BIT(0)
6004e49867SJeff LaBundy 
6104e49867SJeff LaBundy #define IQS269_FILT_STR_LP_LTA_MASK		GENMASK(7, 6)
6204e49867SJeff LaBundy #define IQS269_FILT_STR_LP_LTA_SHIFT		6
6304e49867SJeff LaBundy #define IQS269_FILT_STR_LP_CNT_MASK		GENMASK(5, 4)
6404e49867SJeff LaBundy #define IQS269_FILT_STR_LP_CNT_SHIFT		4
6504e49867SJeff LaBundy #define IQS269_FILT_STR_NP_LTA_MASK		GENMASK(3, 2)
6604e49867SJeff LaBundy #define IQS269_FILT_STR_NP_LTA_SHIFT		2
6704e49867SJeff LaBundy #define IQS269_FILT_STR_NP_CNT_MASK		GENMASK(1, 0)
6804e49867SJeff LaBundy #define IQS269_FILT_STR_MAX			3
6904e49867SJeff LaBundy 
7004e49867SJeff LaBundy #define IQS269_EVENT_MASK_SYS			BIT(6)
7104e49867SJeff LaBundy #define IQS269_EVENT_MASK_DEEP			BIT(2)
7204e49867SJeff LaBundy #define IQS269_EVENT_MASK_TOUCH			BIT(1)
7304e49867SJeff LaBundy #define IQS269_EVENT_MASK_PROX			BIT(0)
7404e49867SJeff LaBundy 
7504e49867SJeff LaBundy #define IQS269_RATE_NP_MS_MAX			255
7604e49867SJeff LaBundy #define IQS269_RATE_LP_MS_MAX			255
7704e49867SJeff LaBundy #define IQS269_RATE_ULP_MS_MAX			4080
7804e49867SJeff LaBundy #define IQS269_TIMEOUT_PWR_MS_MAX		130560
7904e49867SJeff LaBundy #define IQS269_TIMEOUT_LTA_MS_MAX		130560
8004e49867SJeff LaBundy 
8104e49867SJeff LaBundy #define IQS269_MISC_A_ATI_BAND_DISABLE		BIT(15)
8204e49867SJeff LaBundy #define IQS269_MISC_A_ATI_LP_ONLY		BIT(14)
8304e49867SJeff LaBundy #define IQS269_MISC_A_ATI_BAND_TIGHTEN		BIT(13)
8404e49867SJeff LaBundy #define IQS269_MISC_A_FILT_DISABLE		BIT(12)
8504e49867SJeff LaBundy #define IQS269_MISC_A_GPIO3_SELECT_MASK		GENMASK(10, 8)
8604e49867SJeff LaBundy #define IQS269_MISC_A_GPIO3_SELECT_SHIFT	8
8704e49867SJeff LaBundy #define IQS269_MISC_A_DUAL_DIR			BIT(6)
8804e49867SJeff LaBundy #define IQS269_MISC_A_TX_FREQ_MASK		GENMASK(5, 4)
8904e49867SJeff LaBundy #define IQS269_MISC_A_TX_FREQ_SHIFT		4
9004e49867SJeff LaBundy #define IQS269_MISC_A_TX_FREQ_MAX		3
9104e49867SJeff LaBundy #define IQS269_MISC_A_GLOBAL_CAP_SIZE		BIT(0)
9204e49867SJeff LaBundy 
9304e49867SJeff LaBundy #define IQS269_MISC_B_RESEED_UI_SEL_MASK	GENMASK(7, 6)
9404e49867SJeff LaBundy #define IQS269_MISC_B_RESEED_UI_SEL_SHIFT	6
9504e49867SJeff LaBundy #define IQS269_MISC_B_RESEED_UI_SEL_MAX		3
9604e49867SJeff LaBundy #define IQS269_MISC_B_TRACKING_UI_ENABLE	BIT(4)
9704e49867SJeff LaBundy #define IQS269_MISC_B_FILT_STR_SLIDER		GENMASK(1, 0)
9804e49867SJeff LaBundy 
9904e49867SJeff LaBundy #define IQS269_CHx_SETTINGS			0x8C
10004e49867SJeff LaBundy 
10104e49867SJeff LaBundy #define IQS269_CHx_ENG_A_MEAS_CAP_SIZE		BIT(15)
10204e49867SJeff LaBundy #define IQS269_CHx_ENG_A_RX_GND_INACTIVE	BIT(13)
10304e49867SJeff LaBundy #define IQS269_CHx_ENG_A_LOCAL_CAP_SIZE		BIT(12)
10404e49867SJeff LaBundy #define IQS269_CHx_ENG_A_ATI_MODE_MASK		GENMASK(9, 8)
10504e49867SJeff LaBundy #define IQS269_CHx_ENG_A_ATI_MODE_SHIFT		8
10604e49867SJeff LaBundy #define IQS269_CHx_ENG_A_ATI_MODE_MAX		3
10704e49867SJeff LaBundy #define IQS269_CHx_ENG_A_INV_LOGIC		BIT(7)
10804e49867SJeff LaBundy #define IQS269_CHx_ENG_A_PROJ_BIAS_MASK		GENMASK(6, 5)
10904e49867SJeff LaBundy #define IQS269_CHx_ENG_A_PROJ_BIAS_SHIFT	5
11004e49867SJeff LaBundy #define IQS269_CHx_ENG_A_PROJ_BIAS_MAX		3
11104e49867SJeff LaBundy #define IQS269_CHx_ENG_A_SENSE_MODE_MASK	GENMASK(3, 0)
11204e49867SJeff LaBundy #define IQS269_CHx_ENG_A_SENSE_MODE_MAX		15
11304e49867SJeff LaBundy 
11404e49867SJeff LaBundy #define IQS269_CHx_ENG_B_LOCAL_CAP_ENABLE	BIT(13)
11504e49867SJeff LaBundy #define IQS269_CHx_ENG_B_SENSE_FREQ_MASK	GENMASK(10, 9)
11604e49867SJeff LaBundy #define IQS269_CHx_ENG_B_SENSE_FREQ_SHIFT	9
11704e49867SJeff LaBundy #define IQS269_CHx_ENG_B_SENSE_FREQ_MAX		3
11804e49867SJeff LaBundy #define IQS269_CHx_ENG_B_STATIC_ENABLE		BIT(8)
11904e49867SJeff LaBundy #define IQS269_CHx_ENG_B_ATI_BASE_MASK		GENMASK(7, 6)
12004e49867SJeff LaBundy #define IQS269_CHx_ENG_B_ATI_BASE_75		0x00
12104e49867SJeff LaBundy #define IQS269_CHx_ENG_B_ATI_BASE_100		0x40
12204e49867SJeff LaBundy #define IQS269_CHx_ENG_B_ATI_BASE_150		0x80
12304e49867SJeff LaBundy #define IQS269_CHx_ENG_B_ATI_BASE_200		0xC0
12404e49867SJeff LaBundy #define IQS269_CHx_ENG_B_ATI_TARGET_MASK	GENMASK(5, 0)
12504e49867SJeff LaBundy #define IQS269_CHx_ENG_B_ATI_TARGET_MAX		2016
12604e49867SJeff LaBundy 
12704e49867SJeff LaBundy #define IQS269_CHx_WEIGHT_MAX			255
12804e49867SJeff LaBundy #define IQS269_CHx_THRESH_MAX			255
12904e49867SJeff LaBundy #define IQS269_CHx_HYST_DEEP_MASK		GENMASK(7, 4)
13004e49867SJeff LaBundy #define IQS269_CHx_HYST_DEEP_SHIFT		4
13104e49867SJeff LaBundy #define IQS269_CHx_HYST_TOUCH_MASK		GENMASK(3, 0)
13204e49867SJeff LaBundy #define IQS269_CHx_HYST_MAX			15
13304e49867SJeff LaBundy 
13404e49867SJeff LaBundy #define IQS269_CHx_HALL_INACTIVE		6
13504e49867SJeff LaBundy #define IQS269_CHx_HALL_ACTIVE			7
13604e49867SJeff LaBundy 
13704e49867SJeff LaBundy #define IQS269_HALL_PAD_R			BIT(0)
13804e49867SJeff LaBundy #define IQS269_HALL_PAD_L			BIT(1)
13904e49867SJeff LaBundy #define IQS269_HALL_PAD_INV			BIT(6)
14004e49867SJeff LaBundy 
14104e49867SJeff LaBundy #define IQS269_HALL_UI				0xF5
14204e49867SJeff LaBundy #define IQS269_HALL_UI_ENABLE			BIT(15)
14304e49867SJeff LaBundy 
14404e49867SJeff LaBundy #define IQS269_MAX_REG				0xFF
14504e49867SJeff LaBundy 
14604e49867SJeff LaBundy #define IQS269_NUM_CH				8
14704e49867SJeff LaBundy #define IQS269_NUM_SL				2
14804e49867SJeff LaBundy 
14904e49867SJeff LaBundy #define IQS269_ATI_POLL_SLEEP_US		(iqs269->delay_mult * 10000)
15004e49867SJeff LaBundy #define IQS269_ATI_POLL_TIMEOUT_US		(iqs269->delay_mult * 500000)
15104e49867SJeff LaBundy #define IQS269_ATI_STABLE_DELAY_MS		(iqs269->delay_mult * 150)
15204e49867SJeff LaBundy 
15304e49867SJeff LaBundy #define IQS269_PWR_MODE_POLL_SLEEP_US		IQS269_ATI_POLL_SLEEP_US
15404e49867SJeff LaBundy #define IQS269_PWR_MODE_POLL_TIMEOUT_US		IQS269_ATI_POLL_TIMEOUT_US
15504e49867SJeff LaBundy 
15604e49867SJeff LaBundy #define iqs269_irq_wait()			usleep_range(100, 150)
15704e49867SJeff LaBundy 
15804e49867SJeff LaBundy enum iqs269_local_cap_size {
15904e49867SJeff LaBundy 	IQS269_LOCAL_CAP_SIZE_0,
16004e49867SJeff LaBundy 	IQS269_LOCAL_CAP_SIZE_GLOBAL_ONLY,
16104e49867SJeff LaBundy 	IQS269_LOCAL_CAP_SIZE_GLOBAL_0pF5,
16204e49867SJeff LaBundy };
16304e49867SJeff LaBundy 
16404e49867SJeff LaBundy enum iqs269_st_offs {
16504e49867SJeff LaBundy 	IQS269_ST_OFFS_PROX,
16604e49867SJeff LaBundy 	IQS269_ST_OFFS_DIR,
16704e49867SJeff LaBundy 	IQS269_ST_OFFS_TOUCH,
16804e49867SJeff LaBundy 	IQS269_ST_OFFS_DEEP,
16904e49867SJeff LaBundy };
17004e49867SJeff LaBundy 
17104e49867SJeff LaBundy enum iqs269_th_offs {
17204e49867SJeff LaBundy 	IQS269_TH_OFFS_PROX,
17304e49867SJeff LaBundy 	IQS269_TH_OFFS_TOUCH,
17404e49867SJeff LaBundy 	IQS269_TH_OFFS_DEEP,
17504e49867SJeff LaBundy };
17604e49867SJeff LaBundy 
17704e49867SJeff LaBundy enum iqs269_event_id {
17804e49867SJeff LaBundy 	IQS269_EVENT_PROX_DN,
17904e49867SJeff LaBundy 	IQS269_EVENT_PROX_UP,
18004e49867SJeff LaBundy 	IQS269_EVENT_TOUCH_DN,
18104e49867SJeff LaBundy 	IQS269_EVENT_TOUCH_UP,
18204e49867SJeff LaBundy 	IQS269_EVENT_DEEP_DN,
18304e49867SJeff LaBundy 	IQS269_EVENT_DEEP_UP,
18404e49867SJeff LaBundy };
18504e49867SJeff LaBundy 
18604e49867SJeff LaBundy struct iqs269_switch_desc {
18704e49867SJeff LaBundy 	unsigned int code;
18804e49867SJeff LaBundy 	bool enabled;
18904e49867SJeff LaBundy };
19004e49867SJeff LaBundy 
19104e49867SJeff LaBundy struct iqs269_event_desc {
19204e49867SJeff LaBundy 	const char *name;
19304e49867SJeff LaBundy 	enum iqs269_st_offs st_offs;
19404e49867SJeff LaBundy 	enum iqs269_th_offs th_offs;
19504e49867SJeff LaBundy 	bool dir_up;
19604e49867SJeff LaBundy 	u8 mask;
19704e49867SJeff LaBundy };
19804e49867SJeff LaBundy 
19904e49867SJeff LaBundy static const struct iqs269_event_desc iqs269_events[] = {
20004e49867SJeff LaBundy 	[IQS269_EVENT_PROX_DN] = {
20104e49867SJeff LaBundy 		.name = "event-prox",
20204e49867SJeff LaBundy 		.st_offs = IQS269_ST_OFFS_PROX,
20304e49867SJeff LaBundy 		.th_offs = IQS269_TH_OFFS_PROX,
20404e49867SJeff LaBundy 		.mask = IQS269_EVENT_MASK_PROX,
20504e49867SJeff LaBundy 	},
20604e49867SJeff LaBundy 	[IQS269_EVENT_PROX_UP] = {
20704e49867SJeff LaBundy 		.name = "event-prox-alt",
20804e49867SJeff LaBundy 		.st_offs = IQS269_ST_OFFS_PROX,
20904e49867SJeff LaBundy 		.th_offs = IQS269_TH_OFFS_PROX,
21004e49867SJeff LaBundy 		.dir_up = true,
21104e49867SJeff LaBundy 		.mask = IQS269_EVENT_MASK_PROX,
21204e49867SJeff LaBundy 	},
21304e49867SJeff LaBundy 	[IQS269_EVENT_TOUCH_DN] = {
21404e49867SJeff LaBundy 		.name = "event-touch",
21504e49867SJeff LaBundy 		.st_offs = IQS269_ST_OFFS_TOUCH,
21604e49867SJeff LaBundy 		.th_offs = IQS269_TH_OFFS_TOUCH,
21704e49867SJeff LaBundy 		.mask = IQS269_EVENT_MASK_TOUCH,
21804e49867SJeff LaBundy 	},
21904e49867SJeff LaBundy 	[IQS269_EVENT_TOUCH_UP] = {
22004e49867SJeff LaBundy 		.name = "event-touch-alt",
22104e49867SJeff LaBundy 		.st_offs = IQS269_ST_OFFS_TOUCH,
22204e49867SJeff LaBundy 		.th_offs = IQS269_TH_OFFS_TOUCH,
22304e49867SJeff LaBundy 		.dir_up = true,
22404e49867SJeff LaBundy 		.mask = IQS269_EVENT_MASK_TOUCH,
22504e49867SJeff LaBundy 	},
22604e49867SJeff LaBundy 	[IQS269_EVENT_DEEP_DN] = {
22704e49867SJeff LaBundy 		.name = "event-deep",
22804e49867SJeff LaBundy 		.st_offs = IQS269_ST_OFFS_DEEP,
22904e49867SJeff LaBundy 		.th_offs = IQS269_TH_OFFS_DEEP,
23004e49867SJeff LaBundy 		.mask = IQS269_EVENT_MASK_DEEP,
23104e49867SJeff LaBundy 	},
23204e49867SJeff LaBundy 	[IQS269_EVENT_DEEP_UP] = {
23304e49867SJeff LaBundy 		.name = "event-deep-alt",
23404e49867SJeff LaBundy 		.st_offs = IQS269_ST_OFFS_DEEP,
23504e49867SJeff LaBundy 		.th_offs = IQS269_TH_OFFS_DEEP,
23604e49867SJeff LaBundy 		.dir_up = true,
23704e49867SJeff LaBundy 		.mask = IQS269_EVENT_MASK_DEEP,
23804e49867SJeff LaBundy 	},
23904e49867SJeff LaBundy };
24004e49867SJeff LaBundy 
24104e49867SJeff LaBundy struct iqs269_ver_info {
24204e49867SJeff LaBundy 	u8 prod_num;
24304e49867SJeff LaBundy 	u8 sw_num;
24404e49867SJeff LaBundy 	u8 hw_num;
24504e49867SJeff LaBundy 	u8 padding;
24604e49867SJeff LaBundy } __packed;
24704e49867SJeff LaBundy 
24804e49867SJeff LaBundy struct iqs269_sys_reg {
24904e49867SJeff LaBundy 	__be16 general;
25004e49867SJeff LaBundy 	u8 active;
25104e49867SJeff LaBundy 	u8 filter;
25204e49867SJeff LaBundy 	u8 reseed;
25304e49867SJeff LaBundy 	u8 event_mask;
25404e49867SJeff LaBundy 	u8 rate_np;
25504e49867SJeff LaBundy 	u8 rate_lp;
25604e49867SJeff LaBundy 	u8 rate_ulp;
25704e49867SJeff LaBundy 	u8 timeout_pwr;
25804e49867SJeff LaBundy 	u8 timeout_rdy;
25904e49867SJeff LaBundy 	u8 timeout_lta;
26004e49867SJeff LaBundy 	__be16 misc_a;
26104e49867SJeff LaBundy 	__be16 misc_b;
26204e49867SJeff LaBundy 	u8 blocking;
26304e49867SJeff LaBundy 	u8 padding;
26404e49867SJeff LaBundy 	u8 slider_select[IQS269_NUM_SL];
26504e49867SJeff LaBundy 	u8 timeout_tap;
26604e49867SJeff LaBundy 	u8 timeout_swipe;
26704e49867SJeff LaBundy 	u8 thresh_swipe;
26804e49867SJeff LaBundy 	u8 redo_ati;
26904e49867SJeff LaBundy } __packed;
27004e49867SJeff LaBundy 
27104e49867SJeff LaBundy struct iqs269_ch_reg {
27204e49867SJeff LaBundy 	u8 rx_enable;
27304e49867SJeff LaBundy 	u8 tx_enable;
27404e49867SJeff LaBundy 	__be16 engine_a;
27504e49867SJeff LaBundy 	__be16 engine_b;
27604e49867SJeff LaBundy 	__be16 ati_comp;
27704e49867SJeff LaBundy 	u8 thresh[3];
27804e49867SJeff LaBundy 	u8 hyst;
27904e49867SJeff LaBundy 	u8 assoc_select;
28004e49867SJeff LaBundy 	u8 assoc_weight;
28104e49867SJeff LaBundy } __packed;
28204e49867SJeff LaBundy 
28304e49867SJeff LaBundy struct iqs269_flags {
28404e49867SJeff LaBundy 	__be16 system;
28504e49867SJeff LaBundy 	u8 gesture;
28604e49867SJeff LaBundy 	u8 padding;
28704e49867SJeff LaBundy 	u8 states[4];
28804e49867SJeff LaBundy } __packed;
28904e49867SJeff LaBundy 
29004e49867SJeff LaBundy struct iqs269_private {
29104e49867SJeff LaBundy 	struct i2c_client *client;
29204e49867SJeff LaBundy 	struct regmap *regmap;
29304e49867SJeff LaBundy 	struct mutex lock;
29404e49867SJeff LaBundy 	struct iqs269_switch_desc switches[ARRAY_SIZE(iqs269_events)];
29504e49867SJeff LaBundy 	struct iqs269_ch_reg ch_reg[IQS269_NUM_CH];
29604e49867SJeff LaBundy 	struct iqs269_sys_reg sys_reg;
29704e49867SJeff LaBundy 	struct input_dev *keypad;
29804e49867SJeff LaBundy 	struct input_dev *slider[IQS269_NUM_SL];
29904e49867SJeff LaBundy 	unsigned int keycode[ARRAY_SIZE(iqs269_events) * IQS269_NUM_CH];
30004e49867SJeff LaBundy 	unsigned int suspend_mode;
30104e49867SJeff LaBundy 	unsigned int delay_mult;
30204e49867SJeff LaBundy 	unsigned int ch_num;
30304e49867SJeff LaBundy 	bool hall_enable;
30404e49867SJeff LaBundy 	bool ati_current;
30504e49867SJeff LaBundy };
30604e49867SJeff LaBundy 
30704e49867SJeff LaBundy static int iqs269_ati_mode_set(struct iqs269_private *iqs269,
30804e49867SJeff LaBundy 			       unsigned int ch_num, unsigned int mode)
30904e49867SJeff LaBundy {
31004e49867SJeff LaBundy 	u16 engine_a;
31104e49867SJeff LaBundy 
31204e49867SJeff LaBundy 	if (ch_num >= IQS269_NUM_CH)
31304e49867SJeff LaBundy 		return -EINVAL;
31404e49867SJeff LaBundy 
31504e49867SJeff LaBundy 	if (mode > IQS269_CHx_ENG_A_ATI_MODE_MAX)
31604e49867SJeff LaBundy 		return -EINVAL;
31704e49867SJeff LaBundy 
31804e49867SJeff LaBundy 	mutex_lock(&iqs269->lock);
31904e49867SJeff LaBundy 
32004e49867SJeff LaBundy 	engine_a = be16_to_cpu(iqs269->ch_reg[ch_num].engine_a);
32104e49867SJeff LaBundy 
32204e49867SJeff LaBundy 	engine_a &= ~IQS269_CHx_ENG_A_ATI_MODE_MASK;
32304e49867SJeff LaBundy 	engine_a |= (mode << IQS269_CHx_ENG_A_ATI_MODE_SHIFT);
32404e49867SJeff LaBundy 
32504e49867SJeff LaBundy 	iqs269->ch_reg[ch_num].engine_a = cpu_to_be16(engine_a);
32604e49867SJeff LaBundy 	iqs269->ati_current = false;
32704e49867SJeff LaBundy 
32804e49867SJeff LaBundy 	mutex_unlock(&iqs269->lock);
32904e49867SJeff LaBundy 
33004e49867SJeff LaBundy 	return 0;
33104e49867SJeff LaBundy }
33204e49867SJeff LaBundy 
33304e49867SJeff LaBundy static int iqs269_ati_mode_get(struct iqs269_private *iqs269,
33404e49867SJeff LaBundy 			       unsigned int ch_num, unsigned int *mode)
33504e49867SJeff LaBundy {
33604e49867SJeff LaBundy 	u16 engine_a;
33704e49867SJeff LaBundy 
33804e49867SJeff LaBundy 	if (ch_num >= IQS269_NUM_CH)
33904e49867SJeff LaBundy 		return -EINVAL;
34004e49867SJeff LaBundy 
34104e49867SJeff LaBundy 	mutex_lock(&iqs269->lock);
34204e49867SJeff LaBundy 	engine_a = be16_to_cpu(iqs269->ch_reg[ch_num].engine_a);
34304e49867SJeff LaBundy 	mutex_unlock(&iqs269->lock);
34404e49867SJeff LaBundy 
34504e49867SJeff LaBundy 	engine_a &= IQS269_CHx_ENG_A_ATI_MODE_MASK;
34604e49867SJeff LaBundy 	*mode = (engine_a >> IQS269_CHx_ENG_A_ATI_MODE_SHIFT);
34704e49867SJeff LaBundy 
34804e49867SJeff LaBundy 	return 0;
34904e49867SJeff LaBundy }
35004e49867SJeff LaBundy 
35104e49867SJeff LaBundy static int iqs269_ati_base_set(struct iqs269_private *iqs269,
35204e49867SJeff LaBundy 			       unsigned int ch_num, unsigned int base)
35304e49867SJeff LaBundy {
35404e49867SJeff LaBundy 	u16 engine_b;
35504e49867SJeff LaBundy 
35604e49867SJeff LaBundy 	if (ch_num >= IQS269_NUM_CH)
35704e49867SJeff LaBundy 		return -EINVAL;
35804e49867SJeff LaBundy 
35904e49867SJeff LaBundy 	switch (base) {
36004e49867SJeff LaBundy 	case 75:
36104e49867SJeff LaBundy 		base = IQS269_CHx_ENG_B_ATI_BASE_75;
36204e49867SJeff LaBundy 		break;
36304e49867SJeff LaBundy 
36404e49867SJeff LaBundy 	case 100:
36504e49867SJeff LaBundy 		base = IQS269_CHx_ENG_B_ATI_BASE_100;
36604e49867SJeff LaBundy 		break;
36704e49867SJeff LaBundy 
36804e49867SJeff LaBundy 	case 150:
36904e49867SJeff LaBundy 		base = IQS269_CHx_ENG_B_ATI_BASE_150;
37004e49867SJeff LaBundy 		break;
37104e49867SJeff LaBundy 
37204e49867SJeff LaBundy 	case 200:
37304e49867SJeff LaBundy 		base = IQS269_CHx_ENG_B_ATI_BASE_200;
37404e49867SJeff LaBundy 		break;
37504e49867SJeff LaBundy 
37604e49867SJeff LaBundy 	default:
37704e49867SJeff LaBundy 		return -EINVAL;
37804e49867SJeff LaBundy 	}
37904e49867SJeff LaBundy 
38004e49867SJeff LaBundy 	mutex_lock(&iqs269->lock);
38104e49867SJeff LaBundy 
38204e49867SJeff LaBundy 	engine_b = be16_to_cpu(iqs269->ch_reg[ch_num].engine_b);
38304e49867SJeff LaBundy 
38404e49867SJeff LaBundy 	engine_b &= ~IQS269_CHx_ENG_B_ATI_BASE_MASK;
38504e49867SJeff LaBundy 	engine_b |= base;
38604e49867SJeff LaBundy 
38704e49867SJeff LaBundy 	iqs269->ch_reg[ch_num].engine_b = cpu_to_be16(engine_b);
38804e49867SJeff LaBundy 	iqs269->ati_current = false;
38904e49867SJeff LaBundy 
39004e49867SJeff LaBundy 	mutex_unlock(&iqs269->lock);
39104e49867SJeff LaBundy 
39204e49867SJeff LaBundy 	return 0;
39304e49867SJeff LaBundy }
39404e49867SJeff LaBundy 
39504e49867SJeff LaBundy static int iqs269_ati_base_get(struct iqs269_private *iqs269,
39604e49867SJeff LaBundy 			       unsigned int ch_num, unsigned int *base)
39704e49867SJeff LaBundy {
39804e49867SJeff LaBundy 	u16 engine_b;
39904e49867SJeff LaBundy 
40004e49867SJeff LaBundy 	if (ch_num >= IQS269_NUM_CH)
40104e49867SJeff LaBundy 		return -EINVAL;
40204e49867SJeff LaBundy 
40304e49867SJeff LaBundy 	mutex_lock(&iqs269->lock);
40404e49867SJeff LaBundy 	engine_b = be16_to_cpu(iqs269->ch_reg[ch_num].engine_b);
40504e49867SJeff LaBundy 	mutex_unlock(&iqs269->lock);
40604e49867SJeff LaBundy 
40704e49867SJeff LaBundy 	switch (engine_b & IQS269_CHx_ENG_B_ATI_BASE_MASK) {
40804e49867SJeff LaBundy 	case IQS269_CHx_ENG_B_ATI_BASE_75:
40904e49867SJeff LaBundy 		*base = 75;
41004e49867SJeff LaBundy 		return 0;
41104e49867SJeff LaBundy 
41204e49867SJeff LaBundy 	case IQS269_CHx_ENG_B_ATI_BASE_100:
41304e49867SJeff LaBundy 		*base = 100;
41404e49867SJeff LaBundy 		return 0;
41504e49867SJeff LaBundy 
41604e49867SJeff LaBundy 	case IQS269_CHx_ENG_B_ATI_BASE_150:
41704e49867SJeff LaBundy 		*base = 150;
41804e49867SJeff LaBundy 		return 0;
41904e49867SJeff LaBundy 
42004e49867SJeff LaBundy 	case IQS269_CHx_ENG_B_ATI_BASE_200:
42104e49867SJeff LaBundy 		*base = 200;
42204e49867SJeff LaBundy 		return 0;
42304e49867SJeff LaBundy 
42404e49867SJeff LaBundy 	default:
42504e49867SJeff LaBundy 		return -EINVAL;
42604e49867SJeff LaBundy 	}
42704e49867SJeff LaBundy }
42804e49867SJeff LaBundy 
42904e49867SJeff LaBundy static int iqs269_ati_target_set(struct iqs269_private *iqs269,
43004e49867SJeff LaBundy 				 unsigned int ch_num, unsigned int target)
43104e49867SJeff LaBundy {
43204e49867SJeff LaBundy 	u16 engine_b;
43304e49867SJeff LaBundy 
43404e49867SJeff LaBundy 	if (ch_num >= IQS269_NUM_CH)
43504e49867SJeff LaBundy 		return -EINVAL;
43604e49867SJeff LaBundy 
43704e49867SJeff LaBundy 	if (target > IQS269_CHx_ENG_B_ATI_TARGET_MAX)
43804e49867SJeff LaBundy 		return -EINVAL;
43904e49867SJeff LaBundy 
44004e49867SJeff LaBundy 	mutex_lock(&iqs269->lock);
44104e49867SJeff LaBundy 
44204e49867SJeff LaBundy 	engine_b = be16_to_cpu(iqs269->ch_reg[ch_num].engine_b);
44304e49867SJeff LaBundy 
44404e49867SJeff LaBundy 	engine_b &= ~IQS269_CHx_ENG_B_ATI_TARGET_MASK;
44504e49867SJeff LaBundy 	engine_b |= target / 32;
44604e49867SJeff LaBundy 
44704e49867SJeff LaBundy 	iqs269->ch_reg[ch_num].engine_b = cpu_to_be16(engine_b);
44804e49867SJeff LaBundy 	iqs269->ati_current = false;
44904e49867SJeff LaBundy 
45004e49867SJeff LaBundy 	mutex_unlock(&iqs269->lock);
45104e49867SJeff LaBundy 
45204e49867SJeff LaBundy 	return 0;
45304e49867SJeff LaBundy }
45404e49867SJeff LaBundy 
45504e49867SJeff LaBundy static int iqs269_ati_target_get(struct iqs269_private *iqs269,
45604e49867SJeff LaBundy 				 unsigned int ch_num, unsigned int *target)
45704e49867SJeff LaBundy {
45804e49867SJeff LaBundy 	u16 engine_b;
45904e49867SJeff LaBundy 
46004e49867SJeff LaBundy 	if (ch_num >= IQS269_NUM_CH)
46104e49867SJeff LaBundy 		return -EINVAL;
46204e49867SJeff LaBundy 
46304e49867SJeff LaBundy 	mutex_lock(&iqs269->lock);
46404e49867SJeff LaBundy 	engine_b = be16_to_cpu(iqs269->ch_reg[ch_num].engine_b);
46504e49867SJeff LaBundy 	mutex_unlock(&iqs269->lock);
46604e49867SJeff LaBundy 
46704e49867SJeff LaBundy 	*target = (engine_b & IQS269_CHx_ENG_B_ATI_TARGET_MASK) * 32;
46804e49867SJeff LaBundy 
46904e49867SJeff LaBundy 	return 0;
47004e49867SJeff LaBundy }
47104e49867SJeff LaBundy 
47204e49867SJeff LaBundy static int iqs269_parse_mask(const struct fwnode_handle *fwnode,
47304e49867SJeff LaBundy 			     const char *propname, u8 *mask)
47404e49867SJeff LaBundy {
47504e49867SJeff LaBundy 	unsigned int val[IQS269_NUM_CH];
47604e49867SJeff LaBundy 	int count, error, i;
47704e49867SJeff LaBundy 
47804e49867SJeff LaBundy 	count = fwnode_property_count_u32(fwnode, propname);
47904e49867SJeff LaBundy 	if (count < 0)
48004e49867SJeff LaBundy 		return 0;
48104e49867SJeff LaBundy 
48204e49867SJeff LaBundy 	if (count > IQS269_NUM_CH)
48304e49867SJeff LaBundy 		return -EINVAL;
48404e49867SJeff LaBundy 
48504e49867SJeff LaBundy 	error = fwnode_property_read_u32_array(fwnode, propname, val, count);
48604e49867SJeff LaBundy 	if (error)
48704e49867SJeff LaBundy 		return error;
48804e49867SJeff LaBundy 
48904e49867SJeff LaBundy 	*mask = 0;
49004e49867SJeff LaBundy 
49104e49867SJeff LaBundy 	for (i = 0; i < count; i++) {
49204e49867SJeff LaBundy 		if (val[i] >= IQS269_NUM_CH)
49304e49867SJeff LaBundy 			return -EINVAL;
49404e49867SJeff LaBundy 
49504e49867SJeff LaBundy 		*mask |= BIT(val[i]);
49604e49867SJeff LaBundy 	}
49704e49867SJeff LaBundy 
49804e49867SJeff LaBundy 	return 0;
49904e49867SJeff LaBundy }
50004e49867SJeff LaBundy 
50104e49867SJeff LaBundy static int iqs269_parse_chan(struct iqs269_private *iqs269,
50204e49867SJeff LaBundy 			     const struct fwnode_handle *ch_node)
50304e49867SJeff LaBundy {
50404e49867SJeff LaBundy 	struct i2c_client *client = iqs269->client;
50504e49867SJeff LaBundy 	struct fwnode_handle *ev_node;
50604e49867SJeff LaBundy 	struct iqs269_ch_reg *ch_reg;
50704e49867SJeff LaBundy 	u16 engine_a, engine_b;
50804e49867SJeff LaBundy 	unsigned int reg, val;
50904e49867SJeff LaBundy 	int error, i;
51004e49867SJeff LaBundy 
51104e49867SJeff LaBundy 	error = fwnode_property_read_u32(ch_node, "reg", &reg);
51204e49867SJeff LaBundy 	if (error) {
51304e49867SJeff LaBundy 		dev_err(&client->dev, "Failed to read channel number: %d\n",
51404e49867SJeff LaBundy 			error);
51504e49867SJeff LaBundy 		return error;
51604e49867SJeff LaBundy 	} else if (reg >= IQS269_NUM_CH) {
51704e49867SJeff LaBundy 		dev_err(&client->dev, "Invalid channel number: %u\n", reg);
51804e49867SJeff LaBundy 		return -EINVAL;
51904e49867SJeff LaBundy 	}
52004e49867SJeff LaBundy 
52104e49867SJeff LaBundy 	iqs269->sys_reg.active |= BIT(reg);
52204e49867SJeff LaBundy 	if (!fwnode_property_present(ch_node, "azoteq,reseed-disable"))
52304e49867SJeff LaBundy 		iqs269->sys_reg.reseed |= BIT(reg);
52404e49867SJeff LaBundy 
52504e49867SJeff LaBundy 	if (fwnode_property_present(ch_node, "azoteq,blocking-enable"))
52604e49867SJeff LaBundy 		iqs269->sys_reg.blocking |= BIT(reg);
52704e49867SJeff LaBundy 
52804e49867SJeff LaBundy 	if (fwnode_property_present(ch_node, "azoteq,slider0-select"))
52904e49867SJeff LaBundy 		iqs269->sys_reg.slider_select[0] |= BIT(reg);
53004e49867SJeff LaBundy 
53104e49867SJeff LaBundy 	if (fwnode_property_present(ch_node, "azoteq,slider1-select"))
53204e49867SJeff LaBundy 		iqs269->sys_reg.slider_select[1] |= BIT(reg);
53304e49867SJeff LaBundy 
53404e49867SJeff LaBundy 	ch_reg = &iqs269->ch_reg[reg];
53504e49867SJeff LaBundy 
53604e49867SJeff LaBundy 	error = regmap_raw_read(iqs269->regmap,
53704e49867SJeff LaBundy 				IQS269_CHx_SETTINGS + reg * sizeof(*ch_reg) / 2,
53804e49867SJeff LaBundy 				ch_reg, sizeof(*ch_reg));
53904e49867SJeff LaBundy 	if (error)
54004e49867SJeff LaBundy 		return error;
54104e49867SJeff LaBundy 
54204e49867SJeff LaBundy 	error = iqs269_parse_mask(ch_node, "azoteq,rx-enable",
54304e49867SJeff LaBundy 				  &ch_reg->rx_enable);
54404e49867SJeff LaBundy 	if (error) {
54504e49867SJeff LaBundy 		dev_err(&client->dev, "Invalid channel %u RX enable mask: %d\n",
54604e49867SJeff LaBundy 			reg, error);
54704e49867SJeff LaBundy 		return error;
54804e49867SJeff LaBundy 	}
54904e49867SJeff LaBundy 
55004e49867SJeff LaBundy 	error = iqs269_parse_mask(ch_node, "azoteq,tx-enable",
55104e49867SJeff LaBundy 				  &ch_reg->tx_enable);
55204e49867SJeff LaBundy 	if (error) {
55304e49867SJeff LaBundy 		dev_err(&client->dev, "Invalid channel %u TX enable mask: %d\n",
55404e49867SJeff LaBundy 			reg, error);
55504e49867SJeff LaBundy 		return error;
55604e49867SJeff LaBundy 	}
55704e49867SJeff LaBundy 
55804e49867SJeff LaBundy 	engine_a = be16_to_cpu(ch_reg->engine_a);
55904e49867SJeff LaBundy 	engine_b = be16_to_cpu(ch_reg->engine_b);
56004e49867SJeff LaBundy 
56104e49867SJeff LaBundy 	engine_a |= IQS269_CHx_ENG_A_MEAS_CAP_SIZE;
56204e49867SJeff LaBundy 	if (fwnode_property_present(ch_node, "azoteq,meas-cap-decrease"))
56304e49867SJeff LaBundy 		engine_a &= ~IQS269_CHx_ENG_A_MEAS_CAP_SIZE;
56404e49867SJeff LaBundy 
56504e49867SJeff LaBundy 	engine_a |= IQS269_CHx_ENG_A_RX_GND_INACTIVE;
56604e49867SJeff LaBundy 	if (fwnode_property_present(ch_node, "azoteq,rx-float-inactive"))
56704e49867SJeff LaBundy 		engine_a &= ~IQS269_CHx_ENG_A_RX_GND_INACTIVE;
56804e49867SJeff LaBundy 
56904e49867SJeff LaBundy 	engine_a &= ~IQS269_CHx_ENG_A_LOCAL_CAP_SIZE;
57004e49867SJeff LaBundy 	engine_b &= ~IQS269_CHx_ENG_B_LOCAL_CAP_ENABLE;
57104e49867SJeff LaBundy 	if (!fwnode_property_read_u32(ch_node, "azoteq,local-cap-size", &val)) {
57204e49867SJeff LaBundy 		switch (val) {
57304e49867SJeff LaBundy 		case IQS269_LOCAL_CAP_SIZE_0:
57404e49867SJeff LaBundy 			break;
57504e49867SJeff LaBundy 
57604e49867SJeff LaBundy 		case IQS269_LOCAL_CAP_SIZE_GLOBAL_0pF5:
57704e49867SJeff LaBundy 			engine_a |= IQS269_CHx_ENG_A_LOCAL_CAP_SIZE;
5786f49c4f5SGustavo A. R. Silva 			fallthrough;
57904e49867SJeff LaBundy 
58004e49867SJeff LaBundy 		case IQS269_LOCAL_CAP_SIZE_GLOBAL_ONLY:
58104e49867SJeff LaBundy 			engine_b |= IQS269_CHx_ENG_B_LOCAL_CAP_ENABLE;
58204e49867SJeff LaBundy 			break;
58304e49867SJeff LaBundy 
58404e49867SJeff LaBundy 		default:
58504e49867SJeff LaBundy 			dev_err(&client->dev,
58604e49867SJeff LaBundy 				"Invalid channel %u local cap. size: %u\n", reg,
58704e49867SJeff LaBundy 				val);
58804e49867SJeff LaBundy 			return -EINVAL;
58904e49867SJeff LaBundy 		}
59004e49867SJeff LaBundy 	}
59104e49867SJeff LaBundy 
59204e49867SJeff LaBundy 	engine_a &= ~IQS269_CHx_ENG_A_INV_LOGIC;
59304e49867SJeff LaBundy 	if (fwnode_property_present(ch_node, "azoteq,invert-enable"))
59404e49867SJeff LaBundy 		engine_a |= IQS269_CHx_ENG_A_INV_LOGIC;
59504e49867SJeff LaBundy 
59604e49867SJeff LaBundy 	if (!fwnode_property_read_u32(ch_node, "azoteq,proj-bias", &val)) {
59704e49867SJeff LaBundy 		if (val > IQS269_CHx_ENG_A_PROJ_BIAS_MAX) {
59804e49867SJeff LaBundy 			dev_err(&client->dev,
59904e49867SJeff LaBundy 				"Invalid channel %u bias current: %u\n", reg,
60004e49867SJeff LaBundy 				val);
60104e49867SJeff LaBundy 			return -EINVAL;
60204e49867SJeff LaBundy 		}
60304e49867SJeff LaBundy 
60404e49867SJeff LaBundy 		engine_a &= ~IQS269_CHx_ENG_A_PROJ_BIAS_MASK;
60504e49867SJeff LaBundy 		engine_a |= (val << IQS269_CHx_ENG_A_PROJ_BIAS_SHIFT);
60604e49867SJeff LaBundy 	}
60704e49867SJeff LaBundy 
60804e49867SJeff LaBundy 	if (!fwnode_property_read_u32(ch_node, "azoteq,sense-mode", &val)) {
60904e49867SJeff LaBundy 		if (val > IQS269_CHx_ENG_A_SENSE_MODE_MAX) {
61004e49867SJeff LaBundy 			dev_err(&client->dev,
61104e49867SJeff LaBundy 				"Invalid channel %u sensing mode: %u\n", reg,
61204e49867SJeff LaBundy 				val);
61304e49867SJeff LaBundy 			return -EINVAL;
61404e49867SJeff LaBundy 		}
61504e49867SJeff LaBundy 
61604e49867SJeff LaBundy 		engine_a &= ~IQS269_CHx_ENG_A_SENSE_MODE_MASK;
61704e49867SJeff LaBundy 		engine_a |= val;
61804e49867SJeff LaBundy 	}
61904e49867SJeff LaBundy 
62004e49867SJeff LaBundy 	if (!fwnode_property_read_u32(ch_node, "azoteq,sense-freq", &val)) {
62104e49867SJeff LaBundy 		if (val > IQS269_CHx_ENG_B_SENSE_FREQ_MAX) {
62204e49867SJeff LaBundy 			dev_err(&client->dev,
62304e49867SJeff LaBundy 				"Invalid channel %u sensing frequency: %u\n",
62404e49867SJeff LaBundy 				reg, val);
62504e49867SJeff LaBundy 			return -EINVAL;
62604e49867SJeff LaBundy 		}
62704e49867SJeff LaBundy 
62804e49867SJeff LaBundy 		engine_b &= ~IQS269_CHx_ENG_B_SENSE_FREQ_MASK;
62904e49867SJeff LaBundy 		engine_b |= (val << IQS269_CHx_ENG_B_SENSE_FREQ_SHIFT);
63004e49867SJeff LaBundy 	}
63104e49867SJeff LaBundy 
63204e49867SJeff LaBundy 	engine_b &= ~IQS269_CHx_ENG_B_STATIC_ENABLE;
63304e49867SJeff LaBundy 	if (fwnode_property_present(ch_node, "azoteq,static-enable"))
63404e49867SJeff LaBundy 		engine_b |= IQS269_CHx_ENG_B_STATIC_ENABLE;
63504e49867SJeff LaBundy 
63604e49867SJeff LaBundy 	ch_reg->engine_a = cpu_to_be16(engine_a);
63704e49867SJeff LaBundy 	ch_reg->engine_b = cpu_to_be16(engine_b);
63804e49867SJeff LaBundy 
63904e49867SJeff LaBundy 	if (!fwnode_property_read_u32(ch_node, "azoteq,ati-mode", &val)) {
64004e49867SJeff LaBundy 		error = iqs269_ati_mode_set(iqs269, reg, val);
64104e49867SJeff LaBundy 		if (error) {
64204e49867SJeff LaBundy 			dev_err(&client->dev,
64304e49867SJeff LaBundy 				"Invalid channel %u ATI mode: %u\n", reg, val);
64404e49867SJeff LaBundy 			return error;
64504e49867SJeff LaBundy 		}
64604e49867SJeff LaBundy 	}
64704e49867SJeff LaBundy 
64804e49867SJeff LaBundy 	if (!fwnode_property_read_u32(ch_node, "azoteq,ati-base", &val)) {
64904e49867SJeff LaBundy 		error = iqs269_ati_base_set(iqs269, reg, val);
65004e49867SJeff LaBundy 		if (error) {
65104e49867SJeff LaBundy 			dev_err(&client->dev,
65204e49867SJeff LaBundy 				"Invalid channel %u ATI base: %u\n", reg, val);
65304e49867SJeff LaBundy 			return error;
65404e49867SJeff LaBundy 		}
65504e49867SJeff LaBundy 	}
65604e49867SJeff LaBundy 
65704e49867SJeff LaBundy 	if (!fwnode_property_read_u32(ch_node, "azoteq,ati-target", &val)) {
65804e49867SJeff LaBundy 		error = iqs269_ati_target_set(iqs269, reg, val);
65904e49867SJeff LaBundy 		if (error) {
66004e49867SJeff LaBundy 			dev_err(&client->dev,
66104e49867SJeff LaBundy 				"Invalid channel %u ATI target: %u\n", reg,
66204e49867SJeff LaBundy 				val);
66304e49867SJeff LaBundy 			return error;
66404e49867SJeff LaBundy 		}
66504e49867SJeff LaBundy 	}
66604e49867SJeff LaBundy 
66704e49867SJeff LaBundy 	error = iqs269_parse_mask(ch_node, "azoteq,assoc-select",
66804e49867SJeff LaBundy 				  &ch_reg->assoc_select);
66904e49867SJeff LaBundy 	if (error) {
67004e49867SJeff LaBundy 		dev_err(&client->dev, "Invalid channel %u association: %d\n",
67104e49867SJeff LaBundy 			reg, error);
67204e49867SJeff LaBundy 		return error;
67304e49867SJeff LaBundy 	}
67404e49867SJeff LaBundy 
67504e49867SJeff LaBundy 	if (!fwnode_property_read_u32(ch_node, "azoteq,assoc-weight", &val)) {
67604e49867SJeff LaBundy 		if (val > IQS269_CHx_WEIGHT_MAX) {
67704e49867SJeff LaBundy 			dev_err(&client->dev,
67804e49867SJeff LaBundy 				"Invalid channel %u associated weight: %u\n",
67904e49867SJeff LaBundy 				reg, val);
68004e49867SJeff LaBundy 			return -EINVAL;
68104e49867SJeff LaBundy 		}
68204e49867SJeff LaBundy 
68304e49867SJeff LaBundy 		ch_reg->assoc_weight = val;
68404e49867SJeff LaBundy 	}
68504e49867SJeff LaBundy 
68604e49867SJeff LaBundy 	for (i = 0; i < ARRAY_SIZE(iqs269_events); i++) {
68704e49867SJeff LaBundy 		ev_node = fwnode_get_named_child_node(ch_node,
68804e49867SJeff LaBundy 						      iqs269_events[i].name);
68904e49867SJeff LaBundy 		if (!ev_node)
69004e49867SJeff LaBundy 			continue;
69104e49867SJeff LaBundy 
69204e49867SJeff LaBundy 		if (!fwnode_property_read_u32(ev_node, "azoteq,thresh", &val)) {
69304e49867SJeff LaBundy 			if (val > IQS269_CHx_THRESH_MAX) {
69404e49867SJeff LaBundy 				dev_err(&client->dev,
69504e49867SJeff LaBundy 					"Invalid channel %u threshold: %u\n",
69604e49867SJeff LaBundy 					reg, val);
69704e49867SJeff LaBundy 				return -EINVAL;
69804e49867SJeff LaBundy 			}
69904e49867SJeff LaBundy 
70004e49867SJeff LaBundy 			ch_reg->thresh[iqs269_events[i].th_offs] = val;
70104e49867SJeff LaBundy 		}
70204e49867SJeff LaBundy 
70304e49867SJeff LaBundy 		if (!fwnode_property_read_u32(ev_node, "azoteq,hyst", &val)) {
70404e49867SJeff LaBundy 			u8 *hyst = &ch_reg->hyst;
70504e49867SJeff LaBundy 
70604e49867SJeff LaBundy 			if (val > IQS269_CHx_HYST_MAX) {
70704e49867SJeff LaBundy 				dev_err(&client->dev,
70804e49867SJeff LaBundy 					"Invalid channel %u hysteresis: %u\n",
70904e49867SJeff LaBundy 					reg, val);
71004e49867SJeff LaBundy 				return -EINVAL;
71104e49867SJeff LaBundy 			}
71204e49867SJeff LaBundy 
71304e49867SJeff LaBundy 			if (i == IQS269_EVENT_DEEP_DN ||
71404e49867SJeff LaBundy 			    i == IQS269_EVENT_DEEP_UP) {
71504e49867SJeff LaBundy 				*hyst &= ~IQS269_CHx_HYST_DEEP_MASK;
71604e49867SJeff LaBundy 				*hyst |= (val << IQS269_CHx_HYST_DEEP_SHIFT);
71704e49867SJeff LaBundy 			} else if (i == IQS269_EVENT_TOUCH_DN ||
71804e49867SJeff LaBundy 				   i == IQS269_EVENT_TOUCH_UP) {
71904e49867SJeff LaBundy 				*hyst &= ~IQS269_CHx_HYST_TOUCH_MASK;
72004e49867SJeff LaBundy 				*hyst |= val;
72104e49867SJeff LaBundy 			}
72204e49867SJeff LaBundy 		}
72304e49867SJeff LaBundy 
72404e49867SJeff LaBundy 		if (fwnode_property_read_u32(ev_node, "linux,code", &val))
72504e49867SJeff LaBundy 			continue;
72604e49867SJeff LaBundy 
72704e49867SJeff LaBundy 		switch (reg) {
72804e49867SJeff LaBundy 		case IQS269_CHx_HALL_ACTIVE:
72904e49867SJeff LaBundy 			if (iqs269->hall_enable) {
73004e49867SJeff LaBundy 				iqs269->switches[i].code = val;
73104e49867SJeff LaBundy 				iqs269->switches[i].enabled = true;
73204e49867SJeff LaBundy 			}
7336f49c4f5SGustavo A. R. Silva 			fallthrough;
73404e49867SJeff LaBundy 
73504e49867SJeff LaBundy 		case IQS269_CHx_HALL_INACTIVE:
73604e49867SJeff LaBundy 			if (iqs269->hall_enable)
73704e49867SJeff LaBundy 				break;
7386f49c4f5SGustavo A. R. Silva 			fallthrough;
73904e49867SJeff LaBundy 
74004e49867SJeff LaBundy 		default:
74104e49867SJeff LaBundy 			iqs269->keycode[i * IQS269_NUM_CH + reg] = val;
74204e49867SJeff LaBundy 		}
74304e49867SJeff LaBundy 
74404e49867SJeff LaBundy 		iqs269->sys_reg.event_mask &= ~iqs269_events[i].mask;
74504e49867SJeff LaBundy 	}
74604e49867SJeff LaBundy 
74704e49867SJeff LaBundy 	return 0;
74804e49867SJeff LaBundy }
74904e49867SJeff LaBundy 
75004e49867SJeff LaBundy static int iqs269_parse_prop(struct iqs269_private *iqs269)
75104e49867SJeff LaBundy {
75204e49867SJeff LaBundy 	struct iqs269_sys_reg *sys_reg = &iqs269->sys_reg;
75304e49867SJeff LaBundy 	struct i2c_client *client = iqs269->client;
75404e49867SJeff LaBundy 	struct fwnode_handle *ch_node;
75504e49867SJeff LaBundy 	u16 general, misc_a, misc_b;
75604e49867SJeff LaBundy 	unsigned int val;
75704e49867SJeff LaBundy 	int error;
75804e49867SJeff LaBundy 
75904e49867SJeff LaBundy 	iqs269->hall_enable = device_property_present(&client->dev,
76004e49867SJeff LaBundy 						      "azoteq,hall-enable");
76104e49867SJeff LaBundy 
76204e49867SJeff LaBundy 	if (!device_property_read_u32(&client->dev, "azoteq,suspend-mode",
76304e49867SJeff LaBundy 				      &val)) {
76404e49867SJeff LaBundy 		if (val > IQS269_SYS_SETTINGS_PWR_MODE_MAX) {
76504e49867SJeff LaBundy 			dev_err(&client->dev, "Invalid suspend mode: %u\n",
76604e49867SJeff LaBundy 				val);
76704e49867SJeff LaBundy 			return -EINVAL;
76804e49867SJeff LaBundy 		}
76904e49867SJeff LaBundy 
77004e49867SJeff LaBundy 		iqs269->suspend_mode = val;
77104e49867SJeff LaBundy 	}
77204e49867SJeff LaBundy 
77304e49867SJeff LaBundy 	error = regmap_raw_read(iqs269->regmap, IQS269_SYS_SETTINGS, sys_reg,
77404e49867SJeff LaBundy 				sizeof(*sys_reg));
77504e49867SJeff LaBundy 	if (error)
77604e49867SJeff LaBundy 		return error;
77704e49867SJeff LaBundy 
77804e49867SJeff LaBundy 	if (!device_property_read_u32(&client->dev, "azoteq,filt-str-lp-lta",
77904e49867SJeff LaBundy 				      &val)) {
78004e49867SJeff LaBundy 		if (val > IQS269_FILT_STR_MAX) {
78104e49867SJeff LaBundy 			dev_err(&client->dev, "Invalid filter strength: %u\n",
78204e49867SJeff LaBundy 				val);
78304e49867SJeff LaBundy 			return -EINVAL;
78404e49867SJeff LaBundy 		}
78504e49867SJeff LaBundy 
78604e49867SJeff LaBundy 		sys_reg->filter &= ~IQS269_FILT_STR_LP_LTA_MASK;
78704e49867SJeff LaBundy 		sys_reg->filter |= (val << IQS269_FILT_STR_LP_LTA_SHIFT);
78804e49867SJeff LaBundy 	}
78904e49867SJeff LaBundy 
79004e49867SJeff LaBundy 	if (!device_property_read_u32(&client->dev, "azoteq,filt-str-lp-cnt",
79104e49867SJeff LaBundy 				      &val)) {
79204e49867SJeff LaBundy 		if (val > IQS269_FILT_STR_MAX) {
79304e49867SJeff LaBundy 			dev_err(&client->dev, "Invalid filter strength: %u\n",
79404e49867SJeff LaBundy 				val);
79504e49867SJeff LaBundy 			return -EINVAL;
79604e49867SJeff LaBundy 		}
79704e49867SJeff LaBundy 
79804e49867SJeff LaBundy 		sys_reg->filter &= ~IQS269_FILT_STR_LP_CNT_MASK;
79904e49867SJeff LaBundy 		sys_reg->filter |= (val << IQS269_FILT_STR_LP_CNT_SHIFT);
80004e49867SJeff LaBundy 	}
80104e49867SJeff LaBundy 
80204e49867SJeff LaBundy 	if (!device_property_read_u32(&client->dev, "azoteq,filt-str-np-lta",
80304e49867SJeff LaBundy 				      &val)) {
80404e49867SJeff LaBundy 		if (val > IQS269_FILT_STR_MAX) {
80504e49867SJeff LaBundy 			dev_err(&client->dev, "Invalid filter strength: %u\n",
80604e49867SJeff LaBundy 				val);
80704e49867SJeff LaBundy 			return -EINVAL;
80804e49867SJeff LaBundy 		}
80904e49867SJeff LaBundy 
81004e49867SJeff LaBundy 		sys_reg->filter &= ~IQS269_FILT_STR_NP_LTA_MASK;
81104e49867SJeff LaBundy 		sys_reg->filter |= (val << IQS269_FILT_STR_NP_LTA_SHIFT);
81204e49867SJeff LaBundy 	}
81304e49867SJeff LaBundy 
81404e49867SJeff LaBundy 	if (!device_property_read_u32(&client->dev, "azoteq,filt-str-np-cnt",
81504e49867SJeff LaBundy 				      &val)) {
81604e49867SJeff LaBundy 		if (val > IQS269_FILT_STR_MAX) {
81704e49867SJeff LaBundy 			dev_err(&client->dev, "Invalid filter strength: %u\n",
81804e49867SJeff LaBundy 				val);
81904e49867SJeff LaBundy 			return -EINVAL;
82004e49867SJeff LaBundy 		}
82104e49867SJeff LaBundy 
82204e49867SJeff LaBundy 		sys_reg->filter &= ~IQS269_FILT_STR_NP_CNT_MASK;
82304e49867SJeff LaBundy 		sys_reg->filter |= val;
82404e49867SJeff LaBundy 	}
82504e49867SJeff LaBundy 
82604e49867SJeff LaBundy 	if (!device_property_read_u32(&client->dev, "azoteq,rate-np-ms",
82704e49867SJeff LaBundy 				      &val)) {
82804e49867SJeff LaBundy 		if (val > IQS269_RATE_NP_MS_MAX) {
82904e49867SJeff LaBundy 			dev_err(&client->dev, "Invalid report rate: %u\n", val);
83004e49867SJeff LaBundy 			return -EINVAL;
83104e49867SJeff LaBundy 		}
83204e49867SJeff LaBundy 
83304e49867SJeff LaBundy 		sys_reg->rate_np = val;
83404e49867SJeff LaBundy 	}
83504e49867SJeff LaBundy 
83604e49867SJeff LaBundy 	if (!device_property_read_u32(&client->dev, "azoteq,rate-lp-ms",
83704e49867SJeff LaBundy 				      &val)) {
83804e49867SJeff LaBundy 		if (val > IQS269_RATE_LP_MS_MAX) {
83904e49867SJeff LaBundy 			dev_err(&client->dev, "Invalid report rate: %u\n", val);
84004e49867SJeff LaBundy 			return -EINVAL;
84104e49867SJeff LaBundy 		}
84204e49867SJeff LaBundy 
84304e49867SJeff LaBundy 		sys_reg->rate_lp = val;
84404e49867SJeff LaBundy 	}
84504e49867SJeff LaBundy 
84604e49867SJeff LaBundy 	if (!device_property_read_u32(&client->dev, "azoteq,rate-ulp-ms",
84704e49867SJeff LaBundy 				      &val)) {
84804e49867SJeff LaBundy 		if (val > IQS269_RATE_ULP_MS_MAX) {
84904e49867SJeff LaBundy 			dev_err(&client->dev, "Invalid report rate: %u\n", val);
85004e49867SJeff LaBundy 			return -EINVAL;
85104e49867SJeff LaBundy 		}
85204e49867SJeff LaBundy 
85304e49867SJeff LaBundy 		sys_reg->rate_ulp = val / 16;
85404e49867SJeff LaBundy 	}
85504e49867SJeff LaBundy 
85604e49867SJeff LaBundy 	if (!device_property_read_u32(&client->dev, "azoteq,timeout-pwr-ms",
85704e49867SJeff LaBundy 				      &val)) {
85804e49867SJeff LaBundy 		if (val > IQS269_TIMEOUT_PWR_MS_MAX) {
85904e49867SJeff LaBundy 			dev_err(&client->dev, "Invalid timeout: %u\n", val);
86004e49867SJeff LaBundy 			return -EINVAL;
86104e49867SJeff LaBundy 		}
86204e49867SJeff LaBundy 
86304e49867SJeff LaBundy 		sys_reg->timeout_pwr = val / 512;
86404e49867SJeff LaBundy 	}
86504e49867SJeff LaBundy 
86604e49867SJeff LaBundy 	if (!device_property_read_u32(&client->dev, "azoteq,timeout-lta-ms",
86704e49867SJeff LaBundy 				      &val)) {
86804e49867SJeff LaBundy 		if (val > IQS269_TIMEOUT_LTA_MS_MAX) {
86904e49867SJeff LaBundy 			dev_err(&client->dev, "Invalid timeout: %u\n", val);
87004e49867SJeff LaBundy 			return -EINVAL;
87104e49867SJeff LaBundy 		}
87204e49867SJeff LaBundy 
87304e49867SJeff LaBundy 		sys_reg->timeout_lta = val / 512;
87404e49867SJeff LaBundy 	}
87504e49867SJeff LaBundy 
87604e49867SJeff LaBundy 	misc_a = be16_to_cpu(sys_reg->misc_a);
87704e49867SJeff LaBundy 	misc_b = be16_to_cpu(sys_reg->misc_b);
87804e49867SJeff LaBundy 
87904e49867SJeff LaBundy 	misc_a &= ~IQS269_MISC_A_ATI_BAND_DISABLE;
88004e49867SJeff LaBundy 	if (device_property_present(&client->dev, "azoteq,ati-band-disable"))
88104e49867SJeff LaBundy 		misc_a |= IQS269_MISC_A_ATI_BAND_DISABLE;
88204e49867SJeff LaBundy 
88304e49867SJeff LaBundy 	misc_a &= ~IQS269_MISC_A_ATI_LP_ONLY;
88404e49867SJeff LaBundy 	if (device_property_present(&client->dev, "azoteq,ati-lp-only"))
88504e49867SJeff LaBundy 		misc_a |= IQS269_MISC_A_ATI_LP_ONLY;
88604e49867SJeff LaBundy 
88704e49867SJeff LaBundy 	misc_a &= ~IQS269_MISC_A_ATI_BAND_TIGHTEN;
88804e49867SJeff LaBundy 	if (device_property_present(&client->dev, "azoteq,ati-band-tighten"))
88904e49867SJeff LaBundy 		misc_a |= IQS269_MISC_A_ATI_BAND_TIGHTEN;
89004e49867SJeff LaBundy 
89104e49867SJeff LaBundy 	misc_a &= ~IQS269_MISC_A_FILT_DISABLE;
89204e49867SJeff LaBundy 	if (device_property_present(&client->dev, "azoteq,filt-disable"))
89304e49867SJeff LaBundy 		misc_a |= IQS269_MISC_A_FILT_DISABLE;
89404e49867SJeff LaBundy 
89504e49867SJeff LaBundy 	if (!device_property_read_u32(&client->dev, "azoteq,gpio3-select",
89604e49867SJeff LaBundy 				      &val)) {
89704e49867SJeff LaBundy 		if (val >= IQS269_NUM_CH) {
89804e49867SJeff LaBundy 			dev_err(&client->dev, "Invalid GPIO3 selection: %u\n",
89904e49867SJeff LaBundy 				val);
90004e49867SJeff LaBundy 			return -EINVAL;
90104e49867SJeff LaBundy 		}
90204e49867SJeff LaBundy 
90304e49867SJeff LaBundy 		misc_a &= ~IQS269_MISC_A_GPIO3_SELECT_MASK;
90404e49867SJeff LaBundy 		misc_a |= (val << IQS269_MISC_A_GPIO3_SELECT_SHIFT);
90504e49867SJeff LaBundy 	}
90604e49867SJeff LaBundy 
90704e49867SJeff LaBundy 	misc_a &= ~IQS269_MISC_A_DUAL_DIR;
90804e49867SJeff LaBundy 	if (device_property_present(&client->dev, "azoteq,dual-direction"))
90904e49867SJeff LaBundy 		misc_a |= IQS269_MISC_A_DUAL_DIR;
91004e49867SJeff LaBundy 
91104e49867SJeff LaBundy 	if (!device_property_read_u32(&client->dev, "azoteq,tx-freq", &val)) {
91204e49867SJeff LaBundy 		if (val > IQS269_MISC_A_TX_FREQ_MAX) {
91304e49867SJeff LaBundy 			dev_err(&client->dev,
91404e49867SJeff LaBundy 				"Invalid excitation frequency: %u\n", val);
91504e49867SJeff LaBundy 			return -EINVAL;
91604e49867SJeff LaBundy 		}
91704e49867SJeff LaBundy 
91804e49867SJeff LaBundy 		misc_a &= ~IQS269_MISC_A_TX_FREQ_MASK;
91904e49867SJeff LaBundy 		misc_a |= (val << IQS269_MISC_A_TX_FREQ_SHIFT);
92004e49867SJeff LaBundy 	}
92104e49867SJeff LaBundy 
92204e49867SJeff LaBundy 	misc_a &= ~IQS269_MISC_A_GLOBAL_CAP_SIZE;
92304e49867SJeff LaBundy 	if (device_property_present(&client->dev, "azoteq,global-cap-increase"))
92404e49867SJeff LaBundy 		misc_a |= IQS269_MISC_A_GLOBAL_CAP_SIZE;
92504e49867SJeff LaBundy 
92604e49867SJeff LaBundy 	if (!device_property_read_u32(&client->dev, "azoteq,reseed-select",
92704e49867SJeff LaBundy 				      &val)) {
92804e49867SJeff LaBundy 		if (val > IQS269_MISC_B_RESEED_UI_SEL_MAX) {
92904e49867SJeff LaBundy 			dev_err(&client->dev, "Invalid reseed selection: %u\n",
93004e49867SJeff LaBundy 				val);
93104e49867SJeff LaBundy 			return -EINVAL;
93204e49867SJeff LaBundy 		}
93304e49867SJeff LaBundy 
93404e49867SJeff LaBundy 		misc_b &= ~IQS269_MISC_B_RESEED_UI_SEL_MASK;
93504e49867SJeff LaBundy 		misc_b |= (val << IQS269_MISC_B_RESEED_UI_SEL_SHIFT);
93604e49867SJeff LaBundy 	}
93704e49867SJeff LaBundy 
93804e49867SJeff LaBundy 	misc_b &= ~IQS269_MISC_B_TRACKING_UI_ENABLE;
93904e49867SJeff LaBundy 	if (device_property_present(&client->dev, "azoteq,tracking-enable"))
94004e49867SJeff LaBundy 		misc_b |= IQS269_MISC_B_TRACKING_UI_ENABLE;
94104e49867SJeff LaBundy 
94204e49867SJeff LaBundy 	if (!device_property_read_u32(&client->dev, "azoteq,filt-str-slider",
94304e49867SJeff LaBundy 				      &val)) {
94404e49867SJeff LaBundy 		if (val > IQS269_FILT_STR_MAX) {
94504e49867SJeff LaBundy 			dev_err(&client->dev, "Invalid filter strength: %u\n",
94604e49867SJeff LaBundy 				val);
94704e49867SJeff LaBundy 			return -EINVAL;
94804e49867SJeff LaBundy 		}
94904e49867SJeff LaBundy 
95004e49867SJeff LaBundy 		misc_b &= ~IQS269_MISC_B_FILT_STR_SLIDER;
95104e49867SJeff LaBundy 		misc_b |= val;
95204e49867SJeff LaBundy 	}
95304e49867SJeff LaBundy 
95404e49867SJeff LaBundy 	sys_reg->misc_a = cpu_to_be16(misc_a);
95504e49867SJeff LaBundy 	sys_reg->misc_b = cpu_to_be16(misc_b);
95604e49867SJeff LaBundy 
95704e49867SJeff LaBundy 	sys_reg->active = 0;
95804e49867SJeff LaBundy 	sys_reg->reseed = 0;
95904e49867SJeff LaBundy 
96004e49867SJeff LaBundy 	sys_reg->blocking = 0;
96104e49867SJeff LaBundy 
96204e49867SJeff LaBundy 	sys_reg->slider_select[0] = 0;
96304e49867SJeff LaBundy 	sys_reg->slider_select[1] = 0;
96404e49867SJeff LaBundy 
96504e49867SJeff LaBundy 	sys_reg->event_mask = ~((u8)IQS269_EVENT_MASK_SYS);
96604e49867SJeff LaBundy 
96704e49867SJeff LaBundy 	device_for_each_child_node(&client->dev, ch_node) {
96804e49867SJeff LaBundy 		error = iqs269_parse_chan(iqs269, ch_node);
96904e49867SJeff LaBundy 		if (error) {
97004e49867SJeff LaBundy 			fwnode_handle_put(ch_node);
97104e49867SJeff LaBundy 			return error;
97204e49867SJeff LaBundy 		}
97304e49867SJeff LaBundy 	}
97404e49867SJeff LaBundy 
97504e49867SJeff LaBundy 	/*
97604e49867SJeff LaBundy 	 * Volunteer all active channels to participate in ATI when REDO-ATI is
97704e49867SJeff LaBundy 	 * manually triggered.
97804e49867SJeff LaBundy 	 */
97904e49867SJeff LaBundy 	sys_reg->redo_ati = sys_reg->active;
98004e49867SJeff LaBundy 
98104e49867SJeff LaBundy 	general = be16_to_cpu(sys_reg->general);
98204e49867SJeff LaBundy 
98304e49867SJeff LaBundy 	if (device_property_present(&client->dev, "azoteq,clk-div")) {
98404e49867SJeff LaBundy 		general |= IQS269_SYS_SETTINGS_CLK_DIV;
98504e49867SJeff LaBundy 		iqs269->delay_mult = 4;
98604e49867SJeff LaBundy 	} else {
98704e49867SJeff LaBundy 		general &= ~IQS269_SYS_SETTINGS_CLK_DIV;
98804e49867SJeff LaBundy 		iqs269->delay_mult = 1;
98904e49867SJeff LaBundy 	}
99004e49867SJeff LaBundy 
99104e49867SJeff LaBundy 	/*
99204e49867SJeff LaBundy 	 * Configure the device to automatically switch between normal and low-
99304e49867SJeff LaBundy 	 * power modes as a function of sensing activity. Ultra-low-power mode,
99404e49867SJeff LaBundy 	 * if enabled, is reserved for suspend.
99504e49867SJeff LaBundy 	 */
99604e49867SJeff LaBundy 	general &= ~IQS269_SYS_SETTINGS_ULP_AUTO;
99704e49867SJeff LaBundy 	general &= ~IQS269_SYS_SETTINGS_DIS_AUTO;
99804e49867SJeff LaBundy 	general &= ~IQS269_SYS_SETTINGS_PWR_MODE_MASK;
99904e49867SJeff LaBundy 
100004e49867SJeff LaBundy 	if (!device_property_read_u32(&client->dev, "azoteq,ulp-update",
100104e49867SJeff LaBundy 				      &val)) {
100204e49867SJeff LaBundy 		if (val > IQS269_SYS_SETTINGS_ULP_UPDATE_MAX) {
100304e49867SJeff LaBundy 			dev_err(&client->dev, "Invalid update rate: %u\n", val);
100404e49867SJeff LaBundy 			return -EINVAL;
100504e49867SJeff LaBundy 		}
100604e49867SJeff LaBundy 
100704e49867SJeff LaBundy 		general &= ~IQS269_SYS_SETTINGS_ULP_UPDATE_MASK;
100804e49867SJeff LaBundy 		general |= (val << IQS269_SYS_SETTINGS_ULP_UPDATE_SHIFT);
100904e49867SJeff LaBundy 	}
101004e49867SJeff LaBundy 
101104e49867SJeff LaBundy 	general &= ~IQS269_SYS_SETTINGS_RESEED_OFFSET;
101204e49867SJeff LaBundy 	if (device_property_present(&client->dev, "azoteq,reseed-offset"))
101304e49867SJeff LaBundy 		general |= IQS269_SYS_SETTINGS_RESEED_OFFSET;
101404e49867SJeff LaBundy 
101504e49867SJeff LaBundy 	general |= IQS269_SYS_SETTINGS_EVENT_MODE;
101604e49867SJeff LaBundy 
101704e49867SJeff LaBundy 	/*
101804e49867SJeff LaBundy 	 * As per the datasheet, enable streaming during normal-power mode if
101904e49867SJeff LaBundy 	 * either slider is in use. In that case, the device returns to event
102004e49867SJeff LaBundy 	 * mode during low-power mode.
102104e49867SJeff LaBundy 	 */
102204e49867SJeff LaBundy 	if (sys_reg->slider_select[0] || sys_reg->slider_select[1])
102304e49867SJeff LaBundy 		general |= IQS269_SYS_SETTINGS_EVENT_MODE_LP;
102404e49867SJeff LaBundy 
102504e49867SJeff LaBundy 	general |= IQS269_SYS_SETTINGS_REDO_ATI;
102604e49867SJeff LaBundy 	general |= IQS269_SYS_SETTINGS_ACK_RESET;
102704e49867SJeff LaBundy 
102804e49867SJeff LaBundy 	sys_reg->general = cpu_to_be16(general);
102904e49867SJeff LaBundy 
103004e49867SJeff LaBundy 	return 0;
103104e49867SJeff LaBundy }
103204e49867SJeff LaBundy 
103304e49867SJeff LaBundy static int iqs269_dev_init(struct iqs269_private *iqs269)
103404e49867SJeff LaBundy {
103504e49867SJeff LaBundy 	struct iqs269_sys_reg *sys_reg = &iqs269->sys_reg;
103604e49867SJeff LaBundy 	struct iqs269_ch_reg *ch_reg;
103704e49867SJeff LaBundy 	unsigned int val;
103804e49867SJeff LaBundy 	int error, i;
103904e49867SJeff LaBundy 
104004e49867SJeff LaBundy 	mutex_lock(&iqs269->lock);
104104e49867SJeff LaBundy 
104204e49867SJeff LaBundy 	error = regmap_update_bits(iqs269->regmap, IQS269_HALL_UI,
104304e49867SJeff LaBundy 				   IQS269_HALL_UI_ENABLE,
104404e49867SJeff LaBundy 				   iqs269->hall_enable ? ~0 : 0);
104504e49867SJeff LaBundy 	if (error)
104604e49867SJeff LaBundy 		goto err_mutex;
104704e49867SJeff LaBundy 
104804e49867SJeff LaBundy 	for (i = 0; i < IQS269_NUM_CH; i++) {
104904e49867SJeff LaBundy 		if (!(sys_reg->active & BIT(i)))
105004e49867SJeff LaBundy 			continue;
105104e49867SJeff LaBundy 
105204e49867SJeff LaBundy 		ch_reg = &iqs269->ch_reg[i];
105304e49867SJeff LaBundy 
105404e49867SJeff LaBundy 		error = regmap_raw_write(iqs269->regmap,
105504e49867SJeff LaBundy 					 IQS269_CHx_SETTINGS + i *
105604e49867SJeff LaBundy 					 sizeof(*ch_reg) / 2, ch_reg,
105704e49867SJeff LaBundy 					 sizeof(*ch_reg));
105804e49867SJeff LaBundy 		if (error)
105904e49867SJeff LaBundy 			goto err_mutex;
106004e49867SJeff LaBundy 	}
106104e49867SJeff LaBundy 
106204e49867SJeff LaBundy 	/*
106304e49867SJeff LaBundy 	 * The REDO-ATI and ATI channel selection fields must be written in the
106404e49867SJeff LaBundy 	 * same block write, so every field between registers 0x80 through 0x8B
106504e49867SJeff LaBundy 	 * (inclusive) must be written as well.
106604e49867SJeff LaBundy 	 */
106704e49867SJeff LaBundy 	error = regmap_raw_write(iqs269->regmap, IQS269_SYS_SETTINGS, sys_reg,
106804e49867SJeff LaBundy 				 sizeof(*sys_reg));
106904e49867SJeff LaBundy 	if (error)
107004e49867SJeff LaBundy 		goto err_mutex;
107104e49867SJeff LaBundy 
107204e49867SJeff LaBundy 	error = regmap_read_poll_timeout(iqs269->regmap, IQS269_SYS_FLAGS, val,
107304e49867SJeff LaBundy 					!(val & IQS269_SYS_FLAGS_IN_ATI),
107404e49867SJeff LaBundy 					 IQS269_ATI_POLL_SLEEP_US,
107504e49867SJeff LaBundy 					 IQS269_ATI_POLL_TIMEOUT_US);
107604e49867SJeff LaBundy 	if (error)
107704e49867SJeff LaBundy 		goto err_mutex;
107804e49867SJeff LaBundy 
107904e49867SJeff LaBundy 	msleep(IQS269_ATI_STABLE_DELAY_MS);
108004e49867SJeff LaBundy 	iqs269->ati_current = true;
108104e49867SJeff LaBundy 
108204e49867SJeff LaBundy err_mutex:
108304e49867SJeff LaBundy 	mutex_unlock(&iqs269->lock);
108404e49867SJeff LaBundy 
108504e49867SJeff LaBundy 	return error;
108604e49867SJeff LaBundy }
108704e49867SJeff LaBundy 
108804e49867SJeff LaBundy static int iqs269_input_init(struct iqs269_private *iqs269)
108904e49867SJeff LaBundy {
109004e49867SJeff LaBundy 	struct i2c_client *client = iqs269->client;
109104e49867SJeff LaBundy 	struct iqs269_flags flags;
109204e49867SJeff LaBundy 	unsigned int sw_code, keycode;
109304e49867SJeff LaBundy 	int error, i, j;
109404e49867SJeff LaBundy 	u8 dir_mask, state;
109504e49867SJeff LaBundy 
109604e49867SJeff LaBundy 	iqs269->keypad = devm_input_allocate_device(&client->dev);
109704e49867SJeff LaBundy 	if (!iqs269->keypad)
109804e49867SJeff LaBundy 		return -ENOMEM;
109904e49867SJeff LaBundy 
110004e49867SJeff LaBundy 	iqs269->keypad->keycodemax = ARRAY_SIZE(iqs269->keycode);
110104e49867SJeff LaBundy 	iqs269->keypad->keycode = iqs269->keycode;
110204e49867SJeff LaBundy 	iqs269->keypad->keycodesize = sizeof(*iqs269->keycode);
110304e49867SJeff LaBundy 
110404e49867SJeff LaBundy 	iqs269->keypad->name = "iqs269a_keypad";
110504e49867SJeff LaBundy 	iqs269->keypad->id.bustype = BUS_I2C;
110604e49867SJeff LaBundy 
110704e49867SJeff LaBundy 	if (iqs269->hall_enable) {
110804e49867SJeff LaBundy 		error = regmap_raw_read(iqs269->regmap, IQS269_SYS_FLAGS,
110904e49867SJeff LaBundy 					&flags, sizeof(flags));
111004e49867SJeff LaBundy 		if (error) {
111104e49867SJeff LaBundy 			dev_err(&client->dev,
111204e49867SJeff LaBundy 				"Failed to read initial status: %d\n", error);
111304e49867SJeff LaBundy 			return error;
111404e49867SJeff LaBundy 		}
111504e49867SJeff LaBundy 	}
111604e49867SJeff LaBundy 
111704e49867SJeff LaBundy 	for (i = 0; i < ARRAY_SIZE(iqs269_events); i++) {
111804e49867SJeff LaBundy 		dir_mask = flags.states[IQS269_ST_OFFS_DIR];
111904e49867SJeff LaBundy 		if (!iqs269_events[i].dir_up)
112004e49867SJeff LaBundy 			dir_mask = ~dir_mask;
112104e49867SJeff LaBundy 
112204e49867SJeff LaBundy 		state = flags.states[iqs269_events[i].st_offs] & dir_mask;
112304e49867SJeff LaBundy 
112404e49867SJeff LaBundy 		sw_code = iqs269->switches[i].code;
112504e49867SJeff LaBundy 
112604e49867SJeff LaBundy 		for (j = 0; j < IQS269_NUM_CH; j++) {
112704e49867SJeff LaBundy 			keycode = iqs269->keycode[i * IQS269_NUM_CH + j];
112804e49867SJeff LaBundy 
112904e49867SJeff LaBundy 			/*
113004e49867SJeff LaBundy 			 * Hall-effect sensing repurposes a pair of dedicated
113104e49867SJeff LaBundy 			 * channels, only one of which reports events.
113204e49867SJeff LaBundy 			 */
113304e49867SJeff LaBundy 			switch (j) {
113404e49867SJeff LaBundy 			case IQS269_CHx_HALL_ACTIVE:
113504e49867SJeff LaBundy 				if (iqs269->hall_enable &&
113604e49867SJeff LaBundy 				    iqs269->switches[i].enabled) {
113704e49867SJeff LaBundy 					input_set_capability(iqs269->keypad,
113804e49867SJeff LaBundy 							     EV_SW, sw_code);
113904e49867SJeff LaBundy 					input_report_switch(iqs269->keypad,
114004e49867SJeff LaBundy 							    sw_code,
114104e49867SJeff LaBundy 							    state & BIT(j));
114204e49867SJeff LaBundy 				}
11436f49c4f5SGustavo A. R. Silva 				fallthrough;
114404e49867SJeff LaBundy 
114504e49867SJeff LaBundy 			case IQS269_CHx_HALL_INACTIVE:
114604e49867SJeff LaBundy 				if (iqs269->hall_enable)
114704e49867SJeff LaBundy 					continue;
11486f49c4f5SGustavo A. R. Silva 				fallthrough;
114904e49867SJeff LaBundy 
115004e49867SJeff LaBundy 			default:
115104e49867SJeff LaBundy 				if (keycode != KEY_RESERVED)
115204e49867SJeff LaBundy 					input_set_capability(iqs269->keypad,
115304e49867SJeff LaBundy 							     EV_KEY, keycode);
115404e49867SJeff LaBundy 			}
115504e49867SJeff LaBundy 		}
115604e49867SJeff LaBundy 	}
115704e49867SJeff LaBundy 
115804e49867SJeff LaBundy 	input_sync(iqs269->keypad);
115904e49867SJeff LaBundy 
116004e49867SJeff LaBundy 	error = input_register_device(iqs269->keypad);
116104e49867SJeff LaBundy 	if (error) {
116204e49867SJeff LaBundy 		dev_err(&client->dev, "Failed to register keypad: %d\n", error);
116304e49867SJeff LaBundy 		return error;
116404e49867SJeff LaBundy 	}
116504e49867SJeff LaBundy 
116604e49867SJeff LaBundy 	for (i = 0; i < IQS269_NUM_SL; i++) {
116704e49867SJeff LaBundy 		if (!iqs269->sys_reg.slider_select[i])
116804e49867SJeff LaBundy 			continue;
116904e49867SJeff LaBundy 
117004e49867SJeff LaBundy 		iqs269->slider[i] = devm_input_allocate_device(&client->dev);
117104e49867SJeff LaBundy 		if (!iqs269->slider[i])
117204e49867SJeff LaBundy 			return -ENOMEM;
117304e49867SJeff LaBundy 
117404e49867SJeff LaBundy 		iqs269->slider[i]->name = i ? "iqs269a_slider_1"
117504e49867SJeff LaBundy 					    : "iqs269a_slider_0";
117604e49867SJeff LaBundy 		iqs269->slider[i]->id.bustype = BUS_I2C;
117704e49867SJeff LaBundy 
117804e49867SJeff LaBundy 		input_set_capability(iqs269->slider[i], EV_KEY, BTN_TOUCH);
117904e49867SJeff LaBundy 		input_set_abs_params(iqs269->slider[i], ABS_X, 0, 255, 0, 0);
118004e49867SJeff LaBundy 
118104e49867SJeff LaBundy 		error = input_register_device(iqs269->slider[i]);
118204e49867SJeff LaBundy 		if (error) {
118304e49867SJeff LaBundy 			dev_err(&client->dev,
118404e49867SJeff LaBundy 				"Failed to register slider %d: %d\n", i, error);
118504e49867SJeff LaBundy 			return error;
118604e49867SJeff LaBundy 		}
118704e49867SJeff LaBundy 	}
118804e49867SJeff LaBundy 
118904e49867SJeff LaBundy 	return 0;
119004e49867SJeff LaBundy }
119104e49867SJeff LaBundy 
119204e49867SJeff LaBundy static int iqs269_report(struct iqs269_private *iqs269)
119304e49867SJeff LaBundy {
119404e49867SJeff LaBundy 	struct i2c_client *client = iqs269->client;
119504e49867SJeff LaBundy 	struct iqs269_flags flags;
119604e49867SJeff LaBundy 	unsigned int sw_code, keycode;
119704e49867SJeff LaBundy 	int error, i, j;
119804e49867SJeff LaBundy 	u8 slider_x[IQS269_NUM_SL];
119904e49867SJeff LaBundy 	u8 dir_mask, state;
120004e49867SJeff LaBundy 
120104e49867SJeff LaBundy 	error = regmap_raw_read(iqs269->regmap, IQS269_SYS_FLAGS, &flags,
120204e49867SJeff LaBundy 				sizeof(flags));
120304e49867SJeff LaBundy 	if (error) {
120404e49867SJeff LaBundy 		dev_err(&client->dev, "Failed to read device status: %d\n",
120504e49867SJeff LaBundy 			error);
120604e49867SJeff LaBundy 		return error;
120704e49867SJeff LaBundy 	}
120804e49867SJeff LaBundy 
120904e49867SJeff LaBundy 	/*
121004e49867SJeff LaBundy 	 * The device resets itself if its own watchdog bites, which can happen
121104e49867SJeff LaBundy 	 * in the event of an I2C communication error. In this case, the device
121204e49867SJeff LaBundy 	 * asserts a SHOW_RESET interrupt and all registers must be restored.
121304e49867SJeff LaBundy 	 */
121404e49867SJeff LaBundy 	if (be16_to_cpu(flags.system) & IQS269_SYS_FLAGS_SHOW_RESET) {
121504e49867SJeff LaBundy 		dev_err(&client->dev, "Unexpected device reset\n");
121604e49867SJeff LaBundy 
121704e49867SJeff LaBundy 		error = iqs269_dev_init(iqs269);
121804e49867SJeff LaBundy 		if (error)
121904e49867SJeff LaBundy 			dev_err(&client->dev,
122004e49867SJeff LaBundy 				"Failed to re-initialize device: %d\n", error);
122104e49867SJeff LaBundy 
122204e49867SJeff LaBundy 		return error;
122304e49867SJeff LaBundy 	}
122404e49867SJeff LaBundy 
122504e49867SJeff LaBundy 	error = regmap_raw_read(iqs269->regmap, IQS269_SLIDER_X, slider_x,
122604e49867SJeff LaBundy 				sizeof(slider_x));
122704e49867SJeff LaBundy 	if (error) {
122804e49867SJeff LaBundy 		dev_err(&client->dev, "Failed to read slider position: %d\n",
122904e49867SJeff LaBundy 			error);
123004e49867SJeff LaBundy 		return error;
123104e49867SJeff LaBundy 	}
123204e49867SJeff LaBundy 
123304e49867SJeff LaBundy 	for (i = 0; i < IQS269_NUM_SL; i++) {
123404e49867SJeff LaBundy 		if (!iqs269->sys_reg.slider_select[i])
123504e49867SJeff LaBundy 			continue;
123604e49867SJeff LaBundy 
123704e49867SJeff LaBundy 		/*
123804e49867SJeff LaBundy 		 * Report BTN_TOUCH if any channel that participates in the
123904e49867SJeff LaBundy 		 * slider is in a state of touch.
124004e49867SJeff LaBundy 		 */
124104e49867SJeff LaBundy 		if (flags.states[IQS269_ST_OFFS_TOUCH] &
124204e49867SJeff LaBundy 		    iqs269->sys_reg.slider_select[i]) {
124304e49867SJeff LaBundy 			input_report_key(iqs269->slider[i], BTN_TOUCH, 1);
124404e49867SJeff LaBundy 			input_report_abs(iqs269->slider[i], ABS_X, slider_x[i]);
124504e49867SJeff LaBundy 		} else {
124604e49867SJeff LaBundy 			input_report_key(iqs269->slider[i], BTN_TOUCH, 0);
124704e49867SJeff LaBundy 		}
124804e49867SJeff LaBundy 
124904e49867SJeff LaBundy 		input_sync(iqs269->slider[i]);
125004e49867SJeff LaBundy 	}
125104e49867SJeff LaBundy 
125204e49867SJeff LaBundy 	for (i = 0; i < ARRAY_SIZE(iqs269_events); i++) {
125304e49867SJeff LaBundy 		dir_mask = flags.states[IQS269_ST_OFFS_DIR];
125404e49867SJeff LaBundy 		if (!iqs269_events[i].dir_up)
125504e49867SJeff LaBundy 			dir_mask = ~dir_mask;
125604e49867SJeff LaBundy 
125704e49867SJeff LaBundy 		state = flags.states[iqs269_events[i].st_offs] & dir_mask;
125804e49867SJeff LaBundy 
125904e49867SJeff LaBundy 		sw_code = iqs269->switches[i].code;
126004e49867SJeff LaBundy 
126104e49867SJeff LaBundy 		for (j = 0; j < IQS269_NUM_CH; j++) {
126204e49867SJeff LaBundy 			keycode = iqs269->keycode[i * IQS269_NUM_CH + j];
126304e49867SJeff LaBundy 
126404e49867SJeff LaBundy 			switch (j) {
126504e49867SJeff LaBundy 			case IQS269_CHx_HALL_ACTIVE:
126604e49867SJeff LaBundy 				if (iqs269->hall_enable &&
126704e49867SJeff LaBundy 				    iqs269->switches[i].enabled)
126804e49867SJeff LaBundy 					input_report_switch(iqs269->keypad,
126904e49867SJeff LaBundy 							    sw_code,
127004e49867SJeff LaBundy 							    state & BIT(j));
12716f49c4f5SGustavo A. R. Silva 				fallthrough;
127204e49867SJeff LaBundy 
127304e49867SJeff LaBundy 			case IQS269_CHx_HALL_INACTIVE:
127404e49867SJeff LaBundy 				if (iqs269->hall_enable)
127504e49867SJeff LaBundy 					continue;
12766f49c4f5SGustavo A. R. Silva 				fallthrough;
127704e49867SJeff LaBundy 
127804e49867SJeff LaBundy 			default:
127904e49867SJeff LaBundy 				input_report_key(iqs269->keypad, keycode,
128004e49867SJeff LaBundy 						 state & BIT(j));
128104e49867SJeff LaBundy 			}
128204e49867SJeff LaBundy 		}
128304e49867SJeff LaBundy 	}
128404e49867SJeff LaBundy 
128504e49867SJeff LaBundy 	input_sync(iqs269->keypad);
128604e49867SJeff LaBundy 
128704e49867SJeff LaBundy 	return 0;
128804e49867SJeff LaBundy }
128904e49867SJeff LaBundy 
129004e49867SJeff LaBundy static irqreturn_t iqs269_irq(int irq, void *context)
129104e49867SJeff LaBundy {
129204e49867SJeff LaBundy 	struct iqs269_private *iqs269 = context;
129304e49867SJeff LaBundy 
129404e49867SJeff LaBundy 	if (iqs269_report(iqs269))
129504e49867SJeff LaBundy 		return IRQ_NONE;
129604e49867SJeff LaBundy 
129704e49867SJeff LaBundy 	/*
129804e49867SJeff LaBundy 	 * The device does not deassert its interrupt (RDY) pin until shortly
129904e49867SJeff LaBundy 	 * after receiving an I2C stop condition; the following delay ensures
130004e49867SJeff LaBundy 	 * the interrupt handler does not return before this time.
130104e49867SJeff LaBundy 	 */
130204e49867SJeff LaBundy 	iqs269_irq_wait();
130304e49867SJeff LaBundy 
130404e49867SJeff LaBundy 	return IRQ_HANDLED;
130504e49867SJeff LaBundy }
130604e49867SJeff LaBundy 
130704e49867SJeff LaBundy static ssize_t counts_show(struct device *dev,
130804e49867SJeff LaBundy 			   struct device_attribute *attr, char *buf)
130904e49867SJeff LaBundy {
131004e49867SJeff LaBundy 	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
131104e49867SJeff LaBundy 	struct i2c_client *client = iqs269->client;
131204e49867SJeff LaBundy 	__le16 counts;
131304e49867SJeff LaBundy 	int error;
131404e49867SJeff LaBundy 
131504e49867SJeff LaBundy 	if (!iqs269->ati_current || iqs269->hall_enable)
131604e49867SJeff LaBundy 		return -EPERM;
131704e49867SJeff LaBundy 
131804e49867SJeff LaBundy 	/*
131904e49867SJeff LaBundy 	 * Unsolicited I2C communication prompts the device to assert its RDY
132004e49867SJeff LaBundy 	 * pin, so disable the interrupt line until the operation is finished
132104e49867SJeff LaBundy 	 * and RDY has been deasserted.
132204e49867SJeff LaBundy 	 */
132304e49867SJeff LaBundy 	disable_irq(client->irq);
132404e49867SJeff LaBundy 
132504e49867SJeff LaBundy 	error = regmap_raw_read(iqs269->regmap,
132604e49867SJeff LaBundy 				IQS269_CHx_COUNTS + iqs269->ch_num * 2,
132704e49867SJeff LaBundy 				&counts, sizeof(counts));
132804e49867SJeff LaBundy 
132904e49867SJeff LaBundy 	iqs269_irq_wait();
133004e49867SJeff LaBundy 	enable_irq(client->irq);
133104e49867SJeff LaBundy 
133204e49867SJeff LaBundy 	if (error)
133304e49867SJeff LaBundy 		return error;
133404e49867SJeff LaBundy 
133504e49867SJeff LaBundy 	return scnprintf(buf, PAGE_SIZE, "%u\n", le16_to_cpu(counts));
133604e49867SJeff LaBundy }
133704e49867SJeff LaBundy 
133804e49867SJeff LaBundy static ssize_t hall_bin_show(struct device *dev,
133904e49867SJeff LaBundy 			     struct device_attribute *attr, char *buf)
134004e49867SJeff LaBundy {
134104e49867SJeff LaBundy 	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
134204e49867SJeff LaBundy 	struct i2c_client *client = iqs269->client;
134304e49867SJeff LaBundy 	unsigned int val;
134404e49867SJeff LaBundy 	int error;
134504e49867SJeff LaBundy 
134604e49867SJeff LaBundy 	disable_irq(client->irq);
134704e49867SJeff LaBundy 
134804e49867SJeff LaBundy 	error = regmap_read(iqs269->regmap, IQS269_CAL_DATA_A, &val);
134904e49867SJeff LaBundy 
135004e49867SJeff LaBundy 	iqs269_irq_wait();
135104e49867SJeff LaBundy 	enable_irq(client->irq);
135204e49867SJeff LaBundy 
135304e49867SJeff LaBundy 	if (error)
135404e49867SJeff LaBundy 		return error;
135504e49867SJeff LaBundy 
135604e49867SJeff LaBundy 	switch (iqs269->ch_reg[IQS269_CHx_HALL_ACTIVE].rx_enable &
135704e49867SJeff LaBundy 		iqs269->ch_reg[IQS269_CHx_HALL_INACTIVE].rx_enable) {
135804e49867SJeff LaBundy 	case IQS269_HALL_PAD_R:
135904e49867SJeff LaBundy 		val &= IQS269_CAL_DATA_A_HALL_BIN_R_MASK;
136004e49867SJeff LaBundy 		val >>= IQS269_CAL_DATA_A_HALL_BIN_R_SHIFT;
136104e49867SJeff LaBundy 		break;
136204e49867SJeff LaBundy 
136304e49867SJeff LaBundy 	case IQS269_HALL_PAD_L:
136404e49867SJeff LaBundy 		val &= IQS269_CAL_DATA_A_HALL_BIN_L_MASK;
136504e49867SJeff LaBundy 		val >>= IQS269_CAL_DATA_A_HALL_BIN_L_SHIFT;
136604e49867SJeff LaBundy 		break;
136704e49867SJeff LaBundy 
136804e49867SJeff LaBundy 	default:
136904e49867SJeff LaBundy 		return -EINVAL;
137004e49867SJeff LaBundy 	}
137104e49867SJeff LaBundy 
137204e49867SJeff LaBundy 	return scnprintf(buf, PAGE_SIZE, "%u\n", val);
137304e49867SJeff LaBundy }
137404e49867SJeff LaBundy 
137504e49867SJeff LaBundy static ssize_t hall_enable_show(struct device *dev,
137604e49867SJeff LaBundy 				struct device_attribute *attr, char *buf)
137704e49867SJeff LaBundy {
137804e49867SJeff LaBundy 	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
137904e49867SJeff LaBundy 
138004e49867SJeff LaBundy 	return scnprintf(buf, PAGE_SIZE, "%u\n", iqs269->hall_enable);
138104e49867SJeff LaBundy }
138204e49867SJeff LaBundy 
138304e49867SJeff LaBundy static ssize_t hall_enable_store(struct device *dev,
138404e49867SJeff LaBundy 				 struct device_attribute *attr, const char *buf,
138504e49867SJeff LaBundy 				 size_t count)
138604e49867SJeff LaBundy {
138704e49867SJeff LaBundy 	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
138804e49867SJeff LaBundy 	unsigned int val;
138904e49867SJeff LaBundy 	int error;
139004e49867SJeff LaBundy 
139104e49867SJeff LaBundy 	error = kstrtouint(buf, 10, &val);
139204e49867SJeff LaBundy 	if (error)
139304e49867SJeff LaBundy 		return error;
139404e49867SJeff LaBundy 
139504e49867SJeff LaBundy 	mutex_lock(&iqs269->lock);
139604e49867SJeff LaBundy 
139704e49867SJeff LaBundy 	iqs269->hall_enable = val;
139804e49867SJeff LaBundy 	iqs269->ati_current = false;
139904e49867SJeff LaBundy 
140004e49867SJeff LaBundy 	mutex_unlock(&iqs269->lock);
140104e49867SJeff LaBundy 
140204e49867SJeff LaBundy 	return count;
140304e49867SJeff LaBundy }
140404e49867SJeff LaBundy 
140504e49867SJeff LaBundy static ssize_t ch_number_show(struct device *dev,
140604e49867SJeff LaBundy 			      struct device_attribute *attr, char *buf)
140704e49867SJeff LaBundy {
140804e49867SJeff LaBundy 	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
140904e49867SJeff LaBundy 
141004e49867SJeff LaBundy 	return scnprintf(buf, PAGE_SIZE, "%u\n", iqs269->ch_num);
141104e49867SJeff LaBundy }
141204e49867SJeff LaBundy 
141304e49867SJeff LaBundy static ssize_t ch_number_store(struct device *dev,
141404e49867SJeff LaBundy 			       struct device_attribute *attr, const char *buf,
141504e49867SJeff LaBundy 			       size_t count)
141604e49867SJeff LaBundy {
141704e49867SJeff LaBundy 	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
141804e49867SJeff LaBundy 	unsigned int val;
141904e49867SJeff LaBundy 	int error;
142004e49867SJeff LaBundy 
142104e49867SJeff LaBundy 	error = kstrtouint(buf, 10, &val);
142204e49867SJeff LaBundy 	if (error)
142304e49867SJeff LaBundy 		return error;
142404e49867SJeff LaBundy 
142504e49867SJeff LaBundy 	if (val >= IQS269_NUM_CH)
142604e49867SJeff LaBundy 		return -EINVAL;
142704e49867SJeff LaBundy 
142804e49867SJeff LaBundy 	iqs269->ch_num = val;
142904e49867SJeff LaBundy 
143004e49867SJeff LaBundy 	return count;
143104e49867SJeff LaBundy }
143204e49867SJeff LaBundy 
143304e49867SJeff LaBundy static ssize_t rx_enable_show(struct device *dev,
143404e49867SJeff LaBundy 			      struct device_attribute *attr, char *buf)
143504e49867SJeff LaBundy {
143604e49867SJeff LaBundy 	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
143704e49867SJeff LaBundy 
143804e49867SJeff LaBundy 	return scnprintf(buf, PAGE_SIZE, "%u\n",
143904e49867SJeff LaBundy 			 iqs269->ch_reg[iqs269->ch_num].rx_enable);
144004e49867SJeff LaBundy }
144104e49867SJeff LaBundy 
144204e49867SJeff LaBundy static ssize_t rx_enable_store(struct device *dev,
144304e49867SJeff LaBundy 			       struct device_attribute *attr, const char *buf,
144404e49867SJeff LaBundy 			       size_t count)
144504e49867SJeff LaBundy {
144604e49867SJeff LaBundy 	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
144704e49867SJeff LaBundy 	unsigned int val;
144804e49867SJeff LaBundy 	int error;
144904e49867SJeff LaBundy 
145004e49867SJeff LaBundy 	error = kstrtouint(buf, 10, &val);
145104e49867SJeff LaBundy 	if (error)
145204e49867SJeff LaBundy 		return error;
145304e49867SJeff LaBundy 
145404e49867SJeff LaBundy 	if (val > 0xFF)
145504e49867SJeff LaBundy 		return -EINVAL;
145604e49867SJeff LaBundy 
145704e49867SJeff LaBundy 	mutex_lock(&iqs269->lock);
145804e49867SJeff LaBundy 
145904e49867SJeff LaBundy 	iqs269->ch_reg[iqs269->ch_num].rx_enable = val;
146004e49867SJeff LaBundy 	iqs269->ati_current = false;
146104e49867SJeff LaBundy 
146204e49867SJeff LaBundy 	mutex_unlock(&iqs269->lock);
146304e49867SJeff LaBundy 
146404e49867SJeff LaBundy 	return count;
146504e49867SJeff LaBundy }
146604e49867SJeff LaBundy 
146704e49867SJeff LaBundy static ssize_t ati_mode_show(struct device *dev,
146804e49867SJeff LaBundy 			     struct device_attribute *attr, char *buf)
146904e49867SJeff LaBundy {
147004e49867SJeff LaBundy 	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
147104e49867SJeff LaBundy 	unsigned int val;
147204e49867SJeff LaBundy 	int error;
147304e49867SJeff LaBundy 
147404e49867SJeff LaBundy 	error = iqs269_ati_mode_get(iqs269, iqs269->ch_num, &val);
147504e49867SJeff LaBundy 	if (error)
147604e49867SJeff LaBundy 		return error;
147704e49867SJeff LaBundy 
147804e49867SJeff LaBundy 	return scnprintf(buf, PAGE_SIZE, "%u\n", val);
147904e49867SJeff LaBundy }
148004e49867SJeff LaBundy 
148104e49867SJeff LaBundy static ssize_t ati_mode_store(struct device *dev,
148204e49867SJeff LaBundy 			      struct device_attribute *attr, const char *buf,
148304e49867SJeff LaBundy 			      size_t count)
148404e49867SJeff LaBundy {
148504e49867SJeff LaBundy 	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
148604e49867SJeff LaBundy 	unsigned int val;
148704e49867SJeff LaBundy 	int error;
148804e49867SJeff LaBundy 
148904e49867SJeff LaBundy 	error = kstrtouint(buf, 10, &val);
149004e49867SJeff LaBundy 	if (error)
149104e49867SJeff LaBundy 		return error;
149204e49867SJeff LaBundy 
149304e49867SJeff LaBundy 	error = iqs269_ati_mode_set(iqs269, iqs269->ch_num, val);
149404e49867SJeff LaBundy 	if (error)
149504e49867SJeff LaBundy 		return error;
149604e49867SJeff LaBundy 
149704e49867SJeff LaBundy 	return count;
149804e49867SJeff LaBundy }
149904e49867SJeff LaBundy 
150004e49867SJeff LaBundy static ssize_t ati_base_show(struct device *dev,
150104e49867SJeff LaBundy 			     struct device_attribute *attr, char *buf)
150204e49867SJeff LaBundy {
150304e49867SJeff LaBundy 	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
150404e49867SJeff LaBundy 	unsigned int val;
150504e49867SJeff LaBundy 	int error;
150604e49867SJeff LaBundy 
150704e49867SJeff LaBundy 	error = iqs269_ati_base_get(iqs269, iqs269->ch_num, &val);
150804e49867SJeff LaBundy 	if (error)
150904e49867SJeff LaBundy 		return error;
151004e49867SJeff LaBundy 
151104e49867SJeff LaBundy 	return scnprintf(buf, PAGE_SIZE, "%u\n", val);
151204e49867SJeff LaBundy }
151304e49867SJeff LaBundy 
151404e49867SJeff LaBundy static ssize_t ati_base_store(struct device *dev,
151504e49867SJeff LaBundy 			      struct device_attribute *attr, const char *buf,
151604e49867SJeff LaBundy 			      size_t count)
151704e49867SJeff LaBundy {
151804e49867SJeff LaBundy 	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
151904e49867SJeff LaBundy 	unsigned int val;
152004e49867SJeff LaBundy 	int error;
152104e49867SJeff LaBundy 
152204e49867SJeff LaBundy 	error = kstrtouint(buf, 10, &val);
152304e49867SJeff LaBundy 	if (error)
152404e49867SJeff LaBundy 		return error;
152504e49867SJeff LaBundy 
152604e49867SJeff LaBundy 	error = iqs269_ati_base_set(iqs269, iqs269->ch_num, val);
152704e49867SJeff LaBundy 	if (error)
152804e49867SJeff LaBundy 		return error;
152904e49867SJeff LaBundy 
153004e49867SJeff LaBundy 	return count;
153104e49867SJeff LaBundy }
153204e49867SJeff LaBundy 
153304e49867SJeff LaBundy static ssize_t ati_target_show(struct device *dev,
153404e49867SJeff LaBundy 			       struct device_attribute *attr, char *buf)
153504e49867SJeff LaBundy {
153604e49867SJeff LaBundy 	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
153704e49867SJeff LaBundy 	unsigned int val;
153804e49867SJeff LaBundy 	int error;
153904e49867SJeff LaBundy 
154004e49867SJeff LaBundy 	error = iqs269_ati_target_get(iqs269, iqs269->ch_num, &val);
154104e49867SJeff LaBundy 	if (error)
154204e49867SJeff LaBundy 		return error;
154304e49867SJeff LaBundy 
154404e49867SJeff LaBundy 	return scnprintf(buf, PAGE_SIZE, "%u\n", val);
154504e49867SJeff LaBundy }
154604e49867SJeff LaBundy 
154704e49867SJeff LaBundy static ssize_t ati_target_store(struct device *dev,
154804e49867SJeff LaBundy 				struct device_attribute *attr, const char *buf,
154904e49867SJeff LaBundy 				size_t count)
155004e49867SJeff LaBundy {
155104e49867SJeff LaBundy 	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
155204e49867SJeff LaBundy 	unsigned int val;
155304e49867SJeff LaBundy 	int error;
155404e49867SJeff LaBundy 
155504e49867SJeff LaBundy 	error = kstrtouint(buf, 10, &val);
155604e49867SJeff LaBundy 	if (error)
155704e49867SJeff LaBundy 		return error;
155804e49867SJeff LaBundy 
155904e49867SJeff LaBundy 	error = iqs269_ati_target_set(iqs269, iqs269->ch_num, val);
156004e49867SJeff LaBundy 	if (error)
156104e49867SJeff LaBundy 		return error;
156204e49867SJeff LaBundy 
156304e49867SJeff LaBundy 	return count;
156404e49867SJeff LaBundy }
156504e49867SJeff LaBundy 
156604e49867SJeff LaBundy static ssize_t ati_trigger_show(struct device *dev,
156704e49867SJeff LaBundy 				struct device_attribute *attr, char *buf)
156804e49867SJeff LaBundy {
156904e49867SJeff LaBundy 	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
157004e49867SJeff LaBundy 
157104e49867SJeff LaBundy 	return scnprintf(buf, PAGE_SIZE, "%u\n", iqs269->ati_current);
157204e49867SJeff LaBundy }
157304e49867SJeff LaBundy 
157404e49867SJeff LaBundy static ssize_t ati_trigger_store(struct device *dev,
157504e49867SJeff LaBundy 				 struct device_attribute *attr, const char *buf,
157604e49867SJeff LaBundy 				 size_t count)
157704e49867SJeff LaBundy {
157804e49867SJeff LaBundy 	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
157904e49867SJeff LaBundy 	struct i2c_client *client = iqs269->client;
158004e49867SJeff LaBundy 	unsigned int val;
158104e49867SJeff LaBundy 	int error;
158204e49867SJeff LaBundy 
158304e49867SJeff LaBundy 	error = kstrtouint(buf, 10, &val);
158404e49867SJeff LaBundy 	if (error)
158504e49867SJeff LaBundy 		return error;
158604e49867SJeff LaBundy 
158704e49867SJeff LaBundy 	if (!val)
158804e49867SJeff LaBundy 		return count;
158904e49867SJeff LaBundy 
159004e49867SJeff LaBundy 	disable_irq(client->irq);
159104e49867SJeff LaBundy 
159204e49867SJeff LaBundy 	error = iqs269_dev_init(iqs269);
159304e49867SJeff LaBundy 
159404e49867SJeff LaBundy 	iqs269_irq_wait();
159504e49867SJeff LaBundy 	enable_irq(client->irq);
159604e49867SJeff LaBundy 
159704e49867SJeff LaBundy 	if (error)
159804e49867SJeff LaBundy 		return error;
159904e49867SJeff LaBundy 
160004e49867SJeff LaBundy 	return count;
160104e49867SJeff LaBundy }
160204e49867SJeff LaBundy 
160304e49867SJeff LaBundy static DEVICE_ATTR_RO(counts);
160404e49867SJeff LaBundy static DEVICE_ATTR_RO(hall_bin);
160504e49867SJeff LaBundy static DEVICE_ATTR_RW(hall_enable);
160604e49867SJeff LaBundy static DEVICE_ATTR_RW(ch_number);
160704e49867SJeff LaBundy static DEVICE_ATTR_RW(rx_enable);
160804e49867SJeff LaBundy static DEVICE_ATTR_RW(ati_mode);
160904e49867SJeff LaBundy static DEVICE_ATTR_RW(ati_base);
161004e49867SJeff LaBundy static DEVICE_ATTR_RW(ati_target);
161104e49867SJeff LaBundy static DEVICE_ATTR_RW(ati_trigger);
161204e49867SJeff LaBundy 
161304e49867SJeff LaBundy static struct attribute *iqs269_attrs[] = {
161404e49867SJeff LaBundy 	&dev_attr_counts.attr,
161504e49867SJeff LaBundy 	&dev_attr_hall_bin.attr,
161604e49867SJeff LaBundy 	&dev_attr_hall_enable.attr,
161704e49867SJeff LaBundy 	&dev_attr_ch_number.attr,
161804e49867SJeff LaBundy 	&dev_attr_rx_enable.attr,
161904e49867SJeff LaBundy 	&dev_attr_ati_mode.attr,
162004e49867SJeff LaBundy 	&dev_attr_ati_base.attr,
162104e49867SJeff LaBundy 	&dev_attr_ati_target.attr,
162204e49867SJeff LaBundy 	&dev_attr_ati_trigger.attr,
162304e49867SJeff LaBundy 	NULL,
162404e49867SJeff LaBundy };
162504e49867SJeff LaBundy 
162604e49867SJeff LaBundy static const struct attribute_group iqs269_attr_group = {
162704e49867SJeff LaBundy 	.attrs = iqs269_attrs,
162804e49867SJeff LaBundy };
162904e49867SJeff LaBundy 
163004e49867SJeff LaBundy static const struct regmap_config iqs269_regmap_config = {
163104e49867SJeff LaBundy 	.reg_bits = 8,
163204e49867SJeff LaBundy 	.val_bits = 16,
163304e49867SJeff LaBundy 	.max_register = IQS269_MAX_REG,
163404e49867SJeff LaBundy };
163504e49867SJeff LaBundy 
163604e49867SJeff LaBundy static int iqs269_probe(struct i2c_client *client)
163704e49867SJeff LaBundy {
163804e49867SJeff LaBundy 	struct iqs269_ver_info ver_info;
163904e49867SJeff LaBundy 	struct iqs269_private *iqs269;
164004e49867SJeff LaBundy 	int error;
164104e49867SJeff LaBundy 
164204e49867SJeff LaBundy 	iqs269 = devm_kzalloc(&client->dev, sizeof(*iqs269), GFP_KERNEL);
164304e49867SJeff LaBundy 	if (!iqs269)
164404e49867SJeff LaBundy 		return -ENOMEM;
164504e49867SJeff LaBundy 
164604e49867SJeff LaBundy 	i2c_set_clientdata(client, iqs269);
164704e49867SJeff LaBundy 	iqs269->client = client;
164804e49867SJeff LaBundy 
164904e49867SJeff LaBundy 	iqs269->regmap = devm_regmap_init_i2c(client, &iqs269_regmap_config);
165004e49867SJeff LaBundy 	if (IS_ERR(iqs269->regmap)) {
165104e49867SJeff LaBundy 		error = PTR_ERR(iqs269->regmap);
165204e49867SJeff LaBundy 		dev_err(&client->dev, "Failed to initialize register map: %d\n",
165304e49867SJeff LaBundy 			error);
165404e49867SJeff LaBundy 		return error;
165504e49867SJeff LaBundy 	}
165604e49867SJeff LaBundy 
165704e49867SJeff LaBundy 	mutex_init(&iqs269->lock);
165804e49867SJeff LaBundy 
165904e49867SJeff LaBundy 	error = regmap_raw_read(iqs269->regmap, IQS269_VER_INFO, &ver_info,
166004e49867SJeff LaBundy 				sizeof(ver_info));
166104e49867SJeff LaBundy 	if (error)
166204e49867SJeff LaBundy 		return error;
166304e49867SJeff LaBundy 
166404e49867SJeff LaBundy 	if (ver_info.prod_num != IQS269_VER_INFO_PROD_NUM) {
166504e49867SJeff LaBundy 		dev_err(&client->dev, "Unrecognized product number: 0x%02X\n",
166604e49867SJeff LaBundy 			ver_info.prod_num);
166704e49867SJeff LaBundy 		return -EINVAL;
166804e49867SJeff LaBundy 	}
166904e49867SJeff LaBundy 
167004e49867SJeff LaBundy 	error = iqs269_parse_prop(iqs269);
167104e49867SJeff LaBundy 	if (error)
167204e49867SJeff LaBundy 		return error;
167304e49867SJeff LaBundy 
167404e49867SJeff LaBundy 	error = iqs269_dev_init(iqs269);
167504e49867SJeff LaBundy 	if (error) {
167604e49867SJeff LaBundy 		dev_err(&client->dev, "Failed to initialize device: %d\n",
167704e49867SJeff LaBundy 			error);
167804e49867SJeff LaBundy 		return error;
167904e49867SJeff LaBundy 	}
168004e49867SJeff LaBundy 
168104e49867SJeff LaBundy 	error = iqs269_input_init(iqs269);
168204e49867SJeff LaBundy 	if (error)
168304e49867SJeff LaBundy 		return error;
168404e49867SJeff LaBundy 
168504e49867SJeff LaBundy 	error = devm_request_threaded_irq(&client->dev, client->irq,
168604e49867SJeff LaBundy 					  NULL, iqs269_irq, IRQF_ONESHOT,
168704e49867SJeff LaBundy 					  client->name, iqs269);
168804e49867SJeff LaBundy 	if (error) {
168904e49867SJeff LaBundy 		dev_err(&client->dev, "Failed to request IRQ: %d\n", error);
169004e49867SJeff LaBundy 		return error;
169104e49867SJeff LaBundy 	}
169204e49867SJeff LaBundy 
169304e49867SJeff LaBundy 	error = devm_device_add_group(&client->dev, &iqs269_attr_group);
169404e49867SJeff LaBundy 	if (error)
169504e49867SJeff LaBundy 		dev_err(&client->dev, "Failed to add attributes: %d\n", error);
169604e49867SJeff LaBundy 
169704e49867SJeff LaBundy 	return error;
169804e49867SJeff LaBundy }
169904e49867SJeff LaBundy 
170004e49867SJeff LaBundy static int __maybe_unused iqs269_suspend(struct device *dev)
170104e49867SJeff LaBundy {
170204e49867SJeff LaBundy 	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
170304e49867SJeff LaBundy 	struct i2c_client *client = iqs269->client;
170404e49867SJeff LaBundy 	unsigned int val;
170504e49867SJeff LaBundy 	int error;
170604e49867SJeff LaBundy 
170704e49867SJeff LaBundy 	if (!iqs269->suspend_mode)
170804e49867SJeff LaBundy 		return 0;
170904e49867SJeff LaBundy 
171004e49867SJeff LaBundy 	disable_irq(client->irq);
171104e49867SJeff LaBundy 
171204e49867SJeff LaBundy 	/*
171304e49867SJeff LaBundy 	 * Automatic power mode switching must be disabled before the device is
171404e49867SJeff LaBundy 	 * forced into any particular power mode. In this case, the device will
171504e49867SJeff LaBundy 	 * transition into normal-power mode.
171604e49867SJeff LaBundy 	 */
171704e49867SJeff LaBundy 	error = regmap_update_bits(iqs269->regmap, IQS269_SYS_SETTINGS,
171804e49867SJeff LaBundy 				   IQS269_SYS_SETTINGS_DIS_AUTO, ~0);
171904e49867SJeff LaBundy 	if (error)
172004e49867SJeff LaBundy 		goto err_irq;
172104e49867SJeff LaBundy 
172204e49867SJeff LaBundy 	/*
172304e49867SJeff LaBundy 	 * The following check ensures the device has completed its transition
172404e49867SJeff LaBundy 	 * into normal-power mode before a manual mode switch is performed.
172504e49867SJeff LaBundy 	 */
172604e49867SJeff LaBundy 	error = regmap_read_poll_timeout(iqs269->regmap, IQS269_SYS_FLAGS, val,
172704e49867SJeff LaBundy 					!(val & IQS269_SYS_FLAGS_PWR_MODE_MASK),
172804e49867SJeff LaBundy 					 IQS269_PWR_MODE_POLL_SLEEP_US,
172904e49867SJeff LaBundy 					 IQS269_PWR_MODE_POLL_TIMEOUT_US);
173004e49867SJeff LaBundy 	if (error)
173104e49867SJeff LaBundy 		goto err_irq;
173204e49867SJeff LaBundy 
173304e49867SJeff LaBundy 	error = regmap_update_bits(iqs269->regmap, IQS269_SYS_SETTINGS,
173404e49867SJeff LaBundy 				   IQS269_SYS_SETTINGS_PWR_MODE_MASK,
173504e49867SJeff LaBundy 				   iqs269->suspend_mode <<
173604e49867SJeff LaBundy 				   IQS269_SYS_SETTINGS_PWR_MODE_SHIFT);
173704e49867SJeff LaBundy 	if (error)
173804e49867SJeff LaBundy 		goto err_irq;
173904e49867SJeff LaBundy 
174004e49867SJeff LaBundy 	/*
174104e49867SJeff LaBundy 	 * This last check ensures the device has completed its transition into
174204e49867SJeff LaBundy 	 * the desired power mode to prevent any spurious interrupts from being
174304e49867SJeff LaBundy 	 * triggered after iqs269_suspend has already returned.
174404e49867SJeff LaBundy 	 */
174504e49867SJeff LaBundy 	error = regmap_read_poll_timeout(iqs269->regmap, IQS269_SYS_FLAGS, val,
174604e49867SJeff LaBundy 					 (val & IQS269_SYS_FLAGS_PWR_MODE_MASK)
174704e49867SJeff LaBundy 					 == (iqs269->suspend_mode <<
174804e49867SJeff LaBundy 					     IQS269_SYS_FLAGS_PWR_MODE_SHIFT),
174904e49867SJeff LaBundy 					 IQS269_PWR_MODE_POLL_SLEEP_US,
175004e49867SJeff LaBundy 					 IQS269_PWR_MODE_POLL_TIMEOUT_US);
175104e49867SJeff LaBundy 
175204e49867SJeff LaBundy err_irq:
175304e49867SJeff LaBundy 	iqs269_irq_wait();
175404e49867SJeff LaBundy 	enable_irq(client->irq);
175504e49867SJeff LaBundy 
175604e49867SJeff LaBundy 	return error;
175704e49867SJeff LaBundy }
175804e49867SJeff LaBundy 
175904e49867SJeff LaBundy static int __maybe_unused iqs269_resume(struct device *dev)
176004e49867SJeff LaBundy {
176104e49867SJeff LaBundy 	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
176204e49867SJeff LaBundy 	struct i2c_client *client = iqs269->client;
176304e49867SJeff LaBundy 	unsigned int val;
176404e49867SJeff LaBundy 	int error;
176504e49867SJeff LaBundy 
176604e49867SJeff LaBundy 	if (!iqs269->suspend_mode)
176704e49867SJeff LaBundy 		return 0;
176804e49867SJeff LaBundy 
176904e49867SJeff LaBundy 	disable_irq(client->irq);
177004e49867SJeff LaBundy 
177104e49867SJeff LaBundy 	error = regmap_update_bits(iqs269->regmap, IQS269_SYS_SETTINGS,
177204e49867SJeff LaBundy 				   IQS269_SYS_SETTINGS_PWR_MODE_MASK, 0);
177304e49867SJeff LaBundy 	if (error)
177404e49867SJeff LaBundy 		goto err_irq;
177504e49867SJeff LaBundy 
177604e49867SJeff LaBundy 	/*
177704e49867SJeff LaBundy 	 * This check ensures the device has returned to normal-power mode
177804e49867SJeff LaBundy 	 * before automatic power mode switching is re-enabled.
177904e49867SJeff LaBundy 	 */
178004e49867SJeff LaBundy 	error = regmap_read_poll_timeout(iqs269->regmap, IQS269_SYS_FLAGS, val,
178104e49867SJeff LaBundy 					!(val & IQS269_SYS_FLAGS_PWR_MODE_MASK),
178204e49867SJeff LaBundy 					 IQS269_PWR_MODE_POLL_SLEEP_US,
178304e49867SJeff LaBundy 					 IQS269_PWR_MODE_POLL_TIMEOUT_US);
178404e49867SJeff LaBundy 	if (error)
178504e49867SJeff LaBundy 		goto err_irq;
178604e49867SJeff LaBundy 
178704e49867SJeff LaBundy 	error = regmap_update_bits(iqs269->regmap, IQS269_SYS_SETTINGS,
178804e49867SJeff LaBundy 				   IQS269_SYS_SETTINGS_DIS_AUTO, 0);
178904e49867SJeff LaBundy 	if (error)
179004e49867SJeff LaBundy 		goto err_irq;
179104e49867SJeff LaBundy 
179204e49867SJeff LaBundy 	/*
179304e49867SJeff LaBundy 	 * This step reports any events that may have been "swallowed" as a
179404e49867SJeff LaBundy 	 * result of polling PWR_MODE (which automatically acknowledges any
179504e49867SJeff LaBundy 	 * pending interrupts).
179604e49867SJeff LaBundy 	 */
179704e49867SJeff LaBundy 	error = iqs269_report(iqs269);
179804e49867SJeff LaBundy 
179904e49867SJeff LaBundy err_irq:
180004e49867SJeff LaBundy 	iqs269_irq_wait();
180104e49867SJeff LaBundy 	enable_irq(client->irq);
180204e49867SJeff LaBundy 
180304e49867SJeff LaBundy 	return error;
180404e49867SJeff LaBundy }
180504e49867SJeff LaBundy 
180604e49867SJeff LaBundy static SIMPLE_DEV_PM_OPS(iqs269_pm, iqs269_suspend, iqs269_resume);
180704e49867SJeff LaBundy 
180804e49867SJeff LaBundy static const struct of_device_id iqs269_of_match[] = {
180904e49867SJeff LaBundy 	{ .compatible = "azoteq,iqs269a" },
181004e49867SJeff LaBundy 	{ }
181104e49867SJeff LaBundy };
181204e49867SJeff LaBundy MODULE_DEVICE_TABLE(of, iqs269_of_match);
181304e49867SJeff LaBundy 
181404e49867SJeff LaBundy static struct i2c_driver iqs269_i2c_driver = {
181504e49867SJeff LaBundy 	.driver = {
181604e49867SJeff LaBundy 		.name = "iqs269a",
181704e49867SJeff LaBundy 		.of_match_table = iqs269_of_match,
181804e49867SJeff LaBundy 		.pm = &iqs269_pm,
181904e49867SJeff LaBundy 	},
182004e49867SJeff LaBundy 	.probe_new = iqs269_probe,
182104e49867SJeff LaBundy };
182204e49867SJeff LaBundy module_i2c_driver(iqs269_i2c_driver);
182304e49867SJeff LaBundy 
182404e49867SJeff LaBundy MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
182504e49867SJeff LaBundy MODULE_DESCRIPTION("Azoteq IQS269A Capacitive Touch Controller");
182604e49867SJeff LaBundy MODULE_LICENSE("GPL");
1827