xref: /OK3568_Linux_fs/kernel/drivers/mfd/iqs62x.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Azoteq IQS620A/621/622/624/625 Multi-Function Sensors
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2019 Jeff LaBundy <jeff@labundy.com>
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * These devices rely on application-specific register settings and calibration
8*4882a593Smuzhiyun  * data developed in and exported from a suite of GUIs offered by the vendor. A
9*4882a593Smuzhiyun  * separate tool converts the GUIs' ASCII-based output into a standard firmware
10*4882a593Smuzhiyun  * file parsed by the driver.
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  * Link to datasheets and GUIs: https://www.azoteq.com/
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * Link to conversion tool: https://github.com/jlabundy/iqs62x-h2bin.git
15*4882a593Smuzhiyun  */
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include <linux/completion.h>
18*4882a593Smuzhiyun #include <linux/delay.h>
19*4882a593Smuzhiyun #include <linux/device.h>
20*4882a593Smuzhiyun #include <linux/err.h>
21*4882a593Smuzhiyun #include <linux/firmware.h>
22*4882a593Smuzhiyun #include <linux/i2c.h>
23*4882a593Smuzhiyun #include <linux/interrupt.h>
24*4882a593Smuzhiyun #include <linux/kernel.h>
25*4882a593Smuzhiyun #include <linux/list.h>
26*4882a593Smuzhiyun #include <linux/mfd/core.h>
27*4882a593Smuzhiyun #include <linux/mfd/iqs62x.h>
28*4882a593Smuzhiyun #include <linux/module.h>
29*4882a593Smuzhiyun #include <linux/notifier.h>
30*4882a593Smuzhiyun #include <linux/of_device.h>
31*4882a593Smuzhiyun #include <linux/property.h>
32*4882a593Smuzhiyun #include <linux/regmap.h>
33*4882a593Smuzhiyun #include <linux/slab.h>
34*4882a593Smuzhiyun #include <asm/unaligned.h>
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun #define IQS62X_PROD_NUM				0x00
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #define IQS62X_SYS_FLAGS			0x10
39*4882a593Smuzhiyun #define IQS62X_SYS_FLAGS_IN_ATI			BIT(2)
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun #define IQS620_HALL_FLAGS			0x16
42*4882a593Smuzhiyun #define IQS621_HALL_FLAGS			0x19
43*4882a593Smuzhiyun #define IQS622_HALL_FLAGS			IQS621_HALL_FLAGS
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun #define IQS624_INTERVAL_NUM			0x18
46*4882a593Smuzhiyun #define IQS625_INTERVAL_NUM			0x12
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun #define IQS622_PROX_SETTINGS_4			0x48
49*4882a593Smuzhiyun #define IQS620_PROX_SETTINGS_4			0x50
50*4882a593Smuzhiyun #define IQS620_PROX_SETTINGS_4_SAR_EN		BIT(7)
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun #define IQS621_ALS_CAL_DIV_LUX			0x82
53*4882a593Smuzhiyun #define IQS621_ALS_CAL_DIV_IR			0x83
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #define IQS620_TEMP_CAL_MULT			0xC2
56*4882a593Smuzhiyun #define IQS620_TEMP_CAL_DIV			0xC3
57*4882a593Smuzhiyun #define IQS620_TEMP_CAL_OFFS			0xC4
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun #define IQS62X_SYS_SETTINGS			0xD0
60*4882a593Smuzhiyun #define IQS62X_SYS_SETTINGS_SOFT_RESET		BIT(7)
61*4882a593Smuzhiyun #define IQS62X_SYS_SETTINGS_ACK_RESET		BIT(6)
62*4882a593Smuzhiyun #define IQS62X_SYS_SETTINGS_EVENT_MODE		BIT(5)
63*4882a593Smuzhiyun #define IQS62X_SYS_SETTINGS_CLK_DIV		BIT(4)
64*4882a593Smuzhiyun #define IQS62X_SYS_SETTINGS_REDO_ATI		BIT(1)
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #define IQS62X_PWR_SETTINGS			0xD2
67*4882a593Smuzhiyun #define IQS62X_PWR_SETTINGS_DIS_AUTO		BIT(5)
68*4882a593Smuzhiyun #define IQS62X_PWR_SETTINGS_PWR_MODE_MASK	(BIT(4) | BIT(3))
69*4882a593Smuzhiyun #define IQS62X_PWR_SETTINGS_PWR_MODE_HALT	(BIT(4) | BIT(3))
70*4882a593Smuzhiyun #define IQS62X_PWR_SETTINGS_PWR_MODE_NORM	0
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun #define IQS62X_OTP_CMD				0xF0
73*4882a593Smuzhiyun #define IQS62X_OTP_CMD_FG3			0x13
74*4882a593Smuzhiyun #define IQS62X_OTP_DATA				0xF1
75*4882a593Smuzhiyun #define IQS62X_MAX_REG				0xFF
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun #define IQS62X_HALL_CAL_MASK			GENMASK(3, 0)
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun #define IQS62X_FW_REC_TYPE_INFO			0
80*4882a593Smuzhiyun #define IQS62X_FW_REC_TYPE_PROD			1
81*4882a593Smuzhiyun #define IQS62X_FW_REC_TYPE_HALL			2
82*4882a593Smuzhiyun #define IQS62X_FW_REC_TYPE_MASK			3
83*4882a593Smuzhiyun #define IQS62X_FW_REC_TYPE_DATA			4
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun #define IQS62X_ATI_POLL_SLEEP_US		10000
86*4882a593Smuzhiyun #define IQS62X_ATI_POLL_TIMEOUT_US		500000
87*4882a593Smuzhiyun #define IQS62X_ATI_STABLE_DELAY_MS		150
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun struct iqs62x_fw_rec {
90*4882a593Smuzhiyun 	u8 type;
91*4882a593Smuzhiyun 	u8 addr;
92*4882a593Smuzhiyun 	u8 len;
93*4882a593Smuzhiyun 	u8 data;
94*4882a593Smuzhiyun } __packed;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun struct iqs62x_fw_blk {
97*4882a593Smuzhiyun 	struct list_head list;
98*4882a593Smuzhiyun 	u8 addr;
99*4882a593Smuzhiyun 	u8 mask;
100*4882a593Smuzhiyun 	u8 len;
101*4882a593Smuzhiyun 	u8 data[];
102*4882a593Smuzhiyun };
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun struct iqs62x_info {
105*4882a593Smuzhiyun 	u8 prod_num;
106*4882a593Smuzhiyun 	u8 sw_num;
107*4882a593Smuzhiyun 	u8 hw_num;
108*4882a593Smuzhiyun } __packed;
109*4882a593Smuzhiyun 
iqs62x_dev_init(struct iqs62x_core * iqs62x)110*4882a593Smuzhiyun static int iqs62x_dev_init(struct iqs62x_core *iqs62x)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun 	struct iqs62x_fw_blk *fw_blk;
113*4882a593Smuzhiyun 	unsigned int val;
114*4882a593Smuzhiyun 	int ret;
115*4882a593Smuzhiyun 	u8 clk_div = 1;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	list_for_each_entry(fw_blk, &iqs62x->fw_blk_head, list) {
118*4882a593Smuzhiyun 		if (fw_blk->mask)
119*4882a593Smuzhiyun 			ret = regmap_update_bits(iqs62x->regmap, fw_blk->addr,
120*4882a593Smuzhiyun 						 fw_blk->mask, *fw_blk->data);
121*4882a593Smuzhiyun 		else
122*4882a593Smuzhiyun 			ret = regmap_raw_write(iqs62x->regmap, fw_blk->addr,
123*4882a593Smuzhiyun 					       fw_blk->data, fw_blk->len);
124*4882a593Smuzhiyun 		if (ret)
125*4882a593Smuzhiyun 			return ret;
126*4882a593Smuzhiyun 	}
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	switch (iqs62x->dev_desc->prod_num) {
129*4882a593Smuzhiyun 	case IQS620_PROD_NUM:
130*4882a593Smuzhiyun 	case IQS622_PROD_NUM:
131*4882a593Smuzhiyun 		ret = regmap_read(iqs62x->regmap,
132*4882a593Smuzhiyun 				  iqs62x->dev_desc->prox_settings, &val);
133*4882a593Smuzhiyun 		if (ret)
134*4882a593Smuzhiyun 			return ret;
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 		if (val & IQS620_PROX_SETTINGS_4_SAR_EN)
137*4882a593Smuzhiyun 			iqs62x->ui_sel = IQS62X_UI_SAR1;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 		fallthrough;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	case IQS621_PROD_NUM:
142*4882a593Smuzhiyun 		ret = regmap_write(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
143*4882a593Smuzhiyun 				   IQS620_GLBL_EVENT_MASK_PMU |
144*4882a593Smuzhiyun 				   iqs62x->dev_desc->prox_mask |
145*4882a593Smuzhiyun 				   iqs62x->dev_desc->sar_mask |
146*4882a593Smuzhiyun 				   iqs62x->dev_desc->hall_mask |
147*4882a593Smuzhiyun 				   iqs62x->dev_desc->hyst_mask |
148*4882a593Smuzhiyun 				   iqs62x->dev_desc->temp_mask |
149*4882a593Smuzhiyun 				   iqs62x->dev_desc->als_mask |
150*4882a593Smuzhiyun 				   iqs62x->dev_desc->ir_mask);
151*4882a593Smuzhiyun 		if (ret)
152*4882a593Smuzhiyun 			return ret;
153*4882a593Smuzhiyun 		break;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	default:
156*4882a593Smuzhiyun 		ret = regmap_write(iqs62x->regmap, IQS624_HALL_UI,
157*4882a593Smuzhiyun 				   IQS624_HALL_UI_WHL_EVENT |
158*4882a593Smuzhiyun 				   IQS624_HALL_UI_INT_EVENT |
159*4882a593Smuzhiyun 				   IQS624_HALL_UI_AUTO_CAL);
160*4882a593Smuzhiyun 		if (ret)
161*4882a593Smuzhiyun 			return ret;
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 		/*
164*4882a593Smuzhiyun 		 * The IQS625 default interval divider is below the minimum
165*4882a593Smuzhiyun 		 * permissible value, and the datasheet mandates that it is
166*4882a593Smuzhiyun 		 * corrected during initialization (unless an updated value
167*4882a593Smuzhiyun 		 * has already been provided by firmware).
168*4882a593Smuzhiyun 		 *
169*4882a593Smuzhiyun 		 * To protect against an unacceptably low user-entered value
170*4882a593Smuzhiyun 		 * stored in the firmware, the same check is extended to the
171*4882a593Smuzhiyun 		 * IQS624 as well.
172*4882a593Smuzhiyun 		 */
173*4882a593Smuzhiyun 		ret = regmap_read(iqs62x->regmap, IQS624_INTERVAL_DIV, &val);
174*4882a593Smuzhiyun 		if (ret)
175*4882a593Smuzhiyun 			return ret;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 		if (val >= iqs62x->dev_desc->interval_div)
178*4882a593Smuzhiyun 			break;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 		ret = regmap_write(iqs62x->regmap, IQS624_INTERVAL_DIV,
181*4882a593Smuzhiyun 				   iqs62x->dev_desc->interval_div);
182*4882a593Smuzhiyun 		if (ret)
183*4882a593Smuzhiyun 			return ret;
184*4882a593Smuzhiyun 	}
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	ret = regmap_read(iqs62x->regmap, IQS62X_SYS_SETTINGS, &val);
187*4882a593Smuzhiyun 	if (ret)
188*4882a593Smuzhiyun 		return ret;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	if (val & IQS62X_SYS_SETTINGS_CLK_DIV)
191*4882a593Smuzhiyun 		clk_div = iqs62x->dev_desc->clk_div;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	ret = regmap_write(iqs62x->regmap, IQS62X_SYS_SETTINGS, val |
194*4882a593Smuzhiyun 			   IQS62X_SYS_SETTINGS_ACK_RESET |
195*4882a593Smuzhiyun 			   IQS62X_SYS_SETTINGS_EVENT_MODE |
196*4882a593Smuzhiyun 			   IQS62X_SYS_SETTINGS_REDO_ATI);
197*4882a593Smuzhiyun 	if (ret)
198*4882a593Smuzhiyun 		return ret;
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	ret = regmap_read_poll_timeout(iqs62x->regmap, IQS62X_SYS_FLAGS, val,
201*4882a593Smuzhiyun 				       !(val & IQS62X_SYS_FLAGS_IN_ATI),
202*4882a593Smuzhiyun 				       IQS62X_ATI_POLL_SLEEP_US,
203*4882a593Smuzhiyun 				       IQS62X_ATI_POLL_TIMEOUT_US * clk_div);
204*4882a593Smuzhiyun 	if (ret)
205*4882a593Smuzhiyun 		return ret;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	msleep(IQS62X_ATI_STABLE_DELAY_MS * clk_div);
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	return 0;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun 
iqs62x_firmware_parse(struct iqs62x_core * iqs62x,const struct firmware * fw)212*4882a593Smuzhiyun static int iqs62x_firmware_parse(struct iqs62x_core *iqs62x,
213*4882a593Smuzhiyun 				 const struct firmware *fw)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun 	struct i2c_client *client = iqs62x->client;
216*4882a593Smuzhiyun 	struct iqs62x_fw_rec *fw_rec;
217*4882a593Smuzhiyun 	struct iqs62x_fw_blk *fw_blk;
218*4882a593Smuzhiyun 	unsigned int val;
219*4882a593Smuzhiyun 	size_t pos = 0;
220*4882a593Smuzhiyun 	int ret = 0;
221*4882a593Smuzhiyun 	u8 mask, len, *data;
222*4882a593Smuzhiyun 	u8 hall_cal_index = 0;
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	while (pos < fw->size) {
225*4882a593Smuzhiyun 		if (pos + sizeof(*fw_rec) > fw->size) {
226*4882a593Smuzhiyun 			ret = -EINVAL;
227*4882a593Smuzhiyun 			break;
228*4882a593Smuzhiyun 		}
229*4882a593Smuzhiyun 		fw_rec = (struct iqs62x_fw_rec *)(fw->data + pos);
230*4882a593Smuzhiyun 		pos += sizeof(*fw_rec);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 		if (pos + fw_rec->len - 1 > fw->size) {
233*4882a593Smuzhiyun 			ret = -EINVAL;
234*4882a593Smuzhiyun 			break;
235*4882a593Smuzhiyun 		}
236*4882a593Smuzhiyun 		pos += fw_rec->len - 1;
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 		switch (fw_rec->type) {
239*4882a593Smuzhiyun 		case IQS62X_FW_REC_TYPE_INFO:
240*4882a593Smuzhiyun 			continue;
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 		case IQS62X_FW_REC_TYPE_PROD:
243*4882a593Smuzhiyun 			if (fw_rec->data == iqs62x->dev_desc->prod_num)
244*4882a593Smuzhiyun 				continue;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 			dev_err(&client->dev,
247*4882a593Smuzhiyun 				"Incompatible product number: 0x%02X\n",
248*4882a593Smuzhiyun 				fw_rec->data);
249*4882a593Smuzhiyun 			ret = -EINVAL;
250*4882a593Smuzhiyun 			break;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 		case IQS62X_FW_REC_TYPE_HALL:
253*4882a593Smuzhiyun 			if (!hall_cal_index) {
254*4882a593Smuzhiyun 				ret = regmap_write(iqs62x->regmap,
255*4882a593Smuzhiyun 						   IQS62X_OTP_CMD,
256*4882a593Smuzhiyun 						   IQS62X_OTP_CMD_FG3);
257*4882a593Smuzhiyun 				if (ret)
258*4882a593Smuzhiyun 					break;
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 				ret = regmap_read(iqs62x->regmap,
261*4882a593Smuzhiyun 						  IQS62X_OTP_DATA, &val);
262*4882a593Smuzhiyun 				if (ret)
263*4882a593Smuzhiyun 					break;
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 				hall_cal_index = val & IQS62X_HALL_CAL_MASK;
266*4882a593Smuzhiyun 				if (!hall_cal_index) {
267*4882a593Smuzhiyun 					dev_err(&client->dev,
268*4882a593Smuzhiyun 						"Uncalibrated device\n");
269*4882a593Smuzhiyun 					ret = -ENODATA;
270*4882a593Smuzhiyun 					break;
271*4882a593Smuzhiyun 				}
272*4882a593Smuzhiyun 			}
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 			if (hall_cal_index > fw_rec->len) {
275*4882a593Smuzhiyun 				ret = -EINVAL;
276*4882a593Smuzhiyun 				break;
277*4882a593Smuzhiyun 			}
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 			mask = 0;
280*4882a593Smuzhiyun 			data = &fw_rec->data + hall_cal_index - 1;
281*4882a593Smuzhiyun 			len = sizeof(*data);
282*4882a593Smuzhiyun 			break;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 		case IQS62X_FW_REC_TYPE_MASK:
285*4882a593Smuzhiyun 			if (fw_rec->len < (sizeof(mask) + sizeof(*data))) {
286*4882a593Smuzhiyun 				ret = -EINVAL;
287*4882a593Smuzhiyun 				break;
288*4882a593Smuzhiyun 			}
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 			mask = fw_rec->data;
291*4882a593Smuzhiyun 			data = &fw_rec->data + sizeof(mask);
292*4882a593Smuzhiyun 			len = sizeof(*data);
293*4882a593Smuzhiyun 			break;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 		case IQS62X_FW_REC_TYPE_DATA:
296*4882a593Smuzhiyun 			mask = 0;
297*4882a593Smuzhiyun 			data = &fw_rec->data;
298*4882a593Smuzhiyun 			len = fw_rec->len;
299*4882a593Smuzhiyun 			break;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 		default:
302*4882a593Smuzhiyun 			dev_err(&client->dev,
303*4882a593Smuzhiyun 				"Unrecognized record type: 0x%02X\n",
304*4882a593Smuzhiyun 				fw_rec->type);
305*4882a593Smuzhiyun 			ret = -EINVAL;
306*4882a593Smuzhiyun 		}
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 		if (ret)
309*4882a593Smuzhiyun 			break;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 		fw_blk = devm_kzalloc(&client->dev,
312*4882a593Smuzhiyun 				      struct_size(fw_blk, data, len),
313*4882a593Smuzhiyun 				      GFP_KERNEL);
314*4882a593Smuzhiyun 		if (!fw_blk) {
315*4882a593Smuzhiyun 			ret = -ENOMEM;
316*4882a593Smuzhiyun 			break;
317*4882a593Smuzhiyun 		}
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 		fw_blk->addr = fw_rec->addr;
320*4882a593Smuzhiyun 		fw_blk->mask = mask;
321*4882a593Smuzhiyun 		fw_blk->len = len;
322*4882a593Smuzhiyun 		memcpy(fw_blk->data, data, len);
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 		list_add(&fw_blk->list, &iqs62x->fw_blk_head);
325*4882a593Smuzhiyun 	}
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	release_firmware(fw);
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	return ret;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun const struct iqs62x_event_desc iqs62x_events[IQS62X_NUM_EVENTS] = {
333*4882a593Smuzhiyun 	[IQS62X_EVENT_PROX_CH0_T] = {
334*4882a593Smuzhiyun 		.reg	= IQS62X_EVENT_PROX,
335*4882a593Smuzhiyun 		.mask	= BIT(4),
336*4882a593Smuzhiyun 		.val	= BIT(4),
337*4882a593Smuzhiyun 	},
338*4882a593Smuzhiyun 	[IQS62X_EVENT_PROX_CH0_P] = {
339*4882a593Smuzhiyun 		.reg	= IQS62X_EVENT_PROX,
340*4882a593Smuzhiyun 		.mask	= BIT(0),
341*4882a593Smuzhiyun 		.val	= BIT(0),
342*4882a593Smuzhiyun 	},
343*4882a593Smuzhiyun 	[IQS62X_EVENT_PROX_CH1_T] = {
344*4882a593Smuzhiyun 		.reg	= IQS62X_EVENT_PROX,
345*4882a593Smuzhiyun 		.mask	= BIT(5),
346*4882a593Smuzhiyun 		.val	= BIT(5),
347*4882a593Smuzhiyun 	},
348*4882a593Smuzhiyun 	[IQS62X_EVENT_PROX_CH1_P] = {
349*4882a593Smuzhiyun 		.reg	= IQS62X_EVENT_PROX,
350*4882a593Smuzhiyun 		.mask	= BIT(1),
351*4882a593Smuzhiyun 		.val	= BIT(1),
352*4882a593Smuzhiyun 	},
353*4882a593Smuzhiyun 	[IQS62X_EVENT_PROX_CH2_T] = {
354*4882a593Smuzhiyun 		.reg	= IQS62X_EVENT_PROX,
355*4882a593Smuzhiyun 		.mask	= BIT(6),
356*4882a593Smuzhiyun 		.val	= BIT(6),
357*4882a593Smuzhiyun 	},
358*4882a593Smuzhiyun 	[IQS62X_EVENT_PROX_CH2_P] = {
359*4882a593Smuzhiyun 		.reg	= IQS62X_EVENT_PROX,
360*4882a593Smuzhiyun 		.mask	= BIT(2),
361*4882a593Smuzhiyun 		.val	= BIT(2),
362*4882a593Smuzhiyun 	},
363*4882a593Smuzhiyun 	[IQS62X_EVENT_HYST_POS_T] = {
364*4882a593Smuzhiyun 		.reg	= IQS62X_EVENT_HYST,
365*4882a593Smuzhiyun 		.mask	= BIT(6) | BIT(7),
366*4882a593Smuzhiyun 		.val	= BIT(6),
367*4882a593Smuzhiyun 	},
368*4882a593Smuzhiyun 	[IQS62X_EVENT_HYST_POS_P] = {
369*4882a593Smuzhiyun 		.reg	= IQS62X_EVENT_HYST,
370*4882a593Smuzhiyun 		.mask	= BIT(5) | BIT(7),
371*4882a593Smuzhiyun 		.val	= BIT(5),
372*4882a593Smuzhiyun 	},
373*4882a593Smuzhiyun 	[IQS62X_EVENT_HYST_NEG_T] = {
374*4882a593Smuzhiyun 		.reg	= IQS62X_EVENT_HYST,
375*4882a593Smuzhiyun 		.mask	= BIT(6) | BIT(7),
376*4882a593Smuzhiyun 		.val	= BIT(6) | BIT(7),
377*4882a593Smuzhiyun 	},
378*4882a593Smuzhiyun 	[IQS62X_EVENT_HYST_NEG_P] = {
379*4882a593Smuzhiyun 		.reg	= IQS62X_EVENT_HYST,
380*4882a593Smuzhiyun 		.mask	= BIT(5) | BIT(7),
381*4882a593Smuzhiyun 		.val	= BIT(5) | BIT(7),
382*4882a593Smuzhiyun 	},
383*4882a593Smuzhiyun 	[IQS62X_EVENT_SAR1_ACT] = {
384*4882a593Smuzhiyun 		.reg	= IQS62X_EVENT_HYST,
385*4882a593Smuzhiyun 		.mask	= BIT(4),
386*4882a593Smuzhiyun 		.val	= BIT(4),
387*4882a593Smuzhiyun 	},
388*4882a593Smuzhiyun 	[IQS62X_EVENT_SAR1_QRD] = {
389*4882a593Smuzhiyun 		.reg	= IQS62X_EVENT_HYST,
390*4882a593Smuzhiyun 		.mask	= BIT(2),
391*4882a593Smuzhiyun 		.val	= BIT(2),
392*4882a593Smuzhiyun 	},
393*4882a593Smuzhiyun 	[IQS62X_EVENT_SAR1_MOVE] = {
394*4882a593Smuzhiyun 		.reg	= IQS62X_EVENT_HYST,
395*4882a593Smuzhiyun 		.mask	= BIT(1),
396*4882a593Smuzhiyun 		.val	= BIT(1),
397*4882a593Smuzhiyun 	},
398*4882a593Smuzhiyun 	[IQS62X_EVENT_SAR1_HALT] = {
399*4882a593Smuzhiyun 		.reg	= IQS62X_EVENT_HYST,
400*4882a593Smuzhiyun 		.mask	= BIT(0),
401*4882a593Smuzhiyun 		.val	= BIT(0),
402*4882a593Smuzhiyun 	},
403*4882a593Smuzhiyun 	[IQS62X_EVENT_WHEEL_UP] = {
404*4882a593Smuzhiyun 		.reg	= IQS62X_EVENT_WHEEL,
405*4882a593Smuzhiyun 		.mask	= BIT(7) | BIT(6),
406*4882a593Smuzhiyun 		.val	= BIT(7),
407*4882a593Smuzhiyun 	},
408*4882a593Smuzhiyun 	[IQS62X_EVENT_WHEEL_DN] = {
409*4882a593Smuzhiyun 		.reg	= IQS62X_EVENT_WHEEL,
410*4882a593Smuzhiyun 		.mask	= BIT(7) | BIT(6),
411*4882a593Smuzhiyun 		.val	= BIT(7) | BIT(6),
412*4882a593Smuzhiyun 	},
413*4882a593Smuzhiyun 	[IQS62X_EVENT_HALL_N_T] = {
414*4882a593Smuzhiyun 		.reg	= IQS62X_EVENT_HALL,
415*4882a593Smuzhiyun 		.mask	= BIT(2) | BIT(0),
416*4882a593Smuzhiyun 		.val	= BIT(2),
417*4882a593Smuzhiyun 	},
418*4882a593Smuzhiyun 	[IQS62X_EVENT_HALL_N_P] = {
419*4882a593Smuzhiyun 		.reg	= IQS62X_EVENT_HALL,
420*4882a593Smuzhiyun 		.mask	= BIT(1) | BIT(0),
421*4882a593Smuzhiyun 		.val	= BIT(1),
422*4882a593Smuzhiyun 	},
423*4882a593Smuzhiyun 	[IQS62X_EVENT_HALL_S_T] = {
424*4882a593Smuzhiyun 		.reg	= IQS62X_EVENT_HALL,
425*4882a593Smuzhiyun 		.mask	= BIT(2) | BIT(0),
426*4882a593Smuzhiyun 		.val	= BIT(2) | BIT(0),
427*4882a593Smuzhiyun 	},
428*4882a593Smuzhiyun 	[IQS62X_EVENT_HALL_S_P] = {
429*4882a593Smuzhiyun 		.reg	= IQS62X_EVENT_HALL,
430*4882a593Smuzhiyun 		.mask	= BIT(1) | BIT(0),
431*4882a593Smuzhiyun 		.val	= BIT(1) | BIT(0),
432*4882a593Smuzhiyun 	},
433*4882a593Smuzhiyun 	[IQS62X_EVENT_SYS_RESET] = {
434*4882a593Smuzhiyun 		.reg	= IQS62X_EVENT_SYS,
435*4882a593Smuzhiyun 		.mask	= BIT(7),
436*4882a593Smuzhiyun 		.val	= BIT(7),
437*4882a593Smuzhiyun 	},
438*4882a593Smuzhiyun };
439*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(iqs62x_events);
440*4882a593Smuzhiyun 
iqs62x_irq(int irq,void * context)441*4882a593Smuzhiyun static irqreturn_t iqs62x_irq(int irq, void *context)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun 	struct iqs62x_core *iqs62x = context;
444*4882a593Smuzhiyun 	struct i2c_client *client = iqs62x->client;
445*4882a593Smuzhiyun 	struct iqs62x_event_data event_data;
446*4882a593Smuzhiyun 	struct iqs62x_event_desc event_desc;
447*4882a593Smuzhiyun 	enum iqs62x_event_reg event_reg;
448*4882a593Smuzhiyun 	unsigned long event_flags = 0;
449*4882a593Smuzhiyun 	int ret, i, j;
450*4882a593Smuzhiyun 	u8 event_map[IQS62X_EVENT_SIZE];
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	/*
453*4882a593Smuzhiyun 	 * The device asserts the RDY output to signal the beginning of a
454*4882a593Smuzhiyun 	 * communication window, which is closed by an I2C stop condition.
455*4882a593Smuzhiyun 	 * As such, all interrupt status is captured in a single read and
456*4882a593Smuzhiyun 	 * broadcast to any interested sub-device drivers.
457*4882a593Smuzhiyun 	 */
458*4882a593Smuzhiyun 	ret = regmap_raw_read(iqs62x->regmap, IQS62X_SYS_FLAGS, event_map,
459*4882a593Smuzhiyun 			      sizeof(event_map));
460*4882a593Smuzhiyun 	if (ret) {
461*4882a593Smuzhiyun 		dev_err(&client->dev, "Failed to read device status: %d\n",
462*4882a593Smuzhiyun 			ret);
463*4882a593Smuzhiyun 		return IRQ_NONE;
464*4882a593Smuzhiyun 	}
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	for (i = 0; i < sizeof(event_map); i++) {
467*4882a593Smuzhiyun 		event_reg = iqs62x->dev_desc->event_regs[iqs62x->ui_sel][i];
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 		switch (event_reg) {
470*4882a593Smuzhiyun 		case IQS62X_EVENT_UI_LO:
471*4882a593Smuzhiyun 			event_data.ui_data = get_unaligned_le16(&event_map[i]);
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 			fallthrough;
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 		case IQS62X_EVENT_UI_HI:
476*4882a593Smuzhiyun 		case IQS62X_EVENT_NONE:
477*4882a593Smuzhiyun 			continue;
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 		case IQS62X_EVENT_ALS:
480*4882a593Smuzhiyun 			event_data.als_flags = event_map[i];
481*4882a593Smuzhiyun 			continue;
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 		case IQS62X_EVENT_IR:
484*4882a593Smuzhiyun 			event_data.ir_flags = event_map[i];
485*4882a593Smuzhiyun 			continue;
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 		case IQS62X_EVENT_INTER:
488*4882a593Smuzhiyun 			event_data.interval = event_map[i];
489*4882a593Smuzhiyun 			continue;
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 		case IQS62X_EVENT_HYST:
492*4882a593Smuzhiyun 			event_map[i] <<= iqs62x->dev_desc->hyst_shift;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 			fallthrough;
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 		case IQS62X_EVENT_WHEEL:
497*4882a593Smuzhiyun 		case IQS62X_EVENT_HALL:
498*4882a593Smuzhiyun 		case IQS62X_EVENT_PROX:
499*4882a593Smuzhiyun 		case IQS62X_EVENT_SYS:
500*4882a593Smuzhiyun 			break;
501*4882a593Smuzhiyun 		}
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 		for (j = 0; j < IQS62X_NUM_EVENTS; j++) {
504*4882a593Smuzhiyun 			event_desc = iqs62x_events[j];
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 			if (event_desc.reg != event_reg)
507*4882a593Smuzhiyun 				continue;
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 			if ((event_map[i] & event_desc.mask) == event_desc.val)
510*4882a593Smuzhiyun 				event_flags |= BIT(j);
511*4882a593Smuzhiyun 		}
512*4882a593Smuzhiyun 	}
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	/*
515*4882a593Smuzhiyun 	 * The device resets itself in response to the I2C master stalling
516*4882a593Smuzhiyun 	 * communication past a fixed timeout. In this case, all registers
517*4882a593Smuzhiyun 	 * are restored and any interested sub-device drivers are notified.
518*4882a593Smuzhiyun 	 */
519*4882a593Smuzhiyun 	if (event_flags & BIT(IQS62X_EVENT_SYS_RESET)) {
520*4882a593Smuzhiyun 		dev_err(&client->dev, "Unexpected device reset\n");
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 		ret = iqs62x_dev_init(iqs62x);
523*4882a593Smuzhiyun 		if (ret) {
524*4882a593Smuzhiyun 			dev_err(&client->dev,
525*4882a593Smuzhiyun 				"Failed to re-initialize device: %d\n", ret);
526*4882a593Smuzhiyun 			return IRQ_NONE;
527*4882a593Smuzhiyun 		}
528*4882a593Smuzhiyun 	}
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	ret = blocking_notifier_call_chain(&iqs62x->nh, event_flags,
531*4882a593Smuzhiyun 					   &event_data);
532*4882a593Smuzhiyun 	if (ret & NOTIFY_STOP_MASK)
533*4882a593Smuzhiyun 		return IRQ_NONE;
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 	/*
536*4882a593Smuzhiyun 	 * Once the communication window is closed, a small delay is added to
537*4882a593Smuzhiyun 	 * ensure the device's RDY output has been deasserted by the time the
538*4882a593Smuzhiyun 	 * interrupt handler returns.
539*4882a593Smuzhiyun 	 */
540*4882a593Smuzhiyun 	usleep_range(50, 100);
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	return IRQ_HANDLED;
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun 
iqs62x_firmware_load(const struct firmware * fw,void * context)545*4882a593Smuzhiyun static void iqs62x_firmware_load(const struct firmware *fw, void *context)
546*4882a593Smuzhiyun {
547*4882a593Smuzhiyun 	struct iqs62x_core *iqs62x = context;
548*4882a593Smuzhiyun 	struct i2c_client *client = iqs62x->client;
549*4882a593Smuzhiyun 	int ret;
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	if (fw) {
552*4882a593Smuzhiyun 		ret = iqs62x_firmware_parse(iqs62x, fw);
553*4882a593Smuzhiyun 		if (ret) {
554*4882a593Smuzhiyun 			dev_err(&client->dev, "Failed to parse firmware: %d\n",
555*4882a593Smuzhiyun 				ret);
556*4882a593Smuzhiyun 			goto err_out;
557*4882a593Smuzhiyun 		}
558*4882a593Smuzhiyun 	}
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	ret = iqs62x_dev_init(iqs62x);
561*4882a593Smuzhiyun 	if (ret) {
562*4882a593Smuzhiyun 		dev_err(&client->dev, "Failed to initialize device: %d\n", ret);
563*4882a593Smuzhiyun 		goto err_out;
564*4882a593Smuzhiyun 	}
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	ret = devm_request_threaded_irq(&client->dev, client->irq,
567*4882a593Smuzhiyun 					NULL, iqs62x_irq, IRQF_ONESHOT,
568*4882a593Smuzhiyun 					client->name, iqs62x);
569*4882a593Smuzhiyun 	if (ret) {
570*4882a593Smuzhiyun 		dev_err(&client->dev, "Failed to request IRQ: %d\n", ret);
571*4882a593Smuzhiyun 		goto err_out;
572*4882a593Smuzhiyun 	}
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
575*4882a593Smuzhiyun 				   iqs62x->dev_desc->sub_devs,
576*4882a593Smuzhiyun 				   iqs62x->dev_desc->num_sub_devs,
577*4882a593Smuzhiyun 				   NULL, 0, NULL);
578*4882a593Smuzhiyun 	if (ret)
579*4882a593Smuzhiyun 		dev_err(&client->dev, "Failed to add sub-devices: %d\n", ret);
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun err_out:
582*4882a593Smuzhiyun 	complete_all(&iqs62x->fw_done);
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun static const struct mfd_cell iqs620at_sub_devs[] = {
586*4882a593Smuzhiyun 	{
587*4882a593Smuzhiyun 		.name = "iqs62x-keys",
588*4882a593Smuzhiyun 		.of_compatible = "azoteq,iqs620a-keys",
589*4882a593Smuzhiyun 	},
590*4882a593Smuzhiyun 	{
591*4882a593Smuzhiyun 		.name = "iqs620a-pwm",
592*4882a593Smuzhiyun 		.of_compatible = "azoteq,iqs620a-pwm",
593*4882a593Smuzhiyun 	},
594*4882a593Smuzhiyun 	{ .name = "iqs620at-temp", },
595*4882a593Smuzhiyun };
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun static const struct mfd_cell iqs620a_sub_devs[] = {
598*4882a593Smuzhiyun 	{
599*4882a593Smuzhiyun 		.name = "iqs62x-keys",
600*4882a593Smuzhiyun 		.of_compatible = "azoteq,iqs620a-keys",
601*4882a593Smuzhiyun 	},
602*4882a593Smuzhiyun 	{
603*4882a593Smuzhiyun 		.name = "iqs620a-pwm",
604*4882a593Smuzhiyun 		.of_compatible = "azoteq,iqs620a-pwm",
605*4882a593Smuzhiyun 	},
606*4882a593Smuzhiyun };
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun static const struct mfd_cell iqs621_sub_devs[] = {
609*4882a593Smuzhiyun 	{
610*4882a593Smuzhiyun 		.name = "iqs62x-keys",
611*4882a593Smuzhiyun 		.of_compatible = "azoteq,iqs621-keys",
612*4882a593Smuzhiyun 	},
613*4882a593Smuzhiyun 	{ .name = "iqs621-als", },
614*4882a593Smuzhiyun };
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun static const struct mfd_cell iqs622_sub_devs[] = {
617*4882a593Smuzhiyun 	{
618*4882a593Smuzhiyun 		.name = "iqs62x-keys",
619*4882a593Smuzhiyun 		.of_compatible = "azoteq,iqs622-keys",
620*4882a593Smuzhiyun 	},
621*4882a593Smuzhiyun 	{ .name = "iqs621-als", },
622*4882a593Smuzhiyun };
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun static const struct mfd_cell iqs624_sub_devs[] = {
625*4882a593Smuzhiyun 	{
626*4882a593Smuzhiyun 		.name = "iqs62x-keys",
627*4882a593Smuzhiyun 		.of_compatible = "azoteq,iqs624-keys",
628*4882a593Smuzhiyun 	},
629*4882a593Smuzhiyun 	{ .name = "iqs624-pos", },
630*4882a593Smuzhiyun };
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun static const struct mfd_cell iqs625_sub_devs[] = {
633*4882a593Smuzhiyun 	{
634*4882a593Smuzhiyun 		.name = "iqs62x-keys",
635*4882a593Smuzhiyun 		.of_compatible = "azoteq,iqs625-keys",
636*4882a593Smuzhiyun 	},
637*4882a593Smuzhiyun 	{ .name = "iqs624-pos", },
638*4882a593Smuzhiyun };
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun static const u8 iqs620at_cal_regs[] = {
641*4882a593Smuzhiyun 	IQS620_TEMP_CAL_MULT,
642*4882a593Smuzhiyun 	IQS620_TEMP_CAL_DIV,
643*4882a593Smuzhiyun 	IQS620_TEMP_CAL_OFFS,
644*4882a593Smuzhiyun };
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun static const u8 iqs621_cal_regs[] = {
647*4882a593Smuzhiyun 	IQS621_ALS_CAL_DIV_LUX,
648*4882a593Smuzhiyun 	IQS621_ALS_CAL_DIV_IR,
649*4882a593Smuzhiyun };
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun static const enum iqs62x_event_reg iqs620a_event_regs[][IQS62X_EVENT_SIZE] = {
652*4882a593Smuzhiyun 	[IQS62X_UI_PROX] = {
653*4882a593Smuzhiyun 		IQS62X_EVENT_SYS,	/* 0x10 */
654*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
655*4882a593Smuzhiyun 		IQS62X_EVENT_PROX,	/* 0x12 */
656*4882a593Smuzhiyun 		IQS62X_EVENT_HYST,	/* 0x13 */
657*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
658*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
659*4882a593Smuzhiyun 		IQS62X_EVENT_HALL,	/* 0x16 */
660*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
661*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
662*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
663*4882a593Smuzhiyun 	},
664*4882a593Smuzhiyun 	[IQS62X_UI_SAR1] = {
665*4882a593Smuzhiyun 		IQS62X_EVENT_SYS,	/* 0x10 */
666*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
667*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
668*4882a593Smuzhiyun 		IQS62X_EVENT_HYST,	/* 0x13 */
669*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
670*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
671*4882a593Smuzhiyun 		IQS62X_EVENT_HALL,	/* 0x16 */
672*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
673*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
674*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
675*4882a593Smuzhiyun 	},
676*4882a593Smuzhiyun };
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun static const enum iqs62x_event_reg iqs621_event_regs[][IQS62X_EVENT_SIZE] = {
679*4882a593Smuzhiyun 	[IQS62X_UI_PROX] = {
680*4882a593Smuzhiyun 		IQS62X_EVENT_SYS,	/* 0x10 */
681*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
682*4882a593Smuzhiyun 		IQS62X_EVENT_PROX,	/* 0x12 */
683*4882a593Smuzhiyun 		IQS62X_EVENT_HYST,	/* 0x13 */
684*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
685*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
686*4882a593Smuzhiyun 		IQS62X_EVENT_ALS,	/* 0x16 */
687*4882a593Smuzhiyun 		IQS62X_EVENT_UI_LO,	/* 0x17 */
688*4882a593Smuzhiyun 		IQS62X_EVENT_UI_HI,	/* 0x18 */
689*4882a593Smuzhiyun 		IQS62X_EVENT_HALL,	/* 0x19 */
690*4882a593Smuzhiyun 	},
691*4882a593Smuzhiyun };
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun static const enum iqs62x_event_reg iqs622_event_regs[][IQS62X_EVENT_SIZE] = {
694*4882a593Smuzhiyun 	[IQS62X_UI_PROX] = {
695*4882a593Smuzhiyun 		IQS62X_EVENT_SYS,	/* 0x10 */
696*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
697*4882a593Smuzhiyun 		IQS62X_EVENT_PROX,	/* 0x12 */
698*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
699*4882a593Smuzhiyun 		IQS62X_EVENT_ALS,	/* 0x14 */
700*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
701*4882a593Smuzhiyun 		IQS62X_EVENT_IR,	/* 0x16 */
702*4882a593Smuzhiyun 		IQS62X_EVENT_UI_LO,	/* 0x17 */
703*4882a593Smuzhiyun 		IQS62X_EVENT_UI_HI,	/* 0x18 */
704*4882a593Smuzhiyun 		IQS62X_EVENT_HALL,	/* 0x19 */
705*4882a593Smuzhiyun 	},
706*4882a593Smuzhiyun 	[IQS62X_UI_SAR1] = {
707*4882a593Smuzhiyun 		IQS62X_EVENT_SYS,	/* 0x10 */
708*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
709*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
710*4882a593Smuzhiyun 		IQS62X_EVENT_HYST,	/* 0x13 */
711*4882a593Smuzhiyun 		IQS62X_EVENT_ALS,	/* 0x14 */
712*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
713*4882a593Smuzhiyun 		IQS62X_EVENT_IR,	/* 0x16 */
714*4882a593Smuzhiyun 		IQS62X_EVENT_UI_LO,	/* 0x17 */
715*4882a593Smuzhiyun 		IQS62X_EVENT_UI_HI,	/* 0x18 */
716*4882a593Smuzhiyun 		IQS62X_EVENT_HALL,	/* 0x19 */
717*4882a593Smuzhiyun 	},
718*4882a593Smuzhiyun };
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun static const enum iqs62x_event_reg iqs624_event_regs[][IQS62X_EVENT_SIZE] = {
721*4882a593Smuzhiyun 	[IQS62X_UI_PROX] = {
722*4882a593Smuzhiyun 		IQS62X_EVENT_SYS,	/* 0x10 */
723*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
724*4882a593Smuzhiyun 		IQS62X_EVENT_PROX,	/* 0x12 */
725*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
726*4882a593Smuzhiyun 		IQS62X_EVENT_WHEEL,	/* 0x14 */
727*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
728*4882a593Smuzhiyun 		IQS62X_EVENT_UI_LO,	/* 0x16 */
729*4882a593Smuzhiyun 		IQS62X_EVENT_UI_HI,	/* 0x17 */
730*4882a593Smuzhiyun 		IQS62X_EVENT_INTER,	/* 0x18 */
731*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
732*4882a593Smuzhiyun 	},
733*4882a593Smuzhiyun };
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun static const enum iqs62x_event_reg iqs625_event_regs[][IQS62X_EVENT_SIZE] = {
736*4882a593Smuzhiyun 	[IQS62X_UI_PROX] = {
737*4882a593Smuzhiyun 		IQS62X_EVENT_SYS,	/* 0x10 */
738*4882a593Smuzhiyun 		IQS62X_EVENT_PROX,	/* 0x11 */
739*4882a593Smuzhiyun 		IQS62X_EVENT_INTER,	/* 0x12 */
740*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
741*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
742*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
743*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
744*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
745*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
746*4882a593Smuzhiyun 		IQS62X_EVENT_NONE,
747*4882a593Smuzhiyun 	},
748*4882a593Smuzhiyun };
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun static const struct iqs62x_dev_desc iqs62x_devs[] = {
751*4882a593Smuzhiyun 	{
752*4882a593Smuzhiyun 		.dev_name	= "iqs620at",
753*4882a593Smuzhiyun 		.sub_devs	= iqs620at_sub_devs,
754*4882a593Smuzhiyun 		.num_sub_devs	= ARRAY_SIZE(iqs620at_sub_devs),
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun 		.prod_num	= IQS620_PROD_NUM,
757*4882a593Smuzhiyun 		.sw_num		= 0x08,
758*4882a593Smuzhiyun 		.cal_regs	= iqs620at_cal_regs,
759*4882a593Smuzhiyun 		.num_cal_regs	= ARRAY_SIZE(iqs620at_cal_regs),
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 		.prox_mask	= BIT(0),
762*4882a593Smuzhiyun 		.sar_mask	= BIT(1) | BIT(7),
763*4882a593Smuzhiyun 		.hall_mask	= BIT(2),
764*4882a593Smuzhiyun 		.hyst_mask	= BIT(3),
765*4882a593Smuzhiyun 		.temp_mask	= BIT(4),
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun 		.prox_settings	= IQS620_PROX_SETTINGS_4,
768*4882a593Smuzhiyun 		.hall_flags	= IQS620_HALL_FLAGS,
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 		.clk_div	= 4,
771*4882a593Smuzhiyun 		.fw_name	= "iqs620a.bin",
772*4882a593Smuzhiyun 		.event_regs	= &iqs620a_event_regs[IQS62X_UI_PROX],
773*4882a593Smuzhiyun 	},
774*4882a593Smuzhiyun 	{
775*4882a593Smuzhiyun 		.dev_name	= "iqs620a",
776*4882a593Smuzhiyun 		.sub_devs	= iqs620a_sub_devs,
777*4882a593Smuzhiyun 		.num_sub_devs	= ARRAY_SIZE(iqs620a_sub_devs),
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 		.prod_num	= IQS620_PROD_NUM,
780*4882a593Smuzhiyun 		.sw_num		= 0x08,
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun 		.prox_mask	= BIT(0),
783*4882a593Smuzhiyun 		.sar_mask	= BIT(1) | BIT(7),
784*4882a593Smuzhiyun 		.hall_mask	= BIT(2),
785*4882a593Smuzhiyun 		.hyst_mask	= BIT(3),
786*4882a593Smuzhiyun 		.temp_mask	= BIT(4),
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun 		.prox_settings	= IQS620_PROX_SETTINGS_4,
789*4882a593Smuzhiyun 		.hall_flags	= IQS620_HALL_FLAGS,
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun 		.clk_div	= 4,
792*4882a593Smuzhiyun 		.fw_name	= "iqs620a.bin",
793*4882a593Smuzhiyun 		.event_regs	= &iqs620a_event_regs[IQS62X_UI_PROX],
794*4882a593Smuzhiyun 	},
795*4882a593Smuzhiyun 	{
796*4882a593Smuzhiyun 		.dev_name	= "iqs621",
797*4882a593Smuzhiyun 		.sub_devs	= iqs621_sub_devs,
798*4882a593Smuzhiyun 		.num_sub_devs	= ARRAY_SIZE(iqs621_sub_devs),
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 		.prod_num	= IQS621_PROD_NUM,
801*4882a593Smuzhiyun 		.sw_num		= 0x09,
802*4882a593Smuzhiyun 		.cal_regs	= iqs621_cal_regs,
803*4882a593Smuzhiyun 		.num_cal_regs	= ARRAY_SIZE(iqs621_cal_regs),
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun 		.prox_mask	= BIT(0),
806*4882a593Smuzhiyun 		.hall_mask	= BIT(1),
807*4882a593Smuzhiyun 		.als_mask	= BIT(2),
808*4882a593Smuzhiyun 		.hyst_mask	= BIT(3),
809*4882a593Smuzhiyun 		.temp_mask	= BIT(4),
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun 		.als_flags	= IQS621_ALS_FLAGS,
812*4882a593Smuzhiyun 		.hall_flags	= IQS621_HALL_FLAGS,
813*4882a593Smuzhiyun 		.hyst_shift	= 5,
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun 		.clk_div	= 2,
816*4882a593Smuzhiyun 		.fw_name	= "iqs621.bin",
817*4882a593Smuzhiyun 		.event_regs	= &iqs621_event_regs[IQS62X_UI_PROX],
818*4882a593Smuzhiyun 	},
819*4882a593Smuzhiyun 	{
820*4882a593Smuzhiyun 		.dev_name	= "iqs622",
821*4882a593Smuzhiyun 		.sub_devs	= iqs622_sub_devs,
822*4882a593Smuzhiyun 		.num_sub_devs	= ARRAY_SIZE(iqs622_sub_devs),
823*4882a593Smuzhiyun 
824*4882a593Smuzhiyun 		.prod_num	= IQS622_PROD_NUM,
825*4882a593Smuzhiyun 		.sw_num		= 0x06,
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun 		.prox_mask	= BIT(0),
828*4882a593Smuzhiyun 		.sar_mask	= BIT(1),
829*4882a593Smuzhiyun 		.hall_mask	= BIT(2),
830*4882a593Smuzhiyun 		.als_mask	= BIT(3),
831*4882a593Smuzhiyun 		.ir_mask	= BIT(4),
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 		.prox_settings	= IQS622_PROX_SETTINGS_4,
834*4882a593Smuzhiyun 		.als_flags	= IQS622_ALS_FLAGS,
835*4882a593Smuzhiyun 		.hall_flags	= IQS622_HALL_FLAGS,
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun 		.clk_div	= 2,
838*4882a593Smuzhiyun 		.fw_name	= "iqs622.bin",
839*4882a593Smuzhiyun 		.event_regs	= &iqs622_event_regs[IQS62X_UI_PROX],
840*4882a593Smuzhiyun 	},
841*4882a593Smuzhiyun 	{
842*4882a593Smuzhiyun 		.dev_name	= "iqs624",
843*4882a593Smuzhiyun 		.sub_devs	= iqs624_sub_devs,
844*4882a593Smuzhiyun 		.num_sub_devs	= ARRAY_SIZE(iqs624_sub_devs),
845*4882a593Smuzhiyun 
846*4882a593Smuzhiyun 		.prod_num	= IQS624_PROD_NUM,
847*4882a593Smuzhiyun 		.sw_num		= 0x0B,
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun 		.interval	= IQS624_INTERVAL_NUM,
850*4882a593Smuzhiyun 		.interval_div	= 3,
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun 		.clk_div	= 2,
853*4882a593Smuzhiyun 		.fw_name	= "iqs624.bin",
854*4882a593Smuzhiyun 		.event_regs	= &iqs624_event_regs[IQS62X_UI_PROX],
855*4882a593Smuzhiyun 	},
856*4882a593Smuzhiyun 	{
857*4882a593Smuzhiyun 		.dev_name	= "iqs625",
858*4882a593Smuzhiyun 		.sub_devs	= iqs625_sub_devs,
859*4882a593Smuzhiyun 		.num_sub_devs	= ARRAY_SIZE(iqs625_sub_devs),
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun 		.prod_num	= IQS625_PROD_NUM,
862*4882a593Smuzhiyun 		.sw_num		= 0x0B,
863*4882a593Smuzhiyun 
864*4882a593Smuzhiyun 		.interval	= IQS625_INTERVAL_NUM,
865*4882a593Smuzhiyun 		.interval_div	= 10,
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 		.clk_div	= 2,
868*4882a593Smuzhiyun 		.fw_name	= "iqs625.bin",
869*4882a593Smuzhiyun 		.event_regs	= &iqs625_event_regs[IQS62X_UI_PROX],
870*4882a593Smuzhiyun 	},
871*4882a593Smuzhiyun };
872*4882a593Smuzhiyun 
873*4882a593Smuzhiyun static const struct regmap_config iqs62x_map_config = {
874*4882a593Smuzhiyun 	.reg_bits = 8,
875*4882a593Smuzhiyun 	.val_bits = 8,
876*4882a593Smuzhiyun 	.max_register = IQS62X_MAX_REG,
877*4882a593Smuzhiyun };
878*4882a593Smuzhiyun 
iqs62x_probe(struct i2c_client * client)879*4882a593Smuzhiyun static int iqs62x_probe(struct i2c_client *client)
880*4882a593Smuzhiyun {
881*4882a593Smuzhiyun 	struct iqs62x_core *iqs62x;
882*4882a593Smuzhiyun 	struct iqs62x_info info;
883*4882a593Smuzhiyun 	unsigned int val;
884*4882a593Smuzhiyun 	int ret, i, j;
885*4882a593Smuzhiyun 	u8 sw_num = 0;
886*4882a593Smuzhiyun 	const char *fw_name = NULL;
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun 	iqs62x = devm_kzalloc(&client->dev, sizeof(*iqs62x), GFP_KERNEL);
889*4882a593Smuzhiyun 	if (!iqs62x)
890*4882a593Smuzhiyun 		return -ENOMEM;
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun 	i2c_set_clientdata(client, iqs62x);
893*4882a593Smuzhiyun 	iqs62x->client = client;
894*4882a593Smuzhiyun 
895*4882a593Smuzhiyun 	BLOCKING_INIT_NOTIFIER_HEAD(&iqs62x->nh);
896*4882a593Smuzhiyun 	INIT_LIST_HEAD(&iqs62x->fw_blk_head);
897*4882a593Smuzhiyun 	init_completion(&iqs62x->fw_done);
898*4882a593Smuzhiyun 
899*4882a593Smuzhiyun 	iqs62x->regmap = devm_regmap_init_i2c(client, &iqs62x_map_config);
900*4882a593Smuzhiyun 	if (IS_ERR(iqs62x->regmap)) {
901*4882a593Smuzhiyun 		ret = PTR_ERR(iqs62x->regmap);
902*4882a593Smuzhiyun 		dev_err(&client->dev, "Failed to initialize register map: %d\n",
903*4882a593Smuzhiyun 			ret);
904*4882a593Smuzhiyun 		return ret;
905*4882a593Smuzhiyun 	}
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 	ret = regmap_raw_read(iqs62x->regmap, IQS62X_PROD_NUM, &info,
908*4882a593Smuzhiyun 			      sizeof(info));
909*4882a593Smuzhiyun 	if (ret)
910*4882a593Smuzhiyun 		return ret;
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun 	/*
913*4882a593Smuzhiyun 	 * The following sequence validates the device's product and software
914*4882a593Smuzhiyun 	 * numbers. It then determines if the device is factory-calibrated by
915*4882a593Smuzhiyun 	 * checking for nonzero values in the device's designated calibration
916*4882a593Smuzhiyun 	 * registers (if applicable). Depending on the device, the absence of
917*4882a593Smuzhiyun 	 * calibration data indicates a reduced feature set or invalid device.
918*4882a593Smuzhiyun 	 *
919*4882a593Smuzhiyun 	 * For devices given in both calibrated and uncalibrated versions, the
920*4882a593Smuzhiyun 	 * calibrated version (e.g. IQS620AT) appears first in the iqs62x_devs
921*4882a593Smuzhiyun 	 * array. The uncalibrated version (e.g. IQS620A) appears next and has
922*4882a593Smuzhiyun 	 * the same product and software numbers, but no calibration registers
923*4882a593Smuzhiyun 	 * are specified.
924*4882a593Smuzhiyun 	 */
925*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(iqs62x_devs); i++) {
926*4882a593Smuzhiyun 		if (info.prod_num != iqs62x_devs[i].prod_num)
927*4882a593Smuzhiyun 			continue;
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun 		iqs62x->dev_desc = &iqs62x_devs[i];
930*4882a593Smuzhiyun 
931*4882a593Smuzhiyun 		if (info.sw_num < iqs62x->dev_desc->sw_num)
932*4882a593Smuzhiyun 			continue;
933*4882a593Smuzhiyun 
934*4882a593Smuzhiyun 		sw_num = info.sw_num;
935*4882a593Smuzhiyun 
936*4882a593Smuzhiyun 		/*
937*4882a593Smuzhiyun 		 * Read each of the device's designated calibration registers,
938*4882a593Smuzhiyun 		 * if any, and exit from the inner loop early if any are equal
939*4882a593Smuzhiyun 		 * to zero (indicating the device is uncalibrated). This could
940*4882a593Smuzhiyun 		 * be acceptable depending on the device (e.g. IQS620A instead
941*4882a593Smuzhiyun 		 * of IQS620AT).
942*4882a593Smuzhiyun 		 */
943*4882a593Smuzhiyun 		for (j = 0; j < iqs62x->dev_desc->num_cal_regs; j++) {
944*4882a593Smuzhiyun 			ret = regmap_read(iqs62x->regmap,
945*4882a593Smuzhiyun 					  iqs62x->dev_desc->cal_regs[j], &val);
946*4882a593Smuzhiyun 			if (ret)
947*4882a593Smuzhiyun 				return ret;
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun 			if (!val)
950*4882a593Smuzhiyun 				break;
951*4882a593Smuzhiyun 		}
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun 		/*
954*4882a593Smuzhiyun 		 * If the number of nonzero values read from the device equals
955*4882a593Smuzhiyun 		 * the number of designated calibration registers (which could
956*4882a593Smuzhiyun 		 * be zero), exit from the outer loop early to signal that the
957*4882a593Smuzhiyun 		 * device's product and software numbers match a known device,
958*4882a593Smuzhiyun 		 * and the device is calibrated (if applicable).
959*4882a593Smuzhiyun 		 */
960*4882a593Smuzhiyun 		if (j == iqs62x->dev_desc->num_cal_regs)
961*4882a593Smuzhiyun 			break;
962*4882a593Smuzhiyun 	}
963*4882a593Smuzhiyun 
964*4882a593Smuzhiyun 	if (!iqs62x->dev_desc) {
965*4882a593Smuzhiyun 		dev_err(&client->dev, "Unrecognized product number: 0x%02X\n",
966*4882a593Smuzhiyun 			info.prod_num);
967*4882a593Smuzhiyun 		return -EINVAL;
968*4882a593Smuzhiyun 	}
969*4882a593Smuzhiyun 
970*4882a593Smuzhiyun 	if (!sw_num) {
971*4882a593Smuzhiyun 		dev_err(&client->dev, "Unrecognized software number: 0x%02X\n",
972*4882a593Smuzhiyun 			info.sw_num);
973*4882a593Smuzhiyun 		return -EINVAL;
974*4882a593Smuzhiyun 	}
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun 	if (i == ARRAY_SIZE(iqs62x_devs)) {
977*4882a593Smuzhiyun 		dev_err(&client->dev, "Uncalibrated device\n");
978*4882a593Smuzhiyun 		return -ENODATA;
979*4882a593Smuzhiyun 	}
980*4882a593Smuzhiyun 
981*4882a593Smuzhiyun 	device_property_read_string(&client->dev, "firmware-name", &fw_name);
982*4882a593Smuzhiyun 
983*4882a593Smuzhiyun 	ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
984*4882a593Smuzhiyun 				      fw_name ? : iqs62x->dev_desc->fw_name,
985*4882a593Smuzhiyun 				      &client->dev, GFP_KERNEL, iqs62x,
986*4882a593Smuzhiyun 				      iqs62x_firmware_load);
987*4882a593Smuzhiyun 	if (ret)
988*4882a593Smuzhiyun 		dev_err(&client->dev, "Failed to request firmware: %d\n", ret);
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun 	return ret;
991*4882a593Smuzhiyun }
992*4882a593Smuzhiyun 
iqs62x_remove(struct i2c_client * client)993*4882a593Smuzhiyun static int iqs62x_remove(struct i2c_client *client)
994*4882a593Smuzhiyun {
995*4882a593Smuzhiyun 	struct iqs62x_core *iqs62x = i2c_get_clientdata(client);
996*4882a593Smuzhiyun 
997*4882a593Smuzhiyun 	wait_for_completion(&iqs62x->fw_done);
998*4882a593Smuzhiyun 
999*4882a593Smuzhiyun 	return 0;
1000*4882a593Smuzhiyun }
1001*4882a593Smuzhiyun 
iqs62x_suspend(struct device * dev)1002*4882a593Smuzhiyun static int __maybe_unused iqs62x_suspend(struct device *dev)
1003*4882a593Smuzhiyun {
1004*4882a593Smuzhiyun 	struct iqs62x_core *iqs62x = dev_get_drvdata(dev);
1005*4882a593Smuzhiyun 	int ret;
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 	wait_for_completion(&iqs62x->fw_done);
1008*4882a593Smuzhiyun 
1009*4882a593Smuzhiyun 	/*
1010*4882a593Smuzhiyun 	 * As per the datasheet, automatic mode switching must be disabled
1011*4882a593Smuzhiyun 	 * before the device is placed in or taken out of halt mode.
1012*4882a593Smuzhiyun 	 */
1013*4882a593Smuzhiyun 	ret = regmap_update_bits(iqs62x->regmap, IQS62X_PWR_SETTINGS,
1014*4882a593Smuzhiyun 				 IQS62X_PWR_SETTINGS_DIS_AUTO, 0xFF);
1015*4882a593Smuzhiyun 	if (ret)
1016*4882a593Smuzhiyun 		return ret;
1017*4882a593Smuzhiyun 
1018*4882a593Smuzhiyun 	return regmap_update_bits(iqs62x->regmap, IQS62X_PWR_SETTINGS,
1019*4882a593Smuzhiyun 				  IQS62X_PWR_SETTINGS_PWR_MODE_MASK,
1020*4882a593Smuzhiyun 				  IQS62X_PWR_SETTINGS_PWR_MODE_HALT);
1021*4882a593Smuzhiyun }
1022*4882a593Smuzhiyun 
iqs62x_resume(struct device * dev)1023*4882a593Smuzhiyun static int __maybe_unused iqs62x_resume(struct device *dev)
1024*4882a593Smuzhiyun {
1025*4882a593Smuzhiyun 	struct iqs62x_core *iqs62x = dev_get_drvdata(dev);
1026*4882a593Smuzhiyun 	int ret;
1027*4882a593Smuzhiyun 
1028*4882a593Smuzhiyun 	ret = regmap_update_bits(iqs62x->regmap, IQS62X_PWR_SETTINGS,
1029*4882a593Smuzhiyun 				 IQS62X_PWR_SETTINGS_PWR_MODE_MASK,
1030*4882a593Smuzhiyun 				 IQS62X_PWR_SETTINGS_PWR_MODE_NORM);
1031*4882a593Smuzhiyun 	if (ret)
1032*4882a593Smuzhiyun 		return ret;
1033*4882a593Smuzhiyun 
1034*4882a593Smuzhiyun 	return regmap_update_bits(iqs62x->regmap, IQS62X_PWR_SETTINGS,
1035*4882a593Smuzhiyun 				  IQS62X_PWR_SETTINGS_DIS_AUTO, 0);
1036*4882a593Smuzhiyun }
1037*4882a593Smuzhiyun 
1038*4882a593Smuzhiyun static SIMPLE_DEV_PM_OPS(iqs62x_pm, iqs62x_suspend, iqs62x_resume);
1039*4882a593Smuzhiyun 
1040*4882a593Smuzhiyun static const struct of_device_id iqs62x_of_match[] = {
1041*4882a593Smuzhiyun 	{ .compatible = "azoteq,iqs620a" },
1042*4882a593Smuzhiyun 	{ .compatible = "azoteq,iqs621" },
1043*4882a593Smuzhiyun 	{ .compatible = "azoteq,iqs622" },
1044*4882a593Smuzhiyun 	{ .compatible = "azoteq,iqs624" },
1045*4882a593Smuzhiyun 	{ .compatible = "azoteq,iqs625" },
1046*4882a593Smuzhiyun 	{ }
1047*4882a593Smuzhiyun };
1048*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, iqs62x_of_match);
1049*4882a593Smuzhiyun 
1050*4882a593Smuzhiyun static struct i2c_driver iqs62x_i2c_driver = {
1051*4882a593Smuzhiyun 	.driver = {
1052*4882a593Smuzhiyun 		.name = "iqs62x",
1053*4882a593Smuzhiyun 		.of_match_table = iqs62x_of_match,
1054*4882a593Smuzhiyun 		.pm = &iqs62x_pm,
1055*4882a593Smuzhiyun 	},
1056*4882a593Smuzhiyun 	.probe_new = iqs62x_probe,
1057*4882a593Smuzhiyun 	.remove = iqs62x_remove,
1058*4882a593Smuzhiyun };
1059*4882a593Smuzhiyun module_i2c_driver(iqs62x_i2c_driver);
1060*4882a593Smuzhiyun 
1061*4882a593Smuzhiyun MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
1062*4882a593Smuzhiyun MODULE_DESCRIPTION("Azoteq IQS620A/621/622/624/625 Multi-Function Sensors");
1063*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1064