diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-02-11 09:19:47 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-02-11 09:19:47 -0800 |
| commit | be653d2d1f435218cf4b7abad96b42a20ce28451 (patch) | |
| tree | 5794ee3ced5d464fdc77b7170644ae559ef91626 /drivers/platform | |
| parent | 192c0159402e6bfbe13de6f8379546943297783d (diff) | |
| parent | 520e345dfdab89aed4a0ad98d5ec35086661a11a (diff) | |
Merge tag 'chrome-platform-v7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux
Pull chrome platform updates from Tzung-Bi Shih:
"New cros_ec_lightbar features:
- Report the number of exposed LED segments via sysfs
- Support large sequence of program to be transmitted
Fixes:
- Don't touch fwnode_handle::dev which is a private field
- Fix wrong assignment for response size in cros_ec_lightbar
Cleanups:
- Use acpi_get_local_u64_address() helper"
* tag 'chrome-platform-v7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux:
platform/chrome: lightbar: Use flexible array member
platform/chrome: lightbar: Fix lightbar_program_ex alignment
platform/chrome: lightbar: Add support for large sequence
platform/chrome: lightbar: Report number of segments
platform/chrome: cros_ec_lightbar: Fix response size initialization
platform/chrome: cros_typec_switch: Use acpi_get_local_u64_address()
platform/chrome: cros_typec_switch: Don't touch struct fwnode_handle::dev
Diffstat (limited to 'drivers/platform')
| -rw-r--r-- | drivers/platform/chrome/cros_ec_lightbar.c | 133 | ||||
| -rw-r--r-- | drivers/platform/chrome/cros_typec_switch.c | 19 |
2 files changed, 110 insertions, 42 deletions
diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c index 8352e9732791..2d1aa6edda1a 100644 --- a/drivers/platform/chrome/cros_ec_lightbar.c +++ b/drivers/platform/chrome/cros_ec_lightbar.c @@ -37,6 +37,11 @@ static bool userspace_control; */ static bool has_manual_suspend; +/* + * Lightbar version + */ +static int lb_version; + static ssize_t interval_msec_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -93,11 +98,8 @@ out: static struct cros_ec_command *alloc_lightbar_cmd_msg(struct cros_ec_dev *ec) { + int len = max(ec->ec_dev->max_response, ec->ec_dev->max_request); struct cros_ec_command *msg; - int len; - - len = max(sizeof(struct ec_params_lightbar), - sizeof(struct ec_response_lightbar)); msg = kmalloc(sizeof(*msg) + len, GFP_KERNEL); if (!msg) @@ -105,6 +107,11 @@ static struct cros_ec_command *alloc_lightbar_cmd_msg(struct cros_ec_dev *ec) msg->version = 0; msg->command = EC_CMD_LIGHTBAR_CMD + ec->cmd_offset; + /* + * Default sizes for regular commands. + * Can be set smaller to optimize transfer, + * larger when sending large light sequences. + */ msg->outsize = sizeof(struct ec_params_lightbar); msg->insize = sizeof(struct ec_response_lightbar); @@ -126,7 +133,7 @@ static int get_lightbar_version(struct cros_ec_dev *ec, param = (struct ec_params_lightbar *)msg->data; param->cmd = LIGHTBAR_CMD_VERSION; msg->outsize = sizeof(param->cmd); - msg->result = sizeof(resp->version); + msg->insize = sizeof(resp->version); ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); if (ret < 0 && ret != -EINVAL) { ret = 0; @@ -180,6 +187,47 @@ static ssize_t version_show(struct device *dev, return sysfs_emit(buf, "%d %d\n", version, flags); } +static ssize_t num_segments_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ec_params_lightbar *param; + struct ec_response_lightbar *resp; + struct cros_ec_command *msg; + struct cros_ec_dev *ec = to_cros_ec_dev(dev); + uint32_t num = 0; + int ret; + + ret = lb_throttle(); + if (ret) + return ret; + + msg = alloc_lightbar_cmd_msg(ec); + if (!msg) + return -ENOMEM; + + param = (struct ec_params_lightbar *)msg->data; + param->cmd = LIGHTBAR_CMD_GET_PARAMS_V3; + msg->outsize = sizeof(param->cmd); + msg->insize = sizeof(resp->get_params_v3); + ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); + if (ret < 0 && ret != -EINVAL) + goto exit; + + if (msg->result == EC_RES_SUCCESS) { + resp = (struct ec_response_lightbar *)msg->data; + num = resp->get_params_v3.reported_led_num; + } + + /* + * Anything else (ie, EC_RES_INVALID_COMMAND) - no direct control over + * LEDs, return that no leds are supported. + */ + ret = sysfs_emit(buf, "%u\n", num); +exit: + kfree(msg); + return ret; +} + static ssize_t brightness_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -430,10 +478,11 @@ exit: static ssize_t program_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int extra_bytes, max_size, ret; + size_t extra_bytes, max_size; struct ec_params_lightbar *param; struct cros_ec_command *msg; struct cros_ec_dev *ec = to_cros_ec_dev(dev); + int ret; /* * We might need to reject the program for size reasons. The EC @@ -441,14 +490,22 @@ static ssize_t program_store(struct device *dev, struct device_attribute *attr, * and send a program that is too big for the protocol. In order * to ensure the latter, we also need to ensure we have extra bytes * to represent the rest of the packet. + * With V3, larger program can be sent, limited only by the EC. + * Only the protocol limit the payload size. */ - extra_bytes = sizeof(*param) - sizeof(param->set_program.data); - max_size = min(EC_LB_PROG_LEN, ec->ec_dev->max_request - extra_bytes); - if (count > max_size) { - dev_err(dev, "Program is %u bytes, too long to send (max: %u)", - (unsigned int)count, max_size); - - return -EINVAL; + if (lb_version < 3) { + extra_bytes = sizeof(*param) - sizeof(param->set_program.data); + max_size = min(EC_LB_PROG_LEN, ec->ec_dev->max_request - extra_bytes); + if (count > max_size) { + dev_err(dev, "Program is %zu bytes, too long to send (max: %zu)", + count, max_size); + + return -EINVAL; + } + } else { + extra_bytes = offsetof(typeof(*param), set_program_ex) + + sizeof(param->set_program_ex); + max_size = ec->ec_dev->max_request - extra_bytes; } msg = alloc_lightbar_cmd_msg(ec); @@ -458,26 +515,44 @@ static ssize_t program_store(struct device *dev, struct device_attribute *attr, ret = lb_throttle(); if (ret) goto exit; + param = (struct ec_params_lightbar *)msg->data; - dev_info(dev, "Copying %zu byte program to EC", count); + if (lb_version < 3) { + dev_info(dev, "Copying %zu byte program to EC", count); - param = (struct ec_params_lightbar *)msg->data; - param->cmd = LIGHTBAR_CMD_SET_PROGRAM; + param->cmd = LIGHTBAR_CMD_SET_PROGRAM; - param->set_program.size = count; - memcpy(param->set_program.data, buf, count); + param->set_program.size = count; + memcpy(param->set_program.data, buf, count); - /* - * We need to set the message size manually or else it will use - * EC_LB_PROG_LEN. This might be too long, and the program - * is unlikely to use all of the space. - */ - msg->outsize = count + extra_bytes; + /* + * We need to set the message size manually or else it will use + * EC_LB_PROG_LEN. This might be too long, and the program + * is unlikely to use all of the space. + */ + msg->outsize = count + extra_bytes; - ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); - if (ret < 0) - goto exit; + ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); + if (ret < 0) + goto exit; + } else { + size_t offset = 0; + size_t payload = 0; + + param->cmd = LIGHTBAR_CMD_SET_PROGRAM_EX; + while (offset < count) { + payload = min(max_size, count - offset); + param->set_program_ex.offset = offset; + param->set_program_ex.size = payload; + memcpy(param->set_program_ex.data, &buf[offset], payload); + msg->outsize = payload + extra_bytes; + ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); + if (ret < 0) + goto exit; + offset += payload; + } + } ret = count; exit: kfree(msg); @@ -512,6 +587,7 @@ static ssize_t userspace_control_store(struct device *dev, /* Module initialization */ static DEVICE_ATTR_RW(interval_msec); +static DEVICE_ATTR_RO(num_segments); static DEVICE_ATTR_RO(version); static DEVICE_ATTR_WO(brightness); static DEVICE_ATTR_WO(led_rgb); @@ -521,6 +597,7 @@ static DEVICE_ATTR_RW(userspace_control); static struct attribute *__lb_cmds_attrs[] = { &dev_attr_interval_msec.attr, + &dev_attr_num_segments.attr, &dev_attr_version.attr, &dev_attr_brightness.attr, &dev_attr_led_rgb.attr, @@ -553,7 +630,7 @@ static int cros_ec_lightbar_probe(struct platform_device *pd) * Ask then for the lightbar version, if it's 0 then the 'cros_ec' * doesn't have a lightbar. */ - if (!get_lightbar_version(ec_dev, NULL, NULL)) + if (!get_lightbar_version(ec_dev, &lb_version, NULL)) return -ENODEV; /* Take control of the lightbar from the EC. */ diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c index 8d7c34abb0a1..fe0eddd2cf45 100644 --- a/drivers/platform/chrome/cros_typec_switch.c +++ b/drivers/platform/chrome/cros_typec_switch.c @@ -211,9 +211,8 @@ static int cros_typec_register_switches(struct cros_typec_switch_data *sdata) struct cros_typec_port *port; struct device *dev = sdata->dev; struct fwnode_handle *fwnode; - struct acpi_device *adev; - unsigned long long index; int nports, ret; + u64 index; nports = device_get_child_node_count(dev); if (nports == 0) { @@ -228,22 +227,14 @@ static int cros_typec_register_switches(struct cros_typec_switch_data *sdata) goto err_switch; } - adev = to_acpi_device_node(fwnode); - if (!adev) { - dev_err(fwnode->dev, "Couldn't get ACPI device handle\n"); - ret = -ENODEV; - goto err_switch; - } - - ret = acpi_evaluate_integer(adev->handle, "_ADR", NULL, &index); - if (ACPI_FAILURE(ret)) { - dev_err(fwnode->dev, "_ADR wasn't evaluated\n"); - ret = -ENODATA; + ret = acpi_get_local_u64_address(ACPI_HANDLE_FWNODE(fwnode), &index); + if (ret) { + dev_err(dev, "_ADR wasn't evaluated for %pfwP\n", fwnode); goto err_switch; } if (index >= EC_USB_PD_MAX_PORTS) { - dev_err(fwnode->dev, "Invalid port index number: %llu\n", index); + dev_err(dev, "%pfwP: Invalid port index number: %llu\n", fwnode, index); ret = -EINVAL; goto err_switch; } |
