summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-09-07 14:28:16 +0100
committerMark Brown <broonie@kernel.org>2026-09-07 14:28:16 +0100
commit981b728ec491034bedcca0f1b6b5933d767faba6 (patch)
tree9e0dac915f8330347ef62f8f861017886dc50137
parentf36faf29a1d5e0625fa01269541e3c70beaf655a (diff)
parent5859f97c6f404d07e89fe9c0d20a318ebf200bd1 (diff)
downloadlinux-next-981b728ec491034bedcca0f1b6b5933d767faba6.tar.gz
linux-next-981b728ec491034bedcca0f1b6b5933d767faba6.zip
Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux.git
-rw-r--r--drivers/platform/chrome/cros_ec_ishtp.c2
-rw-r--r--drivers/platform/chrome/cros_ec_proto.c43
-rw-r--r--drivers/platform/chrome/cros_ec_proto_test.c158
-rw-r--r--drivers/platform/chrome/cros_ec_rpmsg.c2
-rw-r--r--drivers/platform/chrome/cros_usbpd_notify.c4
-rw-r--r--include/linux/platform_data/cros_ec_commands.h72
6 files changed, 262 insertions, 19 deletions
diff --git a/drivers/platform/chrome/cros_ec_ishtp.c b/drivers/platform/chrome/cros_ec_ishtp.c
index 3766cef81fe8..b21a27ad3762 100644
--- a/drivers/platform/chrome/cros_ec_ishtp.c
+++ b/drivers/platform/chrome/cros_ec_ishtp.c
@@ -369,7 +369,7 @@ static void ish_event_cb(struct ishtp_cl_device *cl_device)
* @cros_ish_cl: ISHTP client instance
* @reset: true if called from reset handler
*
- * This function complete the initializtion of the client.
+ * This function complete the initialization of the client.
*
* Return: 0 for success, negative error code for failure.
*/
diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c
index 724d1313f6b2..b81b37c7169a 100644
--- a/drivers/platform/chrome/cros_ec_proto.c
+++ b/drivers/platform/chrome/cros_ec_proto.c
@@ -138,7 +138,8 @@ static int cros_ec_xfer_command(struct cros_ec_device *ec_dev, struct cros_ec_co
return ret;
}
-static int cros_ec_wait_until_complete(struct cros_ec_device *ec_dev, uint32_t *result)
+static int cros_ec_wait_until_complete(struct cros_ec_device *ec_dev,
+ struct cros_ec_command *orig_msg)
{
DEFINE_RAW_FLEX(struct cros_ec_command, msg, data,
sizeof(struct ec_response_get_comms_status));
@@ -161,23 +162,41 @@ static int cros_ec_wait_until_complete(struct cros_ec_device *ec_dev, uint32_t *
if (ret < 0)
return ret;
- *result = msg->result;
+ orig_msg->result = msg->result;
if (msg->result != EC_RES_SUCCESS)
return ret;
- if (ret == 0) {
- ret = -EPROTO;
- break;
- }
+ if (ret == 0)
+ return -EPROTO;
+
+ if (!(status->flags & EC_COMMS_STATUS_PROCESSING)) {
+ u32 orig_cmd, orig_outsize, orig_version;
+
+ /* If no response payload is expected, return 0. */
+ if (orig_msg->insize == 0)
+ return 0;
- if (!(status->flags & EC_COMMS_STATUS_PROCESSING))
+ /*
+ * Request the response using EC_CMD_RESEND_RESPONSE.
+ * Restore the original message fields so it appears
+ * to be a direct response to the original command.
+ */
+ orig_cmd = orig_msg->command;
+ orig_outsize = orig_msg->outsize;
+ orig_version = orig_msg->version;
+
+ orig_msg->command = EC_CMD_RESEND_RESPONSE;
+ orig_msg->outsize = 0;
+ orig_msg->version = 0;
+ ret = cros_ec_xfer_command(ec_dev, orig_msg);
+ orig_msg->command = orig_cmd;
+ orig_msg->outsize = orig_outsize;
+ orig_msg->version = orig_version;
return ret;
+ }
}
- if (i >= EC_COMMAND_RETRIES)
- ret = -EAGAIN;
-
- return ret;
+ return -EAGAIN;
}
static int cros_ec_send_command(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)
@@ -185,7 +204,7 @@ static int cros_ec_send_command(struct cros_ec_device *ec_dev, struct cros_ec_co
int ret = cros_ec_xfer_command(ec_dev, msg);
if (msg->result == EC_RES_IN_PROGRESS)
- ret = cros_ec_wait_until_complete(ec_dev, &msg->result);
+ ret = cros_ec_wait_until_complete(ec_dev, msg);
return ret;
}
diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c
index 3f281996a686..cbaaf98d6877 100644
--- a/drivers/platform/chrome/cros_ec_proto_test.c
+++ b/drivers/platform/chrome/cros_ec_proto_test.c
@@ -1744,7 +1744,7 @@ static void cros_ec_proto_test_cmd_xfer_protocol_v2_no_op(struct kunit *test)
KUNIT_EXPECT_EQ(test, ret, -EIO);
}
-static void cros_ec_proto_test_cmd_xfer_in_progress_normal(struct kunit *test)
+static void cros_ec_proto_test_cmd_xfer_in_progress_payload_0byte(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
@@ -1774,7 +1774,7 @@ static void cros_ec_proto_test_cmd_xfer_in_progress_normal(struct kunit *test)
}
ret = cros_ec_cmd_xfer(ec_dev, &msg);
- KUNIT_EXPECT_EQ(test, ret, sizeof(struct ec_response_get_comms_status));
+ KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_EQ(test, msg.result, EC_RES_SUCCESS);
@@ -1799,6 +1799,156 @@ static void cros_ec_proto_test_cmd_xfer_in_progress_normal(struct kunit *test)
KUNIT_EXPECT_EQ(test, cros_kunit_ec_pkt_xfer_mock_called, 2);
}
+static void cros_ec_proto_test_cmd_xfer_in_progress_payload_4bytes(struct kunit *test)
+{
+ struct cros_ec_proto_test_priv *priv = test->priv;
+ struct cros_ec_device *ec_dev = &priv->ec_dev;
+ struct ec_xfer_mock *mock;
+ u8 resp_data[4] = {0x11, 0x22, 0x33, 0x44};
+ struct {
+ struct cros_ec_command msg;
+ u8 data[4];
+ } buf;
+ struct cros_ec_command *msg = &buf.msg;
+ int ret;
+
+ memset(&buf, 0, sizeof(buf));
+ msg->version = 1;
+ msg->command = 0x1234;
+ msg->insize = sizeof(buf.data);
+
+ ec_dev->max_response = sizeof(buf.data);
+ ec_dev->pkt_xfer = cros_kunit_ec_pkt_xfer_mock;
+
+ /* For initial command returning EC_RES_IN_PROGRESS. */
+ {
+ mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_IN_PROGRESS, 0);
+ KUNIT_ASSERT_PTR_NE(test, mock, NULL);
+ }
+
+ /* For EC_CMD_GET_COMMS_STATUS status polling. */
+ {
+ struct ec_response_get_comms_status *data;
+
+ mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
+ KUNIT_ASSERT_PTR_NE(test, mock, NULL);
+
+ data = (struct ec_response_get_comms_status *)mock->o_data;
+ data->flags = 0;
+ }
+
+ /* For EC_CMD_RESEND_RESPONSE returning 4 bytes payload. */
+ {
+ mock = cros_kunit_ec_xfer_mock_add(test, sizeof(resp_data));
+ KUNIT_ASSERT_PTR_NE(test, mock, NULL);
+ memcpy(mock->o_data, resp_data, sizeof(resp_data));
+ }
+
+ ret = cros_ec_cmd_xfer(ec_dev, msg);
+ KUNIT_EXPECT_EQ(test, ret, 4);
+ KUNIT_EXPECT_EQ(test, msg->result, EC_RES_SUCCESS);
+ KUNIT_EXPECT_EQ(test, msg->command, 0x1234);
+ KUNIT_EXPECT_EQ(test, msg->insize, sizeof(buf.data));
+ KUNIT_EXPECT_EQ(test, msg->version, 1);
+ KUNIT_EXPECT_EQ(test, memcmp(msg->data, resp_data, sizeof(resp_data)), 0);
+
+ /* Verify mock sequence */
+ {
+ mock = cros_kunit_ec_xfer_mock_next();
+ KUNIT_EXPECT_PTR_NE(test, mock, NULL);
+
+ mock = cros_kunit_ec_xfer_mock_next();
+ KUNIT_EXPECT_PTR_NE(test, mock, NULL);
+ KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_COMMS_STATUS);
+
+ mock = cros_kunit_ec_xfer_mock_next();
+ KUNIT_EXPECT_PTR_NE(test, mock, NULL);
+ KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_RESEND_RESPONSE);
+ KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
+ KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
+ KUNIT_EXPECT_EQ(test, mock->msg.insize, 4);
+ }
+
+ KUNIT_EXPECT_EQ(test, cros_kunit_ec_pkt_xfer_mock_called, 3);
+}
+
+static void cros_ec_proto_test_cmd_xfer_in_progress_payload_gt4bytes(struct kunit *test)
+{
+ struct cros_ec_proto_test_priv *priv = test->priv;
+ struct cros_ec_device *ec_dev = &priv->ec_dev;
+ struct ec_xfer_mock *mock;
+ u8 resp_data[16];
+ struct {
+ struct cros_ec_command msg;
+ u8 data[16];
+ } buf;
+ struct cros_ec_command *msg = &buf.msg;
+ int ret, i;
+
+ for (i = 0; i < sizeof(resp_data); ++i)
+ resp_data[i] = (u8)(i + 1);
+
+ memset(&buf, 0, sizeof(buf));
+ msg->version = 0;
+ msg->command = 0x5678;
+ msg->insize = sizeof(buf.data);
+
+ ec_dev->max_response = sizeof(buf.data);
+ ec_dev->pkt_xfer = cros_kunit_ec_pkt_xfer_mock;
+
+ /* For initial command returning EC_RES_IN_PROGRESS. */
+ {
+ mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_IN_PROGRESS, 0);
+ KUNIT_ASSERT_PTR_NE(test, mock, NULL);
+ }
+
+ /* For EC_CMD_GET_COMMS_STATUS status polling. */
+ {
+ struct ec_response_get_comms_status *data;
+
+ mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
+ KUNIT_ASSERT_PTR_NE(test, mock, NULL);
+
+ data = (struct ec_response_get_comms_status *)mock->o_data;
+ data->flags = 0;
+ }
+
+ /* For EC_CMD_RESEND_RESPONSE returning 16 bytes payload. */
+ {
+ mock = cros_kunit_ec_xfer_mock_add(test, sizeof(resp_data));
+ KUNIT_ASSERT_PTR_NE(test, mock, NULL);
+ memcpy(mock->o_data, resp_data, sizeof(resp_data));
+ }
+
+ ret = cros_ec_cmd_xfer(ec_dev, msg);
+ KUNIT_EXPECT_EQ(test, ret, 16);
+ KUNIT_EXPECT_EQ(test, msg->result, EC_RES_SUCCESS);
+ KUNIT_EXPECT_EQ(test, msg->command, 0x5678);
+ KUNIT_EXPECT_EQ(test, msg->outsize, 0);
+ KUNIT_EXPECT_EQ(test, msg->insize, sizeof(buf.data));
+ KUNIT_EXPECT_EQ(test, msg->version, 0);
+ KUNIT_EXPECT_EQ(test, memcmp(msg->data, resp_data, sizeof(resp_data)), 0);
+
+ /* Verify mock sequence */
+ {
+ mock = cros_kunit_ec_xfer_mock_next();
+ KUNIT_EXPECT_PTR_NE(test, mock, NULL);
+
+ mock = cros_kunit_ec_xfer_mock_next();
+ KUNIT_EXPECT_PTR_NE(test, mock, NULL);
+ KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_COMMS_STATUS);
+
+ mock = cros_kunit_ec_xfer_mock_next();
+ KUNIT_EXPECT_PTR_NE(test, mock, NULL);
+ KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_RESEND_RESPONSE);
+ KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
+ KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
+ KUNIT_EXPECT_EQ(test, mock->msg.insize, 16);
+ }
+
+ KUNIT_EXPECT_EQ(test, cros_kunit_ec_pkt_xfer_mock_called, 3);
+}
+
static void cros_ec_proto_test_cmd_xfer_in_progress_retries_eagain(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
@@ -2703,7 +2853,9 @@ static struct kunit_case cros_ec_proto_test_cases[] = {
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_protocol_v3_no_op),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_protocol_v2_normal),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_protocol_v2_no_op),
- KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_normal),
+ KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_payload_0byte),
+ KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_payload_4bytes),
+ KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_payload_gt4bytes),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_retries_eagain),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_retries_status_processing),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_xfer_error),
diff --git a/drivers/platform/chrome/cros_ec_rpmsg.c b/drivers/platform/chrome/cros_ec_rpmsg.c
index 09bd9e49464e..7390c2c91ea5 100644
--- a/drivers/platform/chrome/cros_ec_rpmsg.c
+++ b/drivers/platform/chrome/cros_ec_rpmsg.c
@@ -20,7 +20,7 @@
#define HOST_EVENT_MARK 2
/**
- * struct cros_ec_rpmsg_response - rpmsg message format from from EC.
+ * struct cros_ec_rpmsg_response - rpmsg message format from EC.
*
* @type: The type of message, should be either HOST_COMMAND_MARK or
* HOST_EVENT_MARK, representing that the message is a response to
diff --git a/drivers/platform/chrome/cros_usbpd_notify.c b/drivers/platform/chrome/cros_usbpd_notify.c
index d842c05f4db0..6f5eea4938cb 100644
--- a/drivers/platform/chrome/cros_usbpd_notify.c
+++ b/drivers/platform/chrome/cros_usbpd_notify.c
@@ -64,7 +64,7 @@ static void cros_usbpd_get_event_and_notify(struct device *dev,
/*
* We still send a 0 event out to older devices which don't
- * have the updated device heirarchy.
+ * have the updated device hierarchy.
*/
if (!ec_dev) {
dev_dbg(dev,
@@ -115,7 +115,7 @@ static int cros_usbpd_notify_probe_acpi(struct platform_device *pdev)
if (!ec_dev) {
/*
* We continue even for older devices which don't have the
- * correct device heirarchy, namely, GOOG0003 is a child
+ * correct device hierarchy, namely, GOOG0003 is a child
* of GOOG0004. If GOOG0003 is a child of GOOG0004 and we
* can't get a pointer to the Chrome EC device, defer the
* probe function.
diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h
index 749d985e9da2..a7bd69d83522 100644
--- a/include/linux/platform_data/cros_ec_commands.h
+++ b/include/linux/platform_data/cros_ec_commands.h
@@ -1344,6 +1344,26 @@ enum ec_feature_code {
* The EC supports UCSI PPM.
*/
EC_FEATURE_UCSI_PPM = 54,
+ /*
+ * The EC supports Strauss keyboard.
+ */
+ EC_FEATURE_STRAUSS = 55,
+ /*
+ * The EC supports PoE.
+ */
+ EC_FEATURE_POE = 56,
+ /*
+ * The EC supports a hybrid boost charger
+ */
+ EC_FEATURE_CHARGER_HYBRID_POWER_BOOST = 57,
+ /*
+ * Support signaling new console logs via host event
+ */
+ EC_FEATURE_CONSOLE_LOG_EVENT = 58,
+ /*
+ * The EC supports power monitoring
+ */
+ EC_FEATURE_PWRMON = 59,
};
#define EC_FEATURE_MASK_0(event_code) BIT(event_code % 32)
@@ -3516,6 +3536,9 @@ enum ec_mkbp_event {
/* Peripheral device charger event */
EC_MKBP_EVENT_PCHG = 12,
+ /* Power monitor telemetry event */
+ EC_MKBP_EVENT_PWRMON = 13,
+
/* Number of MKBP events */
EC_MKBP_EVENT_COUNT,
};
@@ -3599,6 +3622,12 @@ union __ec_align_offset1 ec_response_get_next_data_v3 {
uint32_t cec_events;
uint8_t cec_message[16];
+
+ struct __ec_todo_packed {
+ int64_t value;
+ uint32_t samples;
+ uint8_t channel_id;
+ } pwrmon_data;
};
BUILD_ASSERT(sizeof(union ec_response_get_next_data_v3) == 18);
@@ -6589,6 +6618,49 @@ struct ec_params_usb_pd_mux_ack {
uint8_t port; /* USB-C port number */
} __ec_align1;
+/**
+ * Power monitoring. Used to read power consumptions on rails
+ */
+#define EC_CMD_PWRMON 0x0608
+
+enum ec_pwrmon_cmd {
+ EC_PWRMON_GET_CHANNEL_COUNT = 0,
+ EC_PWRMON_DUMP_INFO = 1,
+ EC_PWRMON_SET_RATE = 2,
+ EC_PWRMON_GET_RATE = 3,
+ EC_PWRMON_START = 4,
+ EC_PWRMON_STOP = 5,
+ EC_PWRMON_LATCH = 6,
+};
+
+struct ec_params_pwrmon {
+ uint8_t cmd;
+ union {
+ uint16_t set_rate;
+ uint8_t channel_id;
+ } __ec_align2;
+
+ /*
+ * The following commands have no args:
+ *
+ * start, stop, latch
+ *
+ */
+} __ec_align4;
+
+struct pwrmon_dump_info {
+ uint8_t channel_id;
+ char channel_name[32];
+} __ec_align4;
+
+struct ec_response_pwrmon {
+ union {
+ uint16_t sample_rate;
+ uint8_t channel_count;
+ struct pwrmon_dump_info dump_info;
+ } __ec_align4;
+} __ec_align4;
+
/*****************************************************************************/
/*
* Reserve a range of host commands for board-specific, experimental, or