aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorVic Yang <victoryang@google.com>2016-08-10 13:05:24 -0400
committerLee Jones <lee.jones@linaro.org>2016-08-31 05:50:59 -0400
commit6f1d912b687d3d17c1731f5bda3b5d6703bce4a0 (patch)
treee3a0ad0da285ff23c315a23eb4d00661c7ad16f3 /drivers/platform
parent694d0d0bb2030d2e36df73e2d23d5770511dbc8d (diff)
mfd: cros_ec: Add MKBP event support
Newer revisions of the ChromeOS EC add more events besides the keyboard ones. So handle interrupts in the MFD driver and let consumers register for notifications for the events they might care. To keep backward compatibility, if the EC doesn't support MKBP event, we fall back to the old MKBP key matrix host command. Cc: Randall Spangler <rspangler@chromium.org> Cc: Vincent Palatin <vpalatin@chromium.org> Cc: Benson Leung <bleung@chromium.org> Signed-off-by: Vic Yang <victoryang@google.com> Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com> Tested-by: Enric Balletbo i Serra <enric.balletbo@collabora.com> Acked-by: Olof Johansson <olof@lixom.net> Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/chrome/cros_ec_proto.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c
index 6c084b266651..04053fe1e980 100644
--- a/drivers/platform/chrome/cros_ec_proto.c
+++ b/drivers/platform/chrome/cros_ec_proto.c
@@ -19,6 +19,7 @@
19#include <linux/device.h> 19#include <linux/device.h>
20#include <linux/module.h> 20#include <linux/module.h>
21#include <linux/slab.h> 21#include <linux/slab.h>
22#include <asm/unaligned.h>
22 23
23#define EC_COMMAND_RETRIES 50 24#define EC_COMMAND_RETRIES 50
24 25
@@ -234,11 +235,44 @@ static int cros_ec_host_command_proto_query_v2(struct cros_ec_device *ec_dev)
234 return ret; 235 return ret;
235} 236}
236 237
238static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev,
239 u16 cmd, u32 *mask)
240{
241 struct ec_params_get_cmd_versions *pver;
242 struct ec_response_get_cmd_versions *rver;
243 struct cros_ec_command *msg;
244 int ret;
245
246 msg = kmalloc(sizeof(*msg) + max(sizeof(*rver), sizeof(*pver)),
247 GFP_KERNEL);
248 if (!msg)
249 return -ENOMEM;
250
251 msg->version = 0;
252 msg->command = EC_CMD_GET_CMD_VERSIONS;
253 msg->insize = sizeof(*rver);
254 msg->outsize = sizeof(*pver);
255
256 pver = (struct ec_params_get_cmd_versions *)msg->data;
257 pver->cmd = cmd;
258
259 ret = cros_ec_cmd_xfer(ec_dev, msg);
260 if (ret > 0) {
261 rver = (struct ec_response_get_cmd_versions *)msg->data;
262 *mask = rver->version_mask;
263 }
264
265 kfree(msg);
266
267 return ret;
268}
269
237int cros_ec_query_all(struct cros_ec_device *ec_dev) 270int cros_ec_query_all(struct cros_ec_device *ec_dev)
238{ 271{
239 struct device *dev = ec_dev->dev; 272 struct device *dev = ec_dev->dev;
240 struct cros_ec_command *proto_msg; 273 struct cros_ec_command *proto_msg;
241 struct ec_response_get_protocol_info *proto_info; 274 struct ec_response_get_protocol_info *proto_info;
275 u32 ver_mask = 0;
242 int ret; 276 int ret;
243 277
244 proto_msg = kzalloc(sizeof(*proto_msg) + sizeof(*proto_info), 278 proto_msg = kzalloc(sizeof(*proto_msg) + sizeof(*proto_info),
@@ -328,6 +362,15 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev)
328 goto exit; 362 goto exit;
329 } 363 }
330 364
365 /* Probe if MKBP event is supported */
366 ret = cros_ec_get_host_command_version_mask(ec_dev,
367 EC_CMD_GET_NEXT_EVENT,
368 &ver_mask);
369 if (ret < 0 || ver_mask == 0)
370 ec_dev->mkbp_event_supported = 0;
371 else
372 ec_dev->mkbp_event_supported = 1;
373
331exit: 374exit:
332 kfree(proto_msg); 375 kfree(proto_msg);
333 return ret; 376 return ret;
@@ -397,3 +440,52 @@ int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
397 return ret; 440 return ret;
398} 441}
399EXPORT_SYMBOL(cros_ec_cmd_xfer_status); 442EXPORT_SYMBOL(cros_ec_cmd_xfer_status);
443
444static int get_next_event(struct cros_ec_device *ec_dev)
445{
446 u8 buffer[sizeof(struct cros_ec_command) + sizeof(ec_dev->event_data)];
447 struct cros_ec_command *msg = (struct cros_ec_command *)&buffer;
448 int ret;
449
450 msg->version = 0;
451 msg->command = EC_CMD_GET_NEXT_EVENT;
452 msg->insize = sizeof(ec_dev->event_data);
453 msg->outsize = 0;
454
455 ret = cros_ec_cmd_xfer(ec_dev, msg);
456 if (ret > 0) {
457 ec_dev->event_size = ret - 1;
458 memcpy(&ec_dev->event_data, msg->data,
459 sizeof(ec_dev->event_data));
460 }
461
462 return ret;
463}
464
465static int get_keyboard_state_event(struct cros_ec_device *ec_dev)
466{
467 u8 buffer[sizeof(struct cros_ec_command) +
468 sizeof(ec_dev->event_data.data)];
469 struct cros_ec_command *msg = (struct cros_ec_command *)&buffer;
470
471 msg->version = 0;
472 msg->command = EC_CMD_MKBP_STATE;
473 msg->insize = sizeof(ec_dev->event_data.data);
474 msg->outsize = 0;
475
476 ec_dev->event_size = cros_ec_cmd_xfer(ec_dev, msg);
477 ec_dev->event_data.event_type = EC_MKBP_EVENT_KEY_MATRIX;
478 memcpy(&ec_dev->event_data.data, msg->data,
479 sizeof(ec_dev->event_data.data));
480
481 return ec_dev->event_size;
482}
483
484int cros_ec_get_next_event(struct cros_ec_device *ec_dev)
485{
486 if (ec_dev->mkbp_event_supported)
487 return get_next_event(ec_dev);
488 else
489 return get_keyboard_state_event(ec_dev);
490}
491EXPORT_SYMBOL(cros_ec_get_next_event);