162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Azoteq IQS269A Capacitive Touch Controller
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2020 Jeff LaBundy <jeff@labundy.com>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * This driver registers up to 3 input devices: one representing capacitive or
862306a36Sopenharmony_ci * inductive keys as well as Hall-effect switches, and one for each of the two
962306a36Sopenharmony_ci * axial sliders presented by the device.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/completion.h>
1362306a36Sopenharmony_ci#include <linux/delay.h>
1462306a36Sopenharmony_ci#include <linux/device.h>
1562306a36Sopenharmony_ci#include <linux/err.h>
1662306a36Sopenharmony_ci#include <linux/i2c.h>
1762306a36Sopenharmony_ci#include <linux/input.h>
1862306a36Sopenharmony_ci#include <linux/interrupt.h>
1962306a36Sopenharmony_ci#include <linux/kernel.h>
2062306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
2162306a36Sopenharmony_ci#include <linux/module.h>
2262306a36Sopenharmony_ci#include <linux/mutex.h>
2362306a36Sopenharmony_ci#include <linux/property.h>
2462306a36Sopenharmony_ci#include <linux/regmap.h>
2562306a36Sopenharmony_ci#include <linux/slab.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define IQS269_VER_INFO				0x00
2862306a36Sopenharmony_ci#define IQS269_VER_INFO_PROD_NUM		0x4F
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define IQS269_SYS_FLAGS			0x02
3162306a36Sopenharmony_ci#define IQS269_SYS_FLAGS_SHOW_RESET		BIT(15)
3262306a36Sopenharmony_ci#define IQS269_SYS_FLAGS_PWR_MODE_MASK		GENMASK(12, 11)
3362306a36Sopenharmony_ci#define IQS269_SYS_FLAGS_PWR_MODE_SHIFT		11
3462306a36Sopenharmony_ci#define IQS269_SYS_FLAGS_IN_ATI			BIT(10)
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define IQS269_CHx_COUNTS			0x08
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define IQS269_SLIDER_X				0x30
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define IQS269_CAL_DATA_A			0x35
4162306a36Sopenharmony_ci#define IQS269_CAL_DATA_A_HALL_BIN_L_MASK	GENMASK(15, 12)
4262306a36Sopenharmony_ci#define IQS269_CAL_DATA_A_HALL_BIN_L_SHIFT	12
4362306a36Sopenharmony_ci#define IQS269_CAL_DATA_A_HALL_BIN_R_MASK	GENMASK(11, 8)
4462306a36Sopenharmony_ci#define IQS269_CAL_DATA_A_HALL_BIN_R_SHIFT	8
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define IQS269_SYS_SETTINGS			0x80
4762306a36Sopenharmony_ci#define IQS269_SYS_SETTINGS_CLK_DIV		BIT(15)
4862306a36Sopenharmony_ci#define IQS269_SYS_SETTINGS_ULP_AUTO		BIT(14)
4962306a36Sopenharmony_ci#define IQS269_SYS_SETTINGS_DIS_AUTO		BIT(13)
5062306a36Sopenharmony_ci#define IQS269_SYS_SETTINGS_PWR_MODE_MASK	GENMASK(12, 11)
5162306a36Sopenharmony_ci#define IQS269_SYS_SETTINGS_PWR_MODE_SHIFT	11
5262306a36Sopenharmony_ci#define IQS269_SYS_SETTINGS_PWR_MODE_MAX	3
5362306a36Sopenharmony_ci#define IQS269_SYS_SETTINGS_ULP_UPDATE_MASK	GENMASK(10, 8)
5462306a36Sopenharmony_ci#define IQS269_SYS_SETTINGS_ULP_UPDATE_SHIFT	8
5562306a36Sopenharmony_ci#define IQS269_SYS_SETTINGS_ULP_UPDATE_MAX	7
5662306a36Sopenharmony_ci#define IQS269_SYS_SETTINGS_RESEED_OFFSET	BIT(6)
5762306a36Sopenharmony_ci#define IQS269_SYS_SETTINGS_EVENT_MODE		BIT(5)
5862306a36Sopenharmony_ci#define IQS269_SYS_SETTINGS_EVENT_MODE_LP	BIT(4)
5962306a36Sopenharmony_ci#define IQS269_SYS_SETTINGS_REDO_ATI		BIT(2)
6062306a36Sopenharmony_ci#define IQS269_SYS_SETTINGS_ACK_RESET		BIT(0)
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#define IQS269_FILT_STR_LP_LTA_MASK		GENMASK(7, 6)
6362306a36Sopenharmony_ci#define IQS269_FILT_STR_LP_LTA_SHIFT		6
6462306a36Sopenharmony_ci#define IQS269_FILT_STR_LP_CNT_MASK		GENMASK(5, 4)
6562306a36Sopenharmony_ci#define IQS269_FILT_STR_LP_CNT_SHIFT		4
6662306a36Sopenharmony_ci#define IQS269_FILT_STR_NP_LTA_MASK		GENMASK(3, 2)
6762306a36Sopenharmony_ci#define IQS269_FILT_STR_NP_LTA_SHIFT		2
6862306a36Sopenharmony_ci#define IQS269_FILT_STR_NP_CNT_MASK		GENMASK(1, 0)
6962306a36Sopenharmony_ci#define IQS269_FILT_STR_MAX			3
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#define IQS269_EVENT_MASK_SYS			BIT(6)
7262306a36Sopenharmony_ci#define IQS269_EVENT_MASK_DEEP			BIT(2)
7362306a36Sopenharmony_ci#define IQS269_EVENT_MASK_TOUCH			BIT(1)
7462306a36Sopenharmony_ci#define IQS269_EVENT_MASK_PROX			BIT(0)
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#define IQS269_RATE_NP_MS_MAX			255
7762306a36Sopenharmony_ci#define IQS269_RATE_LP_MS_MAX			255
7862306a36Sopenharmony_ci#define IQS269_RATE_ULP_MS_MAX			4080
7962306a36Sopenharmony_ci#define IQS269_TIMEOUT_PWR_MS_MAX		130560
8062306a36Sopenharmony_ci#define IQS269_TIMEOUT_LTA_MS_MAX		130560
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci#define IQS269_MISC_A_ATI_BAND_DISABLE		BIT(15)
8362306a36Sopenharmony_ci#define IQS269_MISC_A_ATI_LP_ONLY		BIT(14)
8462306a36Sopenharmony_ci#define IQS269_MISC_A_ATI_BAND_TIGHTEN		BIT(13)
8562306a36Sopenharmony_ci#define IQS269_MISC_A_FILT_DISABLE		BIT(12)
8662306a36Sopenharmony_ci#define IQS269_MISC_A_GPIO3_SELECT_MASK		GENMASK(10, 8)
8762306a36Sopenharmony_ci#define IQS269_MISC_A_GPIO3_SELECT_SHIFT	8
8862306a36Sopenharmony_ci#define IQS269_MISC_A_DUAL_DIR			BIT(6)
8962306a36Sopenharmony_ci#define IQS269_MISC_A_TX_FREQ_MASK		GENMASK(5, 4)
9062306a36Sopenharmony_ci#define IQS269_MISC_A_TX_FREQ_SHIFT		4
9162306a36Sopenharmony_ci#define IQS269_MISC_A_TX_FREQ_MAX		3
9262306a36Sopenharmony_ci#define IQS269_MISC_A_GLOBAL_CAP_SIZE		BIT(0)
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci#define IQS269_MISC_B_RESEED_UI_SEL_MASK	GENMASK(7, 6)
9562306a36Sopenharmony_ci#define IQS269_MISC_B_RESEED_UI_SEL_SHIFT	6
9662306a36Sopenharmony_ci#define IQS269_MISC_B_RESEED_UI_SEL_MAX		3
9762306a36Sopenharmony_ci#define IQS269_MISC_B_TRACKING_UI_ENABLE	BIT(4)
9862306a36Sopenharmony_ci#define IQS269_MISC_B_FILT_STR_SLIDER		GENMASK(1, 0)
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#define IQS269_CHx_ENG_A_MEAS_CAP_SIZE		BIT(15)
10162306a36Sopenharmony_ci#define IQS269_CHx_ENG_A_RX_GND_INACTIVE	BIT(13)
10262306a36Sopenharmony_ci#define IQS269_CHx_ENG_A_LOCAL_CAP_SIZE		BIT(12)
10362306a36Sopenharmony_ci#define IQS269_CHx_ENG_A_ATI_MODE_MASK		GENMASK(9, 8)
10462306a36Sopenharmony_ci#define IQS269_CHx_ENG_A_ATI_MODE_SHIFT		8
10562306a36Sopenharmony_ci#define IQS269_CHx_ENG_A_ATI_MODE_MAX		3
10662306a36Sopenharmony_ci#define IQS269_CHx_ENG_A_INV_LOGIC		BIT(7)
10762306a36Sopenharmony_ci#define IQS269_CHx_ENG_A_PROJ_BIAS_MASK		GENMASK(6, 5)
10862306a36Sopenharmony_ci#define IQS269_CHx_ENG_A_PROJ_BIAS_SHIFT	5
10962306a36Sopenharmony_ci#define IQS269_CHx_ENG_A_PROJ_BIAS_MAX		3
11062306a36Sopenharmony_ci#define IQS269_CHx_ENG_A_SENSE_MODE_MASK	GENMASK(3, 0)
11162306a36Sopenharmony_ci#define IQS269_CHx_ENG_A_SENSE_MODE_MAX		15
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#define IQS269_CHx_ENG_B_LOCAL_CAP_ENABLE	BIT(13)
11462306a36Sopenharmony_ci#define IQS269_CHx_ENG_B_SENSE_FREQ_MASK	GENMASK(10, 9)
11562306a36Sopenharmony_ci#define IQS269_CHx_ENG_B_SENSE_FREQ_SHIFT	9
11662306a36Sopenharmony_ci#define IQS269_CHx_ENG_B_SENSE_FREQ_MAX		3
11762306a36Sopenharmony_ci#define IQS269_CHx_ENG_B_STATIC_ENABLE		BIT(8)
11862306a36Sopenharmony_ci#define IQS269_CHx_ENG_B_ATI_BASE_MASK		GENMASK(7, 6)
11962306a36Sopenharmony_ci#define IQS269_CHx_ENG_B_ATI_BASE_75		0x00
12062306a36Sopenharmony_ci#define IQS269_CHx_ENG_B_ATI_BASE_100		0x40
12162306a36Sopenharmony_ci#define IQS269_CHx_ENG_B_ATI_BASE_150		0x80
12262306a36Sopenharmony_ci#define IQS269_CHx_ENG_B_ATI_BASE_200		0xC0
12362306a36Sopenharmony_ci#define IQS269_CHx_ENG_B_ATI_TARGET_MASK	GENMASK(5, 0)
12462306a36Sopenharmony_ci#define IQS269_CHx_ENG_B_ATI_TARGET_MAX		2016
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci#define IQS269_CHx_WEIGHT_MAX			255
12762306a36Sopenharmony_ci#define IQS269_CHx_THRESH_MAX			255
12862306a36Sopenharmony_ci#define IQS269_CHx_HYST_DEEP_MASK		GENMASK(7, 4)
12962306a36Sopenharmony_ci#define IQS269_CHx_HYST_DEEP_SHIFT		4
13062306a36Sopenharmony_ci#define IQS269_CHx_HYST_TOUCH_MASK		GENMASK(3, 0)
13162306a36Sopenharmony_ci#define IQS269_CHx_HYST_MAX			15
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci#define IQS269_CHx_HALL_INACTIVE		6
13462306a36Sopenharmony_ci#define IQS269_CHx_HALL_ACTIVE			7
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci#define IQS269_HALL_PAD_R			BIT(0)
13762306a36Sopenharmony_ci#define IQS269_HALL_PAD_L			BIT(1)
13862306a36Sopenharmony_ci#define IQS269_HALL_PAD_INV			BIT(6)
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci#define IQS269_HALL_UI				0xF5
14162306a36Sopenharmony_ci#define IQS269_HALL_UI_ENABLE			BIT(15)
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci#define IQS269_MAX_REG				0xFF
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci#define IQS269_NUM_CH				8
14662306a36Sopenharmony_ci#define IQS269_NUM_SL				2
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci#define iqs269_irq_wait()			usleep_range(200, 250)
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cienum iqs269_local_cap_size {
15162306a36Sopenharmony_ci	IQS269_LOCAL_CAP_SIZE_0,
15262306a36Sopenharmony_ci	IQS269_LOCAL_CAP_SIZE_GLOBAL_ONLY,
15362306a36Sopenharmony_ci	IQS269_LOCAL_CAP_SIZE_GLOBAL_0pF5,
15462306a36Sopenharmony_ci};
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cienum iqs269_st_offs {
15762306a36Sopenharmony_ci	IQS269_ST_OFFS_PROX,
15862306a36Sopenharmony_ci	IQS269_ST_OFFS_DIR,
15962306a36Sopenharmony_ci	IQS269_ST_OFFS_TOUCH,
16062306a36Sopenharmony_ci	IQS269_ST_OFFS_DEEP,
16162306a36Sopenharmony_ci};
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cienum iqs269_th_offs {
16462306a36Sopenharmony_ci	IQS269_TH_OFFS_PROX,
16562306a36Sopenharmony_ci	IQS269_TH_OFFS_TOUCH,
16662306a36Sopenharmony_ci	IQS269_TH_OFFS_DEEP,
16762306a36Sopenharmony_ci};
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cienum iqs269_event_id {
17062306a36Sopenharmony_ci	IQS269_EVENT_PROX_DN,
17162306a36Sopenharmony_ci	IQS269_EVENT_PROX_UP,
17262306a36Sopenharmony_ci	IQS269_EVENT_TOUCH_DN,
17362306a36Sopenharmony_ci	IQS269_EVENT_TOUCH_UP,
17462306a36Sopenharmony_ci	IQS269_EVENT_DEEP_DN,
17562306a36Sopenharmony_ci	IQS269_EVENT_DEEP_UP,
17662306a36Sopenharmony_ci};
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistruct iqs269_switch_desc {
17962306a36Sopenharmony_ci	unsigned int code;
18062306a36Sopenharmony_ci	bool enabled;
18162306a36Sopenharmony_ci};
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistruct iqs269_event_desc {
18462306a36Sopenharmony_ci	const char *name;
18562306a36Sopenharmony_ci	enum iqs269_st_offs st_offs;
18662306a36Sopenharmony_ci	enum iqs269_th_offs th_offs;
18762306a36Sopenharmony_ci	bool dir_up;
18862306a36Sopenharmony_ci	u8 mask;
18962306a36Sopenharmony_ci};
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic const struct iqs269_event_desc iqs269_events[] = {
19262306a36Sopenharmony_ci	[IQS269_EVENT_PROX_DN] = {
19362306a36Sopenharmony_ci		.name = "event-prox",
19462306a36Sopenharmony_ci		.st_offs = IQS269_ST_OFFS_PROX,
19562306a36Sopenharmony_ci		.th_offs = IQS269_TH_OFFS_PROX,
19662306a36Sopenharmony_ci		.mask = IQS269_EVENT_MASK_PROX,
19762306a36Sopenharmony_ci	},
19862306a36Sopenharmony_ci	[IQS269_EVENT_PROX_UP] = {
19962306a36Sopenharmony_ci		.name = "event-prox-alt",
20062306a36Sopenharmony_ci		.st_offs = IQS269_ST_OFFS_PROX,
20162306a36Sopenharmony_ci		.th_offs = IQS269_TH_OFFS_PROX,
20262306a36Sopenharmony_ci		.dir_up = true,
20362306a36Sopenharmony_ci		.mask = IQS269_EVENT_MASK_PROX,
20462306a36Sopenharmony_ci	},
20562306a36Sopenharmony_ci	[IQS269_EVENT_TOUCH_DN] = {
20662306a36Sopenharmony_ci		.name = "event-touch",
20762306a36Sopenharmony_ci		.st_offs = IQS269_ST_OFFS_TOUCH,
20862306a36Sopenharmony_ci		.th_offs = IQS269_TH_OFFS_TOUCH,
20962306a36Sopenharmony_ci		.mask = IQS269_EVENT_MASK_TOUCH,
21062306a36Sopenharmony_ci	},
21162306a36Sopenharmony_ci	[IQS269_EVENT_TOUCH_UP] = {
21262306a36Sopenharmony_ci		.name = "event-touch-alt",
21362306a36Sopenharmony_ci		.st_offs = IQS269_ST_OFFS_TOUCH,
21462306a36Sopenharmony_ci		.th_offs = IQS269_TH_OFFS_TOUCH,
21562306a36Sopenharmony_ci		.dir_up = true,
21662306a36Sopenharmony_ci		.mask = IQS269_EVENT_MASK_TOUCH,
21762306a36Sopenharmony_ci	},
21862306a36Sopenharmony_ci	[IQS269_EVENT_DEEP_DN] = {
21962306a36Sopenharmony_ci		.name = "event-deep",
22062306a36Sopenharmony_ci		.st_offs = IQS269_ST_OFFS_DEEP,
22162306a36Sopenharmony_ci		.th_offs = IQS269_TH_OFFS_DEEP,
22262306a36Sopenharmony_ci		.mask = IQS269_EVENT_MASK_DEEP,
22362306a36Sopenharmony_ci	},
22462306a36Sopenharmony_ci	[IQS269_EVENT_DEEP_UP] = {
22562306a36Sopenharmony_ci		.name = "event-deep-alt",
22662306a36Sopenharmony_ci		.st_offs = IQS269_ST_OFFS_DEEP,
22762306a36Sopenharmony_ci		.th_offs = IQS269_TH_OFFS_DEEP,
22862306a36Sopenharmony_ci		.dir_up = true,
22962306a36Sopenharmony_ci		.mask = IQS269_EVENT_MASK_DEEP,
23062306a36Sopenharmony_ci	},
23162306a36Sopenharmony_ci};
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistruct iqs269_ver_info {
23462306a36Sopenharmony_ci	u8 prod_num;
23562306a36Sopenharmony_ci	u8 sw_num;
23662306a36Sopenharmony_ci	u8 hw_num;
23762306a36Sopenharmony_ci	u8 padding;
23862306a36Sopenharmony_ci} __packed;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistruct iqs269_ch_reg {
24162306a36Sopenharmony_ci	u8 rx_enable;
24262306a36Sopenharmony_ci	u8 tx_enable;
24362306a36Sopenharmony_ci	__be16 engine_a;
24462306a36Sopenharmony_ci	__be16 engine_b;
24562306a36Sopenharmony_ci	__be16 ati_comp;
24662306a36Sopenharmony_ci	u8 thresh[3];
24762306a36Sopenharmony_ci	u8 hyst;
24862306a36Sopenharmony_ci	u8 assoc_select;
24962306a36Sopenharmony_ci	u8 assoc_weight;
25062306a36Sopenharmony_ci} __packed;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistruct iqs269_sys_reg {
25362306a36Sopenharmony_ci	__be16 general;
25462306a36Sopenharmony_ci	u8 active;
25562306a36Sopenharmony_ci	u8 filter;
25662306a36Sopenharmony_ci	u8 reseed;
25762306a36Sopenharmony_ci	u8 event_mask;
25862306a36Sopenharmony_ci	u8 rate_np;
25962306a36Sopenharmony_ci	u8 rate_lp;
26062306a36Sopenharmony_ci	u8 rate_ulp;
26162306a36Sopenharmony_ci	u8 timeout_pwr;
26262306a36Sopenharmony_ci	u8 timeout_rdy;
26362306a36Sopenharmony_ci	u8 timeout_lta;
26462306a36Sopenharmony_ci	__be16 misc_a;
26562306a36Sopenharmony_ci	__be16 misc_b;
26662306a36Sopenharmony_ci	u8 blocking;
26762306a36Sopenharmony_ci	u8 padding;
26862306a36Sopenharmony_ci	u8 slider_select[IQS269_NUM_SL];
26962306a36Sopenharmony_ci	u8 timeout_tap;
27062306a36Sopenharmony_ci	u8 timeout_swipe;
27162306a36Sopenharmony_ci	u8 thresh_swipe;
27262306a36Sopenharmony_ci	u8 redo_ati;
27362306a36Sopenharmony_ci	struct iqs269_ch_reg ch_reg[IQS269_NUM_CH];
27462306a36Sopenharmony_ci} __packed;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistruct iqs269_flags {
27762306a36Sopenharmony_ci	__be16 system;
27862306a36Sopenharmony_ci	u8 gesture;
27962306a36Sopenharmony_ci	u8 padding;
28062306a36Sopenharmony_ci	u8 states[4];
28162306a36Sopenharmony_ci} __packed;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistruct iqs269_private {
28462306a36Sopenharmony_ci	struct i2c_client *client;
28562306a36Sopenharmony_ci	struct regmap *regmap;
28662306a36Sopenharmony_ci	struct mutex lock;
28762306a36Sopenharmony_ci	struct iqs269_switch_desc switches[ARRAY_SIZE(iqs269_events)];
28862306a36Sopenharmony_ci	struct iqs269_sys_reg sys_reg;
28962306a36Sopenharmony_ci	struct completion ati_done;
29062306a36Sopenharmony_ci	struct input_dev *keypad;
29162306a36Sopenharmony_ci	struct input_dev *slider[IQS269_NUM_SL];
29262306a36Sopenharmony_ci	unsigned int keycode[ARRAY_SIZE(iqs269_events) * IQS269_NUM_CH];
29362306a36Sopenharmony_ci	unsigned int ch_num;
29462306a36Sopenharmony_ci	bool hall_enable;
29562306a36Sopenharmony_ci	bool ati_current;
29662306a36Sopenharmony_ci};
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cistatic int iqs269_ati_mode_set(struct iqs269_private *iqs269,
29962306a36Sopenharmony_ci			       unsigned int ch_num, unsigned int mode)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
30262306a36Sopenharmony_ci	u16 engine_a;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (ch_num >= IQS269_NUM_CH)
30562306a36Sopenharmony_ci		return -EINVAL;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	if (mode > IQS269_CHx_ENG_A_ATI_MODE_MAX)
30862306a36Sopenharmony_ci		return -EINVAL;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	mutex_lock(&iqs269->lock);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	engine_a = be16_to_cpu(ch_reg[ch_num].engine_a);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	engine_a &= ~IQS269_CHx_ENG_A_ATI_MODE_MASK;
31562306a36Sopenharmony_ci	engine_a |= (mode << IQS269_CHx_ENG_A_ATI_MODE_SHIFT);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	ch_reg[ch_num].engine_a = cpu_to_be16(engine_a);
31862306a36Sopenharmony_ci	iqs269->ati_current = false;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	mutex_unlock(&iqs269->lock);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	return 0;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic int iqs269_ati_mode_get(struct iqs269_private *iqs269,
32662306a36Sopenharmony_ci			       unsigned int ch_num, unsigned int *mode)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
32962306a36Sopenharmony_ci	u16 engine_a;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	if (ch_num >= IQS269_NUM_CH)
33262306a36Sopenharmony_ci		return -EINVAL;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	mutex_lock(&iqs269->lock);
33562306a36Sopenharmony_ci	engine_a = be16_to_cpu(ch_reg[ch_num].engine_a);
33662306a36Sopenharmony_ci	mutex_unlock(&iqs269->lock);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	engine_a &= IQS269_CHx_ENG_A_ATI_MODE_MASK;
33962306a36Sopenharmony_ci	*mode = (engine_a >> IQS269_CHx_ENG_A_ATI_MODE_SHIFT);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	return 0;
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic int iqs269_ati_base_set(struct iqs269_private *iqs269,
34562306a36Sopenharmony_ci			       unsigned int ch_num, unsigned int base)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
34862306a36Sopenharmony_ci	u16 engine_b;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	if (ch_num >= IQS269_NUM_CH)
35162306a36Sopenharmony_ci		return -EINVAL;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	switch (base) {
35462306a36Sopenharmony_ci	case 75:
35562306a36Sopenharmony_ci		base = IQS269_CHx_ENG_B_ATI_BASE_75;
35662306a36Sopenharmony_ci		break;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	case 100:
35962306a36Sopenharmony_ci		base = IQS269_CHx_ENG_B_ATI_BASE_100;
36062306a36Sopenharmony_ci		break;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	case 150:
36362306a36Sopenharmony_ci		base = IQS269_CHx_ENG_B_ATI_BASE_150;
36462306a36Sopenharmony_ci		break;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	case 200:
36762306a36Sopenharmony_ci		base = IQS269_CHx_ENG_B_ATI_BASE_200;
36862306a36Sopenharmony_ci		break;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	default:
37162306a36Sopenharmony_ci		return -EINVAL;
37262306a36Sopenharmony_ci	}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	mutex_lock(&iqs269->lock);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	engine_b = be16_to_cpu(ch_reg[ch_num].engine_b);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	engine_b &= ~IQS269_CHx_ENG_B_ATI_BASE_MASK;
37962306a36Sopenharmony_ci	engine_b |= base;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	ch_reg[ch_num].engine_b = cpu_to_be16(engine_b);
38262306a36Sopenharmony_ci	iqs269->ati_current = false;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	mutex_unlock(&iqs269->lock);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	return 0;
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cistatic int iqs269_ati_base_get(struct iqs269_private *iqs269,
39062306a36Sopenharmony_ci			       unsigned int ch_num, unsigned int *base)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
39362306a36Sopenharmony_ci	u16 engine_b;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	if (ch_num >= IQS269_NUM_CH)
39662306a36Sopenharmony_ci		return -EINVAL;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	mutex_lock(&iqs269->lock);
39962306a36Sopenharmony_ci	engine_b = be16_to_cpu(ch_reg[ch_num].engine_b);
40062306a36Sopenharmony_ci	mutex_unlock(&iqs269->lock);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	switch (engine_b & IQS269_CHx_ENG_B_ATI_BASE_MASK) {
40362306a36Sopenharmony_ci	case IQS269_CHx_ENG_B_ATI_BASE_75:
40462306a36Sopenharmony_ci		*base = 75;
40562306a36Sopenharmony_ci		return 0;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	case IQS269_CHx_ENG_B_ATI_BASE_100:
40862306a36Sopenharmony_ci		*base = 100;
40962306a36Sopenharmony_ci		return 0;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	case IQS269_CHx_ENG_B_ATI_BASE_150:
41262306a36Sopenharmony_ci		*base = 150;
41362306a36Sopenharmony_ci		return 0;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	case IQS269_CHx_ENG_B_ATI_BASE_200:
41662306a36Sopenharmony_ci		*base = 200;
41762306a36Sopenharmony_ci		return 0;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	default:
42062306a36Sopenharmony_ci		return -EINVAL;
42162306a36Sopenharmony_ci	}
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic int iqs269_ati_target_set(struct iqs269_private *iqs269,
42562306a36Sopenharmony_ci				 unsigned int ch_num, unsigned int target)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
42862306a36Sopenharmony_ci	u16 engine_b;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	if (ch_num >= IQS269_NUM_CH)
43162306a36Sopenharmony_ci		return -EINVAL;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	if (target > IQS269_CHx_ENG_B_ATI_TARGET_MAX)
43462306a36Sopenharmony_ci		return -EINVAL;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	mutex_lock(&iqs269->lock);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	engine_b = be16_to_cpu(ch_reg[ch_num].engine_b);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	engine_b &= ~IQS269_CHx_ENG_B_ATI_TARGET_MASK;
44162306a36Sopenharmony_ci	engine_b |= target / 32;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	ch_reg[ch_num].engine_b = cpu_to_be16(engine_b);
44462306a36Sopenharmony_ci	iqs269->ati_current = false;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	mutex_unlock(&iqs269->lock);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	return 0;
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic int iqs269_ati_target_get(struct iqs269_private *iqs269,
45262306a36Sopenharmony_ci				 unsigned int ch_num, unsigned int *target)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
45562306a36Sopenharmony_ci	u16 engine_b;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	if (ch_num >= IQS269_NUM_CH)
45862306a36Sopenharmony_ci		return -EINVAL;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	mutex_lock(&iqs269->lock);
46162306a36Sopenharmony_ci	engine_b = be16_to_cpu(ch_reg[ch_num].engine_b);
46262306a36Sopenharmony_ci	mutex_unlock(&iqs269->lock);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	*target = (engine_b & IQS269_CHx_ENG_B_ATI_TARGET_MASK) * 32;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	return 0;
46762306a36Sopenharmony_ci}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_cistatic int iqs269_parse_mask(const struct fwnode_handle *fwnode,
47062306a36Sopenharmony_ci			     const char *propname, u8 *mask)
47162306a36Sopenharmony_ci{
47262306a36Sopenharmony_ci	unsigned int val[IQS269_NUM_CH];
47362306a36Sopenharmony_ci	int count, error, i;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	count = fwnode_property_count_u32(fwnode, propname);
47662306a36Sopenharmony_ci	if (count < 0)
47762306a36Sopenharmony_ci		return 0;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	if (count > IQS269_NUM_CH)
48062306a36Sopenharmony_ci		return -EINVAL;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	error = fwnode_property_read_u32_array(fwnode, propname, val, count);
48362306a36Sopenharmony_ci	if (error)
48462306a36Sopenharmony_ci		return error;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	*mask = 0;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
48962306a36Sopenharmony_ci		if (val[i] >= IQS269_NUM_CH)
49062306a36Sopenharmony_ci			return -EINVAL;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci		*mask |= BIT(val[i]);
49362306a36Sopenharmony_ci	}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	return 0;
49662306a36Sopenharmony_ci}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_cistatic int iqs269_parse_chan(struct iqs269_private *iqs269,
49962306a36Sopenharmony_ci			     const struct fwnode_handle *ch_node)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	struct i2c_client *client = iqs269->client;
50262306a36Sopenharmony_ci	struct fwnode_handle *ev_node;
50362306a36Sopenharmony_ci	struct iqs269_ch_reg *ch_reg;
50462306a36Sopenharmony_ci	u16 engine_a, engine_b;
50562306a36Sopenharmony_ci	unsigned int reg, val;
50662306a36Sopenharmony_ci	int error, i;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	error = fwnode_property_read_u32(ch_node, "reg", &reg);
50962306a36Sopenharmony_ci	if (error) {
51062306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to read channel number: %d\n",
51162306a36Sopenharmony_ci			error);
51262306a36Sopenharmony_ci		return error;
51362306a36Sopenharmony_ci	} else if (reg >= IQS269_NUM_CH) {
51462306a36Sopenharmony_ci		dev_err(&client->dev, "Invalid channel number: %u\n", reg);
51562306a36Sopenharmony_ci		return -EINVAL;
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	iqs269->sys_reg.active |= BIT(reg);
51962306a36Sopenharmony_ci	if (!fwnode_property_present(ch_node, "azoteq,reseed-disable"))
52062306a36Sopenharmony_ci		iqs269->sys_reg.reseed |= BIT(reg);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	if (fwnode_property_present(ch_node, "azoteq,blocking-enable"))
52362306a36Sopenharmony_ci		iqs269->sys_reg.blocking |= BIT(reg);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	if (fwnode_property_present(ch_node, "azoteq,slider0-select"))
52662306a36Sopenharmony_ci		iqs269->sys_reg.slider_select[0] |= BIT(reg);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	if (fwnode_property_present(ch_node, "azoteq,slider1-select"))
52962306a36Sopenharmony_ci		iqs269->sys_reg.slider_select[1] |= BIT(reg);
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	ch_reg = &iqs269->sys_reg.ch_reg[reg];
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	error = iqs269_parse_mask(ch_node, "azoteq,rx-enable",
53462306a36Sopenharmony_ci				  &ch_reg->rx_enable);
53562306a36Sopenharmony_ci	if (error) {
53662306a36Sopenharmony_ci		dev_err(&client->dev, "Invalid channel %u RX enable mask: %d\n",
53762306a36Sopenharmony_ci			reg, error);
53862306a36Sopenharmony_ci		return error;
53962306a36Sopenharmony_ci	}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	error = iqs269_parse_mask(ch_node, "azoteq,tx-enable",
54262306a36Sopenharmony_ci				  &ch_reg->tx_enable);
54362306a36Sopenharmony_ci	if (error) {
54462306a36Sopenharmony_ci		dev_err(&client->dev, "Invalid channel %u TX enable mask: %d\n",
54562306a36Sopenharmony_ci			reg, error);
54662306a36Sopenharmony_ci		return error;
54762306a36Sopenharmony_ci	}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	engine_a = be16_to_cpu(ch_reg->engine_a);
55062306a36Sopenharmony_ci	engine_b = be16_to_cpu(ch_reg->engine_b);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	engine_a |= IQS269_CHx_ENG_A_MEAS_CAP_SIZE;
55362306a36Sopenharmony_ci	if (fwnode_property_present(ch_node, "azoteq,meas-cap-decrease"))
55462306a36Sopenharmony_ci		engine_a &= ~IQS269_CHx_ENG_A_MEAS_CAP_SIZE;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	engine_a |= IQS269_CHx_ENG_A_RX_GND_INACTIVE;
55762306a36Sopenharmony_ci	if (fwnode_property_present(ch_node, "azoteq,rx-float-inactive"))
55862306a36Sopenharmony_ci		engine_a &= ~IQS269_CHx_ENG_A_RX_GND_INACTIVE;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	engine_a &= ~IQS269_CHx_ENG_A_LOCAL_CAP_SIZE;
56162306a36Sopenharmony_ci	engine_b &= ~IQS269_CHx_ENG_B_LOCAL_CAP_ENABLE;
56262306a36Sopenharmony_ci	if (!fwnode_property_read_u32(ch_node, "azoteq,local-cap-size", &val)) {
56362306a36Sopenharmony_ci		switch (val) {
56462306a36Sopenharmony_ci		case IQS269_LOCAL_CAP_SIZE_0:
56562306a36Sopenharmony_ci			break;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci		case IQS269_LOCAL_CAP_SIZE_GLOBAL_0pF5:
56862306a36Sopenharmony_ci			engine_a |= IQS269_CHx_ENG_A_LOCAL_CAP_SIZE;
56962306a36Sopenharmony_ci			fallthrough;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci		case IQS269_LOCAL_CAP_SIZE_GLOBAL_ONLY:
57262306a36Sopenharmony_ci			engine_b |= IQS269_CHx_ENG_B_LOCAL_CAP_ENABLE;
57362306a36Sopenharmony_ci			break;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci		default:
57662306a36Sopenharmony_ci			dev_err(&client->dev,
57762306a36Sopenharmony_ci				"Invalid channel %u local cap. size: %u\n", reg,
57862306a36Sopenharmony_ci				val);
57962306a36Sopenharmony_ci			return -EINVAL;
58062306a36Sopenharmony_ci		}
58162306a36Sopenharmony_ci	}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	engine_a &= ~IQS269_CHx_ENG_A_INV_LOGIC;
58462306a36Sopenharmony_ci	if (fwnode_property_present(ch_node, "azoteq,invert-enable"))
58562306a36Sopenharmony_ci		engine_a |= IQS269_CHx_ENG_A_INV_LOGIC;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	if (!fwnode_property_read_u32(ch_node, "azoteq,proj-bias", &val)) {
58862306a36Sopenharmony_ci		if (val > IQS269_CHx_ENG_A_PROJ_BIAS_MAX) {
58962306a36Sopenharmony_ci			dev_err(&client->dev,
59062306a36Sopenharmony_ci				"Invalid channel %u bias current: %u\n", reg,
59162306a36Sopenharmony_ci				val);
59262306a36Sopenharmony_ci			return -EINVAL;
59362306a36Sopenharmony_ci		}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci		engine_a &= ~IQS269_CHx_ENG_A_PROJ_BIAS_MASK;
59662306a36Sopenharmony_ci		engine_a |= (val << IQS269_CHx_ENG_A_PROJ_BIAS_SHIFT);
59762306a36Sopenharmony_ci	}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	if (!fwnode_property_read_u32(ch_node, "azoteq,sense-mode", &val)) {
60062306a36Sopenharmony_ci		if (val > IQS269_CHx_ENG_A_SENSE_MODE_MAX) {
60162306a36Sopenharmony_ci			dev_err(&client->dev,
60262306a36Sopenharmony_ci				"Invalid channel %u sensing mode: %u\n", reg,
60362306a36Sopenharmony_ci				val);
60462306a36Sopenharmony_ci			return -EINVAL;
60562306a36Sopenharmony_ci		}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci		engine_a &= ~IQS269_CHx_ENG_A_SENSE_MODE_MASK;
60862306a36Sopenharmony_ci		engine_a |= val;
60962306a36Sopenharmony_ci	}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	if (!fwnode_property_read_u32(ch_node, "azoteq,sense-freq", &val)) {
61262306a36Sopenharmony_ci		if (val > IQS269_CHx_ENG_B_SENSE_FREQ_MAX) {
61362306a36Sopenharmony_ci			dev_err(&client->dev,
61462306a36Sopenharmony_ci				"Invalid channel %u sensing frequency: %u\n",
61562306a36Sopenharmony_ci				reg, val);
61662306a36Sopenharmony_ci			return -EINVAL;
61762306a36Sopenharmony_ci		}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci		engine_b &= ~IQS269_CHx_ENG_B_SENSE_FREQ_MASK;
62062306a36Sopenharmony_ci		engine_b |= (val << IQS269_CHx_ENG_B_SENSE_FREQ_SHIFT);
62162306a36Sopenharmony_ci	}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	engine_b &= ~IQS269_CHx_ENG_B_STATIC_ENABLE;
62462306a36Sopenharmony_ci	if (fwnode_property_present(ch_node, "azoteq,static-enable"))
62562306a36Sopenharmony_ci		engine_b |= IQS269_CHx_ENG_B_STATIC_ENABLE;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	ch_reg->engine_a = cpu_to_be16(engine_a);
62862306a36Sopenharmony_ci	ch_reg->engine_b = cpu_to_be16(engine_b);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	if (!fwnode_property_read_u32(ch_node, "azoteq,ati-mode", &val)) {
63162306a36Sopenharmony_ci		error = iqs269_ati_mode_set(iqs269, reg, val);
63262306a36Sopenharmony_ci		if (error) {
63362306a36Sopenharmony_ci			dev_err(&client->dev,
63462306a36Sopenharmony_ci				"Invalid channel %u ATI mode: %u\n", reg, val);
63562306a36Sopenharmony_ci			return error;
63662306a36Sopenharmony_ci		}
63762306a36Sopenharmony_ci	}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	if (!fwnode_property_read_u32(ch_node, "azoteq,ati-base", &val)) {
64062306a36Sopenharmony_ci		error = iqs269_ati_base_set(iqs269, reg, val);
64162306a36Sopenharmony_ci		if (error) {
64262306a36Sopenharmony_ci			dev_err(&client->dev,
64362306a36Sopenharmony_ci				"Invalid channel %u ATI base: %u\n", reg, val);
64462306a36Sopenharmony_ci			return error;
64562306a36Sopenharmony_ci		}
64662306a36Sopenharmony_ci	}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	if (!fwnode_property_read_u32(ch_node, "azoteq,ati-target", &val)) {
64962306a36Sopenharmony_ci		error = iqs269_ati_target_set(iqs269, reg, val);
65062306a36Sopenharmony_ci		if (error) {
65162306a36Sopenharmony_ci			dev_err(&client->dev,
65262306a36Sopenharmony_ci				"Invalid channel %u ATI target: %u\n", reg,
65362306a36Sopenharmony_ci				val);
65462306a36Sopenharmony_ci			return error;
65562306a36Sopenharmony_ci		}
65662306a36Sopenharmony_ci	}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	error = iqs269_parse_mask(ch_node, "azoteq,assoc-select",
65962306a36Sopenharmony_ci				  &ch_reg->assoc_select);
66062306a36Sopenharmony_ci	if (error) {
66162306a36Sopenharmony_ci		dev_err(&client->dev, "Invalid channel %u association: %d\n",
66262306a36Sopenharmony_ci			reg, error);
66362306a36Sopenharmony_ci		return error;
66462306a36Sopenharmony_ci	}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	if (!fwnode_property_read_u32(ch_node, "azoteq,assoc-weight", &val)) {
66762306a36Sopenharmony_ci		if (val > IQS269_CHx_WEIGHT_MAX) {
66862306a36Sopenharmony_ci			dev_err(&client->dev,
66962306a36Sopenharmony_ci				"Invalid channel %u associated weight: %u\n",
67062306a36Sopenharmony_ci				reg, val);
67162306a36Sopenharmony_ci			return -EINVAL;
67262306a36Sopenharmony_ci		}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci		ch_reg->assoc_weight = val;
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(iqs269_events); i++) {
67862306a36Sopenharmony_ci		ev_node = fwnode_get_named_child_node(ch_node,
67962306a36Sopenharmony_ci						      iqs269_events[i].name);
68062306a36Sopenharmony_ci		if (!ev_node)
68162306a36Sopenharmony_ci			continue;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci		if (!fwnode_property_read_u32(ev_node, "azoteq,thresh", &val)) {
68462306a36Sopenharmony_ci			if (val > IQS269_CHx_THRESH_MAX) {
68562306a36Sopenharmony_ci				dev_err(&client->dev,
68662306a36Sopenharmony_ci					"Invalid channel %u threshold: %u\n",
68762306a36Sopenharmony_ci					reg, val);
68862306a36Sopenharmony_ci				fwnode_handle_put(ev_node);
68962306a36Sopenharmony_ci				return -EINVAL;
69062306a36Sopenharmony_ci			}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci			ch_reg->thresh[iqs269_events[i].th_offs] = val;
69362306a36Sopenharmony_ci		}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci		if (!fwnode_property_read_u32(ev_node, "azoteq,hyst", &val)) {
69662306a36Sopenharmony_ci			u8 *hyst = &ch_reg->hyst;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci			if (val > IQS269_CHx_HYST_MAX) {
69962306a36Sopenharmony_ci				dev_err(&client->dev,
70062306a36Sopenharmony_ci					"Invalid channel %u hysteresis: %u\n",
70162306a36Sopenharmony_ci					reg, val);
70262306a36Sopenharmony_ci				fwnode_handle_put(ev_node);
70362306a36Sopenharmony_ci				return -EINVAL;
70462306a36Sopenharmony_ci			}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci			if (i == IQS269_EVENT_DEEP_DN ||
70762306a36Sopenharmony_ci			    i == IQS269_EVENT_DEEP_UP) {
70862306a36Sopenharmony_ci				*hyst &= ~IQS269_CHx_HYST_DEEP_MASK;
70962306a36Sopenharmony_ci				*hyst |= (val << IQS269_CHx_HYST_DEEP_SHIFT);
71062306a36Sopenharmony_ci			} else if (i == IQS269_EVENT_TOUCH_DN ||
71162306a36Sopenharmony_ci				   i == IQS269_EVENT_TOUCH_UP) {
71262306a36Sopenharmony_ci				*hyst &= ~IQS269_CHx_HYST_TOUCH_MASK;
71362306a36Sopenharmony_ci				*hyst |= val;
71462306a36Sopenharmony_ci			}
71562306a36Sopenharmony_ci		}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci		error = fwnode_property_read_u32(ev_node, "linux,code", &val);
71862306a36Sopenharmony_ci		fwnode_handle_put(ev_node);
71962306a36Sopenharmony_ci		if (error == -EINVAL) {
72062306a36Sopenharmony_ci			continue;
72162306a36Sopenharmony_ci		} else if (error) {
72262306a36Sopenharmony_ci			dev_err(&client->dev,
72362306a36Sopenharmony_ci				"Failed to read channel %u code: %d\n", reg,
72462306a36Sopenharmony_ci				error);
72562306a36Sopenharmony_ci			return error;
72662306a36Sopenharmony_ci		}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci		switch (reg) {
72962306a36Sopenharmony_ci		case IQS269_CHx_HALL_ACTIVE:
73062306a36Sopenharmony_ci			if (iqs269->hall_enable) {
73162306a36Sopenharmony_ci				iqs269->switches[i].code = val;
73262306a36Sopenharmony_ci				iqs269->switches[i].enabled = true;
73362306a36Sopenharmony_ci			}
73462306a36Sopenharmony_ci			fallthrough;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci		case IQS269_CHx_HALL_INACTIVE:
73762306a36Sopenharmony_ci			if (iqs269->hall_enable)
73862306a36Sopenharmony_ci				break;
73962306a36Sopenharmony_ci			fallthrough;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci		default:
74262306a36Sopenharmony_ci			iqs269->keycode[i * IQS269_NUM_CH + reg] = val;
74362306a36Sopenharmony_ci		}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci		iqs269->sys_reg.event_mask &= ~iqs269_events[i].mask;
74662306a36Sopenharmony_ci	}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	return 0;
74962306a36Sopenharmony_ci}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_cistatic int iqs269_parse_prop(struct iqs269_private *iqs269)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	struct iqs269_sys_reg *sys_reg = &iqs269->sys_reg;
75462306a36Sopenharmony_ci	struct i2c_client *client = iqs269->client;
75562306a36Sopenharmony_ci	struct fwnode_handle *ch_node;
75662306a36Sopenharmony_ci	u16 general, misc_a, misc_b;
75762306a36Sopenharmony_ci	unsigned int val;
75862306a36Sopenharmony_ci	int error;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	iqs269->hall_enable = device_property_present(&client->dev,
76162306a36Sopenharmony_ci						      "azoteq,hall-enable");
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	error = regmap_raw_read(iqs269->regmap, IQS269_SYS_SETTINGS, sys_reg,
76462306a36Sopenharmony_ci				sizeof(*sys_reg));
76562306a36Sopenharmony_ci	if (error)
76662306a36Sopenharmony_ci		return error;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	if (!device_property_read_u32(&client->dev, "azoteq,filt-str-lp-lta",
76962306a36Sopenharmony_ci				      &val)) {
77062306a36Sopenharmony_ci		if (val > IQS269_FILT_STR_MAX) {
77162306a36Sopenharmony_ci			dev_err(&client->dev, "Invalid filter strength: %u\n",
77262306a36Sopenharmony_ci				val);
77362306a36Sopenharmony_ci			return -EINVAL;
77462306a36Sopenharmony_ci		}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci		sys_reg->filter &= ~IQS269_FILT_STR_LP_LTA_MASK;
77762306a36Sopenharmony_ci		sys_reg->filter |= (val << IQS269_FILT_STR_LP_LTA_SHIFT);
77862306a36Sopenharmony_ci	}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	if (!device_property_read_u32(&client->dev, "azoteq,filt-str-lp-cnt",
78162306a36Sopenharmony_ci				      &val)) {
78262306a36Sopenharmony_ci		if (val > IQS269_FILT_STR_MAX) {
78362306a36Sopenharmony_ci			dev_err(&client->dev, "Invalid filter strength: %u\n",
78462306a36Sopenharmony_ci				val);
78562306a36Sopenharmony_ci			return -EINVAL;
78662306a36Sopenharmony_ci		}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci		sys_reg->filter &= ~IQS269_FILT_STR_LP_CNT_MASK;
78962306a36Sopenharmony_ci		sys_reg->filter |= (val << IQS269_FILT_STR_LP_CNT_SHIFT);
79062306a36Sopenharmony_ci	}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	if (!device_property_read_u32(&client->dev, "azoteq,filt-str-np-lta",
79362306a36Sopenharmony_ci				      &val)) {
79462306a36Sopenharmony_ci		if (val > IQS269_FILT_STR_MAX) {
79562306a36Sopenharmony_ci			dev_err(&client->dev, "Invalid filter strength: %u\n",
79662306a36Sopenharmony_ci				val);
79762306a36Sopenharmony_ci			return -EINVAL;
79862306a36Sopenharmony_ci		}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci		sys_reg->filter &= ~IQS269_FILT_STR_NP_LTA_MASK;
80162306a36Sopenharmony_ci		sys_reg->filter |= (val << IQS269_FILT_STR_NP_LTA_SHIFT);
80262306a36Sopenharmony_ci	}
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	if (!device_property_read_u32(&client->dev, "azoteq,filt-str-np-cnt",
80562306a36Sopenharmony_ci				      &val)) {
80662306a36Sopenharmony_ci		if (val > IQS269_FILT_STR_MAX) {
80762306a36Sopenharmony_ci			dev_err(&client->dev, "Invalid filter strength: %u\n",
80862306a36Sopenharmony_ci				val);
80962306a36Sopenharmony_ci			return -EINVAL;
81062306a36Sopenharmony_ci		}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci		sys_reg->filter &= ~IQS269_FILT_STR_NP_CNT_MASK;
81362306a36Sopenharmony_ci		sys_reg->filter |= val;
81462306a36Sopenharmony_ci	}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	if (!device_property_read_u32(&client->dev, "azoteq,rate-np-ms",
81762306a36Sopenharmony_ci				      &val)) {
81862306a36Sopenharmony_ci		if (val > IQS269_RATE_NP_MS_MAX) {
81962306a36Sopenharmony_ci			dev_err(&client->dev, "Invalid report rate: %u\n", val);
82062306a36Sopenharmony_ci			return -EINVAL;
82162306a36Sopenharmony_ci		}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci		sys_reg->rate_np = val;
82462306a36Sopenharmony_ci	}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	if (!device_property_read_u32(&client->dev, "azoteq,rate-lp-ms",
82762306a36Sopenharmony_ci				      &val)) {
82862306a36Sopenharmony_ci		if (val > IQS269_RATE_LP_MS_MAX) {
82962306a36Sopenharmony_ci			dev_err(&client->dev, "Invalid report rate: %u\n", val);
83062306a36Sopenharmony_ci			return -EINVAL;
83162306a36Sopenharmony_ci		}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci		sys_reg->rate_lp = val;
83462306a36Sopenharmony_ci	}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	if (!device_property_read_u32(&client->dev, "azoteq,rate-ulp-ms",
83762306a36Sopenharmony_ci				      &val)) {
83862306a36Sopenharmony_ci		if (val > IQS269_RATE_ULP_MS_MAX) {
83962306a36Sopenharmony_ci			dev_err(&client->dev, "Invalid report rate: %u\n", val);
84062306a36Sopenharmony_ci			return -EINVAL;
84162306a36Sopenharmony_ci		}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci		sys_reg->rate_ulp = val / 16;
84462306a36Sopenharmony_ci	}
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	if (!device_property_read_u32(&client->dev, "azoteq,timeout-pwr-ms",
84762306a36Sopenharmony_ci				      &val)) {
84862306a36Sopenharmony_ci		if (val > IQS269_TIMEOUT_PWR_MS_MAX) {
84962306a36Sopenharmony_ci			dev_err(&client->dev, "Invalid timeout: %u\n", val);
85062306a36Sopenharmony_ci			return -EINVAL;
85162306a36Sopenharmony_ci		}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci		sys_reg->timeout_pwr = val / 512;
85462306a36Sopenharmony_ci	}
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	if (!device_property_read_u32(&client->dev, "azoteq,timeout-lta-ms",
85762306a36Sopenharmony_ci				      &val)) {
85862306a36Sopenharmony_ci		if (val > IQS269_TIMEOUT_LTA_MS_MAX) {
85962306a36Sopenharmony_ci			dev_err(&client->dev, "Invalid timeout: %u\n", val);
86062306a36Sopenharmony_ci			return -EINVAL;
86162306a36Sopenharmony_ci		}
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci		sys_reg->timeout_lta = val / 512;
86462306a36Sopenharmony_ci	}
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	misc_a = be16_to_cpu(sys_reg->misc_a);
86762306a36Sopenharmony_ci	misc_b = be16_to_cpu(sys_reg->misc_b);
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	misc_a &= ~IQS269_MISC_A_ATI_BAND_DISABLE;
87062306a36Sopenharmony_ci	if (device_property_present(&client->dev, "azoteq,ati-band-disable"))
87162306a36Sopenharmony_ci		misc_a |= IQS269_MISC_A_ATI_BAND_DISABLE;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	misc_a &= ~IQS269_MISC_A_ATI_LP_ONLY;
87462306a36Sopenharmony_ci	if (device_property_present(&client->dev, "azoteq,ati-lp-only"))
87562306a36Sopenharmony_ci		misc_a |= IQS269_MISC_A_ATI_LP_ONLY;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	misc_a &= ~IQS269_MISC_A_ATI_BAND_TIGHTEN;
87862306a36Sopenharmony_ci	if (device_property_present(&client->dev, "azoteq,ati-band-tighten"))
87962306a36Sopenharmony_ci		misc_a |= IQS269_MISC_A_ATI_BAND_TIGHTEN;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	misc_a &= ~IQS269_MISC_A_FILT_DISABLE;
88262306a36Sopenharmony_ci	if (device_property_present(&client->dev, "azoteq,filt-disable"))
88362306a36Sopenharmony_ci		misc_a |= IQS269_MISC_A_FILT_DISABLE;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	if (!device_property_read_u32(&client->dev, "azoteq,gpio3-select",
88662306a36Sopenharmony_ci				      &val)) {
88762306a36Sopenharmony_ci		if (val >= IQS269_NUM_CH) {
88862306a36Sopenharmony_ci			dev_err(&client->dev, "Invalid GPIO3 selection: %u\n",
88962306a36Sopenharmony_ci				val);
89062306a36Sopenharmony_ci			return -EINVAL;
89162306a36Sopenharmony_ci		}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci		misc_a &= ~IQS269_MISC_A_GPIO3_SELECT_MASK;
89462306a36Sopenharmony_ci		misc_a |= (val << IQS269_MISC_A_GPIO3_SELECT_SHIFT);
89562306a36Sopenharmony_ci	}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	misc_a &= ~IQS269_MISC_A_DUAL_DIR;
89862306a36Sopenharmony_ci	if (device_property_present(&client->dev, "azoteq,dual-direction"))
89962306a36Sopenharmony_ci		misc_a |= IQS269_MISC_A_DUAL_DIR;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	if (!device_property_read_u32(&client->dev, "azoteq,tx-freq", &val)) {
90262306a36Sopenharmony_ci		if (val > IQS269_MISC_A_TX_FREQ_MAX) {
90362306a36Sopenharmony_ci			dev_err(&client->dev,
90462306a36Sopenharmony_ci				"Invalid excitation frequency: %u\n", val);
90562306a36Sopenharmony_ci			return -EINVAL;
90662306a36Sopenharmony_ci		}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci		misc_a &= ~IQS269_MISC_A_TX_FREQ_MASK;
90962306a36Sopenharmony_ci		misc_a |= (val << IQS269_MISC_A_TX_FREQ_SHIFT);
91062306a36Sopenharmony_ci	}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	misc_a &= ~IQS269_MISC_A_GLOBAL_CAP_SIZE;
91362306a36Sopenharmony_ci	if (device_property_present(&client->dev, "azoteq,global-cap-increase"))
91462306a36Sopenharmony_ci		misc_a |= IQS269_MISC_A_GLOBAL_CAP_SIZE;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	if (!device_property_read_u32(&client->dev, "azoteq,reseed-select",
91762306a36Sopenharmony_ci				      &val)) {
91862306a36Sopenharmony_ci		if (val > IQS269_MISC_B_RESEED_UI_SEL_MAX) {
91962306a36Sopenharmony_ci			dev_err(&client->dev, "Invalid reseed selection: %u\n",
92062306a36Sopenharmony_ci				val);
92162306a36Sopenharmony_ci			return -EINVAL;
92262306a36Sopenharmony_ci		}
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci		misc_b &= ~IQS269_MISC_B_RESEED_UI_SEL_MASK;
92562306a36Sopenharmony_ci		misc_b |= (val << IQS269_MISC_B_RESEED_UI_SEL_SHIFT);
92662306a36Sopenharmony_ci	}
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	misc_b &= ~IQS269_MISC_B_TRACKING_UI_ENABLE;
92962306a36Sopenharmony_ci	if (device_property_present(&client->dev, "azoteq,tracking-enable"))
93062306a36Sopenharmony_ci		misc_b |= IQS269_MISC_B_TRACKING_UI_ENABLE;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	if (!device_property_read_u32(&client->dev, "azoteq,filt-str-slider",
93362306a36Sopenharmony_ci				      &val)) {
93462306a36Sopenharmony_ci		if (val > IQS269_FILT_STR_MAX) {
93562306a36Sopenharmony_ci			dev_err(&client->dev, "Invalid filter strength: %u\n",
93662306a36Sopenharmony_ci				val);
93762306a36Sopenharmony_ci			return -EINVAL;
93862306a36Sopenharmony_ci		}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci		misc_b &= ~IQS269_MISC_B_FILT_STR_SLIDER;
94162306a36Sopenharmony_ci		misc_b |= val;
94262306a36Sopenharmony_ci	}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	sys_reg->misc_a = cpu_to_be16(misc_a);
94562306a36Sopenharmony_ci	sys_reg->misc_b = cpu_to_be16(misc_b);
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	sys_reg->active = 0;
94862306a36Sopenharmony_ci	sys_reg->reseed = 0;
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	sys_reg->blocking = 0;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	sys_reg->slider_select[0] = 0;
95362306a36Sopenharmony_ci	sys_reg->slider_select[1] = 0;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	sys_reg->event_mask = ~((u8)IQS269_EVENT_MASK_SYS);
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	device_for_each_child_node(&client->dev, ch_node) {
95862306a36Sopenharmony_ci		error = iqs269_parse_chan(iqs269, ch_node);
95962306a36Sopenharmony_ci		if (error) {
96062306a36Sopenharmony_ci			fwnode_handle_put(ch_node);
96162306a36Sopenharmony_ci			return error;
96262306a36Sopenharmony_ci		}
96362306a36Sopenharmony_ci	}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	/*
96662306a36Sopenharmony_ci	 * Volunteer all active channels to participate in ATI when REDO-ATI is
96762306a36Sopenharmony_ci	 * manually triggered.
96862306a36Sopenharmony_ci	 */
96962306a36Sopenharmony_ci	sys_reg->redo_ati = sys_reg->active;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	general = be16_to_cpu(sys_reg->general);
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	if (device_property_present(&client->dev, "azoteq,clk-div"))
97462306a36Sopenharmony_ci		general |= IQS269_SYS_SETTINGS_CLK_DIV;
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	/*
97762306a36Sopenharmony_ci	 * Configure the device to automatically switch between normal and low-
97862306a36Sopenharmony_ci	 * power modes as a function of sensing activity. Ultra-low-power mode,
97962306a36Sopenharmony_ci	 * if enabled, is reserved for suspend.
98062306a36Sopenharmony_ci	 */
98162306a36Sopenharmony_ci	general &= ~IQS269_SYS_SETTINGS_ULP_AUTO;
98262306a36Sopenharmony_ci	general &= ~IQS269_SYS_SETTINGS_DIS_AUTO;
98362306a36Sopenharmony_ci	general &= ~IQS269_SYS_SETTINGS_PWR_MODE_MASK;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	if (!device_property_read_u32(&client->dev, "azoteq,suspend-mode",
98662306a36Sopenharmony_ci				      &val)) {
98762306a36Sopenharmony_ci		if (val > IQS269_SYS_SETTINGS_PWR_MODE_MAX) {
98862306a36Sopenharmony_ci			dev_err(&client->dev, "Invalid suspend mode: %u\n",
98962306a36Sopenharmony_ci				val);
99062306a36Sopenharmony_ci			return -EINVAL;
99162306a36Sopenharmony_ci		}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci		general |= (val << IQS269_SYS_SETTINGS_PWR_MODE_SHIFT);
99462306a36Sopenharmony_ci	}
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	if (!device_property_read_u32(&client->dev, "azoteq,ulp-update",
99762306a36Sopenharmony_ci				      &val)) {
99862306a36Sopenharmony_ci		if (val > IQS269_SYS_SETTINGS_ULP_UPDATE_MAX) {
99962306a36Sopenharmony_ci			dev_err(&client->dev, "Invalid update rate: %u\n", val);
100062306a36Sopenharmony_ci			return -EINVAL;
100162306a36Sopenharmony_ci		}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci		general &= ~IQS269_SYS_SETTINGS_ULP_UPDATE_MASK;
100462306a36Sopenharmony_ci		general |= (val << IQS269_SYS_SETTINGS_ULP_UPDATE_SHIFT);
100562306a36Sopenharmony_ci	}
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	general &= ~IQS269_SYS_SETTINGS_RESEED_OFFSET;
100862306a36Sopenharmony_ci	if (device_property_present(&client->dev, "azoteq,reseed-offset"))
100962306a36Sopenharmony_ci		general |= IQS269_SYS_SETTINGS_RESEED_OFFSET;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	general |= IQS269_SYS_SETTINGS_EVENT_MODE;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	/*
101462306a36Sopenharmony_ci	 * As per the datasheet, enable streaming during normal-power mode if
101562306a36Sopenharmony_ci	 * either slider is in use. In that case, the device returns to event
101662306a36Sopenharmony_ci	 * mode during low-power mode.
101762306a36Sopenharmony_ci	 */
101862306a36Sopenharmony_ci	if (sys_reg->slider_select[0] || sys_reg->slider_select[1])
101962306a36Sopenharmony_ci		general |= IQS269_SYS_SETTINGS_EVENT_MODE_LP;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	general |= IQS269_SYS_SETTINGS_REDO_ATI;
102262306a36Sopenharmony_ci	general |= IQS269_SYS_SETTINGS_ACK_RESET;
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	sys_reg->general = cpu_to_be16(general);
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	return 0;
102762306a36Sopenharmony_ci}
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_cistatic int iqs269_dev_init(struct iqs269_private *iqs269)
103062306a36Sopenharmony_ci{
103162306a36Sopenharmony_ci	int error;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	mutex_lock(&iqs269->lock);
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	error = regmap_update_bits(iqs269->regmap, IQS269_HALL_UI,
103662306a36Sopenharmony_ci				   IQS269_HALL_UI_ENABLE,
103762306a36Sopenharmony_ci				   iqs269->hall_enable ? ~0 : 0);
103862306a36Sopenharmony_ci	if (error)
103962306a36Sopenharmony_ci		goto err_mutex;
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	error = regmap_raw_write(iqs269->regmap, IQS269_SYS_SETTINGS,
104262306a36Sopenharmony_ci				 &iqs269->sys_reg, sizeof(iqs269->sys_reg));
104362306a36Sopenharmony_ci	if (error)
104462306a36Sopenharmony_ci		goto err_mutex;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	/*
104762306a36Sopenharmony_ci	 * The following delay gives the device time to deassert its RDY output
104862306a36Sopenharmony_ci	 * so as to prevent an interrupt from being serviced prematurely.
104962306a36Sopenharmony_ci	 */
105062306a36Sopenharmony_ci	usleep_range(2000, 2100);
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	iqs269->ati_current = true;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_cierr_mutex:
105562306a36Sopenharmony_ci	mutex_unlock(&iqs269->lock);
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	return error;
105862306a36Sopenharmony_ci}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_cistatic int iqs269_input_init(struct iqs269_private *iqs269)
106162306a36Sopenharmony_ci{
106262306a36Sopenharmony_ci	struct i2c_client *client = iqs269->client;
106362306a36Sopenharmony_ci	unsigned int sw_code, keycode;
106462306a36Sopenharmony_ci	int error, i, j;
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	iqs269->keypad = devm_input_allocate_device(&client->dev);
106762306a36Sopenharmony_ci	if (!iqs269->keypad)
106862306a36Sopenharmony_ci		return -ENOMEM;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	iqs269->keypad->keycodemax = ARRAY_SIZE(iqs269->keycode);
107162306a36Sopenharmony_ci	iqs269->keypad->keycode = iqs269->keycode;
107262306a36Sopenharmony_ci	iqs269->keypad->keycodesize = sizeof(*iqs269->keycode);
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	iqs269->keypad->name = "iqs269a_keypad";
107562306a36Sopenharmony_ci	iqs269->keypad->id.bustype = BUS_I2C;
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(iqs269_events); i++) {
107862306a36Sopenharmony_ci		sw_code = iqs269->switches[i].code;
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci		for (j = 0; j < IQS269_NUM_CH; j++) {
108162306a36Sopenharmony_ci			keycode = iqs269->keycode[i * IQS269_NUM_CH + j];
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci			/*
108462306a36Sopenharmony_ci			 * Hall-effect sensing repurposes a pair of dedicated
108562306a36Sopenharmony_ci			 * channels, only one of which reports events.
108662306a36Sopenharmony_ci			 */
108762306a36Sopenharmony_ci			switch (j) {
108862306a36Sopenharmony_ci			case IQS269_CHx_HALL_ACTIVE:
108962306a36Sopenharmony_ci				if (iqs269->hall_enable &&
109062306a36Sopenharmony_ci				    iqs269->switches[i].enabled)
109162306a36Sopenharmony_ci					input_set_capability(iqs269->keypad,
109262306a36Sopenharmony_ci							     EV_SW, sw_code);
109362306a36Sopenharmony_ci				fallthrough;
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci			case IQS269_CHx_HALL_INACTIVE:
109662306a36Sopenharmony_ci				if (iqs269->hall_enable)
109762306a36Sopenharmony_ci					continue;
109862306a36Sopenharmony_ci				fallthrough;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci			default:
110162306a36Sopenharmony_ci				if (keycode != KEY_RESERVED)
110262306a36Sopenharmony_ci					input_set_capability(iqs269->keypad,
110362306a36Sopenharmony_ci							     EV_KEY, keycode);
110462306a36Sopenharmony_ci			}
110562306a36Sopenharmony_ci		}
110662306a36Sopenharmony_ci	}
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	for (i = 0; i < IQS269_NUM_SL; i++) {
110962306a36Sopenharmony_ci		if (!iqs269->sys_reg.slider_select[i])
111062306a36Sopenharmony_ci			continue;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci		iqs269->slider[i] = devm_input_allocate_device(&client->dev);
111362306a36Sopenharmony_ci		if (!iqs269->slider[i])
111462306a36Sopenharmony_ci			return -ENOMEM;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci		iqs269->slider[i]->name = i ? "iqs269a_slider_1"
111762306a36Sopenharmony_ci					    : "iqs269a_slider_0";
111862306a36Sopenharmony_ci		iqs269->slider[i]->id.bustype = BUS_I2C;
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci		input_set_capability(iqs269->slider[i], EV_KEY, BTN_TOUCH);
112162306a36Sopenharmony_ci		input_set_abs_params(iqs269->slider[i], ABS_X, 0, 255, 0, 0);
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci		error = input_register_device(iqs269->slider[i]);
112462306a36Sopenharmony_ci		if (error) {
112562306a36Sopenharmony_ci			dev_err(&client->dev,
112662306a36Sopenharmony_ci				"Failed to register slider %d: %d\n", i, error);
112762306a36Sopenharmony_ci			return error;
112862306a36Sopenharmony_ci		}
112962306a36Sopenharmony_ci	}
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	return 0;
113262306a36Sopenharmony_ci}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_cistatic int iqs269_report(struct iqs269_private *iqs269)
113562306a36Sopenharmony_ci{
113662306a36Sopenharmony_ci	struct i2c_client *client = iqs269->client;
113762306a36Sopenharmony_ci	struct iqs269_flags flags;
113862306a36Sopenharmony_ci	unsigned int sw_code, keycode;
113962306a36Sopenharmony_ci	int error, i, j;
114062306a36Sopenharmony_ci	u8 slider_x[IQS269_NUM_SL];
114162306a36Sopenharmony_ci	u8 dir_mask, state;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	error = regmap_raw_read(iqs269->regmap, IQS269_SYS_FLAGS, &flags,
114462306a36Sopenharmony_ci				sizeof(flags));
114562306a36Sopenharmony_ci	if (error) {
114662306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to read device status: %d\n",
114762306a36Sopenharmony_ci			error);
114862306a36Sopenharmony_ci		return error;
114962306a36Sopenharmony_ci	}
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	/*
115262306a36Sopenharmony_ci	 * The device resets itself if its own watchdog bites, which can happen
115362306a36Sopenharmony_ci	 * in the event of an I2C communication error. In this case, the device
115462306a36Sopenharmony_ci	 * asserts a SHOW_RESET interrupt and all registers must be restored.
115562306a36Sopenharmony_ci	 */
115662306a36Sopenharmony_ci	if (be16_to_cpu(flags.system) & IQS269_SYS_FLAGS_SHOW_RESET) {
115762306a36Sopenharmony_ci		dev_err(&client->dev, "Unexpected device reset\n");
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci		error = iqs269_dev_init(iqs269);
116062306a36Sopenharmony_ci		if (error)
116162306a36Sopenharmony_ci			dev_err(&client->dev,
116262306a36Sopenharmony_ci				"Failed to re-initialize device: %d\n", error);
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci		return error;
116562306a36Sopenharmony_ci	}
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	if (be16_to_cpu(flags.system) & IQS269_SYS_FLAGS_IN_ATI)
116862306a36Sopenharmony_ci		return 0;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	error = regmap_raw_read(iqs269->regmap, IQS269_SLIDER_X, slider_x,
117162306a36Sopenharmony_ci				sizeof(slider_x));
117262306a36Sopenharmony_ci	if (error) {
117362306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to read slider position: %d\n",
117462306a36Sopenharmony_ci			error);
117562306a36Sopenharmony_ci		return error;
117662306a36Sopenharmony_ci	}
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	for (i = 0; i < IQS269_NUM_SL; i++) {
117962306a36Sopenharmony_ci		if (!iqs269->sys_reg.slider_select[i])
118062306a36Sopenharmony_ci			continue;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci		/*
118362306a36Sopenharmony_ci		 * Report BTN_TOUCH if any channel that participates in the
118462306a36Sopenharmony_ci		 * slider is in a state of touch.
118562306a36Sopenharmony_ci		 */
118662306a36Sopenharmony_ci		if (flags.states[IQS269_ST_OFFS_TOUCH] &
118762306a36Sopenharmony_ci		    iqs269->sys_reg.slider_select[i]) {
118862306a36Sopenharmony_ci			input_report_key(iqs269->slider[i], BTN_TOUCH, 1);
118962306a36Sopenharmony_ci			input_report_abs(iqs269->slider[i], ABS_X, slider_x[i]);
119062306a36Sopenharmony_ci		} else {
119162306a36Sopenharmony_ci			input_report_key(iqs269->slider[i], BTN_TOUCH, 0);
119262306a36Sopenharmony_ci		}
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci		input_sync(iqs269->slider[i]);
119562306a36Sopenharmony_ci	}
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(iqs269_events); i++) {
119862306a36Sopenharmony_ci		dir_mask = flags.states[IQS269_ST_OFFS_DIR];
119962306a36Sopenharmony_ci		if (!iqs269_events[i].dir_up)
120062306a36Sopenharmony_ci			dir_mask = ~dir_mask;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci		state = flags.states[iqs269_events[i].st_offs] & dir_mask;
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci		sw_code = iqs269->switches[i].code;
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci		for (j = 0; j < IQS269_NUM_CH; j++) {
120762306a36Sopenharmony_ci			keycode = iqs269->keycode[i * IQS269_NUM_CH + j];
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci			switch (j) {
121062306a36Sopenharmony_ci			case IQS269_CHx_HALL_ACTIVE:
121162306a36Sopenharmony_ci				if (iqs269->hall_enable &&
121262306a36Sopenharmony_ci				    iqs269->switches[i].enabled)
121362306a36Sopenharmony_ci					input_report_switch(iqs269->keypad,
121462306a36Sopenharmony_ci							    sw_code,
121562306a36Sopenharmony_ci							    state & BIT(j));
121662306a36Sopenharmony_ci				fallthrough;
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci			case IQS269_CHx_HALL_INACTIVE:
121962306a36Sopenharmony_ci				if (iqs269->hall_enable)
122062306a36Sopenharmony_ci					continue;
122162306a36Sopenharmony_ci				fallthrough;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci			default:
122462306a36Sopenharmony_ci				input_report_key(iqs269->keypad, keycode,
122562306a36Sopenharmony_ci						 state & BIT(j));
122662306a36Sopenharmony_ci			}
122762306a36Sopenharmony_ci		}
122862306a36Sopenharmony_ci	}
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	input_sync(iqs269->keypad);
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	/*
123362306a36Sopenharmony_ci	 * The following completion signals that ATI has finished, any initial
123462306a36Sopenharmony_ci	 * switch states have been reported and the keypad can be registered.
123562306a36Sopenharmony_ci	 */
123662306a36Sopenharmony_ci	complete_all(&iqs269->ati_done);
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	return 0;
123962306a36Sopenharmony_ci}
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_cistatic irqreturn_t iqs269_irq(int irq, void *context)
124262306a36Sopenharmony_ci{
124362306a36Sopenharmony_ci	struct iqs269_private *iqs269 = context;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	if (iqs269_report(iqs269))
124662306a36Sopenharmony_ci		return IRQ_NONE;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	/*
124962306a36Sopenharmony_ci	 * The device does not deassert its interrupt (RDY) pin until shortly
125062306a36Sopenharmony_ci	 * after receiving an I2C stop condition; the following delay ensures
125162306a36Sopenharmony_ci	 * the interrupt handler does not return before this time.
125262306a36Sopenharmony_ci	 */
125362306a36Sopenharmony_ci	iqs269_irq_wait();
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	return IRQ_HANDLED;
125662306a36Sopenharmony_ci}
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_cistatic ssize_t counts_show(struct device *dev,
125962306a36Sopenharmony_ci			   struct device_attribute *attr, char *buf)
126062306a36Sopenharmony_ci{
126162306a36Sopenharmony_ci	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
126262306a36Sopenharmony_ci	struct i2c_client *client = iqs269->client;
126362306a36Sopenharmony_ci	__le16 counts;
126462306a36Sopenharmony_ci	int error;
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	if (!iqs269->ati_current || iqs269->hall_enable)
126762306a36Sopenharmony_ci		return -EPERM;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	if (!completion_done(&iqs269->ati_done))
127062306a36Sopenharmony_ci		return -EBUSY;
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	/*
127362306a36Sopenharmony_ci	 * Unsolicited I2C communication prompts the device to assert its RDY
127462306a36Sopenharmony_ci	 * pin, so disable the interrupt line until the operation is finished
127562306a36Sopenharmony_ci	 * and RDY has been deasserted.
127662306a36Sopenharmony_ci	 */
127762306a36Sopenharmony_ci	disable_irq(client->irq);
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	error = regmap_raw_read(iqs269->regmap,
128062306a36Sopenharmony_ci				IQS269_CHx_COUNTS + iqs269->ch_num * 2,
128162306a36Sopenharmony_ci				&counts, sizeof(counts));
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	iqs269_irq_wait();
128462306a36Sopenharmony_ci	enable_irq(client->irq);
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	if (error)
128762306a36Sopenharmony_ci		return error;
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%u\n", le16_to_cpu(counts));
129062306a36Sopenharmony_ci}
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_cistatic ssize_t hall_bin_show(struct device *dev,
129362306a36Sopenharmony_ci			     struct device_attribute *attr, char *buf)
129462306a36Sopenharmony_ci{
129562306a36Sopenharmony_ci	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
129662306a36Sopenharmony_ci	struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
129762306a36Sopenharmony_ci	struct i2c_client *client = iqs269->client;
129862306a36Sopenharmony_ci	unsigned int val;
129962306a36Sopenharmony_ci	int error;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	disable_irq(client->irq);
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	error = regmap_read(iqs269->regmap, IQS269_CAL_DATA_A, &val);
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	iqs269_irq_wait();
130662306a36Sopenharmony_ci	enable_irq(client->irq);
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	if (error)
130962306a36Sopenharmony_ci		return error;
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	switch (ch_reg[IQS269_CHx_HALL_ACTIVE].rx_enable &
131262306a36Sopenharmony_ci		ch_reg[IQS269_CHx_HALL_INACTIVE].rx_enable) {
131362306a36Sopenharmony_ci	case IQS269_HALL_PAD_R:
131462306a36Sopenharmony_ci		val &= IQS269_CAL_DATA_A_HALL_BIN_R_MASK;
131562306a36Sopenharmony_ci		val >>= IQS269_CAL_DATA_A_HALL_BIN_R_SHIFT;
131662306a36Sopenharmony_ci		break;
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	case IQS269_HALL_PAD_L:
131962306a36Sopenharmony_ci		val &= IQS269_CAL_DATA_A_HALL_BIN_L_MASK;
132062306a36Sopenharmony_ci		val >>= IQS269_CAL_DATA_A_HALL_BIN_L_SHIFT;
132162306a36Sopenharmony_ci		break;
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	default:
132462306a36Sopenharmony_ci		return -EINVAL;
132562306a36Sopenharmony_ci	}
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%u\n", val);
132862306a36Sopenharmony_ci}
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_cistatic ssize_t hall_enable_show(struct device *dev,
133162306a36Sopenharmony_ci				struct device_attribute *attr, char *buf)
133262306a36Sopenharmony_ci{
133362306a36Sopenharmony_ci	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%u\n", iqs269->hall_enable);
133662306a36Sopenharmony_ci}
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_cistatic ssize_t hall_enable_store(struct device *dev,
133962306a36Sopenharmony_ci				 struct device_attribute *attr, const char *buf,
134062306a36Sopenharmony_ci				 size_t count)
134162306a36Sopenharmony_ci{
134262306a36Sopenharmony_ci	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
134362306a36Sopenharmony_ci	unsigned int val;
134462306a36Sopenharmony_ci	int error;
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	error = kstrtouint(buf, 10, &val);
134762306a36Sopenharmony_ci	if (error)
134862306a36Sopenharmony_ci		return error;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	mutex_lock(&iqs269->lock);
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	iqs269->hall_enable = val;
135362306a36Sopenharmony_ci	iqs269->ati_current = false;
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	mutex_unlock(&iqs269->lock);
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	return count;
135862306a36Sopenharmony_ci}
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_cistatic ssize_t ch_number_show(struct device *dev,
136162306a36Sopenharmony_ci			      struct device_attribute *attr, char *buf)
136262306a36Sopenharmony_ci{
136362306a36Sopenharmony_ci	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%u\n", iqs269->ch_num);
136662306a36Sopenharmony_ci}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_cistatic ssize_t ch_number_store(struct device *dev,
136962306a36Sopenharmony_ci			       struct device_attribute *attr, const char *buf,
137062306a36Sopenharmony_ci			       size_t count)
137162306a36Sopenharmony_ci{
137262306a36Sopenharmony_ci	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
137362306a36Sopenharmony_ci	unsigned int val;
137462306a36Sopenharmony_ci	int error;
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	error = kstrtouint(buf, 10, &val);
137762306a36Sopenharmony_ci	if (error)
137862306a36Sopenharmony_ci		return error;
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	if (val >= IQS269_NUM_CH)
138162306a36Sopenharmony_ci		return -EINVAL;
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	iqs269->ch_num = val;
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	return count;
138662306a36Sopenharmony_ci}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_cistatic ssize_t rx_enable_show(struct device *dev,
138962306a36Sopenharmony_ci			      struct device_attribute *attr, char *buf)
139062306a36Sopenharmony_ci{
139162306a36Sopenharmony_ci	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
139262306a36Sopenharmony_ci	struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%u\n",
139562306a36Sopenharmony_ci			 ch_reg[iqs269->ch_num].rx_enable);
139662306a36Sopenharmony_ci}
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_cistatic ssize_t rx_enable_store(struct device *dev,
139962306a36Sopenharmony_ci			       struct device_attribute *attr, const char *buf,
140062306a36Sopenharmony_ci			       size_t count)
140162306a36Sopenharmony_ci{
140262306a36Sopenharmony_ci	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
140362306a36Sopenharmony_ci	struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
140462306a36Sopenharmony_ci	unsigned int val;
140562306a36Sopenharmony_ci	int error;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	error = kstrtouint(buf, 10, &val);
140862306a36Sopenharmony_ci	if (error)
140962306a36Sopenharmony_ci		return error;
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	if (val > 0xFF)
141262306a36Sopenharmony_ci		return -EINVAL;
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	mutex_lock(&iqs269->lock);
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	ch_reg[iqs269->ch_num].rx_enable = val;
141762306a36Sopenharmony_ci	iqs269->ati_current = false;
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	mutex_unlock(&iqs269->lock);
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	return count;
142262306a36Sopenharmony_ci}
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_cistatic ssize_t ati_mode_show(struct device *dev,
142562306a36Sopenharmony_ci			     struct device_attribute *attr, char *buf)
142662306a36Sopenharmony_ci{
142762306a36Sopenharmony_ci	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
142862306a36Sopenharmony_ci	unsigned int val;
142962306a36Sopenharmony_ci	int error;
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	error = iqs269_ati_mode_get(iqs269, iqs269->ch_num, &val);
143262306a36Sopenharmony_ci	if (error)
143362306a36Sopenharmony_ci		return error;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%u\n", val);
143662306a36Sopenharmony_ci}
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_cistatic ssize_t ati_mode_store(struct device *dev,
143962306a36Sopenharmony_ci			      struct device_attribute *attr, const char *buf,
144062306a36Sopenharmony_ci			      size_t count)
144162306a36Sopenharmony_ci{
144262306a36Sopenharmony_ci	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
144362306a36Sopenharmony_ci	unsigned int val;
144462306a36Sopenharmony_ci	int error;
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	error = kstrtouint(buf, 10, &val);
144762306a36Sopenharmony_ci	if (error)
144862306a36Sopenharmony_ci		return error;
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	error = iqs269_ati_mode_set(iqs269, iqs269->ch_num, val);
145162306a36Sopenharmony_ci	if (error)
145262306a36Sopenharmony_ci		return error;
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	return count;
145562306a36Sopenharmony_ci}
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_cistatic ssize_t ati_base_show(struct device *dev,
145862306a36Sopenharmony_ci			     struct device_attribute *attr, char *buf)
145962306a36Sopenharmony_ci{
146062306a36Sopenharmony_ci	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
146162306a36Sopenharmony_ci	unsigned int val;
146262306a36Sopenharmony_ci	int error;
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	error = iqs269_ati_base_get(iqs269, iqs269->ch_num, &val);
146562306a36Sopenharmony_ci	if (error)
146662306a36Sopenharmony_ci		return error;
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%u\n", val);
146962306a36Sopenharmony_ci}
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_cistatic ssize_t ati_base_store(struct device *dev,
147262306a36Sopenharmony_ci			      struct device_attribute *attr, const char *buf,
147362306a36Sopenharmony_ci			      size_t count)
147462306a36Sopenharmony_ci{
147562306a36Sopenharmony_ci	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
147662306a36Sopenharmony_ci	unsigned int val;
147762306a36Sopenharmony_ci	int error;
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	error = kstrtouint(buf, 10, &val);
148062306a36Sopenharmony_ci	if (error)
148162306a36Sopenharmony_ci		return error;
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	error = iqs269_ati_base_set(iqs269, iqs269->ch_num, val);
148462306a36Sopenharmony_ci	if (error)
148562306a36Sopenharmony_ci		return error;
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	return count;
148862306a36Sopenharmony_ci}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_cistatic ssize_t ati_target_show(struct device *dev,
149162306a36Sopenharmony_ci			       struct device_attribute *attr, char *buf)
149262306a36Sopenharmony_ci{
149362306a36Sopenharmony_ci	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
149462306a36Sopenharmony_ci	unsigned int val;
149562306a36Sopenharmony_ci	int error;
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	error = iqs269_ati_target_get(iqs269, iqs269->ch_num, &val);
149862306a36Sopenharmony_ci	if (error)
149962306a36Sopenharmony_ci		return error;
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%u\n", val);
150262306a36Sopenharmony_ci}
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_cistatic ssize_t ati_target_store(struct device *dev,
150562306a36Sopenharmony_ci				struct device_attribute *attr, const char *buf,
150662306a36Sopenharmony_ci				size_t count)
150762306a36Sopenharmony_ci{
150862306a36Sopenharmony_ci	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
150962306a36Sopenharmony_ci	unsigned int val;
151062306a36Sopenharmony_ci	int error;
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci	error = kstrtouint(buf, 10, &val);
151362306a36Sopenharmony_ci	if (error)
151462306a36Sopenharmony_ci		return error;
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	error = iqs269_ati_target_set(iqs269, iqs269->ch_num, val);
151762306a36Sopenharmony_ci	if (error)
151862306a36Sopenharmony_ci		return error;
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	return count;
152162306a36Sopenharmony_ci}
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_cistatic ssize_t ati_trigger_show(struct device *dev,
152462306a36Sopenharmony_ci				struct device_attribute *attr, char *buf)
152562306a36Sopenharmony_ci{
152662306a36Sopenharmony_ci	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%u\n",
152962306a36Sopenharmony_ci			 iqs269->ati_current &&
153062306a36Sopenharmony_ci			 completion_done(&iqs269->ati_done));
153162306a36Sopenharmony_ci}
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_cistatic ssize_t ati_trigger_store(struct device *dev,
153462306a36Sopenharmony_ci				 struct device_attribute *attr, const char *buf,
153562306a36Sopenharmony_ci				 size_t count)
153662306a36Sopenharmony_ci{
153762306a36Sopenharmony_ci	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
153862306a36Sopenharmony_ci	struct i2c_client *client = iqs269->client;
153962306a36Sopenharmony_ci	unsigned int val;
154062306a36Sopenharmony_ci	int error;
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	error = kstrtouint(buf, 10, &val);
154362306a36Sopenharmony_ci	if (error)
154462306a36Sopenharmony_ci		return error;
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	if (!val)
154762306a36Sopenharmony_ci		return count;
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	disable_irq(client->irq);
155062306a36Sopenharmony_ci	reinit_completion(&iqs269->ati_done);
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	error = iqs269_dev_init(iqs269);
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	iqs269_irq_wait();
155562306a36Sopenharmony_ci	enable_irq(client->irq);
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	if (error)
155862306a36Sopenharmony_ci		return error;
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	if (!wait_for_completion_timeout(&iqs269->ati_done,
156162306a36Sopenharmony_ci					 msecs_to_jiffies(2000)))
156262306a36Sopenharmony_ci		return -ETIMEDOUT;
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	return count;
156562306a36Sopenharmony_ci}
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(counts);
156862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(hall_bin);
156962306a36Sopenharmony_cistatic DEVICE_ATTR_RW(hall_enable);
157062306a36Sopenharmony_cistatic DEVICE_ATTR_RW(ch_number);
157162306a36Sopenharmony_cistatic DEVICE_ATTR_RW(rx_enable);
157262306a36Sopenharmony_cistatic DEVICE_ATTR_RW(ati_mode);
157362306a36Sopenharmony_cistatic DEVICE_ATTR_RW(ati_base);
157462306a36Sopenharmony_cistatic DEVICE_ATTR_RW(ati_target);
157562306a36Sopenharmony_cistatic DEVICE_ATTR_RW(ati_trigger);
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_cistatic struct attribute *iqs269_attrs[] = {
157862306a36Sopenharmony_ci	&dev_attr_counts.attr,
157962306a36Sopenharmony_ci	&dev_attr_hall_bin.attr,
158062306a36Sopenharmony_ci	&dev_attr_hall_enable.attr,
158162306a36Sopenharmony_ci	&dev_attr_ch_number.attr,
158262306a36Sopenharmony_ci	&dev_attr_rx_enable.attr,
158362306a36Sopenharmony_ci	&dev_attr_ati_mode.attr,
158462306a36Sopenharmony_ci	&dev_attr_ati_base.attr,
158562306a36Sopenharmony_ci	&dev_attr_ati_target.attr,
158662306a36Sopenharmony_ci	&dev_attr_ati_trigger.attr,
158762306a36Sopenharmony_ci	NULL,
158862306a36Sopenharmony_ci};
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_cistatic const struct attribute_group iqs269_attr_group = {
159162306a36Sopenharmony_ci	.attrs = iqs269_attrs,
159262306a36Sopenharmony_ci};
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_cistatic const struct regmap_config iqs269_regmap_config = {
159562306a36Sopenharmony_ci	.reg_bits = 8,
159662306a36Sopenharmony_ci	.val_bits = 16,
159762306a36Sopenharmony_ci	.max_register = IQS269_MAX_REG,
159862306a36Sopenharmony_ci};
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_cistatic int iqs269_probe(struct i2c_client *client)
160162306a36Sopenharmony_ci{
160262306a36Sopenharmony_ci	struct iqs269_ver_info ver_info;
160362306a36Sopenharmony_ci	struct iqs269_private *iqs269;
160462306a36Sopenharmony_ci	int error;
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci	iqs269 = devm_kzalloc(&client->dev, sizeof(*iqs269), GFP_KERNEL);
160762306a36Sopenharmony_ci	if (!iqs269)
160862306a36Sopenharmony_ci		return -ENOMEM;
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	i2c_set_clientdata(client, iqs269);
161162306a36Sopenharmony_ci	iqs269->client = client;
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	iqs269->regmap = devm_regmap_init_i2c(client, &iqs269_regmap_config);
161462306a36Sopenharmony_ci	if (IS_ERR(iqs269->regmap)) {
161562306a36Sopenharmony_ci		error = PTR_ERR(iqs269->regmap);
161662306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to initialize register map: %d\n",
161762306a36Sopenharmony_ci			error);
161862306a36Sopenharmony_ci		return error;
161962306a36Sopenharmony_ci	}
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	mutex_init(&iqs269->lock);
162262306a36Sopenharmony_ci	init_completion(&iqs269->ati_done);
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	error = regmap_raw_read(iqs269->regmap, IQS269_VER_INFO, &ver_info,
162562306a36Sopenharmony_ci				sizeof(ver_info));
162662306a36Sopenharmony_ci	if (error)
162762306a36Sopenharmony_ci		return error;
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	if (ver_info.prod_num != IQS269_VER_INFO_PROD_NUM) {
163062306a36Sopenharmony_ci		dev_err(&client->dev, "Unrecognized product number: 0x%02X\n",
163162306a36Sopenharmony_ci			ver_info.prod_num);
163262306a36Sopenharmony_ci		return -EINVAL;
163362306a36Sopenharmony_ci	}
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	error = iqs269_parse_prop(iqs269);
163662306a36Sopenharmony_ci	if (error)
163762306a36Sopenharmony_ci		return error;
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	error = iqs269_dev_init(iqs269);
164062306a36Sopenharmony_ci	if (error) {
164162306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to initialize device: %d\n",
164262306a36Sopenharmony_ci			error);
164362306a36Sopenharmony_ci		return error;
164462306a36Sopenharmony_ci	}
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci	error = iqs269_input_init(iqs269);
164762306a36Sopenharmony_ci	if (error)
164862306a36Sopenharmony_ci		return error;
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	error = devm_request_threaded_irq(&client->dev, client->irq,
165162306a36Sopenharmony_ci					  NULL, iqs269_irq, IRQF_ONESHOT,
165262306a36Sopenharmony_ci					  client->name, iqs269);
165362306a36Sopenharmony_ci	if (error) {
165462306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to request IRQ: %d\n", error);
165562306a36Sopenharmony_ci		return error;
165662306a36Sopenharmony_ci	}
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci	if (!wait_for_completion_timeout(&iqs269->ati_done,
165962306a36Sopenharmony_ci					 msecs_to_jiffies(2000))) {
166062306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to complete ATI\n");
166162306a36Sopenharmony_ci		return -ETIMEDOUT;
166262306a36Sopenharmony_ci	}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	/*
166562306a36Sopenharmony_ci	 * The keypad may include one or more switches and is not registered
166662306a36Sopenharmony_ci	 * until ATI is complete and the initial switch states are read.
166762306a36Sopenharmony_ci	 */
166862306a36Sopenharmony_ci	error = input_register_device(iqs269->keypad);
166962306a36Sopenharmony_ci	if (error) {
167062306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to register keypad: %d\n", error);
167162306a36Sopenharmony_ci		return error;
167262306a36Sopenharmony_ci	}
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	error = devm_device_add_group(&client->dev, &iqs269_attr_group);
167562306a36Sopenharmony_ci	if (error)
167662306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to add attributes: %d\n", error);
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	return error;
167962306a36Sopenharmony_ci}
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_cistatic u16 iqs269_general_get(struct iqs269_private *iqs269)
168262306a36Sopenharmony_ci{
168362306a36Sopenharmony_ci	u16 general = be16_to_cpu(iqs269->sys_reg.general);
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	general &= ~IQS269_SYS_SETTINGS_REDO_ATI;
168662306a36Sopenharmony_ci	general &= ~IQS269_SYS_SETTINGS_ACK_RESET;
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	return general | IQS269_SYS_SETTINGS_DIS_AUTO;
168962306a36Sopenharmony_ci}
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_cistatic int iqs269_suspend(struct device *dev)
169262306a36Sopenharmony_ci{
169362306a36Sopenharmony_ci	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
169462306a36Sopenharmony_ci	struct i2c_client *client = iqs269->client;
169562306a36Sopenharmony_ci	int error;
169662306a36Sopenharmony_ci	u16 general = iqs269_general_get(iqs269);
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci	if (!(general & IQS269_SYS_SETTINGS_PWR_MODE_MASK))
169962306a36Sopenharmony_ci		return 0;
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	disable_irq(client->irq);
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_ci	error = regmap_write(iqs269->regmap, IQS269_SYS_SETTINGS, general);
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci	iqs269_irq_wait();
170662306a36Sopenharmony_ci	enable_irq(client->irq);
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	return error;
170962306a36Sopenharmony_ci}
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_cistatic int iqs269_resume(struct device *dev)
171262306a36Sopenharmony_ci{
171362306a36Sopenharmony_ci	struct iqs269_private *iqs269 = dev_get_drvdata(dev);
171462306a36Sopenharmony_ci	struct i2c_client *client = iqs269->client;
171562306a36Sopenharmony_ci	int error;
171662306a36Sopenharmony_ci	u16 general = iqs269_general_get(iqs269);
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci	if (!(general & IQS269_SYS_SETTINGS_PWR_MODE_MASK))
171962306a36Sopenharmony_ci		return 0;
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	disable_irq(client->irq);
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	error = regmap_write(iqs269->regmap, IQS269_SYS_SETTINGS,
172462306a36Sopenharmony_ci			     general & ~IQS269_SYS_SETTINGS_PWR_MODE_MASK);
172562306a36Sopenharmony_ci	if (!error)
172662306a36Sopenharmony_ci		error = regmap_write(iqs269->regmap, IQS269_SYS_SETTINGS,
172762306a36Sopenharmony_ci				     general & ~IQS269_SYS_SETTINGS_DIS_AUTO);
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	iqs269_irq_wait();
173062306a36Sopenharmony_ci	enable_irq(client->irq);
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	return error;
173362306a36Sopenharmony_ci}
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(iqs269_pm, iqs269_suspend, iqs269_resume);
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_cistatic const struct of_device_id iqs269_of_match[] = {
173862306a36Sopenharmony_ci	{ .compatible = "azoteq,iqs269a" },
173962306a36Sopenharmony_ci	{ }
174062306a36Sopenharmony_ci};
174162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, iqs269_of_match);
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_cistatic struct i2c_driver iqs269_i2c_driver = {
174462306a36Sopenharmony_ci	.driver = {
174562306a36Sopenharmony_ci		.name = "iqs269a",
174662306a36Sopenharmony_ci		.of_match_table = iqs269_of_match,
174762306a36Sopenharmony_ci		.pm = pm_sleep_ptr(&iqs269_pm),
174862306a36Sopenharmony_ci	},
174962306a36Sopenharmony_ci	.probe = iqs269_probe,
175062306a36Sopenharmony_ci};
175162306a36Sopenharmony_cimodule_i2c_driver(iqs269_i2c_driver);
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ciMODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
175462306a36Sopenharmony_ciMODULE_DESCRIPTION("Azoteq IQS269A Capacitive Touch Controller");
175562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1756