aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/platform/chrome/cros_ec_lightbar.c69
-rw-r--r--include/linux/mfd/cros_ec_commands.h12
2 files changed, 79 insertions, 2 deletions
diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c
index 8df3d447cacf..26675059707e 100644
--- a/drivers/platform/chrome/cros_ec_lightbar.c
+++ b/drivers/platform/chrome/cros_ec_lightbar.c
@@ -295,7 +295,8 @@ exit:
295 295
296static char const *seqname[] = { 296static char const *seqname[] = {
297 "ERROR", "S5", "S3", "S0", "S5S3", "S3S0", 297 "ERROR", "S5", "S3", "S0", "S5S3", "S3S0",
298 "S0S3", "S3S5", "STOP", "RUN", "PULSE", "TEST", "KONAMI", 298 "S0S3", "S3S5", "STOP", "RUN", "KONAMI",
299 "TAP", "PROGRAM",
299}; 300};
300 301
301static ssize_t sequence_show(struct device *dev, 302static ssize_t sequence_show(struct device *dev,
@@ -390,6 +391,69 @@ exit:
390 return ret; 391 return ret;
391} 392}
392 393
394static ssize_t program_store(struct device *dev, struct device_attribute *attr,
395 const char *buf, size_t count)
396{
397 int extra_bytes, max_size, ret;
398 struct ec_params_lightbar *param;
399 struct cros_ec_command *msg;
400 struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev,
401 class_dev);
402
403 /*
404 * We might need to reject the program for size reasons. The EC
405 * enforces a maximum program size, but we also don't want to try
406 * and send a program that is too big for the protocol. In order
407 * to ensure the latter, we also need to ensure we have extra bytes
408 * to represent the rest of the packet.
409 */
410 extra_bytes = sizeof(*param) - sizeof(param->set_program.data);
411 max_size = min(EC_LB_PROG_LEN, ec->ec_dev->max_request - extra_bytes);
412 if (count > max_size) {
413 dev_err(dev, "Program is %u bytes, too long to send (max: %u)",
414 (unsigned int)count, max_size);
415
416 return -EINVAL;
417 }
418
419 msg = alloc_lightbar_cmd_msg(ec);
420 if (!msg)
421 return -ENOMEM;
422
423 ret = lb_throttle();
424 if (ret)
425 goto exit;
426
427 dev_info(dev, "Copying %zu byte program to EC", count);
428
429 param = (struct ec_params_lightbar *)msg->data;
430 param->cmd = LIGHTBAR_CMD_SET_PROGRAM;
431
432 param->set_program.size = count;
433 memcpy(param->set_program.data, buf, count);
434
435 /*
436 * We need to set the message size manually or else it will use
437 * EC_LB_PROG_LEN. This might be too long, and the program
438 * is unlikely to use all of the space.
439 */
440 msg->outsize = count + extra_bytes;
441
442 ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
443 if (ret < 0)
444 goto exit;
445 if (msg->result != EC_RES_SUCCESS) {
446 ret = -EINVAL;
447 goto exit;
448 }
449
450 ret = count;
451exit:
452 kfree(msg);
453
454 return ret;
455}
456
393/* Module initialization */ 457/* Module initialization */
394 458
395static DEVICE_ATTR_RW(interval_msec); 459static DEVICE_ATTR_RW(interval_msec);
@@ -397,12 +461,15 @@ static DEVICE_ATTR_RO(version);
397static DEVICE_ATTR_WO(brightness); 461static DEVICE_ATTR_WO(brightness);
398static DEVICE_ATTR_WO(led_rgb); 462static DEVICE_ATTR_WO(led_rgb);
399static DEVICE_ATTR_RW(sequence); 463static DEVICE_ATTR_RW(sequence);
464static DEVICE_ATTR_WO(program);
465
400static struct attribute *__lb_cmds_attrs[] = { 466static struct attribute *__lb_cmds_attrs[] = {
401 &dev_attr_interval_msec.attr, 467 &dev_attr_interval_msec.attr,
402 &dev_attr_version.attr, 468 &dev_attr_version.attr,
403 &dev_attr_brightness.attr, 469 &dev_attr_brightness.attr,
404 &dev_attr_led_rgb.attr, 470 &dev_attr_led_rgb.attr,
405 &dev_attr_sequence.attr, 471 &dev_attr_sequence.attr,
472 &dev_attr_program.attr,
406 NULL, 473 NULL,
407}; 474};
408 475
diff --git a/include/linux/mfd/cros_ec_commands.h b/include/linux/mfd/cros_ec_commands.h
index 1b19e424e1cf..dbea5802e83b 100644
--- a/include/linux/mfd/cros_ec_commands.h
+++ b/include/linux/mfd/cros_ec_commands.h
@@ -1162,6 +1162,13 @@ struct lightbar_params_v1 {
1162 struct rgb_s color[8]; /* 0-3 are Google colors */ 1162 struct rgb_s color[8]; /* 0-3 are Google colors */
1163} __packed; 1163} __packed;
1164 1164
1165/* Lightbar program */
1166#define EC_LB_PROG_LEN 192
1167struct lightbar_program {
1168 uint8_t size;
1169 uint8_t data[EC_LB_PROG_LEN];
1170};
1171
1165struct ec_params_lightbar { 1172struct ec_params_lightbar {
1166 uint8_t cmd; /* Command (see enum lightbar_command) */ 1173 uint8_t cmd; /* Command (see enum lightbar_command) */
1167 union { 1174 union {
@@ -1188,6 +1195,7 @@ struct ec_params_lightbar {
1188 1195
1189 struct lightbar_params_v0 set_params_v0; 1196 struct lightbar_params_v0 set_params_v0;
1190 struct lightbar_params_v1 set_params_v1; 1197 struct lightbar_params_v1 set_params_v1;
1198 struct lightbar_program set_program;
1191 }; 1199 };
1192} __packed; 1200} __packed;
1193 1201
@@ -1220,7 +1228,8 @@ struct ec_response_lightbar {
1220 struct { 1228 struct {
1221 /* no return params */ 1229 /* no return params */
1222 } off, on, init, set_brightness, seq, reg, set_rgb, 1230 } off, on, init, set_brightness, seq, reg, set_rgb,
1223 demo, set_params_v0, set_params_v1; 1231 demo, set_params_v0, set_params_v1,
1232 set_program;
1224 }; 1233 };
1225} __packed; 1234} __packed;
1226 1235
@@ -1244,6 +1253,7 @@ enum lightbar_command {
1244 LIGHTBAR_CMD_GET_DEMO = 15, 1253 LIGHTBAR_CMD_GET_DEMO = 15,
1245 LIGHTBAR_CMD_GET_PARAMS_V1 = 16, 1254 LIGHTBAR_CMD_GET_PARAMS_V1 = 16,
1246 LIGHTBAR_CMD_SET_PARAMS_V1 = 17, 1255 LIGHTBAR_CMD_SET_PARAMS_V1 = 17,
1256 LIGHTBAR_CMD_SET_PROGRAM = 18,
1247 LIGHTBAR_NUM_CMDS 1257 LIGHTBAR_NUM_CMDS
1248}; 1258};
1249 1259