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