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