xref: /OK3568_Linux_fs/kernel/drivers/platform/chrome/cros_ec_proto.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun // ChromeOS EC communication protocol helper functions
3*4882a593Smuzhiyun //
4*4882a593Smuzhiyun // Copyright (C) 2015 Google, Inc
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include <linux/delay.h>
7*4882a593Smuzhiyun #include <linux/device.h>
8*4882a593Smuzhiyun #include <linux/module.h>
9*4882a593Smuzhiyun #include <linux/platform_data/cros_ec_commands.h>
10*4882a593Smuzhiyun #include <linux/platform_data/cros_ec_proto.h>
11*4882a593Smuzhiyun #include <linux/slab.h>
12*4882a593Smuzhiyun #include <asm/unaligned.h>
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include "cros_ec_trace.h"
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #define EC_COMMAND_RETRIES	50
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun static const int cros_ec_error_map[] = {
19*4882a593Smuzhiyun 	[EC_RES_INVALID_COMMAND] = -EOPNOTSUPP,
20*4882a593Smuzhiyun 	[EC_RES_ERROR] = -EIO,
21*4882a593Smuzhiyun 	[EC_RES_INVALID_PARAM] = -EINVAL,
22*4882a593Smuzhiyun 	[EC_RES_ACCESS_DENIED] = -EACCES,
23*4882a593Smuzhiyun 	[EC_RES_INVALID_RESPONSE] = -EPROTO,
24*4882a593Smuzhiyun 	[EC_RES_INVALID_VERSION] = -ENOPROTOOPT,
25*4882a593Smuzhiyun 	[EC_RES_INVALID_CHECKSUM] = -EBADMSG,
26*4882a593Smuzhiyun 	[EC_RES_IN_PROGRESS] = -EINPROGRESS,
27*4882a593Smuzhiyun 	[EC_RES_UNAVAILABLE] = -ENODATA,
28*4882a593Smuzhiyun 	[EC_RES_TIMEOUT] = -ETIMEDOUT,
29*4882a593Smuzhiyun 	[EC_RES_OVERFLOW] = -EOVERFLOW,
30*4882a593Smuzhiyun 	[EC_RES_INVALID_HEADER] = -EBADR,
31*4882a593Smuzhiyun 	[EC_RES_REQUEST_TRUNCATED] = -EBADR,
32*4882a593Smuzhiyun 	[EC_RES_RESPONSE_TOO_BIG] = -EFBIG,
33*4882a593Smuzhiyun 	[EC_RES_BUS_ERROR] = -EFAULT,
34*4882a593Smuzhiyun 	[EC_RES_BUSY] = -EBUSY,
35*4882a593Smuzhiyun 	[EC_RES_INVALID_HEADER_VERSION] = -EBADMSG,
36*4882a593Smuzhiyun 	[EC_RES_INVALID_HEADER_CRC] = -EBADMSG,
37*4882a593Smuzhiyun 	[EC_RES_INVALID_DATA_CRC] = -EBADMSG,
38*4882a593Smuzhiyun 	[EC_RES_DUP_UNAVAILABLE] = -ENODATA,
39*4882a593Smuzhiyun };
40*4882a593Smuzhiyun 
cros_ec_map_error(uint32_t result)41*4882a593Smuzhiyun static int cros_ec_map_error(uint32_t result)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun 	int ret = 0;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	if (result != EC_RES_SUCCESS) {
46*4882a593Smuzhiyun 		if (result < ARRAY_SIZE(cros_ec_error_map) && cros_ec_error_map[result])
47*4882a593Smuzhiyun 			ret = cros_ec_error_map[result];
48*4882a593Smuzhiyun 		else
49*4882a593Smuzhiyun 			ret = -EPROTO;
50*4882a593Smuzhiyun 	}
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	return ret;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun 
prepare_packet(struct cros_ec_device * ec_dev,struct cros_ec_command * msg)55*4882a593Smuzhiyun static int prepare_packet(struct cros_ec_device *ec_dev,
56*4882a593Smuzhiyun 			  struct cros_ec_command *msg)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	struct ec_host_request *request;
59*4882a593Smuzhiyun 	u8 *out;
60*4882a593Smuzhiyun 	int i;
61*4882a593Smuzhiyun 	u8 csum = 0;
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	BUG_ON(ec_dev->proto_version != EC_HOST_REQUEST_VERSION);
64*4882a593Smuzhiyun 	BUG_ON(msg->outsize + sizeof(*request) > ec_dev->dout_size);
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	out = ec_dev->dout;
67*4882a593Smuzhiyun 	request = (struct ec_host_request *)out;
68*4882a593Smuzhiyun 	request->struct_version = EC_HOST_REQUEST_VERSION;
69*4882a593Smuzhiyun 	request->checksum = 0;
70*4882a593Smuzhiyun 	request->command = msg->command;
71*4882a593Smuzhiyun 	request->command_version = msg->version;
72*4882a593Smuzhiyun 	request->reserved = 0;
73*4882a593Smuzhiyun 	request->data_len = msg->outsize;
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	for (i = 0; i < sizeof(*request); i++)
76*4882a593Smuzhiyun 		csum += out[i];
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	/* Copy data and update checksum */
79*4882a593Smuzhiyun 	memcpy(out + sizeof(*request), msg->data, msg->outsize);
80*4882a593Smuzhiyun 	for (i = 0; i < msg->outsize; i++)
81*4882a593Smuzhiyun 		csum += msg->data[i];
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	request->checksum = -csum;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	return sizeof(*request) + msg->outsize;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun 
send_command(struct cros_ec_device * ec_dev,struct cros_ec_command * msg)88*4882a593Smuzhiyun static int send_command(struct cros_ec_device *ec_dev,
89*4882a593Smuzhiyun 			struct cros_ec_command *msg)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	int ret;
92*4882a593Smuzhiyun 	int (*xfer_fxn)(struct cros_ec_device *ec, struct cros_ec_command *msg);
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	if (ec_dev->proto_version > 2)
95*4882a593Smuzhiyun 		xfer_fxn = ec_dev->pkt_xfer;
96*4882a593Smuzhiyun 	else
97*4882a593Smuzhiyun 		xfer_fxn = ec_dev->cmd_xfer;
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	if (!xfer_fxn) {
100*4882a593Smuzhiyun 		/*
101*4882a593Smuzhiyun 		 * This error can happen if a communication error happened and
102*4882a593Smuzhiyun 		 * the EC is trying to use protocol v2, on an underlying
103*4882a593Smuzhiyun 		 * communication mechanism that does not support v2.
104*4882a593Smuzhiyun 		 */
105*4882a593Smuzhiyun 		dev_err_once(ec_dev->dev,
106*4882a593Smuzhiyun 			     "missing EC transfer API, cannot send command\n");
107*4882a593Smuzhiyun 		return -EIO;
108*4882a593Smuzhiyun 	}
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	trace_cros_ec_request_start(msg);
111*4882a593Smuzhiyun 	ret = (*xfer_fxn)(ec_dev, msg);
112*4882a593Smuzhiyun 	trace_cros_ec_request_done(msg, ret);
113*4882a593Smuzhiyun 	if (msg->result == EC_RES_IN_PROGRESS) {
114*4882a593Smuzhiyun 		int i;
115*4882a593Smuzhiyun 		struct cros_ec_command *status_msg;
116*4882a593Smuzhiyun 		struct ec_response_get_comms_status *status;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 		status_msg = kmalloc(sizeof(*status_msg) + sizeof(*status),
119*4882a593Smuzhiyun 				     GFP_KERNEL);
120*4882a593Smuzhiyun 		if (!status_msg)
121*4882a593Smuzhiyun 			return -ENOMEM;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 		status_msg->version = 0;
124*4882a593Smuzhiyun 		status_msg->command = EC_CMD_GET_COMMS_STATUS;
125*4882a593Smuzhiyun 		status_msg->insize = sizeof(*status);
126*4882a593Smuzhiyun 		status_msg->outsize = 0;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 		/*
129*4882a593Smuzhiyun 		 * Query the EC's status until it's no longer busy or
130*4882a593Smuzhiyun 		 * we encounter an error.
131*4882a593Smuzhiyun 		 */
132*4882a593Smuzhiyun 		for (i = 0; i < EC_COMMAND_RETRIES; i++) {
133*4882a593Smuzhiyun 			usleep_range(10000, 11000);
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 			trace_cros_ec_request_start(status_msg);
136*4882a593Smuzhiyun 			ret = (*xfer_fxn)(ec_dev, status_msg);
137*4882a593Smuzhiyun 			trace_cros_ec_request_done(status_msg, ret);
138*4882a593Smuzhiyun 			if (ret == -EAGAIN)
139*4882a593Smuzhiyun 				continue;
140*4882a593Smuzhiyun 			if (ret < 0)
141*4882a593Smuzhiyun 				break;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 			msg->result = status_msg->result;
144*4882a593Smuzhiyun 			if (status_msg->result != EC_RES_SUCCESS)
145*4882a593Smuzhiyun 				break;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 			status = (struct ec_response_get_comms_status *)
148*4882a593Smuzhiyun 				 status_msg->data;
149*4882a593Smuzhiyun 			if (!(status->flags & EC_COMMS_STATUS_PROCESSING))
150*4882a593Smuzhiyun 				break;
151*4882a593Smuzhiyun 		}
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 		kfree(status_msg);
154*4882a593Smuzhiyun 	}
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	return ret;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun /**
160*4882a593Smuzhiyun  * cros_ec_prepare_tx() - Prepare an outgoing message in the output buffer.
161*4882a593Smuzhiyun  * @ec_dev: Device to register.
162*4882a593Smuzhiyun  * @msg: Message to write.
163*4882a593Smuzhiyun  *
164*4882a593Smuzhiyun  * This is intended to be used by all ChromeOS EC drivers, but at present
165*4882a593Smuzhiyun  * only SPI uses it. Once LPC uses the same protocol it can start using it.
166*4882a593Smuzhiyun  * I2C could use it now, with a refactor of the existing code.
167*4882a593Smuzhiyun  *
168*4882a593Smuzhiyun  * Return: 0 on success or negative error code.
169*4882a593Smuzhiyun  */
cros_ec_prepare_tx(struct cros_ec_device * ec_dev,struct cros_ec_command * msg)170*4882a593Smuzhiyun int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
171*4882a593Smuzhiyun 		       struct cros_ec_command *msg)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun 	u8 *out;
174*4882a593Smuzhiyun 	u8 csum;
175*4882a593Smuzhiyun 	int i;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	if (ec_dev->proto_version > 2)
178*4882a593Smuzhiyun 		return prepare_packet(ec_dev, msg);
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	BUG_ON(msg->outsize > EC_PROTO2_MAX_PARAM_SIZE);
181*4882a593Smuzhiyun 	out = ec_dev->dout;
182*4882a593Smuzhiyun 	out[0] = EC_CMD_VERSION0 + msg->version;
183*4882a593Smuzhiyun 	out[1] = msg->command;
184*4882a593Smuzhiyun 	out[2] = msg->outsize;
185*4882a593Smuzhiyun 	csum = out[0] + out[1] + out[2];
186*4882a593Smuzhiyun 	for (i = 0; i < msg->outsize; i++)
187*4882a593Smuzhiyun 		csum += out[EC_MSG_TX_HEADER_BYTES + i] = msg->data[i];
188*4882a593Smuzhiyun 	out[EC_MSG_TX_HEADER_BYTES + msg->outsize] = csum;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	return EC_MSG_TX_PROTO_BYTES + msg->outsize;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun EXPORT_SYMBOL(cros_ec_prepare_tx);
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun /**
195*4882a593Smuzhiyun  * cros_ec_check_result() - Check ec_msg->result.
196*4882a593Smuzhiyun  * @ec_dev: EC device.
197*4882a593Smuzhiyun  * @msg: Message to check.
198*4882a593Smuzhiyun  *
199*4882a593Smuzhiyun  * This is used by ChromeOS EC drivers to check the ec_msg->result for
200*4882a593Smuzhiyun  * errors and to warn about them.
201*4882a593Smuzhiyun  *
202*4882a593Smuzhiyun  * Return: 0 on success or negative error code.
203*4882a593Smuzhiyun  */
cros_ec_check_result(struct cros_ec_device * ec_dev,struct cros_ec_command * msg)204*4882a593Smuzhiyun int cros_ec_check_result(struct cros_ec_device *ec_dev,
205*4882a593Smuzhiyun 			 struct cros_ec_command *msg)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun 	switch (msg->result) {
208*4882a593Smuzhiyun 	case EC_RES_SUCCESS:
209*4882a593Smuzhiyun 		return 0;
210*4882a593Smuzhiyun 	case EC_RES_IN_PROGRESS:
211*4882a593Smuzhiyun 		dev_dbg(ec_dev->dev, "command 0x%02x in progress\n",
212*4882a593Smuzhiyun 			msg->command);
213*4882a593Smuzhiyun 		return -EAGAIN;
214*4882a593Smuzhiyun 	default:
215*4882a593Smuzhiyun 		dev_dbg(ec_dev->dev, "command 0x%02x returned %d\n",
216*4882a593Smuzhiyun 			msg->command, msg->result);
217*4882a593Smuzhiyun 		return 0;
218*4882a593Smuzhiyun 	}
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun EXPORT_SYMBOL(cros_ec_check_result);
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun /*
223*4882a593Smuzhiyun  * cros_ec_get_host_event_wake_mask
224*4882a593Smuzhiyun  *
225*4882a593Smuzhiyun  * Get the mask of host events that cause wake from suspend.
226*4882a593Smuzhiyun  *
227*4882a593Smuzhiyun  * @ec_dev: EC device to call
228*4882a593Smuzhiyun  * @msg: message structure to use
229*4882a593Smuzhiyun  * @mask: result when function returns >=0.
230*4882a593Smuzhiyun  *
231*4882a593Smuzhiyun  * LOCKING:
232*4882a593Smuzhiyun  * the caller has ec_dev->lock mutex, or the caller knows there is
233*4882a593Smuzhiyun  * no other command in progress.
234*4882a593Smuzhiyun  */
cros_ec_get_host_event_wake_mask(struct cros_ec_device * ec_dev,struct cros_ec_command * msg,uint32_t * mask)235*4882a593Smuzhiyun static int cros_ec_get_host_event_wake_mask(struct cros_ec_device *ec_dev,
236*4882a593Smuzhiyun 					    struct cros_ec_command *msg,
237*4882a593Smuzhiyun 					    uint32_t *mask)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun 	struct ec_response_host_event_mask *r;
240*4882a593Smuzhiyun 	int ret;
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	msg->command = EC_CMD_HOST_EVENT_GET_WAKE_MASK;
243*4882a593Smuzhiyun 	msg->version = 0;
244*4882a593Smuzhiyun 	msg->outsize = 0;
245*4882a593Smuzhiyun 	msg->insize = sizeof(*r);
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	ret = send_command(ec_dev, msg);
248*4882a593Smuzhiyun 	if (ret >= 0) {
249*4882a593Smuzhiyun 		if (msg->result == EC_RES_INVALID_COMMAND)
250*4882a593Smuzhiyun 			return -EOPNOTSUPP;
251*4882a593Smuzhiyun 		if (msg->result != EC_RES_SUCCESS)
252*4882a593Smuzhiyun 			return -EPROTO;
253*4882a593Smuzhiyun 	}
254*4882a593Smuzhiyun 	if (ret > 0) {
255*4882a593Smuzhiyun 		r = (struct ec_response_host_event_mask *)msg->data;
256*4882a593Smuzhiyun 		*mask = r->mask;
257*4882a593Smuzhiyun 	}
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	return ret;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun 
cros_ec_host_command_proto_query(struct cros_ec_device * ec_dev,int devidx,struct cros_ec_command * msg)262*4882a593Smuzhiyun static int cros_ec_host_command_proto_query(struct cros_ec_device *ec_dev,
263*4882a593Smuzhiyun 					    int devidx,
264*4882a593Smuzhiyun 					    struct cros_ec_command *msg)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun 	/*
267*4882a593Smuzhiyun 	 * Try using v3+ to query for supported protocols. If this
268*4882a593Smuzhiyun 	 * command fails, fall back to v2. Returns the highest protocol
269*4882a593Smuzhiyun 	 * supported by the EC.
270*4882a593Smuzhiyun 	 * Also sets the max request/response/passthru size.
271*4882a593Smuzhiyun 	 */
272*4882a593Smuzhiyun 	int ret;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	if (!ec_dev->pkt_xfer)
275*4882a593Smuzhiyun 		return -EPROTONOSUPPORT;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	memset(msg, 0, sizeof(*msg));
278*4882a593Smuzhiyun 	msg->command = EC_CMD_PASSTHRU_OFFSET(devidx) | EC_CMD_GET_PROTOCOL_INFO;
279*4882a593Smuzhiyun 	msg->insize = sizeof(struct ec_response_get_protocol_info);
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	ret = send_command(ec_dev, msg);
282*4882a593Smuzhiyun 	/*
283*4882a593Smuzhiyun 	 * Send command once again when timeout occurred.
284*4882a593Smuzhiyun 	 * Fingerprint MCU (FPMCU) is restarted during system boot which
285*4882a593Smuzhiyun 	 * introduces small window in which FPMCU won't respond for any
286*4882a593Smuzhiyun 	 * messages sent by kernel. There is no need to wait before next
287*4882a593Smuzhiyun 	 * attempt because we waited at least EC_MSG_DEADLINE_MS.
288*4882a593Smuzhiyun 	 */
289*4882a593Smuzhiyun 	if (ret == -ETIMEDOUT)
290*4882a593Smuzhiyun 		ret = send_command(ec_dev, msg);
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	if (ret < 0) {
293*4882a593Smuzhiyun 		dev_dbg(ec_dev->dev,
294*4882a593Smuzhiyun 			"failed to check for EC[%d] protocol version: %d\n",
295*4882a593Smuzhiyun 			devidx, ret);
296*4882a593Smuzhiyun 		return ret;
297*4882a593Smuzhiyun 	}
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	if (devidx > 0 && msg->result == EC_RES_INVALID_COMMAND)
300*4882a593Smuzhiyun 		return -ENODEV;
301*4882a593Smuzhiyun 	else if (msg->result != EC_RES_SUCCESS)
302*4882a593Smuzhiyun 		return msg->result;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	return 0;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun 
cros_ec_host_command_proto_query_v2(struct cros_ec_device * ec_dev)307*4882a593Smuzhiyun static int cros_ec_host_command_proto_query_v2(struct cros_ec_device *ec_dev)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun 	struct cros_ec_command *msg;
310*4882a593Smuzhiyun 	struct ec_params_hello *hello_params;
311*4882a593Smuzhiyun 	struct ec_response_hello *hello_response;
312*4882a593Smuzhiyun 	int ret;
313*4882a593Smuzhiyun 	int len = max(sizeof(*hello_params), sizeof(*hello_response));
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	msg = kmalloc(sizeof(*msg) + len, GFP_KERNEL);
316*4882a593Smuzhiyun 	if (!msg)
317*4882a593Smuzhiyun 		return -ENOMEM;
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	msg->version = 0;
320*4882a593Smuzhiyun 	msg->command = EC_CMD_HELLO;
321*4882a593Smuzhiyun 	hello_params = (struct ec_params_hello *)msg->data;
322*4882a593Smuzhiyun 	msg->outsize = sizeof(*hello_params);
323*4882a593Smuzhiyun 	hello_response = (struct ec_response_hello *)msg->data;
324*4882a593Smuzhiyun 	msg->insize = sizeof(*hello_response);
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	hello_params->in_data = 0xa0b0c0d0;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	ret = send_command(ec_dev, msg);
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	if (ret < 0) {
331*4882a593Smuzhiyun 		dev_dbg(ec_dev->dev,
332*4882a593Smuzhiyun 			"EC failed to respond to v2 hello: %d\n",
333*4882a593Smuzhiyun 			ret);
334*4882a593Smuzhiyun 		goto exit;
335*4882a593Smuzhiyun 	} else if (msg->result != EC_RES_SUCCESS) {
336*4882a593Smuzhiyun 		dev_err(ec_dev->dev,
337*4882a593Smuzhiyun 			"EC responded to v2 hello with error: %d\n",
338*4882a593Smuzhiyun 			msg->result);
339*4882a593Smuzhiyun 		ret = msg->result;
340*4882a593Smuzhiyun 		goto exit;
341*4882a593Smuzhiyun 	} else if (hello_response->out_data != 0xa1b2c3d4) {
342*4882a593Smuzhiyun 		dev_err(ec_dev->dev,
343*4882a593Smuzhiyun 			"EC responded to v2 hello with bad result: %u\n",
344*4882a593Smuzhiyun 			hello_response->out_data);
345*4882a593Smuzhiyun 		ret = -EBADMSG;
346*4882a593Smuzhiyun 		goto exit;
347*4882a593Smuzhiyun 	}
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	ret = 0;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun  exit:
352*4882a593Smuzhiyun 	kfree(msg);
353*4882a593Smuzhiyun 	return ret;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun /*
357*4882a593Smuzhiyun  * cros_ec_get_host_command_version_mask
358*4882a593Smuzhiyun  *
359*4882a593Smuzhiyun  * Get the version mask of a given command.
360*4882a593Smuzhiyun  *
361*4882a593Smuzhiyun  * @ec_dev: EC device to call
362*4882a593Smuzhiyun  * @msg: message structure to use
363*4882a593Smuzhiyun  * @cmd: command to get the version of.
364*4882a593Smuzhiyun  * @mask: result when function returns 0.
365*4882a593Smuzhiyun  *
366*4882a593Smuzhiyun  * @return 0 on success, error code otherwise
367*4882a593Smuzhiyun  *
368*4882a593Smuzhiyun  * LOCKING:
369*4882a593Smuzhiyun  * the caller has ec_dev->lock mutex or the caller knows there is
370*4882a593Smuzhiyun  * no other command in progress.
371*4882a593Smuzhiyun  */
cros_ec_get_host_command_version_mask(struct cros_ec_device * ec_dev,u16 cmd,u32 * mask)372*4882a593Smuzhiyun static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev,
373*4882a593Smuzhiyun 	u16 cmd, u32 *mask)
374*4882a593Smuzhiyun {
375*4882a593Smuzhiyun 	struct ec_params_get_cmd_versions *pver;
376*4882a593Smuzhiyun 	struct ec_response_get_cmd_versions *rver;
377*4882a593Smuzhiyun 	struct cros_ec_command *msg;
378*4882a593Smuzhiyun 	int ret;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	msg = kmalloc(sizeof(*msg) + max(sizeof(*rver), sizeof(*pver)),
381*4882a593Smuzhiyun 		      GFP_KERNEL);
382*4882a593Smuzhiyun 	if (!msg)
383*4882a593Smuzhiyun 		return -ENOMEM;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	msg->version = 0;
386*4882a593Smuzhiyun 	msg->command = EC_CMD_GET_CMD_VERSIONS;
387*4882a593Smuzhiyun 	msg->insize = sizeof(*rver);
388*4882a593Smuzhiyun 	msg->outsize = sizeof(*pver);
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	pver = (struct ec_params_get_cmd_versions *)msg->data;
391*4882a593Smuzhiyun 	pver->cmd = cmd;
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	ret = send_command(ec_dev, msg);
394*4882a593Smuzhiyun 	if (ret > 0) {
395*4882a593Smuzhiyun 		rver = (struct ec_response_get_cmd_versions *)msg->data;
396*4882a593Smuzhiyun 		*mask = rver->version_mask;
397*4882a593Smuzhiyun 	}
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	kfree(msg);
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	return ret;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun /**
405*4882a593Smuzhiyun  * cros_ec_query_all() -  Query the protocol version supported by the
406*4882a593Smuzhiyun  *         ChromeOS EC.
407*4882a593Smuzhiyun  * @ec_dev: Device to register.
408*4882a593Smuzhiyun  *
409*4882a593Smuzhiyun  * Return: 0 on success or negative error code.
410*4882a593Smuzhiyun  */
cros_ec_query_all(struct cros_ec_device * ec_dev)411*4882a593Smuzhiyun int cros_ec_query_all(struct cros_ec_device *ec_dev)
412*4882a593Smuzhiyun {
413*4882a593Smuzhiyun 	struct device *dev = ec_dev->dev;
414*4882a593Smuzhiyun 	struct cros_ec_command *proto_msg;
415*4882a593Smuzhiyun 	struct ec_response_get_protocol_info *proto_info;
416*4882a593Smuzhiyun 	u32 ver_mask = 0;
417*4882a593Smuzhiyun 	int ret;
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	proto_msg = kzalloc(sizeof(*proto_msg) + sizeof(*proto_info),
420*4882a593Smuzhiyun 			    GFP_KERNEL);
421*4882a593Smuzhiyun 	if (!proto_msg)
422*4882a593Smuzhiyun 		return -ENOMEM;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	/* First try sending with proto v3. */
425*4882a593Smuzhiyun 	ec_dev->proto_version = 3;
426*4882a593Smuzhiyun 	ret = cros_ec_host_command_proto_query(ec_dev, 0, proto_msg);
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	if (ret == 0) {
429*4882a593Smuzhiyun 		proto_info = (struct ec_response_get_protocol_info *)
430*4882a593Smuzhiyun 			proto_msg->data;
431*4882a593Smuzhiyun 		ec_dev->max_request = proto_info->max_request_packet_size -
432*4882a593Smuzhiyun 			sizeof(struct ec_host_request);
433*4882a593Smuzhiyun 		ec_dev->max_response = proto_info->max_response_packet_size -
434*4882a593Smuzhiyun 			sizeof(struct ec_host_response);
435*4882a593Smuzhiyun 		ec_dev->proto_version =
436*4882a593Smuzhiyun 			min(EC_HOST_REQUEST_VERSION,
437*4882a593Smuzhiyun 					fls(proto_info->protocol_versions) - 1);
438*4882a593Smuzhiyun 		dev_dbg(ec_dev->dev,
439*4882a593Smuzhiyun 			"using proto v%u\n",
440*4882a593Smuzhiyun 			ec_dev->proto_version);
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 		ec_dev->din_size = ec_dev->max_response +
443*4882a593Smuzhiyun 			sizeof(struct ec_host_response) +
444*4882a593Smuzhiyun 			EC_MAX_RESPONSE_OVERHEAD;
445*4882a593Smuzhiyun 		ec_dev->dout_size = ec_dev->max_request +
446*4882a593Smuzhiyun 			sizeof(struct ec_host_request) +
447*4882a593Smuzhiyun 			EC_MAX_REQUEST_OVERHEAD;
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 		/*
450*4882a593Smuzhiyun 		 * Check for PD
451*4882a593Smuzhiyun 		 */
452*4882a593Smuzhiyun 		ret = cros_ec_host_command_proto_query(ec_dev, 1, proto_msg);
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 		if (ret) {
455*4882a593Smuzhiyun 			dev_dbg(ec_dev->dev, "no PD chip found: %d\n", ret);
456*4882a593Smuzhiyun 			ec_dev->max_passthru = 0;
457*4882a593Smuzhiyun 		} else {
458*4882a593Smuzhiyun 			dev_dbg(ec_dev->dev, "found PD chip\n");
459*4882a593Smuzhiyun 			ec_dev->max_passthru =
460*4882a593Smuzhiyun 				proto_info->max_request_packet_size -
461*4882a593Smuzhiyun 				sizeof(struct ec_host_request);
462*4882a593Smuzhiyun 		}
463*4882a593Smuzhiyun 	} else {
464*4882a593Smuzhiyun 		/* Try querying with a v2 hello message. */
465*4882a593Smuzhiyun 		ec_dev->proto_version = 2;
466*4882a593Smuzhiyun 		ret = cros_ec_host_command_proto_query_v2(ec_dev);
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 		if (ret == 0) {
469*4882a593Smuzhiyun 			/* V2 hello succeeded. */
470*4882a593Smuzhiyun 			dev_dbg(ec_dev->dev, "falling back to proto v2\n");
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 			ec_dev->max_request = EC_PROTO2_MAX_PARAM_SIZE;
473*4882a593Smuzhiyun 			ec_dev->max_response = EC_PROTO2_MAX_PARAM_SIZE;
474*4882a593Smuzhiyun 			ec_dev->max_passthru = 0;
475*4882a593Smuzhiyun 			ec_dev->pkt_xfer = NULL;
476*4882a593Smuzhiyun 			ec_dev->din_size = EC_PROTO2_MSG_BYTES;
477*4882a593Smuzhiyun 			ec_dev->dout_size = EC_PROTO2_MSG_BYTES;
478*4882a593Smuzhiyun 		} else {
479*4882a593Smuzhiyun 			/*
480*4882a593Smuzhiyun 			 * It's possible for a test to occur too early when
481*4882a593Smuzhiyun 			 * the EC isn't listening. If this happens, we'll
482*4882a593Smuzhiyun 			 * test later when the first command is run.
483*4882a593Smuzhiyun 			 */
484*4882a593Smuzhiyun 			ec_dev->proto_version = EC_PROTO_VERSION_UNKNOWN;
485*4882a593Smuzhiyun 			dev_dbg(ec_dev->dev, "EC query failed: %d\n", ret);
486*4882a593Smuzhiyun 			goto exit;
487*4882a593Smuzhiyun 		}
488*4882a593Smuzhiyun 	}
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 	devm_kfree(dev, ec_dev->din);
491*4882a593Smuzhiyun 	devm_kfree(dev, ec_dev->dout);
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	ec_dev->din = devm_kzalloc(dev, ec_dev->din_size, GFP_KERNEL);
494*4882a593Smuzhiyun 	if (!ec_dev->din) {
495*4882a593Smuzhiyun 		ret = -ENOMEM;
496*4882a593Smuzhiyun 		goto exit;
497*4882a593Smuzhiyun 	}
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	ec_dev->dout = devm_kzalloc(dev, ec_dev->dout_size, GFP_KERNEL);
500*4882a593Smuzhiyun 	if (!ec_dev->dout) {
501*4882a593Smuzhiyun 		devm_kfree(dev, ec_dev->din);
502*4882a593Smuzhiyun 		ret = -ENOMEM;
503*4882a593Smuzhiyun 		goto exit;
504*4882a593Smuzhiyun 	}
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	/* Probe if MKBP event is supported */
507*4882a593Smuzhiyun 	ret = cros_ec_get_host_command_version_mask(ec_dev,
508*4882a593Smuzhiyun 						    EC_CMD_GET_NEXT_EVENT,
509*4882a593Smuzhiyun 						    &ver_mask);
510*4882a593Smuzhiyun 	if (ret < 0 || ver_mask == 0) {
511*4882a593Smuzhiyun 		ec_dev->mkbp_event_supported = 0;
512*4882a593Smuzhiyun 	} else {
513*4882a593Smuzhiyun 		ec_dev->mkbp_event_supported = fls(ver_mask);
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 		dev_dbg(ec_dev->dev, "MKBP support version %u\n", ec_dev->mkbp_event_supported - 1);
516*4882a593Smuzhiyun 	}
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	/* Probe if host sleep v1 is supported for S0ix failure detection. */
519*4882a593Smuzhiyun 	ret = cros_ec_get_host_command_version_mask(ec_dev,
520*4882a593Smuzhiyun 						    EC_CMD_HOST_SLEEP_EVENT,
521*4882a593Smuzhiyun 						    &ver_mask);
522*4882a593Smuzhiyun 	ec_dev->host_sleep_v1 = (ret >= 0 && (ver_mask & EC_VER_MASK(1)));
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	/* Get host event wake mask. */
525*4882a593Smuzhiyun 	ret = cros_ec_get_host_event_wake_mask(ec_dev, proto_msg,
526*4882a593Smuzhiyun 					       &ec_dev->host_event_wake_mask);
527*4882a593Smuzhiyun 	if (ret < 0) {
528*4882a593Smuzhiyun 		/*
529*4882a593Smuzhiyun 		 * If the EC doesn't support EC_CMD_HOST_EVENT_GET_WAKE_MASK,
530*4882a593Smuzhiyun 		 * use a reasonable default. Note that we ignore various
531*4882a593Smuzhiyun 		 * battery, AC status, and power-state events, because (a)
532*4882a593Smuzhiyun 		 * those can be quite common (e.g., when sitting at full
533*4882a593Smuzhiyun 		 * charge, on AC) and (b) these are not actionable wake events;
534*4882a593Smuzhiyun 		 * if anything, we'd like to continue suspending (to save
535*4882a593Smuzhiyun 		 * power), not wake up.
536*4882a593Smuzhiyun 		 */
537*4882a593Smuzhiyun 		ec_dev->host_event_wake_mask = U32_MAX &
538*4882a593Smuzhiyun 			~(EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_CLOSED) |
539*4882a593Smuzhiyun 			  EC_HOST_EVENT_MASK(EC_HOST_EVENT_AC_DISCONNECTED) |
540*4882a593Smuzhiyun 			  EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY_LOW) |
541*4882a593Smuzhiyun 			  EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY_CRITICAL) |
542*4882a593Smuzhiyun 			  EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY) |
543*4882a593Smuzhiyun 			  EC_HOST_EVENT_MASK(EC_HOST_EVENT_PD_MCU) |
544*4882a593Smuzhiyun 			  EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY_STATUS));
545*4882a593Smuzhiyun 		/*
546*4882a593Smuzhiyun 		 * Old ECs may not support this command. Complain about all
547*4882a593Smuzhiyun 		 * other errors.
548*4882a593Smuzhiyun 		 */
549*4882a593Smuzhiyun 		if (ret != -EOPNOTSUPP)
550*4882a593Smuzhiyun 			dev_err(ec_dev->dev,
551*4882a593Smuzhiyun 				"failed to retrieve wake mask: %d\n", ret);
552*4882a593Smuzhiyun 	}
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	ret = 0;
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun exit:
557*4882a593Smuzhiyun 	kfree(proto_msg);
558*4882a593Smuzhiyun 	return ret;
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun EXPORT_SYMBOL(cros_ec_query_all);
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun /**
563*4882a593Smuzhiyun  * cros_ec_cmd_xfer() - Send a command to the ChromeOS EC.
564*4882a593Smuzhiyun  * @ec_dev: EC device.
565*4882a593Smuzhiyun  * @msg: Message to write.
566*4882a593Smuzhiyun  *
567*4882a593Smuzhiyun  * Call this to send a command to the ChromeOS EC. This should be used instead
568*4882a593Smuzhiyun  * of calling the EC's cmd_xfer() callback directly. This function does not
569*4882a593Smuzhiyun  * convert EC command execution error codes to Linux error codes. Most
570*4882a593Smuzhiyun  * in-kernel users will want to use cros_ec_cmd_xfer_status() instead since
571*4882a593Smuzhiyun  * that function implements the conversion.
572*4882a593Smuzhiyun  *
573*4882a593Smuzhiyun  * Return:
574*4882a593Smuzhiyun  * >0 - EC command was executed successfully. The return value is the number
575*4882a593Smuzhiyun  *      of bytes returned by the EC (excluding the header).
576*4882a593Smuzhiyun  * =0 - EC communication was successful. EC command execution results are
577*4882a593Smuzhiyun  *      reported in msg->result. The result will be EC_RES_SUCCESS if the
578*4882a593Smuzhiyun  *      command was executed successfully or report an EC command execution
579*4882a593Smuzhiyun  *      error.
580*4882a593Smuzhiyun  * <0 - EC communication error. Return value is the Linux error code.
581*4882a593Smuzhiyun  */
cros_ec_cmd_xfer(struct cros_ec_device * ec_dev,struct cros_ec_command * msg)582*4882a593Smuzhiyun int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)
583*4882a593Smuzhiyun {
584*4882a593Smuzhiyun 	int ret;
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	mutex_lock(&ec_dev->lock);
587*4882a593Smuzhiyun 	if (ec_dev->proto_version == EC_PROTO_VERSION_UNKNOWN) {
588*4882a593Smuzhiyun 		ret = cros_ec_query_all(ec_dev);
589*4882a593Smuzhiyun 		if (ret) {
590*4882a593Smuzhiyun 			dev_err(ec_dev->dev,
591*4882a593Smuzhiyun 				"EC version unknown and query failed; aborting command\n");
592*4882a593Smuzhiyun 			mutex_unlock(&ec_dev->lock);
593*4882a593Smuzhiyun 			return ret;
594*4882a593Smuzhiyun 		}
595*4882a593Smuzhiyun 	}
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	if (msg->insize > ec_dev->max_response) {
598*4882a593Smuzhiyun 		dev_dbg(ec_dev->dev, "clamping message receive buffer\n");
599*4882a593Smuzhiyun 		msg->insize = ec_dev->max_response;
600*4882a593Smuzhiyun 	}
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	if (msg->command < EC_CMD_PASSTHRU_OFFSET(1)) {
603*4882a593Smuzhiyun 		if (msg->outsize > ec_dev->max_request) {
604*4882a593Smuzhiyun 			dev_err(ec_dev->dev,
605*4882a593Smuzhiyun 				"request of size %u is too big (max: %u)\n",
606*4882a593Smuzhiyun 				msg->outsize,
607*4882a593Smuzhiyun 				ec_dev->max_request);
608*4882a593Smuzhiyun 			mutex_unlock(&ec_dev->lock);
609*4882a593Smuzhiyun 			return -EMSGSIZE;
610*4882a593Smuzhiyun 		}
611*4882a593Smuzhiyun 	} else {
612*4882a593Smuzhiyun 		if (msg->outsize > ec_dev->max_passthru) {
613*4882a593Smuzhiyun 			dev_err(ec_dev->dev,
614*4882a593Smuzhiyun 				"passthru rq of size %u is too big (max: %u)\n",
615*4882a593Smuzhiyun 				msg->outsize,
616*4882a593Smuzhiyun 				ec_dev->max_passthru);
617*4882a593Smuzhiyun 			mutex_unlock(&ec_dev->lock);
618*4882a593Smuzhiyun 			return -EMSGSIZE;
619*4882a593Smuzhiyun 		}
620*4882a593Smuzhiyun 	}
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	ret = send_command(ec_dev, msg);
623*4882a593Smuzhiyun 	mutex_unlock(&ec_dev->lock);
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	return ret;
626*4882a593Smuzhiyun }
627*4882a593Smuzhiyun EXPORT_SYMBOL(cros_ec_cmd_xfer);
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun /**
630*4882a593Smuzhiyun  * cros_ec_cmd_xfer_status() - Send a command to the ChromeOS EC.
631*4882a593Smuzhiyun  * @ec_dev: EC device.
632*4882a593Smuzhiyun  * @msg: Message to write.
633*4882a593Smuzhiyun  *
634*4882a593Smuzhiyun  * Call this to send a command to the ChromeOS EC. This should be used instead of calling the EC's
635*4882a593Smuzhiyun  * cmd_xfer() callback directly. It returns success status only if both the command was transmitted
636*4882a593Smuzhiyun  * successfully and the EC replied with success status.
637*4882a593Smuzhiyun  *
638*4882a593Smuzhiyun  * Return:
639*4882a593Smuzhiyun  * >=0 - The number of bytes transferred.
640*4882a593Smuzhiyun  * <0 - Linux error code
641*4882a593Smuzhiyun  */
cros_ec_cmd_xfer_status(struct cros_ec_device * ec_dev,struct cros_ec_command * msg)642*4882a593Smuzhiyun int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
643*4882a593Smuzhiyun 			    struct cros_ec_command *msg)
644*4882a593Smuzhiyun {
645*4882a593Smuzhiyun 	int ret, mapped;
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	ret = cros_ec_cmd_xfer(ec_dev, msg);
648*4882a593Smuzhiyun 	if (ret < 0)
649*4882a593Smuzhiyun 		return ret;
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun 	mapped = cros_ec_map_error(msg->result);
652*4882a593Smuzhiyun 	if (mapped) {
653*4882a593Smuzhiyun 		dev_dbg(ec_dev->dev, "Command result (err: %d [%d])\n",
654*4882a593Smuzhiyun 			msg->result, mapped);
655*4882a593Smuzhiyun 		ret = mapped;
656*4882a593Smuzhiyun 	}
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	return ret;
659*4882a593Smuzhiyun }
660*4882a593Smuzhiyun EXPORT_SYMBOL(cros_ec_cmd_xfer_status);
661*4882a593Smuzhiyun 
get_next_event_xfer(struct cros_ec_device * ec_dev,struct cros_ec_command * msg,struct ec_response_get_next_event_v1 * event,int version,uint32_t size)662*4882a593Smuzhiyun static int get_next_event_xfer(struct cros_ec_device *ec_dev,
663*4882a593Smuzhiyun 			       struct cros_ec_command *msg,
664*4882a593Smuzhiyun 			       struct ec_response_get_next_event_v1 *event,
665*4882a593Smuzhiyun 			       int version, uint32_t size)
666*4882a593Smuzhiyun {
667*4882a593Smuzhiyun 	int ret;
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 	msg->version = version;
670*4882a593Smuzhiyun 	msg->command = EC_CMD_GET_NEXT_EVENT;
671*4882a593Smuzhiyun 	msg->insize = size;
672*4882a593Smuzhiyun 	msg->outsize = 0;
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	ret = cros_ec_cmd_xfer_status(ec_dev, msg);
675*4882a593Smuzhiyun 	if (ret > 0) {
676*4882a593Smuzhiyun 		ec_dev->event_size = ret - 1;
677*4882a593Smuzhiyun 		ec_dev->event_data = *event;
678*4882a593Smuzhiyun 	}
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 	return ret;
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun 
get_next_event(struct cros_ec_device * ec_dev)683*4882a593Smuzhiyun static int get_next_event(struct cros_ec_device *ec_dev)
684*4882a593Smuzhiyun {
685*4882a593Smuzhiyun 	struct {
686*4882a593Smuzhiyun 		struct cros_ec_command msg;
687*4882a593Smuzhiyun 		struct ec_response_get_next_event_v1 event;
688*4882a593Smuzhiyun 	} __packed buf;
689*4882a593Smuzhiyun 	struct cros_ec_command *msg = &buf.msg;
690*4882a593Smuzhiyun 	struct ec_response_get_next_event_v1 *event = &buf.event;
691*4882a593Smuzhiyun 	const int cmd_version = ec_dev->mkbp_event_supported - 1;
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 	memset(msg, 0, sizeof(*msg));
694*4882a593Smuzhiyun 	if (ec_dev->suspended) {
695*4882a593Smuzhiyun 		dev_dbg(ec_dev->dev, "Device suspended.\n");
696*4882a593Smuzhiyun 		return -EHOSTDOWN;
697*4882a593Smuzhiyun 	}
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	if (cmd_version == 0)
700*4882a593Smuzhiyun 		return get_next_event_xfer(ec_dev, msg, event, 0,
701*4882a593Smuzhiyun 				  sizeof(struct ec_response_get_next_event));
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	return get_next_event_xfer(ec_dev, msg, event, cmd_version,
704*4882a593Smuzhiyun 				sizeof(struct ec_response_get_next_event_v1));
705*4882a593Smuzhiyun }
706*4882a593Smuzhiyun 
get_keyboard_state_event(struct cros_ec_device * ec_dev)707*4882a593Smuzhiyun static int get_keyboard_state_event(struct cros_ec_device *ec_dev)
708*4882a593Smuzhiyun {
709*4882a593Smuzhiyun 	u8 buffer[sizeof(struct cros_ec_command) +
710*4882a593Smuzhiyun 		  sizeof(ec_dev->event_data.data)];
711*4882a593Smuzhiyun 	struct cros_ec_command *msg = (struct cros_ec_command *)&buffer;
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun 	msg->version = 0;
714*4882a593Smuzhiyun 	msg->command = EC_CMD_MKBP_STATE;
715*4882a593Smuzhiyun 	msg->insize = sizeof(ec_dev->event_data.data);
716*4882a593Smuzhiyun 	msg->outsize = 0;
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	ec_dev->event_size = cros_ec_cmd_xfer_status(ec_dev, msg);
719*4882a593Smuzhiyun 	ec_dev->event_data.event_type = EC_MKBP_EVENT_KEY_MATRIX;
720*4882a593Smuzhiyun 	memcpy(&ec_dev->event_data.data, msg->data,
721*4882a593Smuzhiyun 	       sizeof(ec_dev->event_data.data));
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun 	return ec_dev->event_size;
724*4882a593Smuzhiyun }
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun /**
727*4882a593Smuzhiyun  * cros_ec_get_next_event() - Fetch next event from the ChromeOS EC.
728*4882a593Smuzhiyun  * @ec_dev: Device to fetch event from.
729*4882a593Smuzhiyun  * @wake_event: Pointer to a bool set to true upon return if the event might be
730*4882a593Smuzhiyun  *              treated as a wake event. Ignored if null.
731*4882a593Smuzhiyun  * @has_more_events: Pointer to bool set to true if more than one event is
732*4882a593Smuzhiyun  *              pending.
733*4882a593Smuzhiyun  *              Some EC will set this flag to indicate cros_ec_get_next_event()
734*4882a593Smuzhiyun  *              can be called multiple times in a row.
735*4882a593Smuzhiyun  *              It is an optimization to prevent issuing a EC command for
736*4882a593Smuzhiyun  *              nothing or wait for another interrupt from the EC to process
737*4882a593Smuzhiyun  *              the next message.
738*4882a593Smuzhiyun  *              Ignored if null.
739*4882a593Smuzhiyun  *
740*4882a593Smuzhiyun  * Return: negative error code on errors; 0 for no data; or else number of
741*4882a593Smuzhiyun  * bytes received (i.e., an event was retrieved successfully). Event types are
742*4882a593Smuzhiyun  * written out to @ec_dev->event_data.event_type on success.
743*4882a593Smuzhiyun  */
cros_ec_get_next_event(struct cros_ec_device * ec_dev,bool * wake_event,bool * has_more_events)744*4882a593Smuzhiyun int cros_ec_get_next_event(struct cros_ec_device *ec_dev,
745*4882a593Smuzhiyun 			   bool *wake_event,
746*4882a593Smuzhiyun 			   bool *has_more_events)
747*4882a593Smuzhiyun {
748*4882a593Smuzhiyun 	u8 event_type;
749*4882a593Smuzhiyun 	u32 host_event;
750*4882a593Smuzhiyun 	int ret;
751*4882a593Smuzhiyun 	u32 ver_mask;
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 	/*
754*4882a593Smuzhiyun 	 * Default value for wake_event.
755*4882a593Smuzhiyun 	 * Wake up on keyboard event, wake up for spurious interrupt or link
756*4882a593Smuzhiyun 	 * error to the EC.
757*4882a593Smuzhiyun 	 */
758*4882a593Smuzhiyun 	if (wake_event)
759*4882a593Smuzhiyun 		*wake_event = true;
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 	/*
762*4882a593Smuzhiyun 	 * Default value for has_more_events.
763*4882a593Smuzhiyun 	 * EC will raise another interrupt if AP does not process all events
764*4882a593Smuzhiyun 	 * anyway.
765*4882a593Smuzhiyun 	 */
766*4882a593Smuzhiyun 	if (has_more_events)
767*4882a593Smuzhiyun 		*has_more_events = false;
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun 	if (!ec_dev->mkbp_event_supported)
770*4882a593Smuzhiyun 		return get_keyboard_state_event(ec_dev);
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 	ret = get_next_event(ec_dev);
773*4882a593Smuzhiyun 	/*
774*4882a593Smuzhiyun 	 * -ENOPROTOOPT is returned when EC returns EC_RES_INVALID_VERSION.
775*4882a593Smuzhiyun 	 * This can occur when EC based device (e.g. Fingerprint MCU) jumps to
776*4882a593Smuzhiyun 	 * the RO image which doesn't support newer version of the command. In
777*4882a593Smuzhiyun 	 * this case we will attempt to update maximum supported version of the
778*4882a593Smuzhiyun 	 * EC_CMD_GET_NEXT_EVENT.
779*4882a593Smuzhiyun 	 */
780*4882a593Smuzhiyun 	if (ret == -ENOPROTOOPT) {
781*4882a593Smuzhiyun 		dev_dbg(ec_dev->dev,
782*4882a593Smuzhiyun 			"GET_NEXT_EVENT returned invalid version error.\n");
783*4882a593Smuzhiyun 		ret = cros_ec_get_host_command_version_mask(ec_dev,
784*4882a593Smuzhiyun 							EC_CMD_GET_NEXT_EVENT,
785*4882a593Smuzhiyun 							&ver_mask);
786*4882a593Smuzhiyun 		if (ret < 0 || ver_mask == 0)
787*4882a593Smuzhiyun 			/*
788*4882a593Smuzhiyun 			 * Do not change the MKBP supported version if we can't
789*4882a593Smuzhiyun 			 * obtain supported version correctly. Please note that
790*4882a593Smuzhiyun 			 * calling EC_CMD_GET_NEXT_EVENT returned
791*4882a593Smuzhiyun 			 * EC_RES_INVALID_VERSION which means that the command
792*4882a593Smuzhiyun 			 * is present.
793*4882a593Smuzhiyun 			 */
794*4882a593Smuzhiyun 			return -ENOPROTOOPT;
795*4882a593Smuzhiyun 
796*4882a593Smuzhiyun 		ec_dev->mkbp_event_supported = fls(ver_mask);
797*4882a593Smuzhiyun 		dev_dbg(ec_dev->dev, "MKBP support version changed to %u\n",
798*4882a593Smuzhiyun 			ec_dev->mkbp_event_supported - 1);
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 		/* Try to get next event with new MKBP support version set. */
801*4882a593Smuzhiyun 		ret = get_next_event(ec_dev);
802*4882a593Smuzhiyun 	}
803*4882a593Smuzhiyun 
804*4882a593Smuzhiyun 	if (ret <= 0)
805*4882a593Smuzhiyun 		return ret;
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun 	if (has_more_events)
808*4882a593Smuzhiyun 		*has_more_events = ec_dev->event_data.event_type &
809*4882a593Smuzhiyun 			EC_MKBP_HAS_MORE_EVENTS;
810*4882a593Smuzhiyun 	ec_dev->event_data.event_type &= EC_MKBP_EVENT_TYPE_MASK;
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun 	if (wake_event) {
813*4882a593Smuzhiyun 		event_type = ec_dev->event_data.event_type;
814*4882a593Smuzhiyun 		host_event = cros_ec_get_host_event(ec_dev);
815*4882a593Smuzhiyun 
816*4882a593Smuzhiyun 		/*
817*4882a593Smuzhiyun 		 * Sensor events need to be parsed by the sensor sub-device.
818*4882a593Smuzhiyun 		 * Defer them, and don't report the wakeup here.
819*4882a593Smuzhiyun 		 */
820*4882a593Smuzhiyun 		if (event_type == EC_MKBP_EVENT_SENSOR_FIFO)
821*4882a593Smuzhiyun 			*wake_event = false;
822*4882a593Smuzhiyun 		/* Masked host-events should not count as wake events. */
823*4882a593Smuzhiyun 		else if (host_event &&
824*4882a593Smuzhiyun 			 !(host_event & ec_dev->host_event_wake_mask))
825*4882a593Smuzhiyun 			*wake_event = false;
826*4882a593Smuzhiyun 	}
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun 	return ret;
829*4882a593Smuzhiyun }
830*4882a593Smuzhiyun EXPORT_SYMBOL(cros_ec_get_next_event);
831*4882a593Smuzhiyun 
832*4882a593Smuzhiyun /**
833*4882a593Smuzhiyun  * cros_ec_get_host_event() - Return a mask of event set by the ChromeOS EC.
834*4882a593Smuzhiyun  * @ec_dev: Device to fetch event from.
835*4882a593Smuzhiyun  *
836*4882a593Smuzhiyun  * When MKBP is supported, when the EC raises an interrupt, we collect the
837*4882a593Smuzhiyun  * events raised and call the functions in the ec notifier. This function
838*4882a593Smuzhiyun  * is a helper to know which events are raised.
839*4882a593Smuzhiyun  *
840*4882a593Smuzhiyun  * Return: 0 on error or non-zero bitmask of one or more EC_HOST_EVENT_*.
841*4882a593Smuzhiyun  */
cros_ec_get_host_event(struct cros_ec_device * ec_dev)842*4882a593Smuzhiyun u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev)
843*4882a593Smuzhiyun {
844*4882a593Smuzhiyun 	u32 host_event;
845*4882a593Smuzhiyun 
846*4882a593Smuzhiyun 	BUG_ON(!ec_dev->mkbp_event_supported);
847*4882a593Smuzhiyun 
848*4882a593Smuzhiyun 	if (ec_dev->event_data.event_type != EC_MKBP_EVENT_HOST_EVENT)
849*4882a593Smuzhiyun 		return 0;
850*4882a593Smuzhiyun 
851*4882a593Smuzhiyun 	if (ec_dev->event_size != sizeof(host_event)) {
852*4882a593Smuzhiyun 		dev_warn(ec_dev->dev, "Invalid host event size\n");
853*4882a593Smuzhiyun 		return 0;
854*4882a593Smuzhiyun 	}
855*4882a593Smuzhiyun 
856*4882a593Smuzhiyun 	host_event = get_unaligned_le32(&ec_dev->event_data.data.host_event);
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun 	return host_event;
859*4882a593Smuzhiyun }
860*4882a593Smuzhiyun EXPORT_SYMBOL(cros_ec_get_host_event);
861*4882a593Smuzhiyun 
862*4882a593Smuzhiyun /**
863*4882a593Smuzhiyun  * cros_ec_check_features() - Test for the presence of EC features
864*4882a593Smuzhiyun  *
865*4882a593Smuzhiyun  * @ec: EC device, does not have to be connected directly to the AP,
866*4882a593Smuzhiyun  *      can be daisy chained through another device.
867*4882a593Smuzhiyun  * @feature: One of ec_feature_code bit.
868*4882a593Smuzhiyun  *
869*4882a593Smuzhiyun  * Call this function to test whether the ChromeOS EC supports a feature.
870*4882a593Smuzhiyun  *
871*4882a593Smuzhiyun  * Return: 1 if supported, 0 if not
872*4882a593Smuzhiyun  */
cros_ec_check_features(struct cros_ec_dev * ec,int feature)873*4882a593Smuzhiyun int cros_ec_check_features(struct cros_ec_dev *ec, int feature)
874*4882a593Smuzhiyun {
875*4882a593Smuzhiyun 	struct cros_ec_command *msg;
876*4882a593Smuzhiyun 	int ret;
877*4882a593Smuzhiyun 
878*4882a593Smuzhiyun 	if (ec->features[0] == -1U && ec->features[1] == -1U) {
879*4882a593Smuzhiyun 		/* features bitmap not read yet */
880*4882a593Smuzhiyun 		msg = kzalloc(sizeof(*msg) + sizeof(ec->features), GFP_KERNEL);
881*4882a593Smuzhiyun 		if (!msg)
882*4882a593Smuzhiyun 			return -ENOMEM;
883*4882a593Smuzhiyun 
884*4882a593Smuzhiyun 		msg->command = EC_CMD_GET_FEATURES + ec->cmd_offset;
885*4882a593Smuzhiyun 		msg->insize = sizeof(ec->features);
886*4882a593Smuzhiyun 
887*4882a593Smuzhiyun 		ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
888*4882a593Smuzhiyun 		if (ret < 0) {
889*4882a593Smuzhiyun 			dev_warn(ec->dev, "cannot get EC features: %d/%d\n",
890*4882a593Smuzhiyun 				 ret, msg->result);
891*4882a593Smuzhiyun 			memset(ec->features, 0, sizeof(ec->features));
892*4882a593Smuzhiyun 		} else {
893*4882a593Smuzhiyun 			memcpy(ec->features, msg->data, sizeof(ec->features));
894*4882a593Smuzhiyun 		}
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun 		dev_dbg(ec->dev, "EC features %08x %08x\n",
897*4882a593Smuzhiyun 			ec->features[0], ec->features[1]);
898*4882a593Smuzhiyun 
899*4882a593Smuzhiyun 		kfree(msg);
900*4882a593Smuzhiyun 	}
901*4882a593Smuzhiyun 
902*4882a593Smuzhiyun 	return ec->features[feature / 32] & EC_FEATURE_MASK_0(feature);
903*4882a593Smuzhiyun }
904*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(cros_ec_check_features);
905*4882a593Smuzhiyun 
906*4882a593Smuzhiyun /**
907*4882a593Smuzhiyun  * cros_ec_get_sensor_count() - Return the number of MEMS sensors supported.
908*4882a593Smuzhiyun  *
909*4882a593Smuzhiyun  * @ec: EC device, does not have to be connected directly to the AP,
910*4882a593Smuzhiyun  *      can be daisy chained through another device.
911*4882a593Smuzhiyun  * Return: < 0 in case of error.
912*4882a593Smuzhiyun  */
cros_ec_get_sensor_count(struct cros_ec_dev * ec)913*4882a593Smuzhiyun int cros_ec_get_sensor_count(struct cros_ec_dev *ec)
914*4882a593Smuzhiyun {
915*4882a593Smuzhiyun 	/*
916*4882a593Smuzhiyun 	 * Issue a command to get the number of sensor reported.
917*4882a593Smuzhiyun 	 * If not supported, check for legacy mode.
918*4882a593Smuzhiyun 	 */
919*4882a593Smuzhiyun 	int ret, sensor_count;
920*4882a593Smuzhiyun 	struct ec_params_motion_sense *params;
921*4882a593Smuzhiyun 	struct ec_response_motion_sense *resp;
922*4882a593Smuzhiyun 	struct cros_ec_command *msg;
923*4882a593Smuzhiyun 	struct cros_ec_device *ec_dev = ec->ec_dev;
924*4882a593Smuzhiyun 	u8 status;
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun 	msg = kzalloc(sizeof(*msg) + max(sizeof(*params), sizeof(*resp)),
927*4882a593Smuzhiyun 		      GFP_KERNEL);
928*4882a593Smuzhiyun 	if (!msg)
929*4882a593Smuzhiyun 		return -ENOMEM;
930*4882a593Smuzhiyun 
931*4882a593Smuzhiyun 	msg->version = 1;
932*4882a593Smuzhiyun 	msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset;
933*4882a593Smuzhiyun 	msg->outsize = sizeof(*params);
934*4882a593Smuzhiyun 	msg->insize = sizeof(*resp);
935*4882a593Smuzhiyun 
936*4882a593Smuzhiyun 	params = (struct ec_params_motion_sense *)msg->data;
937*4882a593Smuzhiyun 	params->cmd = MOTIONSENSE_CMD_DUMP;
938*4882a593Smuzhiyun 
939*4882a593Smuzhiyun 	ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
940*4882a593Smuzhiyun 	if (ret < 0) {
941*4882a593Smuzhiyun 		sensor_count = ret;
942*4882a593Smuzhiyun 	} else {
943*4882a593Smuzhiyun 		resp = (struct ec_response_motion_sense *)msg->data;
944*4882a593Smuzhiyun 		sensor_count = resp->dump.sensor_count;
945*4882a593Smuzhiyun 	}
946*4882a593Smuzhiyun 	kfree(msg);
947*4882a593Smuzhiyun 
948*4882a593Smuzhiyun 	/*
949*4882a593Smuzhiyun 	 * Check legacy mode: Let's find out if sensors are accessible
950*4882a593Smuzhiyun 	 * via LPC interface.
951*4882a593Smuzhiyun 	 */
952*4882a593Smuzhiyun 	if (sensor_count < 0 && ec->cmd_offset == 0 && ec_dev->cmd_readmem) {
953*4882a593Smuzhiyun 		ret = ec_dev->cmd_readmem(ec_dev, EC_MEMMAP_ACC_STATUS,
954*4882a593Smuzhiyun 				1, &status);
955*4882a593Smuzhiyun 		if (ret >= 0 &&
956*4882a593Smuzhiyun 		    (status & EC_MEMMAP_ACC_STATUS_PRESENCE_BIT)) {
957*4882a593Smuzhiyun 			/*
958*4882a593Smuzhiyun 			 * We have 2 sensors, one in the lid, one in the base.
959*4882a593Smuzhiyun 			 */
960*4882a593Smuzhiyun 			sensor_count = 2;
961*4882a593Smuzhiyun 		} else {
962*4882a593Smuzhiyun 			/*
963*4882a593Smuzhiyun 			 * EC uses LPC interface and no sensors are presented.
964*4882a593Smuzhiyun 			 */
965*4882a593Smuzhiyun 			sensor_count = 0;
966*4882a593Smuzhiyun 		}
967*4882a593Smuzhiyun 	}
968*4882a593Smuzhiyun 	return sensor_count;
969*4882a593Smuzhiyun }
970*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(cros_ec_get_sensor_count);
971