brintos

brintos / linux-shallow public Read only

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