xref: /OK3568_Linux_fs/kernel/drivers/input/mouse/cyapa.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Cypress APA trackpad with I2C interface
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Author: Dudley Du <dudl@cypress.com>
5*4882a593Smuzhiyun  * Further cleanup and restructuring by:
6*4882a593Smuzhiyun  *   Daniel Kurtz <djkurtz@chromium.org>
7*4882a593Smuzhiyun  *   Benson Leung <bleung@chromium.org>
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Copyright (C) 2011-2015 Cypress Semiconductor, Inc.
10*4882a593Smuzhiyun  * Copyright (C) 2011-2012 Google, Inc.
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  * This file is subject to the terms and conditions of the GNU General Public
13*4882a593Smuzhiyun  * License.  See the file COPYING in the main directory of this archive for
14*4882a593Smuzhiyun  * more details.
15*4882a593Smuzhiyun  */
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include <linux/delay.h>
18*4882a593Smuzhiyun #include <linux/i2c.h>
19*4882a593Smuzhiyun #include <linux/input.h>
20*4882a593Smuzhiyun #include <linux/input/mt.h>
21*4882a593Smuzhiyun #include <linux/interrupt.h>
22*4882a593Smuzhiyun #include <linux/module.h>
23*4882a593Smuzhiyun #include <linux/mutex.h>
24*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
25*4882a593Smuzhiyun #include <linux/slab.h>
26*4882a593Smuzhiyun #include <linux/uaccess.h>
27*4882a593Smuzhiyun #include <linux/pm_runtime.h>
28*4882a593Smuzhiyun #include <linux/acpi.h>
29*4882a593Smuzhiyun #include <linux/of.h>
30*4882a593Smuzhiyun #include "cyapa.h"
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #define CYAPA_ADAPTER_FUNC_NONE   0
34*4882a593Smuzhiyun #define CYAPA_ADAPTER_FUNC_I2C    1
35*4882a593Smuzhiyun #define CYAPA_ADAPTER_FUNC_SMBUS  2
36*4882a593Smuzhiyun #define CYAPA_ADAPTER_FUNC_BOTH   3
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #define CYAPA_FW_NAME		"cyapa.bin"
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun const char product_id[] = "CYTRA";
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun static int cyapa_reinitialize(struct cyapa *cyapa);
43*4882a593Smuzhiyun 
cyapa_is_pip_bl_mode(struct cyapa * cyapa)44*4882a593Smuzhiyun bool cyapa_is_pip_bl_mode(struct cyapa *cyapa)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun 	if (cyapa->gen == CYAPA_GEN6 && cyapa->state == CYAPA_STATE_GEN6_BL)
47*4882a593Smuzhiyun 		return true;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_BL)
50*4882a593Smuzhiyun 		return true;
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	return false;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun 
cyapa_is_pip_app_mode(struct cyapa * cyapa)55*4882a593Smuzhiyun bool cyapa_is_pip_app_mode(struct cyapa *cyapa)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun 	if (cyapa->gen == CYAPA_GEN6 && cyapa->state == CYAPA_STATE_GEN6_APP)
58*4882a593Smuzhiyun 		return true;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_APP)
61*4882a593Smuzhiyun 		return true;
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	return false;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun 
cyapa_is_bootloader_mode(struct cyapa * cyapa)66*4882a593Smuzhiyun static bool cyapa_is_bootloader_mode(struct cyapa *cyapa)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun 	if (cyapa_is_pip_bl_mode(cyapa))
69*4882a593Smuzhiyun 		return true;
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	if (cyapa->gen == CYAPA_GEN3 &&
72*4882a593Smuzhiyun 		cyapa->state >= CYAPA_STATE_BL_BUSY &&
73*4882a593Smuzhiyun 		cyapa->state <= CYAPA_STATE_BL_ACTIVE)
74*4882a593Smuzhiyun 		return true;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	return false;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
cyapa_is_operational_mode(struct cyapa * cyapa)79*4882a593Smuzhiyun static inline bool cyapa_is_operational_mode(struct cyapa *cyapa)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun 	if (cyapa_is_pip_app_mode(cyapa))
82*4882a593Smuzhiyun 		return true;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	if (cyapa->gen == CYAPA_GEN3 && cyapa->state == CYAPA_STATE_OP)
85*4882a593Smuzhiyun 		return true;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	return false;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun /* Returns 0 on success, else negative errno on failure. */
cyapa_i2c_read(struct cyapa * cyapa,u8 reg,size_t len,u8 * values)91*4882a593Smuzhiyun static ssize_t cyapa_i2c_read(struct cyapa *cyapa, u8 reg, size_t len,
92*4882a593Smuzhiyun 					u8 *values)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	struct i2c_client *client = cyapa->client;
95*4882a593Smuzhiyun 	struct i2c_msg msgs[] = {
96*4882a593Smuzhiyun 		{
97*4882a593Smuzhiyun 			.addr = client->addr,
98*4882a593Smuzhiyun 			.flags = 0,
99*4882a593Smuzhiyun 			.len = 1,
100*4882a593Smuzhiyun 			.buf = &reg,
101*4882a593Smuzhiyun 		},
102*4882a593Smuzhiyun 		{
103*4882a593Smuzhiyun 			.addr = client->addr,
104*4882a593Smuzhiyun 			.flags = I2C_M_RD,
105*4882a593Smuzhiyun 			.len = len,
106*4882a593Smuzhiyun 			.buf = values,
107*4882a593Smuzhiyun 		},
108*4882a593Smuzhiyun 	};
109*4882a593Smuzhiyun 	int ret;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	if (ret != ARRAY_SIZE(msgs))
114*4882a593Smuzhiyun 		return ret < 0 ? ret : -EIO;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	return 0;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun /**
120*4882a593Smuzhiyun  * cyapa_i2c_write - Execute i2c block data write operation
121*4882a593Smuzhiyun  * @cyapa: Handle to this driver
122*4882a593Smuzhiyun  * @ret: Offset of the data to written in the register map
123*4882a593Smuzhiyun  * @len: number of bytes to write
124*4882a593Smuzhiyun  * @values: Data to be written
125*4882a593Smuzhiyun  *
126*4882a593Smuzhiyun  * Return negative errno code on error; return zero when success.
127*4882a593Smuzhiyun  */
cyapa_i2c_write(struct cyapa * cyapa,u8 reg,size_t len,const void * values)128*4882a593Smuzhiyun static int cyapa_i2c_write(struct cyapa *cyapa, u8 reg,
129*4882a593Smuzhiyun 					 size_t len, const void *values)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun 	struct i2c_client *client = cyapa->client;
132*4882a593Smuzhiyun 	char buf[32];
133*4882a593Smuzhiyun 	int ret;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	if (len > sizeof(buf) - 1)
136*4882a593Smuzhiyun 		return -ENOMEM;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	buf[0] = reg;
139*4882a593Smuzhiyun 	memcpy(&buf[1], values, len);
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	ret = i2c_master_send(client, buf, len + 1);
142*4882a593Smuzhiyun 	if (ret != len + 1)
143*4882a593Smuzhiyun 		return ret < 0 ? ret : -EIO;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	return 0;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun 
cyapa_check_adapter_functionality(struct i2c_client * client)148*4882a593Smuzhiyun static u8 cyapa_check_adapter_functionality(struct i2c_client *client)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun 	u8 ret = CYAPA_ADAPTER_FUNC_NONE;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
153*4882a593Smuzhiyun 		ret |= CYAPA_ADAPTER_FUNC_I2C;
154*4882a593Smuzhiyun 	if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
155*4882a593Smuzhiyun 				     I2C_FUNC_SMBUS_BLOCK_DATA |
156*4882a593Smuzhiyun 				     I2C_FUNC_SMBUS_I2C_BLOCK))
157*4882a593Smuzhiyun 		ret |= CYAPA_ADAPTER_FUNC_SMBUS;
158*4882a593Smuzhiyun 	return ret;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun /*
162*4882a593Smuzhiyun  * Query device for its current operating state.
163*4882a593Smuzhiyun  */
cyapa_get_state(struct cyapa * cyapa)164*4882a593Smuzhiyun static int cyapa_get_state(struct cyapa *cyapa)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun 	u8 status[BL_STATUS_SIZE];
167*4882a593Smuzhiyun 	u8 cmd[32];
168*4882a593Smuzhiyun 	/* The i2c address of gen4 and gen5 trackpad device must be even. */
169*4882a593Smuzhiyun 	bool even_addr = ((cyapa->client->addr & 0x0001) == 0);
170*4882a593Smuzhiyun 	bool smbus = false;
171*4882a593Smuzhiyun 	int retries = 2;
172*4882a593Smuzhiyun 	int error;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	cyapa->state = CYAPA_STATE_NO_DEVICE;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	/*
177*4882a593Smuzhiyun 	 * Get trackpad status by reading 3 registers starting from 0.
178*4882a593Smuzhiyun 	 * If the device is in the bootloader, this will be BL_HEAD.
179*4882a593Smuzhiyun 	 * If the device is in operation mode, this will be the DATA regs.
180*4882a593Smuzhiyun 	 *
181*4882a593Smuzhiyun 	 */
182*4882a593Smuzhiyun 	error = cyapa_i2c_reg_read_block(cyapa, BL_HEAD_OFFSET, BL_STATUS_SIZE,
183*4882a593Smuzhiyun 				       status);
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	/*
186*4882a593Smuzhiyun 	 * On smbus systems in OP mode, the i2c_reg_read will fail with
187*4882a593Smuzhiyun 	 * -ETIMEDOUT.  In this case, try again using the smbus equivalent
188*4882a593Smuzhiyun 	 * command.  This should return a BL_HEAD indicating CYAPA_STATE_OP.
189*4882a593Smuzhiyun 	 */
190*4882a593Smuzhiyun 	if (cyapa->smbus && (error == -ETIMEDOUT || error == -ENXIO)) {
191*4882a593Smuzhiyun 		if (!even_addr)
192*4882a593Smuzhiyun 			error = cyapa_read_block(cyapa,
193*4882a593Smuzhiyun 					CYAPA_CMD_BL_STATUS, status);
194*4882a593Smuzhiyun 		smbus = true;
195*4882a593Smuzhiyun 	}
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	if (error != BL_STATUS_SIZE)
198*4882a593Smuzhiyun 		goto error;
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	/*
201*4882a593Smuzhiyun 	 * Detect trackpad protocol based on characteristic registers and bits.
202*4882a593Smuzhiyun 	 */
203*4882a593Smuzhiyun 	do {
204*4882a593Smuzhiyun 		cyapa->status[REG_OP_STATUS] = status[REG_OP_STATUS];
205*4882a593Smuzhiyun 		cyapa->status[REG_BL_STATUS] = status[REG_BL_STATUS];
206*4882a593Smuzhiyun 		cyapa->status[REG_BL_ERROR] = status[REG_BL_ERROR];
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 		if (cyapa->gen == CYAPA_GEN_UNKNOWN ||
209*4882a593Smuzhiyun 				cyapa->gen == CYAPA_GEN3) {
210*4882a593Smuzhiyun 			error = cyapa_gen3_ops.state_parse(cyapa,
211*4882a593Smuzhiyun 					status, BL_STATUS_SIZE);
212*4882a593Smuzhiyun 			if (!error)
213*4882a593Smuzhiyun 				goto out_detected;
214*4882a593Smuzhiyun 		}
215*4882a593Smuzhiyun 		if (cyapa->gen == CYAPA_GEN_UNKNOWN ||
216*4882a593Smuzhiyun 				cyapa->gen == CYAPA_GEN6 ||
217*4882a593Smuzhiyun 				cyapa->gen == CYAPA_GEN5) {
218*4882a593Smuzhiyun 			error = cyapa_pip_state_parse(cyapa,
219*4882a593Smuzhiyun 					status, BL_STATUS_SIZE);
220*4882a593Smuzhiyun 			if (!error)
221*4882a593Smuzhiyun 				goto out_detected;
222*4882a593Smuzhiyun 		}
223*4882a593Smuzhiyun 		/* For old Gen5 trackpads detecting. */
224*4882a593Smuzhiyun 		if ((cyapa->gen == CYAPA_GEN_UNKNOWN ||
225*4882a593Smuzhiyun 				cyapa->gen == CYAPA_GEN5) &&
226*4882a593Smuzhiyun 			!smbus && even_addr) {
227*4882a593Smuzhiyun 			error = cyapa_gen5_ops.state_parse(cyapa,
228*4882a593Smuzhiyun 					status, BL_STATUS_SIZE);
229*4882a593Smuzhiyun 			if (!error)
230*4882a593Smuzhiyun 				goto out_detected;
231*4882a593Smuzhiyun 		}
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 		/*
234*4882a593Smuzhiyun 		 * Write 0x00 0x00 to trackpad device to force update its
235*4882a593Smuzhiyun 		 * status, then redo the detection again.
236*4882a593Smuzhiyun 		 */
237*4882a593Smuzhiyun 		if (!smbus) {
238*4882a593Smuzhiyun 			cmd[0] = 0x00;
239*4882a593Smuzhiyun 			cmd[1] = 0x00;
240*4882a593Smuzhiyun 			error = cyapa_i2c_write(cyapa, 0, 2, cmd);
241*4882a593Smuzhiyun 			if (error)
242*4882a593Smuzhiyun 				goto error;
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 			msleep(50);
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 			error = cyapa_i2c_read(cyapa, BL_HEAD_OFFSET,
247*4882a593Smuzhiyun 					BL_STATUS_SIZE, status);
248*4882a593Smuzhiyun 			if (error)
249*4882a593Smuzhiyun 				goto error;
250*4882a593Smuzhiyun 		}
251*4882a593Smuzhiyun 	} while (--retries > 0 && !smbus);
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	goto error;
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun out_detected:
256*4882a593Smuzhiyun 	if (cyapa->state <= CYAPA_STATE_BL_BUSY)
257*4882a593Smuzhiyun 		return -EAGAIN;
258*4882a593Smuzhiyun 	return 0;
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun error:
261*4882a593Smuzhiyun 	return (error < 0) ? error : -EAGAIN;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun /*
265*4882a593Smuzhiyun  * Poll device for its status in a loop, waiting up to timeout for a response.
266*4882a593Smuzhiyun  *
267*4882a593Smuzhiyun  * When the device switches state, it usually takes ~300 ms.
268*4882a593Smuzhiyun  * However, when running a new firmware image, the device must calibrate its
269*4882a593Smuzhiyun  * sensors, which can take as long as 2 seconds.
270*4882a593Smuzhiyun  *
271*4882a593Smuzhiyun  * Note: The timeout has granularity of the polling rate, which is 100 ms.
272*4882a593Smuzhiyun  *
273*4882a593Smuzhiyun  * Returns:
274*4882a593Smuzhiyun  *   0 when the device eventually responds with a valid non-busy state.
275*4882a593Smuzhiyun  *   -ETIMEDOUT if device never responds (too many -EAGAIN)
276*4882a593Smuzhiyun  *   -EAGAIN    if bootload is busy, or unknown state.
277*4882a593Smuzhiyun  *   < 0        other errors
278*4882a593Smuzhiyun  */
cyapa_poll_state(struct cyapa * cyapa,unsigned int timeout)279*4882a593Smuzhiyun int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun 	int error;
282*4882a593Smuzhiyun 	int tries = timeout / 100;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	do {
285*4882a593Smuzhiyun 		error = cyapa_get_state(cyapa);
286*4882a593Smuzhiyun 		if (!error && cyapa->state > CYAPA_STATE_BL_BUSY)
287*4882a593Smuzhiyun 			return 0;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 		msleep(100);
290*4882a593Smuzhiyun 	} while (tries--);
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	return (error == -EAGAIN || error == -ETIMEDOUT) ? -ETIMEDOUT : error;
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun /*
296*4882a593Smuzhiyun  * Check if device is operational.
297*4882a593Smuzhiyun  *
298*4882a593Smuzhiyun  * An operational device is responding, has exited bootloader, and has
299*4882a593Smuzhiyun  * firmware supported by this driver.
300*4882a593Smuzhiyun  *
301*4882a593Smuzhiyun  * Returns:
302*4882a593Smuzhiyun  *   -ENODEV no device
303*4882a593Smuzhiyun  *   -EBUSY  no device or in bootloader
304*4882a593Smuzhiyun  *   -EIO    failure while reading from device
305*4882a593Smuzhiyun  *   -ETIMEDOUT timeout failure for bus idle or bus no response
306*4882a593Smuzhiyun  *   -EAGAIN device is still in bootloader
307*4882a593Smuzhiyun  *           if ->state = CYAPA_STATE_BL_IDLE, device has invalid firmware
308*4882a593Smuzhiyun  *   -EINVAL device is in operational mode, but not supported by this driver
309*4882a593Smuzhiyun  *   0       device is supported
310*4882a593Smuzhiyun  */
cyapa_check_is_operational(struct cyapa * cyapa)311*4882a593Smuzhiyun static int cyapa_check_is_operational(struct cyapa *cyapa)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun 	int error;
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	error = cyapa_poll_state(cyapa, 4000);
316*4882a593Smuzhiyun 	if (error)
317*4882a593Smuzhiyun 		return error;
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	switch (cyapa->gen) {
320*4882a593Smuzhiyun 	case CYAPA_GEN6:
321*4882a593Smuzhiyun 		cyapa->ops = &cyapa_gen6_ops;
322*4882a593Smuzhiyun 		break;
323*4882a593Smuzhiyun 	case CYAPA_GEN5:
324*4882a593Smuzhiyun 		cyapa->ops = &cyapa_gen5_ops;
325*4882a593Smuzhiyun 		break;
326*4882a593Smuzhiyun 	case CYAPA_GEN3:
327*4882a593Smuzhiyun 		cyapa->ops = &cyapa_gen3_ops;
328*4882a593Smuzhiyun 		break;
329*4882a593Smuzhiyun 	default:
330*4882a593Smuzhiyun 		return -ENODEV;
331*4882a593Smuzhiyun 	}
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	error = cyapa->ops->operational_check(cyapa);
334*4882a593Smuzhiyun 	if (!error && cyapa_is_operational_mode(cyapa))
335*4882a593Smuzhiyun 		cyapa->operational = true;
336*4882a593Smuzhiyun 	else
337*4882a593Smuzhiyun 		cyapa->operational = false;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	return error;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun /*
344*4882a593Smuzhiyun  * Returns 0 on device detected, negative errno on no device detected.
345*4882a593Smuzhiyun  * And when the device is detected and operational, it will be reset to
346*4882a593Smuzhiyun  * full power active mode automatically.
347*4882a593Smuzhiyun  */
cyapa_detect(struct cyapa * cyapa)348*4882a593Smuzhiyun static int cyapa_detect(struct cyapa *cyapa)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun 	struct device *dev = &cyapa->client->dev;
351*4882a593Smuzhiyun 	int error;
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	error = cyapa_check_is_operational(cyapa);
354*4882a593Smuzhiyun 	if (error) {
355*4882a593Smuzhiyun 		if (error != -ETIMEDOUT && error != -ENODEV &&
356*4882a593Smuzhiyun 			cyapa_is_bootloader_mode(cyapa)) {
357*4882a593Smuzhiyun 			dev_warn(dev, "device detected but not operational\n");
358*4882a593Smuzhiyun 			return 0;
359*4882a593Smuzhiyun 		}
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 		dev_err(dev, "no device detected: %d\n", error);
362*4882a593Smuzhiyun 		return error;
363*4882a593Smuzhiyun 	}
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	return 0;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun 
cyapa_open(struct input_dev * input)368*4882a593Smuzhiyun static int cyapa_open(struct input_dev *input)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun 	struct cyapa *cyapa = input_get_drvdata(input);
371*4882a593Smuzhiyun 	struct i2c_client *client = cyapa->client;
372*4882a593Smuzhiyun 	struct device *dev = &client->dev;
373*4882a593Smuzhiyun 	int error;
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	error = mutex_lock_interruptible(&cyapa->state_sync_lock);
376*4882a593Smuzhiyun 	if (error)
377*4882a593Smuzhiyun 		return error;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	if (cyapa->operational) {
380*4882a593Smuzhiyun 		/*
381*4882a593Smuzhiyun 		 * though failed to set active power mode,
382*4882a593Smuzhiyun 		 * but still may be able to work in lower scan rate
383*4882a593Smuzhiyun 		 * when in operational mode.
384*4882a593Smuzhiyun 		 */
385*4882a593Smuzhiyun 		error = cyapa->ops->set_power_mode(cyapa,
386*4882a593Smuzhiyun 				PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE);
387*4882a593Smuzhiyun 		if (error) {
388*4882a593Smuzhiyun 			dev_warn(dev, "set active power failed: %d\n", error);
389*4882a593Smuzhiyun 			goto out;
390*4882a593Smuzhiyun 		}
391*4882a593Smuzhiyun 	} else {
392*4882a593Smuzhiyun 		error = cyapa_reinitialize(cyapa);
393*4882a593Smuzhiyun 		if (error || !cyapa->operational) {
394*4882a593Smuzhiyun 			error = error ? error : -EAGAIN;
395*4882a593Smuzhiyun 			goto out;
396*4882a593Smuzhiyun 		}
397*4882a593Smuzhiyun 	}
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	enable_irq(client->irq);
400*4882a593Smuzhiyun 	if (!pm_runtime_enabled(dev)) {
401*4882a593Smuzhiyun 		pm_runtime_set_active(dev);
402*4882a593Smuzhiyun 		pm_runtime_enable(dev);
403*4882a593Smuzhiyun 	}
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	pm_runtime_get_sync(dev);
406*4882a593Smuzhiyun 	pm_runtime_mark_last_busy(dev);
407*4882a593Smuzhiyun 	pm_runtime_put_sync_autosuspend(dev);
408*4882a593Smuzhiyun out:
409*4882a593Smuzhiyun 	mutex_unlock(&cyapa->state_sync_lock);
410*4882a593Smuzhiyun 	return error;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun 
cyapa_close(struct input_dev * input)413*4882a593Smuzhiyun static void cyapa_close(struct input_dev *input)
414*4882a593Smuzhiyun {
415*4882a593Smuzhiyun 	struct cyapa *cyapa = input_get_drvdata(input);
416*4882a593Smuzhiyun 	struct i2c_client *client = cyapa->client;
417*4882a593Smuzhiyun 	struct device *dev = &cyapa->client->dev;
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	mutex_lock(&cyapa->state_sync_lock);
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	disable_irq(client->irq);
422*4882a593Smuzhiyun 	if (pm_runtime_enabled(dev))
423*4882a593Smuzhiyun 		pm_runtime_disable(dev);
424*4882a593Smuzhiyun 	pm_runtime_set_suspended(dev);
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	if (cyapa->operational)
427*4882a593Smuzhiyun 		cyapa->ops->set_power_mode(cyapa,
428*4882a593Smuzhiyun 				PWR_MODE_OFF, 0, CYAPA_PM_DEACTIVE);
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	mutex_unlock(&cyapa->state_sync_lock);
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun 
cyapa_create_input_dev(struct cyapa * cyapa)433*4882a593Smuzhiyun static int cyapa_create_input_dev(struct cyapa *cyapa)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun 	struct device *dev = &cyapa->client->dev;
436*4882a593Smuzhiyun 	struct input_dev *input;
437*4882a593Smuzhiyun 	int error;
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	if (!cyapa->physical_size_x || !cyapa->physical_size_y)
440*4882a593Smuzhiyun 		return -EINVAL;
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	input = devm_input_allocate_device(dev);
443*4882a593Smuzhiyun 	if (!input) {
444*4882a593Smuzhiyun 		dev_err(dev, "failed to allocate memory for input device.\n");
445*4882a593Smuzhiyun 		return -ENOMEM;
446*4882a593Smuzhiyun 	}
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	input->name = CYAPA_NAME;
449*4882a593Smuzhiyun 	input->phys = cyapa->phys;
450*4882a593Smuzhiyun 	input->id.bustype = BUS_I2C;
451*4882a593Smuzhiyun 	input->id.version = 1;
452*4882a593Smuzhiyun 	input->id.product = 0;  /* Means any product in eventcomm. */
453*4882a593Smuzhiyun 	input->dev.parent = &cyapa->client->dev;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	input->open = cyapa_open;
456*4882a593Smuzhiyun 	input->close = cyapa_close;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	input_set_drvdata(input, cyapa);
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	__set_bit(EV_ABS, input->evbit);
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	/* Finger position */
463*4882a593Smuzhiyun 	input_set_abs_params(input, ABS_MT_POSITION_X, 0, cyapa->max_abs_x, 0,
464*4882a593Smuzhiyun 			     0);
465*4882a593Smuzhiyun 	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cyapa->max_abs_y, 0,
466*4882a593Smuzhiyun 			     0);
467*4882a593Smuzhiyun 	input_set_abs_params(input, ABS_MT_PRESSURE, 0, cyapa->max_z, 0, 0);
468*4882a593Smuzhiyun 	if (cyapa->gen > CYAPA_GEN3) {
469*4882a593Smuzhiyun 		input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
470*4882a593Smuzhiyun 		input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);
471*4882a593Smuzhiyun 		/*
472*4882a593Smuzhiyun 		 * Orientation is the angle between the vertical axis and
473*4882a593Smuzhiyun 		 * the major axis of the contact ellipse.
474*4882a593Smuzhiyun 		 * The range is -127 to 127.
475*4882a593Smuzhiyun 		 * the positive direction is clockwise form the vertical axis.
476*4882a593Smuzhiyun 		 * If the ellipse of contact degenerates into a circle,
477*4882a593Smuzhiyun 		 * orientation is reported as 0.
478*4882a593Smuzhiyun 		 *
479*4882a593Smuzhiyun 		 * Also, for Gen5 trackpad the accurate of this orientation
480*4882a593Smuzhiyun 		 * value is value + (-30 ~ 30).
481*4882a593Smuzhiyun 		 */
482*4882a593Smuzhiyun 		input_set_abs_params(input, ABS_MT_ORIENTATION,
483*4882a593Smuzhiyun 				-127, 127, 0, 0);
484*4882a593Smuzhiyun 	}
485*4882a593Smuzhiyun 	if (cyapa->gen >= CYAPA_GEN5) {
486*4882a593Smuzhiyun 		input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
487*4882a593Smuzhiyun 		input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 255, 0, 0);
488*4882a593Smuzhiyun 		input_set_abs_params(input, ABS_DISTANCE, 0, 1, 0, 0);
489*4882a593Smuzhiyun 	}
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	input_abs_set_res(input, ABS_MT_POSITION_X,
492*4882a593Smuzhiyun 			  cyapa->max_abs_x / cyapa->physical_size_x);
493*4882a593Smuzhiyun 	input_abs_set_res(input, ABS_MT_POSITION_Y,
494*4882a593Smuzhiyun 			  cyapa->max_abs_y / cyapa->physical_size_y);
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK)
497*4882a593Smuzhiyun 		__set_bit(BTN_LEFT, input->keybit);
498*4882a593Smuzhiyun 	if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK)
499*4882a593Smuzhiyun 		__set_bit(BTN_MIDDLE, input->keybit);
500*4882a593Smuzhiyun 	if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK)
501*4882a593Smuzhiyun 		__set_bit(BTN_RIGHT, input->keybit);
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	if (cyapa->btn_capability == CAPABILITY_LEFT_BTN_MASK)
504*4882a593Smuzhiyun 		__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	/* Handle pointer emulation and unused slots in core */
507*4882a593Smuzhiyun 	error = input_mt_init_slots(input, CYAPA_MAX_MT_SLOTS,
508*4882a593Smuzhiyun 				    INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED);
509*4882a593Smuzhiyun 	if (error) {
510*4882a593Smuzhiyun 		dev_err(dev, "failed to initialize MT slots: %d\n", error);
511*4882a593Smuzhiyun 		return error;
512*4882a593Smuzhiyun 	}
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	/* Register the device in input subsystem */
515*4882a593Smuzhiyun 	error = input_register_device(input);
516*4882a593Smuzhiyun 	if (error) {
517*4882a593Smuzhiyun 		dev_err(dev, "failed to register input device: %d\n", error);
518*4882a593Smuzhiyun 		return error;
519*4882a593Smuzhiyun 	}
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	cyapa->input = input;
522*4882a593Smuzhiyun 	return 0;
523*4882a593Smuzhiyun }
524*4882a593Smuzhiyun 
cyapa_enable_irq_for_cmd(struct cyapa * cyapa)525*4882a593Smuzhiyun static void cyapa_enable_irq_for_cmd(struct cyapa *cyapa)
526*4882a593Smuzhiyun {
527*4882a593Smuzhiyun 	struct input_dev *input = cyapa->input;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	if (!input || !input->users) {
530*4882a593Smuzhiyun 		/*
531*4882a593Smuzhiyun 		 * When input is NULL, TP must be in deep sleep mode.
532*4882a593Smuzhiyun 		 * In this mode, later non-power I2C command will always failed
533*4882a593Smuzhiyun 		 * if not bring it out of deep sleep mode firstly,
534*4882a593Smuzhiyun 		 * so must command TP to active mode here.
535*4882a593Smuzhiyun 		 */
536*4882a593Smuzhiyun 		if (!input || cyapa->operational)
537*4882a593Smuzhiyun 			cyapa->ops->set_power_mode(cyapa,
538*4882a593Smuzhiyun 				PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE);
539*4882a593Smuzhiyun 		/* Gen3 always using polling mode for command. */
540*4882a593Smuzhiyun 		if (cyapa->gen >= CYAPA_GEN5)
541*4882a593Smuzhiyun 			enable_irq(cyapa->client->irq);
542*4882a593Smuzhiyun 	}
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun 
cyapa_disable_irq_for_cmd(struct cyapa * cyapa)545*4882a593Smuzhiyun static void cyapa_disable_irq_for_cmd(struct cyapa *cyapa)
546*4882a593Smuzhiyun {
547*4882a593Smuzhiyun 	struct input_dev *input = cyapa->input;
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	if (!input || !input->users) {
550*4882a593Smuzhiyun 		if (cyapa->gen >= CYAPA_GEN5)
551*4882a593Smuzhiyun 			disable_irq(cyapa->client->irq);
552*4882a593Smuzhiyun 		if (!input || cyapa->operational)
553*4882a593Smuzhiyun 			cyapa->ops->set_power_mode(cyapa,
554*4882a593Smuzhiyun 					PWR_MODE_OFF, 0, CYAPA_PM_ACTIVE);
555*4882a593Smuzhiyun 	}
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun /*
559*4882a593Smuzhiyun  * cyapa_sleep_time_to_pwr_cmd and cyapa_pwr_cmd_to_sleep_time
560*4882a593Smuzhiyun  *
561*4882a593Smuzhiyun  * These are helper functions that convert to and from integer idle
562*4882a593Smuzhiyun  * times and register settings to write to the PowerMode register.
563*4882a593Smuzhiyun  * The trackpad supports between 20ms to 1000ms scan intervals.
564*4882a593Smuzhiyun  * The time will be increased in increments of 10ms from 20ms to 100ms.
565*4882a593Smuzhiyun  * From 100ms to 1000ms, time will be increased in increments of 20ms.
566*4882a593Smuzhiyun  *
567*4882a593Smuzhiyun  * When Idle_Time < 100, the format to convert Idle_Time to Idle_Command is:
568*4882a593Smuzhiyun  *   Idle_Command = Idle Time / 10;
569*4882a593Smuzhiyun  * When Idle_Time >= 100, the format to convert Idle_Time to Idle_Command is:
570*4882a593Smuzhiyun  *   Idle_Command = Idle Time / 20 + 5;
571*4882a593Smuzhiyun  */
cyapa_sleep_time_to_pwr_cmd(u16 sleep_time)572*4882a593Smuzhiyun u8 cyapa_sleep_time_to_pwr_cmd(u16 sleep_time)
573*4882a593Smuzhiyun {
574*4882a593Smuzhiyun 	u16 encoded_time;
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	sleep_time = clamp_val(sleep_time, 20, 1000);
577*4882a593Smuzhiyun 	encoded_time = sleep_time < 100 ? sleep_time / 10 : sleep_time / 20 + 5;
578*4882a593Smuzhiyun 	return (encoded_time << 2) & PWR_MODE_MASK;
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun 
cyapa_pwr_cmd_to_sleep_time(u8 pwr_mode)581*4882a593Smuzhiyun u16 cyapa_pwr_cmd_to_sleep_time(u8 pwr_mode)
582*4882a593Smuzhiyun {
583*4882a593Smuzhiyun 	u8 encoded_time = pwr_mode >> 2;
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 	return (encoded_time < 10) ? encoded_time * 10
586*4882a593Smuzhiyun 				   : (encoded_time - 5) * 20;
587*4882a593Smuzhiyun }
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun /* 0 on driver initialize and detected successfully, negative on failure. */
cyapa_initialize(struct cyapa * cyapa)590*4882a593Smuzhiyun static int cyapa_initialize(struct cyapa *cyapa)
591*4882a593Smuzhiyun {
592*4882a593Smuzhiyun 	int error = 0;
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	cyapa->state = CYAPA_STATE_NO_DEVICE;
595*4882a593Smuzhiyun 	cyapa->gen = CYAPA_GEN_UNKNOWN;
596*4882a593Smuzhiyun 	mutex_init(&cyapa->state_sync_lock);
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	/*
599*4882a593Smuzhiyun 	 * Set to hard code default, they will be updated with trackpad set
600*4882a593Smuzhiyun 	 * default values after probe and initialized.
601*4882a593Smuzhiyun 	 */
602*4882a593Smuzhiyun 	cyapa->suspend_power_mode = PWR_MODE_SLEEP;
603*4882a593Smuzhiyun 	cyapa->suspend_sleep_time =
604*4882a593Smuzhiyun 		cyapa_pwr_cmd_to_sleep_time(cyapa->suspend_power_mode);
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 	/* ops.initialize() is aimed to prepare for module communications. */
607*4882a593Smuzhiyun 	error = cyapa_gen3_ops.initialize(cyapa);
608*4882a593Smuzhiyun 	if (!error)
609*4882a593Smuzhiyun 		error = cyapa_gen5_ops.initialize(cyapa);
610*4882a593Smuzhiyun 	if (!error)
611*4882a593Smuzhiyun 		error = cyapa_gen6_ops.initialize(cyapa);
612*4882a593Smuzhiyun 	if (error)
613*4882a593Smuzhiyun 		return error;
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	error = cyapa_detect(cyapa);
616*4882a593Smuzhiyun 	if (error)
617*4882a593Smuzhiyun 		return error;
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun 	/* Power down the device until we need it. */
620*4882a593Smuzhiyun 	if (cyapa->operational)
621*4882a593Smuzhiyun 		cyapa->ops->set_power_mode(cyapa,
622*4882a593Smuzhiyun 				PWR_MODE_OFF, 0, CYAPA_PM_ACTIVE);
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	return 0;
625*4882a593Smuzhiyun }
626*4882a593Smuzhiyun 
cyapa_reinitialize(struct cyapa * cyapa)627*4882a593Smuzhiyun static int cyapa_reinitialize(struct cyapa *cyapa)
628*4882a593Smuzhiyun {
629*4882a593Smuzhiyun 	struct device *dev = &cyapa->client->dev;
630*4882a593Smuzhiyun 	struct input_dev *input = cyapa->input;
631*4882a593Smuzhiyun 	int error;
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 	if (pm_runtime_enabled(dev))
634*4882a593Smuzhiyun 		pm_runtime_disable(dev);
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	/* Avoid command failures when TP was in OFF state. */
637*4882a593Smuzhiyun 	if (cyapa->operational)
638*4882a593Smuzhiyun 		cyapa->ops->set_power_mode(cyapa,
639*4882a593Smuzhiyun 				PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE);
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	error = cyapa_detect(cyapa);
642*4882a593Smuzhiyun 	if (error)
643*4882a593Smuzhiyun 		goto out;
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	if (!input && cyapa->operational) {
646*4882a593Smuzhiyun 		error = cyapa_create_input_dev(cyapa);
647*4882a593Smuzhiyun 		if (error) {
648*4882a593Smuzhiyun 			dev_err(dev, "create input_dev instance failed: %d\n",
649*4882a593Smuzhiyun 					error);
650*4882a593Smuzhiyun 			goto out;
651*4882a593Smuzhiyun 		}
652*4882a593Smuzhiyun 	}
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun out:
655*4882a593Smuzhiyun 	if (!input || !input->users) {
656*4882a593Smuzhiyun 		/* Reset to power OFF state to save power when no user open. */
657*4882a593Smuzhiyun 		if (cyapa->operational)
658*4882a593Smuzhiyun 			cyapa->ops->set_power_mode(cyapa,
659*4882a593Smuzhiyun 					PWR_MODE_OFF, 0, CYAPA_PM_DEACTIVE);
660*4882a593Smuzhiyun 	} else if (!error && cyapa->operational) {
661*4882a593Smuzhiyun 		/*
662*4882a593Smuzhiyun 		 * Make sure only enable runtime PM when device is
663*4882a593Smuzhiyun 		 * in operational mode and input->users > 0.
664*4882a593Smuzhiyun 		 */
665*4882a593Smuzhiyun 		pm_runtime_set_active(dev);
666*4882a593Smuzhiyun 		pm_runtime_enable(dev);
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 		pm_runtime_get_sync(dev);
669*4882a593Smuzhiyun 		pm_runtime_mark_last_busy(dev);
670*4882a593Smuzhiyun 		pm_runtime_put_sync_autosuspend(dev);
671*4882a593Smuzhiyun 	}
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun 	return error;
674*4882a593Smuzhiyun }
675*4882a593Smuzhiyun 
cyapa_irq(int irq,void * dev_id)676*4882a593Smuzhiyun static irqreturn_t cyapa_irq(int irq, void *dev_id)
677*4882a593Smuzhiyun {
678*4882a593Smuzhiyun 	struct cyapa *cyapa = dev_id;
679*4882a593Smuzhiyun 	struct device *dev = &cyapa->client->dev;
680*4882a593Smuzhiyun 	int error;
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun 	if (device_may_wakeup(dev))
683*4882a593Smuzhiyun 		pm_wakeup_event(dev, 0);
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun 	/* Interrupt event can be caused by host command to trackpad device. */
686*4882a593Smuzhiyun 	if (cyapa->ops->irq_cmd_handler(cyapa)) {
687*4882a593Smuzhiyun 		/*
688*4882a593Smuzhiyun 		 * Interrupt event maybe from trackpad device input reporting.
689*4882a593Smuzhiyun 		 */
690*4882a593Smuzhiyun 		if (!cyapa->input) {
691*4882a593Smuzhiyun 			/*
692*4882a593Smuzhiyun 			 * Still in probing or in firmware image
693*4882a593Smuzhiyun 			 * updating or reading.
694*4882a593Smuzhiyun 			 */
695*4882a593Smuzhiyun 			cyapa->ops->sort_empty_output_data(cyapa,
696*4882a593Smuzhiyun 					NULL, NULL, NULL);
697*4882a593Smuzhiyun 			goto out;
698*4882a593Smuzhiyun 		}
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 		if (cyapa->operational) {
701*4882a593Smuzhiyun 			error = cyapa->ops->irq_handler(cyapa);
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 			/*
704*4882a593Smuzhiyun 			 * Apply runtime power management to touch report event
705*4882a593Smuzhiyun 			 * except the events caused by the command responses.
706*4882a593Smuzhiyun 			 * Note:
707*4882a593Smuzhiyun 			 * It will introduce about 20~40 ms additional delay
708*4882a593Smuzhiyun 			 * time in receiving for first valid touch report data.
709*4882a593Smuzhiyun 			 * The time is used to execute device runtime resume
710*4882a593Smuzhiyun 			 * process.
711*4882a593Smuzhiyun 			 */
712*4882a593Smuzhiyun 			pm_runtime_get_sync(dev);
713*4882a593Smuzhiyun 			pm_runtime_mark_last_busy(dev);
714*4882a593Smuzhiyun 			pm_runtime_put_sync_autosuspend(dev);
715*4882a593Smuzhiyun 		}
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 		if (!cyapa->operational || error) {
718*4882a593Smuzhiyun 			if (!mutex_trylock(&cyapa->state_sync_lock)) {
719*4882a593Smuzhiyun 				cyapa->ops->sort_empty_output_data(cyapa,
720*4882a593Smuzhiyun 					NULL, NULL, NULL);
721*4882a593Smuzhiyun 				goto out;
722*4882a593Smuzhiyun 			}
723*4882a593Smuzhiyun 			cyapa_reinitialize(cyapa);
724*4882a593Smuzhiyun 			mutex_unlock(&cyapa->state_sync_lock);
725*4882a593Smuzhiyun 		}
726*4882a593Smuzhiyun 	}
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun out:
729*4882a593Smuzhiyun 	return IRQ_HANDLED;
730*4882a593Smuzhiyun }
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun /*
733*4882a593Smuzhiyun  **************************************************************
734*4882a593Smuzhiyun  * sysfs interface
735*4882a593Smuzhiyun  **************************************************************
736*4882a593Smuzhiyun */
737*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
cyapa_show_suspend_scanrate(struct device * dev,struct device_attribute * attr,char * buf)738*4882a593Smuzhiyun static ssize_t cyapa_show_suspend_scanrate(struct device *dev,
739*4882a593Smuzhiyun 					   struct device_attribute *attr,
740*4882a593Smuzhiyun 					   char *buf)
741*4882a593Smuzhiyun {
742*4882a593Smuzhiyun 	struct cyapa *cyapa = dev_get_drvdata(dev);
743*4882a593Smuzhiyun 	u8 pwr_cmd;
744*4882a593Smuzhiyun 	u16 sleep_time;
745*4882a593Smuzhiyun 	int len;
746*4882a593Smuzhiyun 	int error;
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun 	error = mutex_lock_interruptible(&cyapa->state_sync_lock);
749*4882a593Smuzhiyun 	if (error)
750*4882a593Smuzhiyun 		return error;
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 	pwr_cmd = cyapa->suspend_power_mode;
753*4882a593Smuzhiyun 	sleep_time = cyapa->suspend_sleep_time;
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun 	mutex_unlock(&cyapa->state_sync_lock);
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun 	switch (pwr_cmd) {
758*4882a593Smuzhiyun 	case PWR_MODE_BTN_ONLY:
759*4882a593Smuzhiyun 		len = scnprintf(buf, PAGE_SIZE, "%s\n", BTN_ONLY_MODE_NAME);
760*4882a593Smuzhiyun 		break;
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun 	case PWR_MODE_OFF:
763*4882a593Smuzhiyun 		len = scnprintf(buf, PAGE_SIZE, "%s\n", OFF_MODE_NAME);
764*4882a593Smuzhiyun 		break;
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 	default:
767*4882a593Smuzhiyun 		len = scnprintf(buf, PAGE_SIZE, "%u\n",
768*4882a593Smuzhiyun 				cyapa->gen == CYAPA_GEN3 ?
769*4882a593Smuzhiyun 					cyapa_pwr_cmd_to_sleep_time(pwr_cmd) :
770*4882a593Smuzhiyun 					sleep_time);
771*4882a593Smuzhiyun 		break;
772*4882a593Smuzhiyun 	}
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun 	return len;
775*4882a593Smuzhiyun }
776*4882a593Smuzhiyun 
cyapa_update_suspend_scanrate(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)777*4882a593Smuzhiyun static ssize_t cyapa_update_suspend_scanrate(struct device *dev,
778*4882a593Smuzhiyun 					     struct device_attribute *attr,
779*4882a593Smuzhiyun 					     const char *buf, size_t count)
780*4882a593Smuzhiyun {
781*4882a593Smuzhiyun 	struct cyapa *cyapa = dev_get_drvdata(dev);
782*4882a593Smuzhiyun 	u16 sleep_time;
783*4882a593Smuzhiyun 	int error;
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	error = mutex_lock_interruptible(&cyapa->state_sync_lock);
786*4882a593Smuzhiyun 	if (error)
787*4882a593Smuzhiyun 		return error;
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun 	if (sysfs_streq(buf, BTN_ONLY_MODE_NAME)) {
790*4882a593Smuzhiyun 		cyapa->suspend_power_mode = PWR_MODE_BTN_ONLY;
791*4882a593Smuzhiyun 	} else if (sysfs_streq(buf, OFF_MODE_NAME)) {
792*4882a593Smuzhiyun 		cyapa->suspend_power_mode = PWR_MODE_OFF;
793*4882a593Smuzhiyun 	} else if (!kstrtou16(buf, 10, &sleep_time)) {
794*4882a593Smuzhiyun 		cyapa->suspend_sleep_time = min_t(u16, sleep_time, 1000);
795*4882a593Smuzhiyun 		cyapa->suspend_power_mode =
796*4882a593Smuzhiyun 			cyapa_sleep_time_to_pwr_cmd(cyapa->suspend_sleep_time);
797*4882a593Smuzhiyun 	} else {
798*4882a593Smuzhiyun 		count = -EINVAL;
799*4882a593Smuzhiyun 	}
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun 	mutex_unlock(&cyapa->state_sync_lock);
802*4882a593Smuzhiyun 
803*4882a593Smuzhiyun 	return count;
804*4882a593Smuzhiyun }
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun static DEVICE_ATTR(suspend_scanrate_ms, S_IRUGO|S_IWUSR,
807*4882a593Smuzhiyun 		   cyapa_show_suspend_scanrate,
808*4882a593Smuzhiyun 		   cyapa_update_suspend_scanrate);
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun static struct attribute *cyapa_power_wakeup_entries[] = {
811*4882a593Smuzhiyun 	&dev_attr_suspend_scanrate_ms.attr,
812*4882a593Smuzhiyun 	NULL,
813*4882a593Smuzhiyun };
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun static const struct attribute_group cyapa_power_wakeup_group = {
816*4882a593Smuzhiyun 	.name = power_group_name,
817*4882a593Smuzhiyun 	.attrs = cyapa_power_wakeup_entries,
818*4882a593Smuzhiyun };
819*4882a593Smuzhiyun 
cyapa_remove_power_wakeup_group(void * data)820*4882a593Smuzhiyun static void cyapa_remove_power_wakeup_group(void *data)
821*4882a593Smuzhiyun {
822*4882a593Smuzhiyun 	struct cyapa *cyapa = data;
823*4882a593Smuzhiyun 
824*4882a593Smuzhiyun 	sysfs_unmerge_group(&cyapa->client->dev.kobj,
825*4882a593Smuzhiyun 				&cyapa_power_wakeup_group);
826*4882a593Smuzhiyun }
827*4882a593Smuzhiyun 
cyapa_prepare_wakeup_controls(struct cyapa * cyapa)828*4882a593Smuzhiyun static int cyapa_prepare_wakeup_controls(struct cyapa *cyapa)
829*4882a593Smuzhiyun {
830*4882a593Smuzhiyun 	struct i2c_client *client = cyapa->client;
831*4882a593Smuzhiyun 	struct device *dev = &client->dev;
832*4882a593Smuzhiyun 	int error;
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun 	if (device_can_wakeup(dev)) {
835*4882a593Smuzhiyun 		error = sysfs_merge_group(&dev->kobj,
836*4882a593Smuzhiyun 					  &cyapa_power_wakeup_group);
837*4882a593Smuzhiyun 		if (error) {
838*4882a593Smuzhiyun 			dev_err(dev, "failed to add power wakeup group: %d\n",
839*4882a593Smuzhiyun 				error);
840*4882a593Smuzhiyun 			return error;
841*4882a593Smuzhiyun 		}
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 		error = devm_add_action(dev,
844*4882a593Smuzhiyun 				cyapa_remove_power_wakeup_group, cyapa);
845*4882a593Smuzhiyun 		if (error) {
846*4882a593Smuzhiyun 			cyapa_remove_power_wakeup_group(cyapa);
847*4882a593Smuzhiyun 			dev_err(dev, "failed to add power cleanup action: %d\n",
848*4882a593Smuzhiyun 				error);
849*4882a593Smuzhiyun 			return error;
850*4882a593Smuzhiyun 		}
851*4882a593Smuzhiyun 	}
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun 	return 0;
854*4882a593Smuzhiyun }
855*4882a593Smuzhiyun #else
cyapa_prepare_wakeup_controls(struct cyapa * cyapa)856*4882a593Smuzhiyun static inline int cyapa_prepare_wakeup_controls(struct cyapa *cyapa)
857*4882a593Smuzhiyun {
858*4882a593Smuzhiyun 	return 0;
859*4882a593Smuzhiyun }
860*4882a593Smuzhiyun #endif /* CONFIG_PM_SLEEP */
861*4882a593Smuzhiyun 
862*4882a593Smuzhiyun #ifdef CONFIG_PM
cyapa_show_rt_suspend_scanrate(struct device * dev,struct device_attribute * attr,char * buf)863*4882a593Smuzhiyun static ssize_t cyapa_show_rt_suspend_scanrate(struct device *dev,
864*4882a593Smuzhiyun 					      struct device_attribute *attr,
865*4882a593Smuzhiyun 					      char *buf)
866*4882a593Smuzhiyun {
867*4882a593Smuzhiyun 	struct cyapa *cyapa = dev_get_drvdata(dev);
868*4882a593Smuzhiyun 	u8 pwr_cmd;
869*4882a593Smuzhiyun 	u16 sleep_time;
870*4882a593Smuzhiyun 	int error;
871*4882a593Smuzhiyun 
872*4882a593Smuzhiyun 	error = mutex_lock_interruptible(&cyapa->state_sync_lock);
873*4882a593Smuzhiyun 	if (error)
874*4882a593Smuzhiyun 		return error;
875*4882a593Smuzhiyun 
876*4882a593Smuzhiyun 	pwr_cmd = cyapa->runtime_suspend_power_mode;
877*4882a593Smuzhiyun 	sleep_time = cyapa->runtime_suspend_sleep_time;
878*4882a593Smuzhiyun 
879*4882a593Smuzhiyun 	mutex_unlock(&cyapa->state_sync_lock);
880*4882a593Smuzhiyun 
881*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "%u\n",
882*4882a593Smuzhiyun 			 cyapa->gen == CYAPA_GEN3 ?
883*4882a593Smuzhiyun 				cyapa_pwr_cmd_to_sleep_time(pwr_cmd) :
884*4882a593Smuzhiyun 				sleep_time);
885*4882a593Smuzhiyun }
886*4882a593Smuzhiyun 
cyapa_update_rt_suspend_scanrate(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)887*4882a593Smuzhiyun static ssize_t cyapa_update_rt_suspend_scanrate(struct device *dev,
888*4882a593Smuzhiyun 						struct device_attribute *attr,
889*4882a593Smuzhiyun 						const char *buf, size_t count)
890*4882a593Smuzhiyun {
891*4882a593Smuzhiyun 	struct cyapa *cyapa = dev_get_drvdata(dev);
892*4882a593Smuzhiyun 	u16 time;
893*4882a593Smuzhiyun 	int error;
894*4882a593Smuzhiyun 
895*4882a593Smuzhiyun 	if (buf == NULL || count == 0 || kstrtou16(buf, 10, &time)) {
896*4882a593Smuzhiyun 		dev_err(dev, "invalid runtime suspend scanrate ms parameter\n");
897*4882a593Smuzhiyun 		return -EINVAL;
898*4882a593Smuzhiyun 	}
899*4882a593Smuzhiyun 
900*4882a593Smuzhiyun 	/*
901*4882a593Smuzhiyun 	 * When the suspend scanrate is changed, pm_runtime_get to resume
902*4882a593Smuzhiyun 	 * a potentially suspended device, update to the new pwr_cmd
903*4882a593Smuzhiyun 	 * and then pm_runtime_put to suspend into the new power mode.
904*4882a593Smuzhiyun 	 */
905*4882a593Smuzhiyun 	pm_runtime_get_sync(dev);
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 	error = mutex_lock_interruptible(&cyapa->state_sync_lock);
908*4882a593Smuzhiyun 	if (error)
909*4882a593Smuzhiyun 		return error;
910*4882a593Smuzhiyun 
911*4882a593Smuzhiyun 	cyapa->runtime_suspend_sleep_time = min_t(u16, time, 1000);
912*4882a593Smuzhiyun 	cyapa->runtime_suspend_power_mode =
913*4882a593Smuzhiyun 		cyapa_sleep_time_to_pwr_cmd(cyapa->runtime_suspend_sleep_time);
914*4882a593Smuzhiyun 
915*4882a593Smuzhiyun 	mutex_unlock(&cyapa->state_sync_lock);
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun 	pm_runtime_put_sync_autosuspend(dev);
918*4882a593Smuzhiyun 
919*4882a593Smuzhiyun 	return count;
920*4882a593Smuzhiyun }
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun static DEVICE_ATTR(runtime_suspend_scanrate_ms, S_IRUGO|S_IWUSR,
923*4882a593Smuzhiyun 		   cyapa_show_rt_suspend_scanrate,
924*4882a593Smuzhiyun 		   cyapa_update_rt_suspend_scanrate);
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun static struct attribute *cyapa_power_runtime_entries[] = {
927*4882a593Smuzhiyun 	&dev_attr_runtime_suspend_scanrate_ms.attr,
928*4882a593Smuzhiyun 	NULL,
929*4882a593Smuzhiyun };
930*4882a593Smuzhiyun 
931*4882a593Smuzhiyun static const struct attribute_group cyapa_power_runtime_group = {
932*4882a593Smuzhiyun 	.name = power_group_name,
933*4882a593Smuzhiyun 	.attrs = cyapa_power_runtime_entries,
934*4882a593Smuzhiyun };
935*4882a593Smuzhiyun 
cyapa_remove_power_runtime_group(void * data)936*4882a593Smuzhiyun static void cyapa_remove_power_runtime_group(void *data)
937*4882a593Smuzhiyun {
938*4882a593Smuzhiyun 	struct cyapa *cyapa = data;
939*4882a593Smuzhiyun 
940*4882a593Smuzhiyun 	sysfs_unmerge_group(&cyapa->client->dev.kobj,
941*4882a593Smuzhiyun 				&cyapa_power_runtime_group);
942*4882a593Smuzhiyun }
943*4882a593Smuzhiyun 
cyapa_start_runtime(struct cyapa * cyapa)944*4882a593Smuzhiyun static int cyapa_start_runtime(struct cyapa *cyapa)
945*4882a593Smuzhiyun {
946*4882a593Smuzhiyun 	struct device *dev = &cyapa->client->dev;
947*4882a593Smuzhiyun 	int error;
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun 	cyapa->runtime_suspend_power_mode = PWR_MODE_IDLE;
950*4882a593Smuzhiyun 	cyapa->runtime_suspend_sleep_time =
951*4882a593Smuzhiyun 		cyapa_pwr_cmd_to_sleep_time(cyapa->runtime_suspend_power_mode);
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun 	error = sysfs_merge_group(&dev->kobj, &cyapa_power_runtime_group);
954*4882a593Smuzhiyun 	if (error) {
955*4882a593Smuzhiyun 		dev_err(dev,
956*4882a593Smuzhiyun 			"failed to create power runtime group: %d\n", error);
957*4882a593Smuzhiyun 		return error;
958*4882a593Smuzhiyun 	}
959*4882a593Smuzhiyun 
960*4882a593Smuzhiyun 	error = devm_add_action(dev, cyapa_remove_power_runtime_group, cyapa);
961*4882a593Smuzhiyun 	if (error) {
962*4882a593Smuzhiyun 		cyapa_remove_power_runtime_group(cyapa);
963*4882a593Smuzhiyun 		dev_err(dev,
964*4882a593Smuzhiyun 			"failed to add power runtime cleanup action: %d\n",
965*4882a593Smuzhiyun 			error);
966*4882a593Smuzhiyun 		return error;
967*4882a593Smuzhiyun 	}
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun 	/* runtime is enabled until device is operational and opened. */
970*4882a593Smuzhiyun 	pm_runtime_set_suspended(dev);
971*4882a593Smuzhiyun 	pm_runtime_use_autosuspend(dev);
972*4882a593Smuzhiyun 	pm_runtime_set_autosuspend_delay(dev, AUTOSUSPEND_DELAY);
973*4882a593Smuzhiyun 
974*4882a593Smuzhiyun 	return 0;
975*4882a593Smuzhiyun }
976*4882a593Smuzhiyun #else
cyapa_start_runtime(struct cyapa * cyapa)977*4882a593Smuzhiyun static inline int cyapa_start_runtime(struct cyapa *cyapa)
978*4882a593Smuzhiyun {
979*4882a593Smuzhiyun 	return 0;
980*4882a593Smuzhiyun }
981*4882a593Smuzhiyun #endif /* CONFIG_PM */
982*4882a593Smuzhiyun 
cyapa_show_fm_ver(struct device * dev,struct device_attribute * attr,char * buf)983*4882a593Smuzhiyun static ssize_t cyapa_show_fm_ver(struct device *dev,
984*4882a593Smuzhiyun 				 struct device_attribute *attr, char *buf)
985*4882a593Smuzhiyun {
986*4882a593Smuzhiyun 	int error;
987*4882a593Smuzhiyun 	struct cyapa *cyapa = dev_get_drvdata(dev);
988*4882a593Smuzhiyun 
989*4882a593Smuzhiyun 	error = mutex_lock_interruptible(&cyapa->state_sync_lock);
990*4882a593Smuzhiyun 	if (error)
991*4882a593Smuzhiyun 		return error;
992*4882a593Smuzhiyun 	error = scnprintf(buf, PAGE_SIZE, "%d.%d\n", cyapa->fw_maj_ver,
993*4882a593Smuzhiyun 			 cyapa->fw_min_ver);
994*4882a593Smuzhiyun 	mutex_unlock(&cyapa->state_sync_lock);
995*4882a593Smuzhiyun 	return error;
996*4882a593Smuzhiyun }
997*4882a593Smuzhiyun 
cyapa_show_product_id(struct device * dev,struct device_attribute * attr,char * buf)998*4882a593Smuzhiyun static ssize_t cyapa_show_product_id(struct device *dev,
999*4882a593Smuzhiyun 				     struct device_attribute *attr, char *buf)
1000*4882a593Smuzhiyun {
1001*4882a593Smuzhiyun 	struct cyapa *cyapa = dev_get_drvdata(dev);
1002*4882a593Smuzhiyun 	int size;
1003*4882a593Smuzhiyun 	int error;
1004*4882a593Smuzhiyun 
1005*4882a593Smuzhiyun 	error = mutex_lock_interruptible(&cyapa->state_sync_lock);
1006*4882a593Smuzhiyun 	if (error)
1007*4882a593Smuzhiyun 		return error;
1008*4882a593Smuzhiyun 	size = scnprintf(buf, PAGE_SIZE, "%s\n", cyapa->product_id);
1009*4882a593Smuzhiyun 	mutex_unlock(&cyapa->state_sync_lock);
1010*4882a593Smuzhiyun 	return size;
1011*4882a593Smuzhiyun }
1012*4882a593Smuzhiyun 
cyapa_firmware(struct cyapa * cyapa,const char * fw_name)1013*4882a593Smuzhiyun static int cyapa_firmware(struct cyapa *cyapa, const char *fw_name)
1014*4882a593Smuzhiyun {
1015*4882a593Smuzhiyun 	struct device *dev = &cyapa->client->dev;
1016*4882a593Smuzhiyun 	const struct firmware *fw;
1017*4882a593Smuzhiyun 	int error;
1018*4882a593Smuzhiyun 
1019*4882a593Smuzhiyun 	error = request_firmware(&fw, fw_name, dev);
1020*4882a593Smuzhiyun 	if (error) {
1021*4882a593Smuzhiyun 		dev_err(dev, "Could not load firmware from %s: %d\n",
1022*4882a593Smuzhiyun 			fw_name, error);
1023*4882a593Smuzhiyun 		return error;
1024*4882a593Smuzhiyun 	}
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun 	error = cyapa->ops->check_fw(cyapa, fw);
1027*4882a593Smuzhiyun 	if (error) {
1028*4882a593Smuzhiyun 		dev_err(dev, "Invalid CYAPA firmware image: %s\n",
1029*4882a593Smuzhiyun 				fw_name);
1030*4882a593Smuzhiyun 		goto done;
1031*4882a593Smuzhiyun 	}
1032*4882a593Smuzhiyun 
1033*4882a593Smuzhiyun 	/*
1034*4882a593Smuzhiyun 	 * Resume the potentially suspended device because doing FW
1035*4882a593Smuzhiyun 	 * update on a device not in the FULL mode has a chance to
1036*4882a593Smuzhiyun 	 * fail.
1037*4882a593Smuzhiyun 	 */
1038*4882a593Smuzhiyun 	pm_runtime_get_sync(dev);
1039*4882a593Smuzhiyun 
1040*4882a593Smuzhiyun 	/* Require IRQ support for firmware update commands. */
1041*4882a593Smuzhiyun 	cyapa_enable_irq_for_cmd(cyapa);
1042*4882a593Smuzhiyun 
1043*4882a593Smuzhiyun 	error = cyapa->ops->bl_enter(cyapa);
1044*4882a593Smuzhiyun 	if (error) {
1045*4882a593Smuzhiyun 		dev_err(dev, "bl_enter failed, %d\n", error);
1046*4882a593Smuzhiyun 		goto err_detect;
1047*4882a593Smuzhiyun 	}
1048*4882a593Smuzhiyun 
1049*4882a593Smuzhiyun 	error = cyapa->ops->bl_activate(cyapa);
1050*4882a593Smuzhiyun 	if (error) {
1051*4882a593Smuzhiyun 		dev_err(dev, "bl_activate failed, %d\n", error);
1052*4882a593Smuzhiyun 		goto err_detect;
1053*4882a593Smuzhiyun 	}
1054*4882a593Smuzhiyun 
1055*4882a593Smuzhiyun 	error = cyapa->ops->bl_initiate(cyapa, fw);
1056*4882a593Smuzhiyun 	if (error) {
1057*4882a593Smuzhiyun 		dev_err(dev, "bl_initiate failed, %d\n", error);
1058*4882a593Smuzhiyun 		goto err_detect;
1059*4882a593Smuzhiyun 	}
1060*4882a593Smuzhiyun 
1061*4882a593Smuzhiyun 	error = cyapa->ops->update_fw(cyapa, fw);
1062*4882a593Smuzhiyun 	if (error) {
1063*4882a593Smuzhiyun 		dev_err(dev, "update_fw failed, %d\n", error);
1064*4882a593Smuzhiyun 		goto err_detect;
1065*4882a593Smuzhiyun 	}
1066*4882a593Smuzhiyun 
1067*4882a593Smuzhiyun err_detect:
1068*4882a593Smuzhiyun 	cyapa_disable_irq_for_cmd(cyapa);
1069*4882a593Smuzhiyun 	pm_runtime_put_noidle(dev);
1070*4882a593Smuzhiyun 
1071*4882a593Smuzhiyun done:
1072*4882a593Smuzhiyun 	release_firmware(fw);
1073*4882a593Smuzhiyun 	return error;
1074*4882a593Smuzhiyun }
1075*4882a593Smuzhiyun 
cyapa_update_fw_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1076*4882a593Smuzhiyun static ssize_t cyapa_update_fw_store(struct device *dev,
1077*4882a593Smuzhiyun 				     struct device_attribute *attr,
1078*4882a593Smuzhiyun 				     const char *buf, size_t count)
1079*4882a593Smuzhiyun {
1080*4882a593Smuzhiyun 	struct cyapa *cyapa = dev_get_drvdata(dev);
1081*4882a593Smuzhiyun 	char fw_name[NAME_MAX];
1082*4882a593Smuzhiyun 	int ret, error;
1083*4882a593Smuzhiyun 
1084*4882a593Smuzhiyun 	if (count >= NAME_MAX) {
1085*4882a593Smuzhiyun 		dev_err(dev, "File name too long\n");
1086*4882a593Smuzhiyun 		return -EINVAL;
1087*4882a593Smuzhiyun 	}
1088*4882a593Smuzhiyun 
1089*4882a593Smuzhiyun 	memcpy(fw_name, buf, count);
1090*4882a593Smuzhiyun 	if (fw_name[count - 1] == '\n')
1091*4882a593Smuzhiyun 		fw_name[count - 1] = '\0';
1092*4882a593Smuzhiyun 	else
1093*4882a593Smuzhiyun 		fw_name[count] = '\0';
1094*4882a593Smuzhiyun 
1095*4882a593Smuzhiyun 	if (cyapa->input) {
1096*4882a593Smuzhiyun 		/*
1097*4882a593Smuzhiyun 		 * Force the input device to be registered after the firmware
1098*4882a593Smuzhiyun 		 * image is updated, so if the corresponding parameters updated
1099*4882a593Smuzhiyun 		 * in the new firmware image can taken effect immediately.
1100*4882a593Smuzhiyun 		 */
1101*4882a593Smuzhiyun 		input_unregister_device(cyapa->input);
1102*4882a593Smuzhiyun 		cyapa->input = NULL;
1103*4882a593Smuzhiyun 	}
1104*4882a593Smuzhiyun 
1105*4882a593Smuzhiyun 	error = mutex_lock_interruptible(&cyapa->state_sync_lock);
1106*4882a593Smuzhiyun 	if (error) {
1107*4882a593Smuzhiyun 		/*
1108*4882a593Smuzhiyun 		 * Whatever, do reinitialize to try to recover TP state to
1109*4882a593Smuzhiyun 		 * previous state just as it entered fw update entrance.
1110*4882a593Smuzhiyun 		 */
1111*4882a593Smuzhiyun 		cyapa_reinitialize(cyapa);
1112*4882a593Smuzhiyun 		return error;
1113*4882a593Smuzhiyun 	}
1114*4882a593Smuzhiyun 
1115*4882a593Smuzhiyun 	error = cyapa_firmware(cyapa, fw_name);
1116*4882a593Smuzhiyun 	if (error)
1117*4882a593Smuzhiyun 		dev_err(dev, "firmware update failed: %d\n", error);
1118*4882a593Smuzhiyun 	else
1119*4882a593Smuzhiyun 		dev_dbg(dev, "firmware update successfully done.\n");
1120*4882a593Smuzhiyun 
1121*4882a593Smuzhiyun 	/*
1122*4882a593Smuzhiyun 	 * Re-detect trackpad device states because firmware update process
1123*4882a593Smuzhiyun 	 * will reset trackpad device into bootloader mode.
1124*4882a593Smuzhiyun 	 */
1125*4882a593Smuzhiyun 	ret = cyapa_reinitialize(cyapa);
1126*4882a593Smuzhiyun 	if (ret) {
1127*4882a593Smuzhiyun 		dev_err(dev, "failed to re-detect after updated: %d\n", ret);
1128*4882a593Smuzhiyun 		error = error ? error : ret;
1129*4882a593Smuzhiyun 	}
1130*4882a593Smuzhiyun 
1131*4882a593Smuzhiyun 	mutex_unlock(&cyapa->state_sync_lock);
1132*4882a593Smuzhiyun 
1133*4882a593Smuzhiyun 	return error ? error : count;
1134*4882a593Smuzhiyun }
1135*4882a593Smuzhiyun 
cyapa_calibrate_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1136*4882a593Smuzhiyun static ssize_t cyapa_calibrate_store(struct device *dev,
1137*4882a593Smuzhiyun 				     struct device_attribute *attr,
1138*4882a593Smuzhiyun 				     const char *buf, size_t count)
1139*4882a593Smuzhiyun {
1140*4882a593Smuzhiyun 	struct cyapa *cyapa = dev_get_drvdata(dev);
1141*4882a593Smuzhiyun 	int error;
1142*4882a593Smuzhiyun 
1143*4882a593Smuzhiyun 	error = mutex_lock_interruptible(&cyapa->state_sync_lock);
1144*4882a593Smuzhiyun 	if (error)
1145*4882a593Smuzhiyun 		return error;
1146*4882a593Smuzhiyun 
1147*4882a593Smuzhiyun 	if (cyapa->operational) {
1148*4882a593Smuzhiyun 		cyapa_enable_irq_for_cmd(cyapa);
1149*4882a593Smuzhiyun 		error = cyapa->ops->calibrate_store(dev, attr, buf, count);
1150*4882a593Smuzhiyun 		cyapa_disable_irq_for_cmd(cyapa);
1151*4882a593Smuzhiyun 	} else {
1152*4882a593Smuzhiyun 		error = -EBUSY;  /* Still running in bootloader mode. */
1153*4882a593Smuzhiyun 	}
1154*4882a593Smuzhiyun 
1155*4882a593Smuzhiyun 	mutex_unlock(&cyapa->state_sync_lock);
1156*4882a593Smuzhiyun 	return error < 0 ? error : count;
1157*4882a593Smuzhiyun }
1158*4882a593Smuzhiyun 
cyapa_show_baseline(struct device * dev,struct device_attribute * attr,char * buf)1159*4882a593Smuzhiyun static ssize_t cyapa_show_baseline(struct device *dev,
1160*4882a593Smuzhiyun 				   struct device_attribute *attr, char *buf)
1161*4882a593Smuzhiyun {
1162*4882a593Smuzhiyun 	struct cyapa *cyapa = dev_get_drvdata(dev);
1163*4882a593Smuzhiyun 	ssize_t error;
1164*4882a593Smuzhiyun 
1165*4882a593Smuzhiyun 	error = mutex_lock_interruptible(&cyapa->state_sync_lock);
1166*4882a593Smuzhiyun 	if (error)
1167*4882a593Smuzhiyun 		return error;
1168*4882a593Smuzhiyun 
1169*4882a593Smuzhiyun 	if (cyapa->operational) {
1170*4882a593Smuzhiyun 		cyapa_enable_irq_for_cmd(cyapa);
1171*4882a593Smuzhiyun 		error = cyapa->ops->show_baseline(dev, attr, buf);
1172*4882a593Smuzhiyun 		cyapa_disable_irq_for_cmd(cyapa);
1173*4882a593Smuzhiyun 	} else {
1174*4882a593Smuzhiyun 		error = -EBUSY;  /* Still running in bootloader mode. */
1175*4882a593Smuzhiyun 	}
1176*4882a593Smuzhiyun 
1177*4882a593Smuzhiyun 	mutex_unlock(&cyapa->state_sync_lock);
1178*4882a593Smuzhiyun 	return error;
1179*4882a593Smuzhiyun }
1180*4882a593Smuzhiyun 
cyapa_state_to_string(struct cyapa * cyapa)1181*4882a593Smuzhiyun static char *cyapa_state_to_string(struct cyapa *cyapa)
1182*4882a593Smuzhiyun {
1183*4882a593Smuzhiyun 	switch (cyapa->state) {
1184*4882a593Smuzhiyun 	case CYAPA_STATE_BL_BUSY:
1185*4882a593Smuzhiyun 		return "bootloader busy";
1186*4882a593Smuzhiyun 	case CYAPA_STATE_BL_IDLE:
1187*4882a593Smuzhiyun 		return "bootloader idle";
1188*4882a593Smuzhiyun 	case CYAPA_STATE_BL_ACTIVE:
1189*4882a593Smuzhiyun 		return "bootloader active";
1190*4882a593Smuzhiyun 	case CYAPA_STATE_GEN5_BL:
1191*4882a593Smuzhiyun 	case CYAPA_STATE_GEN6_BL:
1192*4882a593Smuzhiyun 		return "bootloader";
1193*4882a593Smuzhiyun 	case CYAPA_STATE_OP:
1194*4882a593Smuzhiyun 	case CYAPA_STATE_GEN5_APP:
1195*4882a593Smuzhiyun 	case CYAPA_STATE_GEN6_APP:
1196*4882a593Smuzhiyun 		return "operational";  /* Normal valid state. */
1197*4882a593Smuzhiyun 	default:
1198*4882a593Smuzhiyun 		return "invalid mode";
1199*4882a593Smuzhiyun 	}
1200*4882a593Smuzhiyun }
1201*4882a593Smuzhiyun 
cyapa_show_mode(struct device * dev,struct device_attribute * attr,char * buf)1202*4882a593Smuzhiyun static ssize_t cyapa_show_mode(struct device *dev,
1203*4882a593Smuzhiyun 				   struct device_attribute *attr, char *buf)
1204*4882a593Smuzhiyun {
1205*4882a593Smuzhiyun 	struct cyapa *cyapa = dev_get_drvdata(dev);
1206*4882a593Smuzhiyun 	int size;
1207*4882a593Smuzhiyun 	int error;
1208*4882a593Smuzhiyun 
1209*4882a593Smuzhiyun 	error = mutex_lock_interruptible(&cyapa->state_sync_lock);
1210*4882a593Smuzhiyun 	if (error)
1211*4882a593Smuzhiyun 		return error;
1212*4882a593Smuzhiyun 
1213*4882a593Smuzhiyun 	size = scnprintf(buf, PAGE_SIZE, "gen%d %s\n",
1214*4882a593Smuzhiyun 			cyapa->gen, cyapa_state_to_string(cyapa));
1215*4882a593Smuzhiyun 
1216*4882a593Smuzhiyun 	mutex_unlock(&cyapa->state_sync_lock);
1217*4882a593Smuzhiyun 	return size;
1218*4882a593Smuzhiyun }
1219*4882a593Smuzhiyun 
1220*4882a593Smuzhiyun static DEVICE_ATTR(firmware_version, S_IRUGO, cyapa_show_fm_ver, NULL);
1221*4882a593Smuzhiyun static DEVICE_ATTR(product_id, S_IRUGO, cyapa_show_product_id, NULL);
1222*4882a593Smuzhiyun static DEVICE_ATTR(update_fw, S_IWUSR, NULL, cyapa_update_fw_store);
1223*4882a593Smuzhiyun static DEVICE_ATTR(baseline, S_IRUGO, cyapa_show_baseline, NULL);
1224*4882a593Smuzhiyun static DEVICE_ATTR(calibrate, S_IWUSR, NULL, cyapa_calibrate_store);
1225*4882a593Smuzhiyun static DEVICE_ATTR(mode, S_IRUGO, cyapa_show_mode, NULL);
1226*4882a593Smuzhiyun 
1227*4882a593Smuzhiyun static struct attribute *cyapa_sysfs_entries[] = {
1228*4882a593Smuzhiyun 	&dev_attr_firmware_version.attr,
1229*4882a593Smuzhiyun 	&dev_attr_product_id.attr,
1230*4882a593Smuzhiyun 	&dev_attr_update_fw.attr,
1231*4882a593Smuzhiyun 	&dev_attr_baseline.attr,
1232*4882a593Smuzhiyun 	&dev_attr_calibrate.attr,
1233*4882a593Smuzhiyun 	&dev_attr_mode.attr,
1234*4882a593Smuzhiyun 	NULL,
1235*4882a593Smuzhiyun };
1236*4882a593Smuzhiyun 
1237*4882a593Smuzhiyun static const struct attribute_group cyapa_sysfs_group = {
1238*4882a593Smuzhiyun 	.attrs = cyapa_sysfs_entries,
1239*4882a593Smuzhiyun };
1240*4882a593Smuzhiyun 
cyapa_disable_regulator(void * data)1241*4882a593Smuzhiyun static void cyapa_disable_regulator(void *data)
1242*4882a593Smuzhiyun {
1243*4882a593Smuzhiyun 	struct cyapa *cyapa = data;
1244*4882a593Smuzhiyun 
1245*4882a593Smuzhiyun 	regulator_disable(cyapa->vcc);
1246*4882a593Smuzhiyun }
1247*4882a593Smuzhiyun 
cyapa_probe(struct i2c_client * client,const struct i2c_device_id * dev_id)1248*4882a593Smuzhiyun static int cyapa_probe(struct i2c_client *client,
1249*4882a593Smuzhiyun 		       const struct i2c_device_id *dev_id)
1250*4882a593Smuzhiyun {
1251*4882a593Smuzhiyun 	struct device *dev = &client->dev;
1252*4882a593Smuzhiyun 	struct cyapa *cyapa;
1253*4882a593Smuzhiyun 	u8 adapter_func;
1254*4882a593Smuzhiyun 	union i2c_smbus_data dummy;
1255*4882a593Smuzhiyun 	int error;
1256*4882a593Smuzhiyun 
1257*4882a593Smuzhiyun 	adapter_func = cyapa_check_adapter_functionality(client);
1258*4882a593Smuzhiyun 	if (adapter_func == CYAPA_ADAPTER_FUNC_NONE) {
1259*4882a593Smuzhiyun 		dev_err(dev, "not a supported I2C/SMBus adapter\n");
1260*4882a593Smuzhiyun 		return -EIO;
1261*4882a593Smuzhiyun 	}
1262*4882a593Smuzhiyun 
1263*4882a593Smuzhiyun 	/* Make sure there is something at this address */
1264*4882a593Smuzhiyun 	if (i2c_smbus_xfer(client->adapter, client->addr, 0,
1265*4882a593Smuzhiyun 			I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0)
1266*4882a593Smuzhiyun 		return -ENODEV;
1267*4882a593Smuzhiyun 
1268*4882a593Smuzhiyun 	cyapa = devm_kzalloc(dev, sizeof(struct cyapa), GFP_KERNEL);
1269*4882a593Smuzhiyun 	if (!cyapa)
1270*4882a593Smuzhiyun 		return -ENOMEM;
1271*4882a593Smuzhiyun 
1272*4882a593Smuzhiyun 	/* i2c isn't supported, use smbus */
1273*4882a593Smuzhiyun 	if (adapter_func == CYAPA_ADAPTER_FUNC_SMBUS)
1274*4882a593Smuzhiyun 		cyapa->smbus = true;
1275*4882a593Smuzhiyun 
1276*4882a593Smuzhiyun 	cyapa->client = client;
1277*4882a593Smuzhiyun 	i2c_set_clientdata(client, cyapa);
1278*4882a593Smuzhiyun 	sprintf(cyapa->phys, "i2c-%d-%04x/input0", client->adapter->nr,
1279*4882a593Smuzhiyun 		client->addr);
1280*4882a593Smuzhiyun 
1281*4882a593Smuzhiyun 	cyapa->vcc = devm_regulator_get(dev, "vcc");
1282*4882a593Smuzhiyun 	if (IS_ERR(cyapa->vcc)) {
1283*4882a593Smuzhiyun 		error = PTR_ERR(cyapa->vcc);
1284*4882a593Smuzhiyun 		dev_err(dev, "failed to get vcc regulator: %d\n", error);
1285*4882a593Smuzhiyun 		return error;
1286*4882a593Smuzhiyun 	}
1287*4882a593Smuzhiyun 
1288*4882a593Smuzhiyun 	error = regulator_enable(cyapa->vcc);
1289*4882a593Smuzhiyun 	if (error) {
1290*4882a593Smuzhiyun 		dev_err(dev, "failed to enable regulator: %d\n", error);
1291*4882a593Smuzhiyun 		return error;
1292*4882a593Smuzhiyun 	}
1293*4882a593Smuzhiyun 
1294*4882a593Smuzhiyun 	error = devm_add_action(dev, cyapa_disable_regulator, cyapa);
1295*4882a593Smuzhiyun 	if (error) {
1296*4882a593Smuzhiyun 		cyapa_disable_regulator(cyapa);
1297*4882a593Smuzhiyun 		dev_err(dev, "failed to add disable regulator action: %d\n",
1298*4882a593Smuzhiyun 			error);
1299*4882a593Smuzhiyun 		return error;
1300*4882a593Smuzhiyun 	}
1301*4882a593Smuzhiyun 
1302*4882a593Smuzhiyun 	error = cyapa_initialize(cyapa);
1303*4882a593Smuzhiyun 	if (error) {
1304*4882a593Smuzhiyun 		dev_err(dev, "failed to detect and initialize tp device.\n");
1305*4882a593Smuzhiyun 		return error;
1306*4882a593Smuzhiyun 	}
1307*4882a593Smuzhiyun 
1308*4882a593Smuzhiyun 	error = devm_device_add_group(dev, &cyapa_sysfs_group);
1309*4882a593Smuzhiyun 	if (error) {
1310*4882a593Smuzhiyun 		dev_err(dev, "failed to create sysfs entries: %d\n", error);
1311*4882a593Smuzhiyun 		return error;
1312*4882a593Smuzhiyun 	}
1313*4882a593Smuzhiyun 
1314*4882a593Smuzhiyun 	error = cyapa_prepare_wakeup_controls(cyapa);
1315*4882a593Smuzhiyun 	if (error) {
1316*4882a593Smuzhiyun 		dev_err(dev, "failed to prepare wakeup controls: %d\n", error);
1317*4882a593Smuzhiyun 		return error;
1318*4882a593Smuzhiyun 	}
1319*4882a593Smuzhiyun 
1320*4882a593Smuzhiyun 	error = cyapa_start_runtime(cyapa);
1321*4882a593Smuzhiyun 	if (error) {
1322*4882a593Smuzhiyun 		dev_err(dev, "failed to start pm_runtime: %d\n", error);
1323*4882a593Smuzhiyun 		return error;
1324*4882a593Smuzhiyun 	}
1325*4882a593Smuzhiyun 
1326*4882a593Smuzhiyun 	error = devm_request_threaded_irq(dev, client->irq,
1327*4882a593Smuzhiyun 					  NULL, cyapa_irq,
1328*4882a593Smuzhiyun 					  IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
1329*4882a593Smuzhiyun 					  "cyapa", cyapa);
1330*4882a593Smuzhiyun 	if (error) {
1331*4882a593Smuzhiyun 		dev_err(dev, "failed to request threaded irq: %d\n", error);
1332*4882a593Smuzhiyun 		return error;
1333*4882a593Smuzhiyun 	}
1334*4882a593Smuzhiyun 
1335*4882a593Smuzhiyun 	/* Disable IRQ until the device is opened */
1336*4882a593Smuzhiyun 	disable_irq(client->irq);
1337*4882a593Smuzhiyun 
1338*4882a593Smuzhiyun 	/*
1339*4882a593Smuzhiyun 	 * Register the device in the input subsystem when it's operational.
1340*4882a593Smuzhiyun 	 * Otherwise, keep in this driver, so it can be be recovered or updated
1341*4882a593Smuzhiyun 	 * through the sysfs mode and update_fw interfaces by user or apps.
1342*4882a593Smuzhiyun 	 */
1343*4882a593Smuzhiyun 	if (cyapa->operational) {
1344*4882a593Smuzhiyun 		error = cyapa_create_input_dev(cyapa);
1345*4882a593Smuzhiyun 		if (error) {
1346*4882a593Smuzhiyun 			dev_err(dev, "create input_dev instance failed: %d\n",
1347*4882a593Smuzhiyun 					error);
1348*4882a593Smuzhiyun 			return error;
1349*4882a593Smuzhiyun 		}
1350*4882a593Smuzhiyun 	}
1351*4882a593Smuzhiyun 
1352*4882a593Smuzhiyun 	return 0;
1353*4882a593Smuzhiyun }
1354*4882a593Smuzhiyun 
cyapa_suspend(struct device * dev)1355*4882a593Smuzhiyun static int __maybe_unused cyapa_suspend(struct device *dev)
1356*4882a593Smuzhiyun {
1357*4882a593Smuzhiyun 	struct i2c_client *client = to_i2c_client(dev);
1358*4882a593Smuzhiyun 	struct cyapa *cyapa = i2c_get_clientdata(client);
1359*4882a593Smuzhiyun 	u8 power_mode;
1360*4882a593Smuzhiyun 	int error;
1361*4882a593Smuzhiyun 
1362*4882a593Smuzhiyun 	error = mutex_lock_interruptible(&cyapa->state_sync_lock);
1363*4882a593Smuzhiyun 	if (error)
1364*4882a593Smuzhiyun 		return error;
1365*4882a593Smuzhiyun 
1366*4882a593Smuzhiyun 	/*
1367*4882a593Smuzhiyun 	 * Runtime PM is enable only when device is in operational mode and
1368*4882a593Smuzhiyun 	 * users in use, so need check it before disable it to
1369*4882a593Smuzhiyun 	 * avoid unbalance warning.
1370*4882a593Smuzhiyun 	 */
1371*4882a593Smuzhiyun 	if (pm_runtime_enabled(dev))
1372*4882a593Smuzhiyun 		pm_runtime_disable(dev);
1373*4882a593Smuzhiyun 	disable_irq(client->irq);
1374*4882a593Smuzhiyun 
1375*4882a593Smuzhiyun 	/*
1376*4882a593Smuzhiyun 	 * Set trackpad device to idle mode if wakeup is allowed,
1377*4882a593Smuzhiyun 	 * otherwise turn off.
1378*4882a593Smuzhiyun 	 */
1379*4882a593Smuzhiyun 	if (cyapa->operational) {
1380*4882a593Smuzhiyun 		power_mode = device_may_wakeup(dev) ? cyapa->suspend_power_mode
1381*4882a593Smuzhiyun 						    : PWR_MODE_OFF;
1382*4882a593Smuzhiyun 		error = cyapa->ops->set_power_mode(cyapa, power_mode,
1383*4882a593Smuzhiyun 				cyapa->suspend_sleep_time, CYAPA_PM_SUSPEND);
1384*4882a593Smuzhiyun 		if (error)
1385*4882a593Smuzhiyun 			dev_err(dev, "suspend set power mode failed: %d\n",
1386*4882a593Smuzhiyun 					error);
1387*4882a593Smuzhiyun 	}
1388*4882a593Smuzhiyun 
1389*4882a593Smuzhiyun 	/*
1390*4882a593Smuzhiyun 	 * Disable proximity interrupt when system idle, want true touch to
1391*4882a593Smuzhiyun 	 * wake the system.
1392*4882a593Smuzhiyun 	 */
1393*4882a593Smuzhiyun 	if (cyapa->dev_pwr_mode != PWR_MODE_OFF)
1394*4882a593Smuzhiyun 		cyapa->ops->set_proximity(cyapa, false);
1395*4882a593Smuzhiyun 
1396*4882a593Smuzhiyun 	if (device_may_wakeup(dev))
1397*4882a593Smuzhiyun 		cyapa->irq_wake = (enable_irq_wake(client->irq) == 0);
1398*4882a593Smuzhiyun 
1399*4882a593Smuzhiyun 	mutex_unlock(&cyapa->state_sync_lock);
1400*4882a593Smuzhiyun 	return 0;
1401*4882a593Smuzhiyun }
1402*4882a593Smuzhiyun 
cyapa_resume(struct device * dev)1403*4882a593Smuzhiyun static int __maybe_unused cyapa_resume(struct device *dev)
1404*4882a593Smuzhiyun {
1405*4882a593Smuzhiyun 	struct i2c_client *client = to_i2c_client(dev);
1406*4882a593Smuzhiyun 	struct cyapa *cyapa = i2c_get_clientdata(client);
1407*4882a593Smuzhiyun 	int error;
1408*4882a593Smuzhiyun 
1409*4882a593Smuzhiyun 	mutex_lock(&cyapa->state_sync_lock);
1410*4882a593Smuzhiyun 
1411*4882a593Smuzhiyun 	if (device_may_wakeup(dev) && cyapa->irq_wake) {
1412*4882a593Smuzhiyun 		disable_irq_wake(client->irq);
1413*4882a593Smuzhiyun 		cyapa->irq_wake = false;
1414*4882a593Smuzhiyun 	}
1415*4882a593Smuzhiyun 
1416*4882a593Smuzhiyun 	/*
1417*4882a593Smuzhiyun 	 * Update device states and runtime PM states.
1418*4882a593Smuzhiyun 	 * Re-Enable proximity interrupt after enter operational mode.
1419*4882a593Smuzhiyun 	 */
1420*4882a593Smuzhiyun 	error = cyapa_reinitialize(cyapa);
1421*4882a593Smuzhiyun 	if (error)
1422*4882a593Smuzhiyun 		dev_warn(dev, "failed to reinitialize TP device: %d\n", error);
1423*4882a593Smuzhiyun 
1424*4882a593Smuzhiyun 	enable_irq(client->irq);
1425*4882a593Smuzhiyun 
1426*4882a593Smuzhiyun 	mutex_unlock(&cyapa->state_sync_lock);
1427*4882a593Smuzhiyun 	return 0;
1428*4882a593Smuzhiyun }
1429*4882a593Smuzhiyun 
cyapa_runtime_suspend(struct device * dev)1430*4882a593Smuzhiyun static int __maybe_unused cyapa_runtime_suspend(struct device *dev)
1431*4882a593Smuzhiyun {
1432*4882a593Smuzhiyun 	struct cyapa *cyapa = dev_get_drvdata(dev);
1433*4882a593Smuzhiyun 	int error;
1434*4882a593Smuzhiyun 
1435*4882a593Smuzhiyun 	error = cyapa->ops->set_power_mode(cyapa,
1436*4882a593Smuzhiyun 			cyapa->runtime_suspend_power_mode,
1437*4882a593Smuzhiyun 			cyapa->runtime_suspend_sleep_time,
1438*4882a593Smuzhiyun 			CYAPA_PM_RUNTIME_SUSPEND);
1439*4882a593Smuzhiyun 	if (error)
1440*4882a593Smuzhiyun 		dev_warn(dev, "runtime suspend failed: %d\n", error);
1441*4882a593Smuzhiyun 
1442*4882a593Smuzhiyun 	return 0;
1443*4882a593Smuzhiyun }
1444*4882a593Smuzhiyun 
cyapa_runtime_resume(struct device * dev)1445*4882a593Smuzhiyun static int __maybe_unused cyapa_runtime_resume(struct device *dev)
1446*4882a593Smuzhiyun {
1447*4882a593Smuzhiyun 	struct cyapa *cyapa = dev_get_drvdata(dev);
1448*4882a593Smuzhiyun 	int error;
1449*4882a593Smuzhiyun 
1450*4882a593Smuzhiyun 	error = cyapa->ops->set_power_mode(cyapa,
1451*4882a593Smuzhiyun 			PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_RUNTIME_RESUME);
1452*4882a593Smuzhiyun 	if (error)
1453*4882a593Smuzhiyun 		dev_warn(dev, "runtime resume failed: %d\n", error);
1454*4882a593Smuzhiyun 
1455*4882a593Smuzhiyun 	return 0;
1456*4882a593Smuzhiyun }
1457*4882a593Smuzhiyun 
1458*4882a593Smuzhiyun static const struct dev_pm_ops cyapa_pm_ops = {
1459*4882a593Smuzhiyun 	SET_SYSTEM_SLEEP_PM_OPS(cyapa_suspend, cyapa_resume)
1460*4882a593Smuzhiyun 	SET_RUNTIME_PM_OPS(cyapa_runtime_suspend, cyapa_runtime_resume, NULL)
1461*4882a593Smuzhiyun };
1462*4882a593Smuzhiyun 
1463*4882a593Smuzhiyun static const struct i2c_device_id cyapa_id_table[] = {
1464*4882a593Smuzhiyun 	{ "cyapa", 0 },
1465*4882a593Smuzhiyun 	{ },
1466*4882a593Smuzhiyun };
1467*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, cyapa_id_table);
1468*4882a593Smuzhiyun 
1469*4882a593Smuzhiyun #ifdef CONFIG_ACPI
1470*4882a593Smuzhiyun static const struct acpi_device_id cyapa_acpi_id[] = {
1471*4882a593Smuzhiyun 	{ "CYAP0000", 0 },  /* Gen3 trackpad with 0x67 I2C address. */
1472*4882a593Smuzhiyun 	{ "CYAP0001", 0 },  /* Gen5 trackpad with 0x24 I2C address. */
1473*4882a593Smuzhiyun 	{ "CYAP0002", 0 },  /* Gen6 trackpad with 0x24 I2C address. */
1474*4882a593Smuzhiyun 	{ }
1475*4882a593Smuzhiyun };
1476*4882a593Smuzhiyun MODULE_DEVICE_TABLE(acpi, cyapa_acpi_id);
1477*4882a593Smuzhiyun #endif
1478*4882a593Smuzhiyun 
1479*4882a593Smuzhiyun #ifdef CONFIG_OF
1480*4882a593Smuzhiyun static const struct of_device_id cyapa_of_match[] = {
1481*4882a593Smuzhiyun 	{ .compatible = "cypress,cyapa" },
1482*4882a593Smuzhiyun 	{ /* sentinel */ }
1483*4882a593Smuzhiyun };
1484*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, cyapa_of_match);
1485*4882a593Smuzhiyun #endif
1486*4882a593Smuzhiyun 
1487*4882a593Smuzhiyun static struct i2c_driver cyapa_driver = {
1488*4882a593Smuzhiyun 	.driver = {
1489*4882a593Smuzhiyun 		.name = "cyapa",
1490*4882a593Smuzhiyun 		.pm = &cyapa_pm_ops,
1491*4882a593Smuzhiyun 		.acpi_match_table = ACPI_PTR(cyapa_acpi_id),
1492*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(cyapa_of_match),
1493*4882a593Smuzhiyun 	},
1494*4882a593Smuzhiyun 
1495*4882a593Smuzhiyun 	.probe = cyapa_probe,
1496*4882a593Smuzhiyun 	.id_table = cyapa_id_table,
1497*4882a593Smuzhiyun };
1498*4882a593Smuzhiyun 
1499*4882a593Smuzhiyun module_i2c_driver(cyapa_driver);
1500*4882a593Smuzhiyun 
1501*4882a593Smuzhiyun MODULE_DESCRIPTION("Cypress APA I2C Trackpad Driver");
1502*4882a593Smuzhiyun MODULE_AUTHOR("Dudley Du <dudl@cypress.com>");
1503*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1504