chrome platform changes for 5.20
cros_ec_proto: * Leverage Kunit and add Kunit test cases. * Clean-ups. * Fix typo. cros_ec_commands: * Fix typo. * Fix compile errors. cros_kbd_led_backlight: * Support OF match. * Support EC PWM backend. cros_ec: * Always expose the last resume result to fix sleep hang detection on ARM-based chromebooks. wilco_ec: * Fix typo. cros_ec_typec: * Clean-ups. * Use Type-C framework utilities to manage altmode structs. -----BEGIN PGP SIGNATURE----- iIkEABYIADEWIQS0yQeDP3cjLyifNRUrxTEGBto89AUCYunptRMcdHp1bmdiaUBr ZXJuZWwub3JnAAoJECvFMQYG2jz0Ty4A/RzxnPvDnnHMwuhgAVcGMNSf5NwIza1I Um5ABCUZ60VuAPoCSFLTNtnfLjZRLniLchDRXS+IsqYZ2IgZ8XgPoZ4lCg== =sehJ -----END PGP SIGNATURE----- Merge tag 'tag-chrome-platform-for-v5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux Pull chrome platform updates from Tzung-Bi Shih: "cros_ec_proto: - Leverage Kunit and add Kunit test cases - Clean-ups - Fix typo cros_ec_commands: - Fix typo - Fix compile errors cros_kbd_led_backlight: - Support OF match - Support EC PWM backend cros_ec: - Always expose the last resume result to fix sleep hang detection on ARM-based chromebooks wilco_ec: - Fix typo cros_ec_typec: - Clean-ups - Use Type-C framework utilities to manage altmode structs" * tag 'tag-chrome-platform-for-v5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux: (59 commits) platform/chrome: cros_kunit_util: add default value for `msg->result` platform/chrome: merge Kunit utils and test cases platform/chrome: cros_kbd_led_backlight: fix build warning platform/chrome: cros_ec_proto: add Kunit test for cros_ec_cmd() platform/chrome: cros_ec_proto: add Kunit tests for get_sensor_count platform/chrome: cros_ec_proto: add Kunit tests for check_features platform/chrome: cros_ec_proto: add Kunit tests for get_host_event platform/chrome: cros_ec_proto: add Kunit tests for get_next_event platform/chrome: cros_ec_proto: add Kunit test for cros_ec_map_error() platform/chrome: cros_ec_proto: add Kunit tests for cmd_xfer_status platform/chrome: cros_ec_proto: return -EPROTO if empty payload platform/chrome: cros_ec_proto: add Kunit test for empty payload platform/chrome: cros_ec_proto: return -EAGAIN when retries timed out platform/chrome: cros_ec_proto: change Kunit expectation when timed out platform/chrome: cros_ec_proto: separate cros_ec_wait_until_complete() platform/chrome: cros_ec_proto: separate cros_ec_xfer_command() platform/chrome: cros_ec_proto: add Kunit tests for cros_ec_send_command() platform/chrome: cros_ec_proto: add Kunit tests for cros_ec_cmd_xfer() platform/chrome: cros_ec_proto: add "cros_ec_" prefix to send_command() platform/chrome: cros_ec_typec: Register port altmodes ...
This commit is contained in:
commit
5bb3bf24b0
|
@ -0,0 +1,35 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/chrome/google,cros-kbd-led-backlight.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ChromeOS keyboard backlight LED driver.
|
||||
|
||||
maintainers:
|
||||
- Tzung-Bi Shih <tzungbi@kernel.org>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: google,cros-kbd-led-backlight
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
cros_ec: ec@0 {
|
||||
compatible = "google,cros-ec-spi";
|
||||
reg = <0>;
|
||||
|
||||
kbd-led-backlight {
|
||||
compatible = "google,cros-kbd-led-backlight";
|
||||
};
|
||||
};
|
||||
};
|
|
@ -90,6 +90,9 @@ properties:
|
|||
pwm:
|
||||
$ref: "/schemas/pwm/google,cros-ec-pwm.yaml#"
|
||||
|
||||
kbd-led-backlight:
|
||||
$ref: "/schemas/chrome/google,cros-kbd-led-backlight.yaml#"
|
||||
|
||||
keyboard-controller:
|
||||
$ref: "/schemas/input/google,cros-ec-keyb.yaml#"
|
||||
|
||||
|
|
|
@ -250,8 +250,8 @@ static int ec_device_probe(struct platform_device *pdev)
|
|||
* The PCHG device cannot be detected by sending EC_FEATURE_GET_CMD, but
|
||||
* it can be detected by querying the number of peripheral chargers.
|
||||
*/
|
||||
retval = cros_ec_command(ec->ec_dev, 0, EC_CMD_PCHG_COUNT, NULL, 0,
|
||||
&pchg_count, sizeof(pchg_count));
|
||||
retval = cros_ec_cmd(ec->ec_dev, 0, EC_CMD_PCHG_COUNT, NULL, 0,
|
||||
&pchg_count, sizeof(pchg_count));
|
||||
if (retval >= 0 && pchg_count.port_count) {
|
||||
retval = mfd_add_hotplug_devices(ec->dev,
|
||||
cros_ec_pchg_cells,
|
||||
|
|
|
@ -139,7 +139,7 @@ config CROS_EC_PROTO
|
|||
|
||||
config CROS_KBD_LED_BACKLIGHT
|
||||
tristate "Backlight LED support for Chrome OS keyboards"
|
||||
depends on LEDS_CLASS && ACPI
|
||||
depends on LEDS_CLASS && (ACPI || CROS_EC)
|
||||
help
|
||||
This option enables support for the keyboard backlight LEDs on
|
||||
select Chrome OS systems.
|
||||
|
@ -267,4 +267,13 @@ config CHROMEOS_PRIVACY_SCREEN
|
|||
|
||||
source "drivers/platform/chrome/wilco_ec/Kconfig"
|
||||
|
||||
# Kunit test cases
|
||||
config CROS_KUNIT
|
||||
tristate "Kunit tests for ChromeOS" if !KUNIT_ALL_TESTS
|
||||
depends on KUNIT && CROS_EC
|
||||
default KUNIT_ALL_TESTS
|
||||
select CROS_EC_PROTO
|
||||
help
|
||||
ChromeOS Kunit tests.
|
||||
|
||||
endif # CHROMEOS_PLATFORMS
|
||||
|
|
|
@ -30,3 +30,8 @@ obj-$(CONFIG_CROS_USBPD_LOGGER) += cros_usbpd_logger.o
|
|||
obj-$(CONFIG_CROS_USBPD_NOTIFY) += cros_usbpd_notify.o
|
||||
|
||||
obj-$(CONFIG_WILCO_EC) += wilco_ec/
|
||||
|
||||
# Kunit test cases
|
||||
obj-$(CONFIG_CROS_KUNIT) += cros_kunit.o
|
||||
cros_kunit-objs := cros_kunit_util.o
|
||||
cros_kunit-objs += cros_ec_proto_test.o
|
||||
|
|
|
@ -19,9 +19,6 @@
|
|||
|
||||
#include "cros_ec.h"
|
||||
|
||||
#define CROS_EC_DEV_EC_INDEX 0
|
||||
#define CROS_EC_DEV_PD_INDEX 1
|
||||
|
||||
static struct cros_ec_platform ec_p = {
|
||||
.ec_name = CROS_EC_DEV_NAME,
|
||||
.cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_EC_INDEX),
|
||||
|
@ -135,16 +132,16 @@ static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event)
|
|||
buf.msg.command = EC_CMD_HOST_SLEEP_EVENT;
|
||||
|
||||
ret = cros_ec_cmd_xfer_status(ec_dev, &buf.msg);
|
||||
|
||||
/* For now, report failure to transition to S0ix with a warning. */
|
||||
/* Report failure to transition to system wide suspend with a warning. */
|
||||
if (ret >= 0 && ec_dev->host_sleep_v1 &&
|
||||
(sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME)) {
|
||||
(sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME ||
|
||||
sleep_event == HOST_SLEEP_EVENT_S3_RESUME)) {
|
||||
ec_dev->last_resume_result =
|
||||
buf.u.resp1.resume_response.sleep_transitions;
|
||||
|
||||
WARN_ONCE(buf.u.resp1.resume_response.sleep_transitions &
|
||||
EC_HOST_RESUME_SLEEP_TIMEOUT,
|
||||
"EC detected sleep transition timeout. Total slp_s0 transitions: %d",
|
||||
"EC detected sleep transition timeout. Total sleep transitions: %d",
|
||||
buf.u.resp1.resume_response.sleep_transitions &
|
||||
EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK);
|
||||
}
|
||||
|
|
|
@ -52,8 +52,8 @@ static int cros_ec_map_error(uint32_t result)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int prepare_packet(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg)
|
||||
static int prepare_tx(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg)
|
||||
{
|
||||
struct ec_host_request *request;
|
||||
u8 *out;
|
||||
|
@ -85,98 +85,13 @@ static int prepare_packet(struct cros_ec_device *ec_dev,
|
|||
return sizeof(*request) + msg->outsize;
|
||||
}
|
||||
|
||||
static int send_command(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg)
|
||||
{
|
||||
int ret;
|
||||
int (*xfer_fxn)(struct cros_ec_device *ec, struct cros_ec_command *msg);
|
||||
|
||||
if (ec_dev->proto_version > 2)
|
||||
xfer_fxn = ec_dev->pkt_xfer;
|
||||
else
|
||||
xfer_fxn = ec_dev->cmd_xfer;
|
||||
|
||||
if (!xfer_fxn) {
|
||||
/*
|
||||
* This error can happen if a communication error happened and
|
||||
* the EC is trying to use protocol v2, on an underlying
|
||||
* communication mechanism that does not support v2.
|
||||
*/
|
||||
dev_err_once(ec_dev->dev,
|
||||
"missing EC transfer API, cannot send command\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
trace_cros_ec_request_start(msg);
|
||||
ret = (*xfer_fxn)(ec_dev, msg);
|
||||
trace_cros_ec_request_done(msg, ret);
|
||||
if (msg->result == EC_RES_IN_PROGRESS) {
|
||||
int i;
|
||||
struct cros_ec_command *status_msg;
|
||||
struct ec_response_get_comms_status *status;
|
||||
|
||||
status_msg = kmalloc(sizeof(*status_msg) + sizeof(*status),
|
||||
GFP_KERNEL);
|
||||
if (!status_msg)
|
||||
return -ENOMEM;
|
||||
|
||||
status_msg->version = 0;
|
||||
status_msg->command = EC_CMD_GET_COMMS_STATUS;
|
||||
status_msg->insize = sizeof(*status);
|
||||
status_msg->outsize = 0;
|
||||
|
||||
/*
|
||||
* Query the EC's status until it's no longer busy or
|
||||
* we encounter an error.
|
||||
*/
|
||||
for (i = 0; i < EC_COMMAND_RETRIES; i++) {
|
||||
usleep_range(10000, 11000);
|
||||
|
||||
trace_cros_ec_request_start(status_msg);
|
||||
ret = (*xfer_fxn)(ec_dev, status_msg);
|
||||
trace_cros_ec_request_done(status_msg, ret);
|
||||
if (ret == -EAGAIN)
|
||||
continue;
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
msg->result = status_msg->result;
|
||||
if (status_msg->result != EC_RES_SUCCESS)
|
||||
break;
|
||||
|
||||
status = (struct ec_response_get_comms_status *)
|
||||
status_msg->data;
|
||||
if (!(status->flags & EC_COMMS_STATUS_PROCESSING))
|
||||
break;
|
||||
}
|
||||
|
||||
kfree(status_msg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* cros_ec_prepare_tx() - Prepare an outgoing message in the output buffer.
|
||||
* @ec_dev: Device to register.
|
||||
* @msg: Message to write.
|
||||
*
|
||||
* This is intended to be used by all ChromeOS EC drivers, but at present
|
||||
* only SPI uses it. Once LPC uses the same protocol it can start using it.
|
||||
* I2C could use it now, with a refactor of the existing code.
|
||||
*
|
||||
* Return: number of prepared bytes on success or negative error code.
|
||||
*/
|
||||
int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg)
|
||||
static int prepare_tx_legacy(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg)
|
||||
{
|
||||
u8 *out;
|
||||
u8 csum;
|
||||
int i;
|
||||
|
||||
if (ec_dev->proto_version > 2)
|
||||
return prepare_packet(ec_dev, msg);
|
||||
|
||||
if (msg->outsize > EC_PROTO2_MAX_PARAM_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -191,6 +106,106 @@ int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
|
|||
|
||||
return EC_MSG_TX_PROTO_BYTES + msg->outsize;
|
||||
}
|
||||
|
||||
static int cros_ec_xfer_command(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)
|
||||
{
|
||||
int ret;
|
||||
int (*xfer_fxn)(struct cros_ec_device *ec, struct cros_ec_command *msg);
|
||||
|
||||
if (ec_dev->proto_version > 2)
|
||||
xfer_fxn = ec_dev->pkt_xfer;
|
||||
else
|
||||
xfer_fxn = ec_dev->cmd_xfer;
|
||||
|
||||
if (!xfer_fxn) {
|
||||
/*
|
||||
* This error can happen if a communication error happened and
|
||||
* the EC is trying to use protocol v2, on an underlying
|
||||
* communication mechanism that does not support v2.
|
||||
*/
|
||||
dev_err_once(ec_dev->dev, "missing EC transfer API, cannot send command\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
trace_cros_ec_request_start(msg);
|
||||
ret = (*xfer_fxn)(ec_dev, msg);
|
||||
trace_cros_ec_request_done(msg, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cros_ec_wait_until_complete(struct cros_ec_device *ec_dev, uint32_t *result)
|
||||
{
|
||||
struct {
|
||||
struct cros_ec_command msg;
|
||||
struct ec_response_get_comms_status status;
|
||||
} __packed buf;
|
||||
struct cros_ec_command *msg = &buf.msg;
|
||||
struct ec_response_get_comms_status *status = &buf.status;
|
||||
int ret = 0, i;
|
||||
|
||||
msg->version = 0;
|
||||
msg->command = EC_CMD_GET_COMMS_STATUS;
|
||||
msg->insize = sizeof(*status);
|
||||
msg->outsize = 0;
|
||||
|
||||
/* Query the EC's status until it's no longer busy or we encounter an error. */
|
||||
for (i = 0; i < EC_COMMAND_RETRIES; ++i) {
|
||||
usleep_range(10000, 11000);
|
||||
|
||||
ret = cros_ec_xfer_command(ec_dev, msg);
|
||||
if (ret == -EAGAIN)
|
||||
continue;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*result = msg->result;
|
||||
if (msg->result != EC_RES_SUCCESS)
|
||||
return ret;
|
||||
|
||||
if (ret == 0) {
|
||||
ret = -EPROTO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(status->flags & EC_COMMS_STATUS_PROCESSING))
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (i >= EC_COMMAND_RETRIES)
|
||||
ret = -EAGAIN;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cros_ec_send_command(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)
|
||||
{
|
||||
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);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* cros_ec_prepare_tx() - Prepare an outgoing message in the output buffer.
|
||||
* @ec_dev: Device to register.
|
||||
* @msg: Message to write.
|
||||
*
|
||||
* This is used by all ChromeOS EC drivers to prepare the outgoing message
|
||||
* according to different protocol versions.
|
||||
*
|
||||
* Return: number of prepared bytes on success or negative error code.
|
||||
*/
|
||||
int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg)
|
||||
{
|
||||
if (ec_dev->proto_version > 2)
|
||||
return prepare_tx(ec_dev, msg);
|
||||
|
||||
return prepare_tx_legacy(ec_dev, msg);
|
||||
}
|
||||
EXPORT_SYMBOL(cros_ec_prepare_tx);
|
||||
|
||||
/**
|
||||
|
@ -199,9 +214,12 @@ EXPORT_SYMBOL(cros_ec_prepare_tx);
|
|||
* @msg: Message to check.
|
||||
*
|
||||
* This is used by ChromeOS EC drivers to check the ec_msg->result for
|
||||
* errors and to warn about them.
|
||||
* EC_RES_IN_PROGRESS and to warn about them.
|
||||
*
|
||||
* Return: 0 on success or negative error code.
|
||||
* The function should not check for furthermore error codes. Otherwise,
|
||||
* it would break the ABI.
|
||||
*
|
||||
* Return: -EAGAIN if ec_msg->result == EC_RES_IN_PROGRESS. Otherwise, 0.
|
||||
*/
|
||||
int cros_ec_check_result(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg)
|
||||
|
@ -228,59 +246,66 @@ EXPORT_SYMBOL(cros_ec_check_result);
|
|||
*
|
||||
* @ec_dev: EC device to call
|
||||
* @msg: message structure to use
|
||||
* @mask: result when function returns >=0.
|
||||
* @mask: result when function returns 0.
|
||||
*
|
||||
* LOCKING:
|
||||
* the caller has ec_dev->lock mutex, or the caller knows there is
|
||||
* no other command in progress.
|
||||
*/
|
||||
static int cros_ec_get_host_event_wake_mask(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg,
|
||||
uint32_t *mask)
|
||||
static int cros_ec_get_host_event_wake_mask(struct cros_ec_device *ec_dev, uint32_t *mask)
|
||||
{
|
||||
struct cros_ec_command *msg;
|
||||
struct ec_response_host_event_mask *r;
|
||||
int ret;
|
||||
int ret, mapped;
|
||||
|
||||
msg = kzalloc(sizeof(*msg) + sizeof(*r), GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
msg->command = EC_CMD_HOST_EVENT_GET_WAKE_MASK;
|
||||
msg->version = 0;
|
||||
msg->outsize = 0;
|
||||
msg->insize = sizeof(*r);
|
||||
|
||||
ret = send_command(ec_dev, msg);
|
||||
if (ret >= 0) {
|
||||
if (msg->result == EC_RES_INVALID_COMMAND)
|
||||
return -EOPNOTSUPP;
|
||||
if (msg->result != EC_RES_SUCCESS)
|
||||
return -EPROTO;
|
||||
}
|
||||
if (ret > 0) {
|
||||
r = (struct ec_response_host_event_mask *)msg->data;
|
||||
*mask = r->mask;
|
||||
ret = cros_ec_send_command(ec_dev, msg);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
mapped = cros_ec_map_error(msg->result);
|
||||
if (mapped) {
|
||||
ret = mapped;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
ret = -EPROTO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
r = (struct ec_response_host_event_mask *)msg->data;
|
||||
*mask = r->mask;
|
||||
ret = 0;
|
||||
exit:
|
||||
kfree(msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cros_ec_host_command_proto_query(struct cros_ec_device *ec_dev,
|
||||
int devidx,
|
||||
struct cros_ec_command *msg)
|
||||
static int cros_ec_get_proto_info(struct cros_ec_device *ec_dev, int devidx)
|
||||
{
|
||||
/*
|
||||
* Try using v3+ to query for supported protocols. If this
|
||||
* command fails, fall back to v2. Returns the highest protocol
|
||||
* supported by the EC.
|
||||
* Also sets the max request/response/passthru size.
|
||||
*/
|
||||
int ret;
|
||||
struct cros_ec_command *msg;
|
||||
struct ec_response_get_protocol_info *info;
|
||||
int ret, mapped;
|
||||
|
||||
if (!ec_dev->pkt_xfer)
|
||||
return -EPROTONOSUPPORT;
|
||||
ec_dev->proto_version = 3;
|
||||
if (devidx > 0)
|
||||
ec_dev->max_passthru = 0;
|
||||
|
||||
msg = kzalloc(sizeof(*msg) + sizeof(*info), GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
msg->command = EC_CMD_PASSTHRU_OFFSET(devidx) | EC_CMD_GET_PROTOCOL_INFO;
|
||||
msg->insize = sizeof(struct ec_response_get_protocol_info);
|
||||
msg->insize = sizeof(*info);
|
||||
|
||||
ret = send_command(ec_dev, msg);
|
||||
ret = cros_ec_send_command(ec_dev, msg);
|
||||
/*
|
||||
* Send command once again when timeout occurred.
|
||||
* Fingerprint MCU (FPMCU) is restarted during system boot which
|
||||
|
@ -289,68 +314,115 @@ static int cros_ec_host_command_proto_query(struct cros_ec_device *ec_dev,
|
|||
* attempt because we waited at least EC_MSG_DEADLINE_MS.
|
||||
*/
|
||||
if (ret == -ETIMEDOUT)
|
||||
ret = send_command(ec_dev, msg);
|
||||
ret = cros_ec_send_command(ec_dev, msg);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_dbg(ec_dev->dev,
|
||||
"failed to check for EC[%d] protocol version: %d\n",
|
||||
devidx, ret);
|
||||
return ret;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (devidx > 0 && msg->result == EC_RES_INVALID_COMMAND)
|
||||
return -ENODEV;
|
||||
else if (msg->result != EC_RES_SUCCESS)
|
||||
return msg->result;
|
||||
mapped = cros_ec_map_error(msg->result);
|
||||
if (mapped) {
|
||||
ret = mapped;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (ret == 0) {
|
||||
ret = -EPROTO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
info = (struct ec_response_get_protocol_info *)msg->data;
|
||||
|
||||
switch (devidx) {
|
||||
case CROS_EC_DEV_EC_INDEX:
|
||||
ec_dev->max_request = info->max_request_packet_size -
|
||||
sizeof(struct ec_host_request);
|
||||
ec_dev->max_response = info->max_response_packet_size -
|
||||
sizeof(struct ec_host_response);
|
||||
ec_dev->proto_version = min(EC_HOST_REQUEST_VERSION,
|
||||
fls(info->protocol_versions) - 1);
|
||||
ec_dev->din_size = info->max_response_packet_size + EC_MAX_RESPONSE_OVERHEAD;
|
||||
ec_dev->dout_size = info->max_request_packet_size + EC_MAX_REQUEST_OVERHEAD;
|
||||
|
||||
dev_dbg(ec_dev->dev, "using proto v%u\n", ec_dev->proto_version);
|
||||
break;
|
||||
case CROS_EC_DEV_PD_INDEX:
|
||||
ec_dev->max_passthru = info->max_request_packet_size -
|
||||
sizeof(struct ec_host_request);
|
||||
|
||||
dev_dbg(ec_dev->dev, "found PD chip\n");
|
||||
break;
|
||||
default:
|
||||
dev_dbg(ec_dev->dev, "unknown passthru index: %d\n", devidx);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
exit:
|
||||
kfree(msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cros_ec_host_command_proto_query_v2(struct cros_ec_device *ec_dev)
|
||||
static int cros_ec_get_proto_info_legacy(struct cros_ec_device *ec_dev)
|
||||
{
|
||||
struct cros_ec_command *msg;
|
||||
struct ec_params_hello *hello_params;
|
||||
struct ec_response_hello *hello_response;
|
||||
int ret;
|
||||
int len = max(sizeof(*hello_params), sizeof(*hello_response));
|
||||
struct ec_params_hello *params;
|
||||
struct ec_response_hello *response;
|
||||
int ret, mapped;
|
||||
|
||||
msg = kmalloc(sizeof(*msg) + len, GFP_KERNEL);
|
||||
ec_dev->proto_version = 2;
|
||||
|
||||
msg = kzalloc(sizeof(*msg) + max(sizeof(*params), sizeof(*response)), GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
msg->version = 0;
|
||||
msg->command = EC_CMD_HELLO;
|
||||
hello_params = (struct ec_params_hello *)msg->data;
|
||||
msg->outsize = sizeof(*hello_params);
|
||||
hello_response = (struct ec_response_hello *)msg->data;
|
||||
msg->insize = sizeof(*hello_response);
|
||||
msg->insize = sizeof(*response);
|
||||
msg->outsize = sizeof(*params);
|
||||
|
||||
hello_params->in_data = 0xa0b0c0d0;
|
||||
|
||||
ret = send_command(ec_dev, msg);
|
||||
params = (struct ec_params_hello *)msg->data;
|
||||
params->in_data = 0xa0b0c0d0;
|
||||
|
||||
ret = cros_ec_send_command(ec_dev, msg);
|
||||
if (ret < 0) {
|
||||
dev_dbg(ec_dev->dev,
|
||||
"EC failed to respond to v2 hello: %d\n",
|
||||
ret);
|
||||
dev_dbg(ec_dev->dev, "EC failed to respond to v2 hello: %d\n", ret);
|
||||
goto exit;
|
||||
} else if (msg->result != EC_RES_SUCCESS) {
|
||||
dev_err(ec_dev->dev,
|
||||
"EC responded to v2 hello with error: %d\n",
|
||||
msg->result);
|
||||
ret = msg->result;
|
||||
}
|
||||
|
||||
mapped = cros_ec_map_error(msg->result);
|
||||
if (mapped) {
|
||||
ret = mapped;
|
||||
dev_err(ec_dev->dev, "EC responded to v2 hello with error: %d\n", msg->result);
|
||||
goto exit;
|
||||
} else if (hello_response->out_data != 0xa1b2c3d4) {
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
ret = -EPROTO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
response = (struct ec_response_hello *)msg->data;
|
||||
if (response->out_data != 0xa1b2c3d4) {
|
||||
dev_err(ec_dev->dev,
|
||||
"EC responded to v2 hello with bad result: %u\n",
|
||||
hello_response->out_data);
|
||||
response->out_data);
|
||||
ret = -EBADMSG;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
ec_dev->max_request = EC_PROTO2_MAX_PARAM_SIZE;
|
||||
ec_dev->max_response = EC_PROTO2_MAX_PARAM_SIZE;
|
||||
ec_dev->max_passthru = 0;
|
||||
ec_dev->pkt_xfer = NULL;
|
||||
ec_dev->din_size = EC_PROTO2_MSG_BYTES;
|
||||
ec_dev->dout_size = EC_PROTO2_MSG_BYTES;
|
||||
|
||||
exit:
|
||||
dev_dbg(ec_dev->dev, "falling back to proto v2\n");
|
||||
ret = 0;
|
||||
exit:
|
||||
kfree(msg);
|
||||
return ret;
|
||||
}
|
||||
|
@ -371,13 +443,12 @@ static int cros_ec_host_command_proto_query_v2(struct cros_ec_device *ec_dev)
|
|||
* the caller has ec_dev->lock mutex or the caller knows there is
|
||||
* no other command in progress.
|
||||
*/
|
||||
static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev,
|
||||
u16 cmd, u32 *mask)
|
||||
static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev, u16 cmd, u32 *mask)
|
||||
{
|
||||
struct ec_params_get_cmd_versions *pver;
|
||||
struct ec_response_get_cmd_versions *rver;
|
||||
struct cros_ec_command *msg;
|
||||
int ret;
|
||||
int ret, mapped;
|
||||
|
||||
msg = kmalloc(sizeof(*msg) + max(sizeof(*rver), sizeof(*pver)),
|
||||
GFP_KERNEL);
|
||||
|
@ -392,14 +463,26 @@ static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev,
|
|||
pver = (struct ec_params_get_cmd_versions *)msg->data;
|
||||
pver->cmd = cmd;
|
||||
|
||||
ret = send_command(ec_dev, msg);
|
||||
if (ret > 0) {
|
||||
rver = (struct ec_response_get_cmd_versions *)msg->data;
|
||||
*mask = rver->version_mask;
|
||||
ret = cros_ec_send_command(ec_dev, msg);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
mapped = cros_ec_map_error(msg->result);
|
||||
if (mapped) {
|
||||
ret = mapped;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
kfree(msg);
|
||||
if (ret == 0) {
|
||||
ret = -EPROTO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rver = (struct ec_response_get_cmd_versions *)msg->data;
|
||||
*mask = rver->version_mask;
|
||||
ret = 0;
|
||||
exit:
|
||||
kfree(msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -413,71 +496,17 @@ static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev,
|
|||
int cros_ec_query_all(struct cros_ec_device *ec_dev)
|
||||
{
|
||||
struct device *dev = ec_dev->dev;
|
||||
struct cros_ec_command *proto_msg;
|
||||
struct ec_response_get_protocol_info *proto_info;
|
||||
u32 ver_mask = 0;
|
||||
u32 ver_mask;
|
||||
int ret;
|
||||
|
||||
proto_msg = kzalloc(sizeof(*proto_msg) + sizeof(*proto_info),
|
||||
GFP_KERNEL);
|
||||
if (!proto_msg)
|
||||
return -ENOMEM;
|
||||
|
||||
/* First try sending with proto v3. */
|
||||
ec_dev->proto_version = 3;
|
||||
ret = cros_ec_host_command_proto_query(ec_dev, 0, proto_msg);
|
||||
|
||||
if (ret == 0) {
|
||||
proto_info = (struct ec_response_get_protocol_info *)
|
||||
proto_msg->data;
|
||||
ec_dev->max_request = proto_info->max_request_packet_size -
|
||||
sizeof(struct ec_host_request);
|
||||
ec_dev->max_response = proto_info->max_response_packet_size -
|
||||
sizeof(struct ec_host_response);
|
||||
ec_dev->proto_version =
|
||||
min(EC_HOST_REQUEST_VERSION,
|
||||
fls(proto_info->protocol_versions) - 1);
|
||||
dev_dbg(ec_dev->dev,
|
||||
"using proto v%u\n",
|
||||
ec_dev->proto_version);
|
||||
|
||||
ec_dev->din_size = ec_dev->max_response +
|
||||
sizeof(struct ec_host_response) +
|
||||
EC_MAX_RESPONSE_OVERHEAD;
|
||||
ec_dev->dout_size = ec_dev->max_request +
|
||||
sizeof(struct ec_host_request) +
|
||||
EC_MAX_REQUEST_OVERHEAD;
|
||||
|
||||
/*
|
||||
* Check for PD
|
||||
*/
|
||||
ret = cros_ec_host_command_proto_query(ec_dev, 1, proto_msg);
|
||||
|
||||
if (ret) {
|
||||
dev_dbg(ec_dev->dev, "no PD chip found: %d\n", ret);
|
||||
ec_dev->max_passthru = 0;
|
||||
} else {
|
||||
dev_dbg(ec_dev->dev, "found PD chip\n");
|
||||
ec_dev->max_passthru =
|
||||
proto_info->max_request_packet_size -
|
||||
sizeof(struct ec_host_request);
|
||||
}
|
||||
if (!cros_ec_get_proto_info(ec_dev, CROS_EC_DEV_EC_INDEX)) {
|
||||
/* Check for PD. */
|
||||
cros_ec_get_proto_info(ec_dev, CROS_EC_DEV_PD_INDEX);
|
||||
} else {
|
||||
/* Try querying with a v2 hello message. */
|
||||
ec_dev->proto_version = 2;
|
||||
ret = cros_ec_host_command_proto_query_v2(ec_dev);
|
||||
|
||||
if (ret == 0) {
|
||||
/* V2 hello succeeded. */
|
||||
dev_dbg(ec_dev->dev, "falling back to proto v2\n");
|
||||
|
||||
ec_dev->max_request = EC_PROTO2_MAX_PARAM_SIZE;
|
||||
ec_dev->max_response = EC_PROTO2_MAX_PARAM_SIZE;
|
||||
ec_dev->max_passthru = 0;
|
||||
ec_dev->pkt_xfer = NULL;
|
||||
ec_dev->din_size = EC_PROTO2_MSG_BYTES;
|
||||
ec_dev->dout_size = EC_PROTO2_MSG_BYTES;
|
||||
} else {
|
||||
ret = cros_ec_get_proto_info_legacy(ec_dev);
|
||||
if (ret) {
|
||||
/*
|
||||
* It's possible for a test to occur too early when
|
||||
* the EC isn't listening. If this happens, we'll
|
||||
|
@ -485,7 +514,7 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev)
|
|||
*/
|
||||
ec_dev->proto_version = EC_PROTO_VERSION_UNKNOWN;
|
||||
dev_dbg(ec_dev->dev, "EC query failed: %d\n", ret);
|
||||
goto exit;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -506,26 +535,21 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev)
|
|||
}
|
||||
|
||||
/* Probe if MKBP event is supported */
|
||||
ret = cros_ec_get_host_command_version_mask(ec_dev,
|
||||
EC_CMD_GET_NEXT_EVENT,
|
||||
&ver_mask);
|
||||
if (ret < 0 || ver_mask == 0)
|
||||
ret = cros_ec_get_host_command_version_mask(ec_dev, EC_CMD_GET_NEXT_EVENT, &ver_mask);
|
||||
if (ret < 0 || ver_mask == 0) {
|
||||
ec_dev->mkbp_event_supported = 0;
|
||||
else
|
||||
} else {
|
||||
ec_dev->mkbp_event_supported = fls(ver_mask);
|
||||
|
||||
dev_dbg(ec_dev->dev, "MKBP support version %u\n",
|
||||
ec_dev->mkbp_event_supported - 1);
|
||||
dev_dbg(ec_dev->dev, "MKBP support version %u\n", ec_dev->mkbp_event_supported - 1);
|
||||
}
|
||||
|
||||
/* Probe if host sleep v1 is supported for S0ix failure detection. */
|
||||
ret = cros_ec_get_host_command_version_mask(ec_dev,
|
||||
EC_CMD_HOST_SLEEP_EVENT,
|
||||
&ver_mask);
|
||||
ec_dev->host_sleep_v1 = (ret >= 0 && (ver_mask & EC_VER_MASK(1)));
|
||||
ret = cros_ec_get_host_command_version_mask(ec_dev, EC_CMD_HOST_SLEEP_EVENT, &ver_mask);
|
||||
ec_dev->host_sleep_v1 = (ret == 0 && (ver_mask & EC_VER_MASK(1)));
|
||||
|
||||
/* Get host event wake mask. */
|
||||
ret = cros_ec_get_host_event_wake_mask(ec_dev, proto_msg,
|
||||
&ec_dev->host_event_wake_mask);
|
||||
ret = cros_ec_get_host_event_wake_mask(ec_dev, &ec_dev->host_event_wake_mask);
|
||||
if (ret < 0) {
|
||||
/*
|
||||
* If the EC doesn't support EC_CMD_HOST_EVENT_GET_WAKE_MASK,
|
||||
|
@ -556,7 +580,6 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev)
|
|||
ret = 0;
|
||||
|
||||
exit:
|
||||
kfree(proto_msg);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(cros_ec_query_all);
|
||||
|
@ -601,7 +624,7 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)
|
|||
msg->insize = ec_dev->max_response;
|
||||
}
|
||||
|
||||
if (msg->command < EC_CMD_PASSTHRU_OFFSET(1)) {
|
||||
if (msg->command < EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX)) {
|
||||
if (msg->outsize > ec_dev->max_request) {
|
||||
dev_err(ec_dev->dev,
|
||||
"request of size %u is too big (max: %u)\n",
|
||||
|
@ -621,7 +644,7 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)
|
|||
}
|
||||
}
|
||||
|
||||
ret = send_command(ec_dev, msg);
|
||||
ret = cros_ec_send_command(ec_dev, msg);
|
||||
mutex_unlock(&ec_dev->lock);
|
||||
|
||||
return ret;
|
||||
|
@ -852,8 +875,8 @@ bool cros_ec_check_features(struct cros_ec_dev *ec, int feature)
|
|||
|
||||
if (features->flags[0] == -1U && features->flags[1] == -1U) {
|
||||
/* features bitmap not read yet */
|
||||
ret = cros_ec_command(ec->ec_dev, 0, EC_CMD_GET_FEATURES + ec->cmd_offset,
|
||||
NULL, 0, features, sizeof(*features));
|
||||
ret = cros_ec_cmd(ec->ec_dev, 0, EC_CMD_GET_FEATURES + ec->cmd_offset,
|
||||
NULL, 0, features, sizeof(*features));
|
||||
if (ret < 0) {
|
||||
dev_warn(ec->dev, "cannot get EC features: %d\n", ret);
|
||||
memset(features, 0, sizeof(*features));
|
||||
|
@ -934,7 +957,7 @@ int cros_ec_get_sensor_count(struct cros_ec_dev *ec)
|
|||
EXPORT_SYMBOL_GPL(cros_ec_get_sensor_count);
|
||||
|
||||
/**
|
||||
* cros_ec_command - Send a command to the EC.
|
||||
* cros_ec_cmd - Send a command to the EC.
|
||||
*
|
||||
* @ec_dev: EC device
|
||||
* @version: EC command version
|
||||
|
@ -946,13 +969,13 @@ EXPORT_SYMBOL_GPL(cros_ec_get_sensor_count);
|
|||
*
|
||||
* Return: >= 0 on success, negative error number on failure.
|
||||
*/
|
||||
int cros_ec_command(struct cros_ec_device *ec_dev,
|
||||
unsigned int version,
|
||||
int command,
|
||||
void *outdata,
|
||||
int outsize,
|
||||
void *indata,
|
||||
int insize)
|
||||
int cros_ec_cmd(struct cros_ec_device *ec_dev,
|
||||
unsigned int version,
|
||||
int command,
|
||||
void *outdata,
|
||||
size_t outsize,
|
||||
void *indata,
|
||||
size_t insize)
|
||||
{
|
||||
struct cros_ec_command *msg;
|
||||
int ret;
|
||||
|
@ -979,4 +1002,4 @@ error:
|
|||
kfree(msg);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cros_ec_command);
|
||||
EXPORT_SYMBOL_GPL(cros_ec_cmd);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -30,8 +30,8 @@ TRACE_EVENT(cros_ec_request_start,
|
|||
),
|
||||
TP_fast_assign(
|
||||
__entry->version = cmd->version;
|
||||
__entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(1);
|
||||
__entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(1);
|
||||
__entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX);
|
||||
__entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX);
|
||||
__entry->outsize = cmd->outsize;
|
||||
__entry->insize = cmd->insize;
|
||||
),
|
||||
|
@ -55,8 +55,8 @@ TRACE_EVENT(cros_ec_request_done,
|
|||
),
|
||||
TP_fast_assign(
|
||||
__entry->version = cmd->version;
|
||||
__entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(1);
|
||||
__entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(1);
|
||||
__entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX);
|
||||
__entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX);
|
||||
__entry->outsize = cmd->outsize;
|
||||
__entry->insize = cmd->insize;
|
||||
__entry->result = cmd->result;
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#define DRV_NAME "cros-ec-typec"
|
||||
|
||||
#define DP_PORT_VDO (BIT(DP_PIN_ASSIGN_C) | BIT(DP_PIN_ASSIGN_D) | DP_CAP_DFP_D)
|
||||
|
||||
/* Supported alt modes. */
|
||||
enum {
|
||||
CROS_EC_ALTMODE_DP = 0,
|
||||
|
@ -60,8 +62,7 @@ struct cros_typec_port {
|
|||
uint8_t mux_flags;
|
||||
uint8_t role;
|
||||
|
||||
/* Port alt modes. */
|
||||
struct typec_altmode p_altmode[CROS_EC_ALTMODE_MAX];
|
||||
struct typec_altmode *port_altmode[CROS_EC_ALTMODE_MAX];
|
||||
|
||||
/* Flag indicating that PD partner discovery data parsing is completed. */
|
||||
bool sop_disc_done;
|
||||
|
@ -254,6 +255,14 @@ static void cros_typec_remove_cable(struct cros_typec_data *typec,
|
|||
port->sop_prime_disc_done = false;
|
||||
}
|
||||
|
||||
static void cros_typec_unregister_port_altmodes(struct cros_typec_port *port)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CROS_EC_ALTMODE_MAX; i++)
|
||||
typec_unregister_altmode(port->port_altmode[i]);
|
||||
}
|
||||
|
||||
static void cros_unregister_ports(struct cros_typec_data *typec)
|
||||
{
|
||||
int i;
|
||||
|
@ -268,34 +277,49 @@ static void cros_unregister_ports(struct cros_typec_data *typec)
|
|||
usb_role_switch_put(typec->ports[i]->role_sw);
|
||||
typec_switch_put(typec->ports[i]->ori_sw);
|
||||
typec_mux_put(typec->ports[i]->mux);
|
||||
cros_typec_unregister_port_altmodes(typec->ports[i]);
|
||||
typec_unregister_port(typec->ports[i]->port);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fake the alt mode structs until we actually start registering Type C port
|
||||
* and partner alt modes.
|
||||
* Register port alt modes with known values till we start retrieving
|
||||
* port capabilities from the EC.
|
||||
*/
|
||||
static void cros_typec_register_port_altmodes(struct cros_typec_data *typec,
|
||||
static int cros_typec_register_port_altmodes(struct cros_typec_data *typec,
|
||||
int port_num)
|
||||
{
|
||||
struct cros_typec_port *port = typec->ports[port_num];
|
||||
struct typec_altmode_desc desc;
|
||||
struct typec_altmode *amode;
|
||||
|
||||
/* All PD capable CrOS devices are assumed to support DP altmode. */
|
||||
port->p_altmode[CROS_EC_ALTMODE_DP].svid = USB_TYPEC_DP_SID;
|
||||
port->p_altmode[CROS_EC_ALTMODE_DP].mode = USB_TYPEC_DP_MODE;
|
||||
desc.svid = USB_TYPEC_DP_SID,
|
||||
desc.mode = USB_TYPEC_DP_MODE,
|
||||
desc.vdo = DP_PORT_VDO,
|
||||
amode = typec_port_register_altmode(port->port, &desc);
|
||||
if (IS_ERR(amode))
|
||||
return PTR_ERR(amode);
|
||||
port->port_altmode[CROS_EC_ALTMODE_DP] = amode;
|
||||
|
||||
/*
|
||||
* Register TBT compatibility alt mode. The EC will not enter the mode
|
||||
* if it doesn't support it, so it's safe to register it unconditionally
|
||||
* here for now.
|
||||
*/
|
||||
port->p_altmode[CROS_EC_ALTMODE_TBT].svid = USB_TYPEC_TBT_SID;
|
||||
port->p_altmode[CROS_EC_ALTMODE_TBT].mode = TYPEC_ANY_MODE;
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
desc.svid = USB_TYPEC_TBT_SID,
|
||||
desc.mode = TYPEC_ANY_MODE,
|
||||
amode = typec_port_register_altmode(port->port, &desc);
|
||||
if (IS_ERR(amode))
|
||||
return PTR_ERR(amode);
|
||||
port->port_altmode[CROS_EC_ALTMODE_TBT] = amode;
|
||||
|
||||
port->state.alt = NULL;
|
||||
port->state.mode = TYPEC_STATE_USB;
|
||||
port->state.data = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cros_typec_init_ports(struct cros_typec_data *typec)
|
||||
|
@ -352,8 +376,8 @@ static int cros_typec_init_ports(struct cros_typec_data *typec)
|
|||
|
||||
cros_port->port = typec_register_port(dev, cap);
|
||||
if (IS_ERR(cros_port->port)) {
|
||||
dev_err(dev, "Failed to register port %d\n", port_num);
|
||||
ret = PTR_ERR(cros_port->port);
|
||||
dev_err_probe(dev, ret, "Failed to register port %d\n", port_num);
|
||||
goto unregister_ports;
|
||||
}
|
||||
|
||||
|
@ -362,7 +386,11 @@ static int cros_typec_init_ports(struct cros_typec_data *typec)
|
|||
dev_dbg(dev, "No switch control for port %d\n",
|
||||
port_num);
|
||||
|
||||
cros_typec_register_port_altmodes(typec, port_num);
|
||||
ret = cros_typec_register_port_altmodes(typec, port_num);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register port altmodes\n");
|
||||
goto unregister_ports;
|
||||
}
|
||||
|
||||
cros_port->disc_data = devm_kzalloc(dev, EC_PROTO2_MAX_RESPONSE_SIZE, GFP_KERNEL);
|
||||
if (!cros_port->disc_data) {
|
||||
|
@ -431,7 +459,7 @@ static int cros_typec_enable_tbt(struct cros_typec_data *typec,
|
|||
data.enter_vdo |= TBT_ENTER_MODE_ACTIVE_CABLE;
|
||||
|
||||
if (!port->state.alt) {
|
||||
port->state.alt = &port->p_altmode[CROS_EC_ALTMODE_TBT];
|
||||
port->state.alt = port->port_altmode[CROS_EC_ALTMODE_TBT];
|
||||
ret = cros_typec_usb_safe_state(port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -473,7 +501,7 @@ static int cros_typec_enable_dp(struct cros_typec_data *typec,
|
|||
/* Configuration VDO. */
|
||||
dp_data.conf = DP_CONF_SET_PIN_ASSIGN(pd_ctrl->dp_mode);
|
||||
if (!port->state.alt) {
|
||||
port->state.alt = &port->p_altmode[CROS_EC_ALTMODE_DP];
|
||||
port->state.alt = port->port_altmode[CROS_EC_ALTMODE_DP];
|
||||
ret = cros_typec_usb_safe_state(port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -525,8 +553,8 @@ static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num,
|
|||
enum typec_orientation orientation;
|
||||
int ret;
|
||||
|
||||
ret = cros_ec_command(typec->ec, 0, EC_CMD_USB_PD_MUX_INFO,
|
||||
&req, sizeof(req), &resp, sizeof(resp));
|
||||
ret = cros_ec_cmd(typec->ec, 0, EC_CMD_USB_PD_MUX_INFO,
|
||||
&req, sizeof(req), &resp, sizeof(resp));
|
||||
if (ret < 0) {
|
||||
dev_warn(typec->dev, "Failed to get mux info for port: %d, err = %d\n",
|
||||
port_num, ret);
|
||||
|
@ -585,8 +613,8 @@ mux_ack:
|
|||
/* Sending Acknowledgment to EC */
|
||||
mux_ack.port = port_num;
|
||||
|
||||
if (cros_ec_command(typec->ec, 0, EC_CMD_USB_PD_MUX_ACK, &mux_ack,
|
||||
sizeof(mux_ack), NULL, 0) < 0)
|
||||
if (cros_ec_cmd(typec->ec, 0, EC_CMD_USB_PD_MUX_ACK, &mux_ack,
|
||||
sizeof(mux_ack), NULL, 0) < 0)
|
||||
dev_warn(typec->dev,
|
||||
"Failed to send Mux ACK to EC for port: %d\n",
|
||||
port_num);
|
||||
|
@ -754,8 +782,8 @@ static int cros_typec_handle_sop_prime_disc(struct cros_typec_data *typec, int p
|
|||
int ret = 0;
|
||||
|
||||
memset(disc, 0, EC_PROTO2_MAX_RESPONSE_SIZE);
|
||||
ret = cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req),
|
||||
disc, EC_PROTO2_MAX_RESPONSE_SIZE);
|
||||
ret = cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req),
|
||||
disc, EC_PROTO2_MAX_RESPONSE_SIZE);
|
||||
if (ret < 0) {
|
||||
dev_err(typec->dev, "Failed to get SOP' discovery data for port: %d\n", port_num);
|
||||
goto sop_prime_disc_exit;
|
||||
|
@ -837,8 +865,8 @@ static int cros_typec_handle_sop_disc(struct cros_typec_data *typec, int port_nu
|
|||
typec_partner_set_pd_revision(port->partner, pd_revision);
|
||||
|
||||
memset(sop_disc, 0, EC_PROTO2_MAX_RESPONSE_SIZE);
|
||||
ret = cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req),
|
||||
sop_disc, EC_PROTO2_MAX_RESPONSE_SIZE);
|
||||
ret = cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req),
|
||||
sop_disc, EC_PROTO2_MAX_RESPONSE_SIZE);
|
||||
if (ret < 0) {
|
||||
dev_err(typec->dev, "Failed to get SOP discovery data for port: %d\n", port_num);
|
||||
goto disc_exit;
|
||||
|
@ -870,8 +898,8 @@ static int cros_typec_send_clear_event(struct cros_typec_data *typec, int port_n
|
|||
.clear_events_mask = events_mask,
|
||||
};
|
||||
|
||||
return cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_CONTROL, &req,
|
||||
sizeof(req), NULL, 0);
|
||||
return cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_CONTROL, &req,
|
||||
sizeof(req), NULL, 0);
|
||||
}
|
||||
|
||||
static void cros_typec_handle_status(struct cros_typec_data *typec, int port_num)
|
||||
|
@ -882,8 +910,8 @@ static void cros_typec_handle_status(struct cros_typec_data *typec, int port_num
|
|||
};
|
||||
int ret;
|
||||
|
||||
ret = cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_STATUS, &req, sizeof(req),
|
||||
&resp, sizeof(resp));
|
||||
ret = cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_STATUS, &req, sizeof(req),
|
||||
&resp, sizeof(resp));
|
||||
if (ret < 0) {
|
||||
dev_warn(typec->dev, "EC_CMD_TYPEC_STATUS failed for port: %d\n", port_num);
|
||||
return;
|
||||
|
@ -960,9 +988,9 @@ static int cros_typec_port_update(struct cros_typec_data *typec, int port_num)
|
|||
req.mux = USB_PD_CTRL_MUX_NO_CHANGE;
|
||||
req.swap = USB_PD_CTRL_SWAP_NONE;
|
||||
|
||||
ret = cros_ec_command(typec->ec, typec->pd_ctrl_ver,
|
||||
EC_CMD_USB_PD_CONTROL, &req, sizeof(req),
|
||||
&resp, sizeof(resp));
|
||||
ret = cros_ec_cmd(typec->ec, typec->pd_ctrl_ver,
|
||||
EC_CMD_USB_PD_CONTROL, &req, sizeof(req),
|
||||
&resp, sizeof(resp));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -997,9 +1025,8 @@ static int cros_typec_get_cmd_version(struct cros_typec_data *typec)
|
|||
|
||||
/* We're interested in the PD control command version. */
|
||||
req_v1.cmd = EC_CMD_USB_PD_CONTROL;
|
||||
ret = cros_ec_command(typec->ec, 1, EC_CMD_GET_CMD_VERSIONS,
|
||||
&req_v1, sizeof(req_v1), &resp,
|
||||
sizeof(resp));
|
||||
ret = cros_ec_cmd(typec->ec, 1, EC_CMD_GET_CMD_VERSIONS,
|
||||
&req_v1, sizeof(req_v1), &resp, sizeof(resp));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -1090,8 +1117,8 @@ static int cros_typec_probe(struct platform_device *pdev)
|
|||
typec->typec_cmd_supported = cros_ec_check_features(ec_dev, EC_FEATURE_TYPEC_CMD);
|
||||
typec->needs_mux_ack = cros_ec_check_features(ec_dev, EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK);
|
||||
|
||||
ret = cros_ec_command(typec->ec, 0, EC_CMD_USB_PD_PORTS, NULL, 0,
|
||||
&resp, sizeof(resp));
|
||||
ret = cros_ec_cmd(typec->ec, 0, EC_CMD_USB_PD_PORTS, NULL, 0,
|
||||
&resp, sizeof(resp));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -4,24 +4,60 @@
|
|||
// Copyright (C) 2012 Google, Inc.
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct keyboard_led {
|
||||
struct led_classdev cdev;
|
||||
struct cros_ec_device *ec;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct keyboard_led_drvdata - keyboard LED driver data.
|
||||
* @init: Init function.
|
||||
* @brightness_get: Get LED brightness level.
|
||||
* @brightness_set: Set LED brightness level. Must not sleep.
|
||||
* @brightness_set_blocking: Set LED brightness level. It can block the
|
||||
* caller for the time required for accessing a
|
||||
* LED device register
|
||||
* @max_brightness: Maximum brightness.
|
||||
*
|
||||
* See struct led_classdev in include/linux/leds.h for more details.
|
||||
*/
|
||||
struct keyboard_led_drvdata {
|
||||
int (*init)(struct platform_device *pdev);
|
||||
|
||||
enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);
|
||||
|
||||
void (*brightness_set)(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness);
|
||||
int (*brightness_set_blocking)(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness);
|
||||
|
||||
enum led_brightness max_brightness;
|
||||
};
|
||||
|
||||
#define KEYBOARD_BACKLIGHT_MAX 100
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
||||
/* Keyboard LED ACPI Device must be defined in firmware */
|
||||
#define ACPI_KEYBOARD_BACKLIGHT_DEVICE "\\_SB.KBLT"
|
||||
#define ACPI_KEYBOARD_BACKLIGHT_READ ACPI_KEYBOARD_BACKLIGHT_DEVICE ".KBQC"
|
||||
#define ACPI_KEYBOARD_BACKLIGHT_WRITE ACPI_KEYBOARD_BACKLIGHT_DEVICE ".KBCM"
|
||||
|
||||
#define ACPI_KEYBOARD_BACKLIGHT_MAX 100
|
||||
|
||||
static void keyboard_led_set_brightness(struct led_classdev *cdev,
|
||||
enum led_brightness brightness)
|
||||
static void keyboard_led_set_brightness_acpi(struct led_classdev *cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
union acpi_object param;
|
||||
struct acpi_object_list input;
|
||||
|
@ -40,7 +76,7 @@ static void keyboard_led_set_brightness(struct led_classdev *cdev,
|
|||
}
|
||||
|
||||
static enum led_brightness
|
||||
keyboard_led_get_brightness(struct led_classdev *cdev)
|
||||
keyboard_led_get_brightness_acpi(struct led_classdev *cdev)
|
||||
{
|
||||
unsigned long long brightness;
|
||||
acpi_status status;
|
||||
|
@ -56,12 +92,10 @@ keyboard_led_get_brightness(struct led_classdev *cdev)
|
|||
return brightness;
|
||||
}
|
||||
|
||||
static int keyboard_led_probe(struct platform_device *pdev)
|
||||
static int keyboard_led_init_acpi(struct platform_device *pdev)
|
||||
{
|
||||
struct led_classdev *cdev;
|
||||
acpi_handle handle;
|
||||
acpi_status status;
|
||||
int error;
|
||||
|
||||
/* Look for the keyboard LED ACPI Device */
|
||||
status = acpi_get_handle(ACPI_ROOT_OBJECT,
|
||||
|
@ -73,33 +107,151 @@ static int keyboard_led_probe(struct platform_device *pdev)
|
|||
return -ENXIO;
|
||||
}
|
||||
|
||||
cdev = devm_kzalloc(&pdev->dev, sizeof(*cdev), GFP_KERNEL);
|
||||
if (!cdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct keyboard_led_drvdata keyboard_led_drvdata_acpi = {
|
||||
.init = keyboard_led_init_acpi,
|
||||
.brightness_set = keyboard_led_set_brightness_acpi,
|
||||
.brightness_get = keyboard_led_get_brightness_acpi,
|
||||
.max_brightness = KEYBOARD_BACKLIGHT_MAX,
|
||||
};
|
||||
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
#if IS_ENABLED(CONFIG_CROS_EC)
|
||||
|
||||
static int
|
||||
keyboard_led_set_brightness_ec_pwm(struct led_classdev *cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct {
|
||||
struct cros_ec_command msg;
|
||||
struct ec_params_pwm_set_keyboard_backlight params;
|
||||
} __packed buf;
|
||||
struct ec_params_pwm_set_keyboard_backlight *params = &buf.params;
|
||||
struct cros_ec_command *msg = &buf.msg;
|
||||
struct keyboard_led *keyboard_led = container_of(cdev, struct keyboard_led, cdev);
|
||||
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
|
||||
msg->command = EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT;
|
||||
msg->outsize = sizeof(*params);
|
||||
|
||||
params->percent = brightness;
|
||||
|
||||
return cros_ec_cmd_xfer_status(keyboard_led->ec, msg);
|
||||
}
|
||||
|
||||
static enum led_brightness
|
||||
keyboard_led_get_brightness_ec_pwm(struct led_classdev *cdev)
|
||||
{
|
||||
struct {
|
||||
struct cros_ec_command msg;
|
||||
struct ec_response_pwm_get_keyboard_backlight resp;
|
||||
} __packed buf;
|
||||
struct ec_response_pwm_get_keyboard_backlight *resp = &buf.resp;
|
||||
struct cros_ec_command *msg = &buf.msg;
|
||||
struct keyboard_led *keyboard_led = container_of(cdev, struct keyboard_led, cdev);
|
||||
int ret;
|
||||
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
|
||||
msg->command = EC_CMD_PWM_GET_KEYBOARD_BACKLIGHT;
|
||||
msg->insize = sizeof(*resp);
|
||||
|
||||
ret = cros_ec_cmd_xfer_status(keyboard_led->ec, msg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return resp->percent;
|
||||
}
|
||||
|
||||
static int keyboard_led_init_ec_pwm(struct platform_device *pdev)
|
||||
{
|
||||
struct keyboard_led *keyboard_led = platform_get_drvdata(pdev);
|
||||
|
||||
keyboard_led->ec = dev_get_drvdata(pdev->dev.parent);
|
||||
if (!keyboard_led->ec) {
|
||||
dev_err(&pdev->dev, "no parent EC device\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const __maybe_unused struct keyboard_led_drvdata keyboard_led_drvdata_ec_pwm = {
|
||||
.init = keyboard_led_init_ec_pwm,
|
||||
.brightness_set_blocking = keyboard_led_set_brightness_ec_pwm,
|
||||
.brightness_get = keyboard_led_get_brightness_ec_pwm,
|
||||
.max_brightness = KEYBOARD_BACKLIGHT_MAX,
|
||||
};
|
||||
|
||||
#else /* IS_ENABLED(CONFIG_CROS_EC) */
|
||||
|
||||
static const __maybe_unused struct keyboard_led_drvdata keyboard_led_drvdata_ec_pwm = {};
|
||||
|
||||
#endif /* IS_ENABLED(CONFIG_CROS_EC) */
|
||||
|
||||
static int keyboard_led_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct keyboard_led_drvdata *drvdata;
|
||||
struct keyboard_led *keyboard_led;
|
||||
int error;
|
||||
|
||||
drvdata = device_get_match_data(&pdev->dev);
|
||||
if (!drvdata)
|
||||
return -EINVAL;
|
||||
|
||||
keyboard_led = devm_kzalloc(&pdev->dev, sizeof(*keyboard_led), GFP_KERNEL);
|
||||
if (!keyboard_led)
|
||||
return -ENOMEM;
|
||||
platform_set_drvdata(pdev, keyboard_led);
|
||||
|
||||
cdev->name = "chromeos::kbd_backlight";
|
||||
cdev->max_brightness = ACPI_KEYBOARD_BACKLIGHT_MAX;
|
||||
cdev->flags |= LED_CORE_SUSPENDRESUME;
|
||||
cdev->brightness_set = keyboard_led_set_brightness;
|
||||
cdev->brightness_get = keyboard_led_get_brightness;
|
||||
if (drvdata->init) {
|
||||
error = drvdata->init(pdev);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
error = devm_led_classdev_register(&pdev->dev, cdev);
|
||||
keyboard_led->cdev.name = "chromeos::kbd_backlight";
|
||||
keyboard_led->cdev.flags |= LED_CORE_SUSPENDRESUME;
|
||||
keyboard_led->cdev.max_brightness = drvdata->max_brightness;
|
||||
keyboard_led->cdev.brightness_set = drvdata->brightness_set;
|
||||
keyboard_led->cdev.brightness_set_blocking = drvdata->brightness_set_blocking;
|
||||
keyboard_led->cdev.brightness_get = drvdata->brightness_get;
|
||||
|
||||
error = devm_led_classdev_register(&pdev->dev, &keyboard_led->cdev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id keyboard_led_id[] = {
|
||||
{ "GOOG0002", 0 },
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id keyboard_led_acpi_match[] = {
|
||||
{ "GOOG0002", (kernel_ulong_t)&keyboard_led_drvdata_acpi },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, keyboard_led_id);
|
||||
MODULE_DEVICE_TABLE(acpi, keyboard_led_acpi_match);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id keyboard_led_of_match[] = {
|
||||
{
|
||||
.compatible = "google,cros-kbd-led-backlight",
|
||||
.data = &keyboard_led_drvdata_ec_pwm,
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, keyboard_led_of_match);
|
||||
#endif
|
||||
|
||||
static struct platform_driver keyboard_led_driver = {
|
||||
.driver = {
|
||||
.name = "chromeos-keyboard-leds",
|
||||
.acpi_match_table = ACPI_PTR(keyboard_led_id),
|
||||
.acpi_match_table = ACPI_PTR(keyboard_led_acpi_match),
|
||||
.of_match_table = of_match_ptr(keyboard_led_of_match),
|
||||
},
|
||||
.probe = keyboard_led_probe,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* CrOS Kunit tests utilities.
|
||||
*/
|
||||
|
||||
#include <kunit/test.h>
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
|
||||
#include "cros_ec.h"
|
||||
#include "cros_kunit_util.h"
|
||||
|
||||
int cros_kunit_ec_xfer_mock_default_result;
|
||||
int cros_kunit_ec_xfer_mock_default_ret;
|
||||
int cros_kunit_ec_cmd_xfer_mock_called;
|
||||
int cros_kunit_ec_pkt_xfer_mock_called;
|
||||
|
||||
static struct list_head cros_kunit_ec_xfer_mock_in;
|
||||
static struct list_head cros_kunit_ec_xfer_mock_out;
|
||||
|
||||
int cros_kunit_ec_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)
|
||||
{
|
||||
struct ec_xfer_mock *mock;
|
||||
|
||||
mock = list_first_entry_or_null(&cros_kunit_ec_xfer_mock_in, struct ec_xfer_mock, list);
|
||||
if (!mock) {
|
||||
msg->result = cros_kunit_ec_xfer_mock_default_result;
|
||||
return cros_kunit_ec_xfer_mock_default_ret;
|
||||
}
|
||||
|
||||
list_del(&mock->list);
|
||||
|
||||
memcpy(&mock->msg, msg, sizeof(*msg));
|
||||
if (msg->outsize) {
|
||||
mock->i_data = kunit_kzalloc(mock->test, msg->outsize, GFP_KERNEL);
|
||||
if (mock->i_data)
|
||||
memcpy(mock->i_data, msg->data, msg->outsize);
|
||||
}
|
||||
|
||||
msg->result = mock->result;
|
||||
if (msg->insize)
|
||||
memcpy(msg->data, mock->o_data, min(msg->insize, mock->o_data_len));
|
||||
|
||||
list_add_tail(&mock->list, &cros_kunit_ec_xfer_mock_out);
|
||||
|
||||
return mock->ret;
|
||||
}
|
||||
|
||||
int cros_kunit_ec_cmd_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)
|
||||
{
|
||||
++cros_kunit_ec_cmd_xfer_mock_called;
|
||||
return cros_kunit_ec_xfer_mock(ec_dev, msg);
|
||||
}
|
||||
|
||||
int cros_kunit_ec_pkt_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)
|
||||
{
|
||||
++cros_kunit_ec_pkt_xfer_mock_called;
|
||||
return cros_kunit_ec_xfer_mock(ec_dev, msg);
|
||||
}
|
||||
|
||||
struct ec_xfer_mock *cros_kunit_ec_xfer_mock_add(struct kunit *test, size_t size)
|
||||
{
|
||||
return cros_kunit_ec_xfer_mock_addx(test, size, EC_RES_SUCCESS, size);
|
||||
}
|
||||
|
||||
struct ec_xfer_mock *cros_kunit_ec_xfer_mock_addx(struct kunit *test,
|
||||
int ret, int result, size_t size)
|
||||
{
|
||||
struct ec_xfer_mock *mock;
|
||||
|
||||
mock = kunit_kzalloc(test, sizeof(*mock), GFP_KERNEL);
|
||||
if (!mock)
|
||||
return NULL;
|
||||
|
||||
list_add_tail(&mock->list, &cros_kunit_ec_xfer_mock_in);
|
||||
mock->test = test;
|
||||
|
||||
mock->ret = ret;
|
||||
mock->result = result;
|
||||
mock->o_data = kunit_kzalloc(test, size, GFP_KERNEL);
|
||||
if (!mock->o_data)
|
||||
return NULL;
|
||||
mock->o_data_len = size;
|
||||
|
||||
return mock;
|
||||
}
|
||||
|
||||
struct ec_xfer_mock *cros_kunit_ec_xfer_mock_next(void)
|
||||
{
|
||||
struct ec_xfer_mock *mock;
|
||||
|
||||
mock = list_first_entry_or_null(&cros_kunit_ec_xfer_mock_out, struct ec_xfer_mock, list);
|
||||
if (mock)
|
||||
list_del(&mock->list);
|
||||
|
||||
return mock;
|
||||
}
|
||||
|
||||
int cros_kunit_readmem_mock_offset;
|
||||
u8 *cros_kunit_readmem_mock_data;
|
||||
int cros_kunit_readmem_mock_ret;
|
||||
|
||||
int cros_kunit_readmem_mock(struct cros_ec_device *ec_dev, unsigned int offset,
|
||||
unsigned int bytes, void *dest)
|
||||
{
|
||||
cros_kunit_readmem_mock_offset = offset;
|
||||
|
||||
memcpy(dest, cros_kunit_readmem_mock_data, bytes);
|
||||
|
||||
return cros_kunit_readmem_mock_ret;
|
||||
}
|
||||
|
||||
void cros_kunit_mock_reset(void)
|
||||
{
|
||||
cros_kunit_ec_xfer_mock_default_result = 0;
|
||||
cros_kunit_ec_xfer_mock_default_ret = 0;
|
||||
cros_kunit_ec_cmd_xfer_mock_called = 0;
|
||||
cros_kunit_ec_pkt_xfer_mock_called = 0;
|
||||
INIT_LIST_HEAD(&cros_kunit_ec_xfer_mock_in);
|
||||
INIT_LIST_HEAD(&cros_kunit_ec_xfer_mock_out);
|
||||
|
||||
cros_kunit_readmem_mock_offset = 0;
|
||||
cros_kunit_readmem_mock_data = NULL;
|
||||
cros_kunit_readmem_mock_ret = 0;
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,48 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* CrOS Kunit tests utilities.
|
||||
*/
|
||||
|
||||
#ifndef _CROS_KUNIT_UTIL_H_
|
||||
#define _CROS_KUNIT_UTIL_H_
|
||||
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
|
||||
struct ec_xfer_mock {
|
||||
struct list_head list;
|
||||
struct kunit *test;
|
||||
|
||||
/* input */
|
||||
struct cros_ec_command msg;
|
||||
void *i_data;
|
||||
|
||||
/* output */
|
||||
int ret;
|
||||
int result;
|
||||
void *o_data;
|
||||
u32 o_data_len;
|
||||
};
|
||||
|
||||
extern int cros_kunit_ec_xfer_mock_default_result;
|
||||
extern int cros_kunit_ec_xfer_mock_default_ret;
|
||||
extern int cros_kunit_ec_cmd_xfer_mock_called;
|
||||
extern int cros_kunit_ec_pkt_xfer_mock_called;
|
||||
|
||||
int cros_kunit_ec_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg);
|
||||
int cros_kunit_ec_cmd_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg);
|
||||
int cros_kunit_ec_pkt_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg);
|
||||
struct ec_xfer_mock *cros_kunit_ec_xfer_mock_add(struct kunit *test, size_t size);
|
||||
struct ec_xfer_mock *cros_kunit_ec_xfer_mock_addx(struct kunit *test,
|
||||
int ret, int result, size_t size);
|
||||
struct ec_xfer_mock *cros_kunit_ec_xfer_mock_next(void);
|
||||
|
||||
extern int cros_kunit_readmem_mock_offset;
|
||||
extern u8 *cros_kunit_readmem_mock_data;
|
||||
extern int cros_kunit_readmem_mock_ret;
|
||||
|
||||
int cros_kunit_readmem_mock(struct cros_ec_device *ec_dev, unsigned int offset,
|
||||
unsigned int bytes, void *dest);
|
||||
|
||||
void cros_kunit_mock_reset(void);
|
||||
|
||||
#endif
|
|
@ -71,8 +71,8 @@ static void cros_usbpd_get_event_and_notify(struct device *dev,
|
|||
}
|
||||
|
||||
/* Check for PD host events on EC. */
|
||||
ret = cros_ec_command(ec_dev, 0, EC_CMD_PD_HOST_EVENT_STATUS,
|
||||
NULL, 0, &host_event_status, sizeof(host_event_status));
|
||||
ret = cros_ec_cmd(ec_dev, 0, EC_CMD_PD_HOST_EVENT_STATUS,
|
||||
NULL, 0, &host_event_status, sizeof(host_event_status));
|
||||
if (ret < 0) {
|
||||
dev_warn(dev, "Can't get host event status (err: %d)\n", ret);
|
||||
goto send_notify;
|
||||
|
|
|
@ -343,7 +343,7 @@ static __poll_t event_poll(struct file *filp, poll_table *wait)
|
|||
*
|
||||
* Removes the first event from the queue, places it in the passed buffer.
|
||||
*
|
||||
* If there are no events in the the queue, then one of two things happens,
|
||||
* If there are no events in the queue, then one of two things happens,
|
||||
* depending on if the file was opened in nonblocking mode: If in nonblocking
|
||||
* mode, then return -EAGAIN to say there's no data. If in blocking mode, then
|
||||
* block until an event is available.
|
||||
|
|
|
@ -22,36 +22,6 @@ struct cros_ec_regulator_data {
|
|||
u16 num_voltages;
|
||||
};
|
||||
|
||||
static int cros_ec_cmd(struct cros_ec_device *ec, u32 version, u32 command,
|
||||
void *outdata, u32 outsize, void *indata, u32 insize)
|
||||
{
|
||||
struct cros_ec_command *msg;
|
||||
int ret;
|
||||
|
||||
msg = kzalloc(sizeof(*msg) + max(outsize, insize), GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
msg->version = version;
|
||||
msg->command = command;
|
||||
msg->outsize = outsize;
|
||||
msg->insize = insize;
|
||||
|
||||
if (outdata && outsize > 0)
|
||||
memcpy(msg->data, outdata, outsize);
|
||||
|
||||
ret = cros_ec_cmd_xfer_status(ec, msg);
|
||||
if (ret < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (insize)
|
||||
memcpy(indata, msg->data, insize);
|
||||
|
||||
cleanup:
|
||||
kfree(msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cros_ec_regulator_enable(struct regulator_dev *dev)
|
||||
{
|
||||
struct cros_ec_regulator_data *data = rdev_get_drvdata(dev);
|
||||
|
@ -61,7 +31,7 @@ static int cros_ec_regulator_enable(struct regulator_dev *dev)
|
|||
};
|
||||
|
||||
return cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_ENABLE, &cmd,
|
||||
sizeof(cmd), NULL, 0);
|
||||
sizeof(cmd), NULL, 0);
|
||||
}
|
||||
|
||||
static int cros_ec_regulator_disable(struct regulator_dev *dev)
|
||||
|
@ -73,7 +43,7 @@ static int cros_ec_regulator_disable(struct regulator_dev *dev)
|
|||
};
|
||||
|
||||
return cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_ENABLE, &cmd,
|
||||
sizeof(cmd), NULL, 0);
|
||||
sizeof(cmd), NULL, 0);
|
||||
}
|
||||
|
||||
static int cros_ec_regulator_is_enabled(struct regulator_dev *dev)
|
||||
|
@ -161,7 +131,7 @@ static int cros_ec_regulator_init_info(struct device *dev,
|
|||
int ret;
|
||||
|
||||
ret = cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_GET_INFO, &cmd,
|
||||
sizeof(cmd), &resp, sizeof(resp));
|
||||
sizeof(cmd), &resp, sizeof(resp));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
#ifndef __CROS_EC_COMMANDS_H
|
||||
#define __CROS_EC_COMMANDS_H
|
||||
|
||||
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define BUILD_ASSERT(_cond)
|
||||
|
||||
|
@ -787,7 +787,7 @@ struct ec_host_response {
|
|||
*
|
||||
* Packets always start with a request or response header. They are followed
|
||||
* by data_len bytes of data. If the data_crc_present flag is set, the data
|
||||
* bytes are followed by a CRC-8 of that data, using using x^8 + x^2 + x + 1
|
||||
* bytes are followed by a CRC-8 of that data, using x^8 + x^2 + x + 1
|
||||
* polynomial.
|
||||
*
|
||||
* Host algorithm when sending a request q:
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
#define CROS_EC_DEV_SCP_NAME "cros_scp"
|
||||
#define CROS_EC_DEV_TP_NAME "cros_tp"
|
||||
|
||||
#define CROS_EC_DEV_EC_INDEX 0
|
||||
#define CROS_EC_DEV_PD_INDEX 1
|
||||
|
||||
/*
|
||||
* The EC is unresponsive for a time after a reboot command. Add a
|
||||
* simple delay to make sure that the bus stays locked.
|
||||
|
@ -231,8 +234,8 @@ bool cros_ec_check_features(struct cros_ec_dev *ec, int feature);
|
|||
|
||||
int cros_ec_get_sensor_count(struct cros_ec_dev *ec);
|
||||
|
||||
int cros_ec_command(struct cros_ec_device *ec_dev, unsigned int version, int command, void *outdata,
|
||||
int outsize, void *indata, int insize);
|
||||
int cros_ec_cmd(struct cros_ec_device *ec_dev, unsigned int version, int command, void *outdata,
|
||||
size_t outsize, void *indata, size_t insize);
|
||||
|
||||
/**
|
||||
* cros_ec_get_time_ns() - Return time in ns.
|
||||
|
|
Loading…
Reference in New Issue