Commit 090a7d04 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'tag-chrome-platform-for-v5.10' of...

Merge tag 'tag-chrome-platform-for-v5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux

Pull chrome platform updates from Benson Leung:
 "cros-ec:
   - Error code cleanup across cros-ec by Guenter
   - Remove cros_ec_cmd_xfer in favor of cros_ec_cmd_xfer_status

  cros_ec_typec:
   - Landed initial USB4 support in typec connector class driver for
     cros_ec
   - Role switch bugfix on disconnect, and reordering configuration
     steps

  cros_ec_lightbar:
   - Fix buffer outsize and result for get_lightbar_version

  misc:
   - Remove config MFD_CROS_EC, now that transition from MFD is complete
   - Enable KEY_LEFTMETA in new location on arm based cros-ec-keyboard
     keymap"

* tag 'tag-chrome-platform-for-v5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux:
  ARM: dts: cros-ec-keyboard: Add alternate keymap for KEY_LEFTMETA
  platform/chrome: Use kobj_to_dev() instead of container_of()
  platform/chrome: cros_ec_proto: Drop cros_ec_cmd_xfer()
  platform/chrome: cros_ec_proto: Update cros_ec_cmd_xfer() call-sites
  platform/chrome: Kconfig: Remove the transitional MFD_CROS_EC config
  platform/chrome: cros_ec_lightbar: Reduce ligthbar get version command
  platform/chrome: cros_ec_trace: Add fields to command traces
  platform/chrome: cros_ec_typec: Re-order connector configuration steps
  platform/chrome: cros_ec_typec: Avoid setting usb role twice during disconnect
  platform/chrome: cros_ec_typec: Send enum values to usb_role_switch_set_role()
  platform/chrome: cros_ec_typec: USB4 support
  pwm: cros-ec: Simplify EC error handling
  platform/chrome: cros_ec_proto: Convert EC error codes to Linux error codes
  platform/input: cros_ec: Replace -ENOTSUPP with -ENOPROTOOPT
  pwm: cros-ec: Accept more error codes from cros_ec_cmd_xfer_status
  platform/chrome: cros_ec_sysfs: Report range of error codes from EC
  cros_ec_lightbar: Accept more error codes from cros_ec_cmd_xfer_status
  iio: cros_ec: Accept -EOPNOTSUPP as 'not supported' error code
parents 4a22709e 3e98fd6d
...@@ -46,6 +46,7 @@ MATRIX_KEY(0x02, 0x08, KEY_LEFTBRACE) ...@@ -46,6 +46,7 @@ MATRIX_KEY(0x02, 0x08, KEY_LEFTBRACE)
MATRIX_KEY(0x02, 0x09, KEY_F8) MATRIX_KEY(0x02, 0x09, KEY_F8)
MATRIX_KEY(0x02, 0x0a, KEY_YEN) MATRIX_KEY(0x02, 0x0a, KEY_YEN)
MATRIX_KEY(0x03, 0x00, KEY_LEFTMETA)
MATRIX_KEY(0x03, 0x01, KEY_GRAVE) MATRIX_KEY(0x03, 0x01, KEY_GRAVE)
MATRIX_KEY(0x03, 0x02, KEY_F2) MATRIX_KEY(0x03, 0x02, KEY_F2)
MATRIX_KEY(0x03, 0x03, KEY_5) MATRIX_KEY(0x03, 0x03, KEY_5)
......
...@@ -73,7 +73,7 @@ static int cros_ec_sensors_read(struct iio_dev *indio_dev, ...@@ -73,7 +73,7 @@ static int cros_ec_sensors_read(struct iio_dev *indio_dev,
st->core.param.sensor_offset.flags = 0; st->core.param.sensor_offset.flags = 0;
ret = cros_ec_motion_send_host_cmd(&st->core, 0); ret = cros_ec_motion_send_host_cmd(&st->core, 0);
if (ret == -EPROTO) { if (ret == -EPROTO || ret == -EOPNOTSUPP) {
/* Reading calibscale is not supported on older EC. */ /* Reading calibscale is not supported on older EC. */
*val = 1; *val = 1;
*val2 = 0; *val2 = 0;
......
...@@ -348,7 +348,7 @@ static int cros_ec_keyb_info(struct cros_ec_device *ec_dev, ...@@ -348,7 +348,7 @@ static int cros_ec_keyb_info(struct cros_ec_device *ec_dev,
params->event_type = event_type; params->event_type = event_type;
ret = cros_ec_cmd_xfer_status(ec_dev, msg); ret = cros_ec_cmd_xfer_status(ec_dev, msg);
if (ret == -ENOTSUPP) { if (ret == -ENOPROTOOPT) {
/* With older ECs we just return 0 for everything */ /* With older ECs we just return 0 for everything */
memset(result, 0, result_size); memset(result, 0, result_size);
ret = 0; ret = 0;
......
...@@ -3,16 +3,6 @@ ...@@ -3,16 +3,6 @@
# Platform support for Chrome OS hardware (Chromebooks and Chromeboxes) # Platform support for Chrome OS hardware (Chromebooks and Chromeboxes)
# #
config MFD_CROS_EC
tristate "Platform support for Chrome hardware (transitional)"
select CHROME_PLATFORMS
select CROS_EC
select MFD_CROS_EC_DEV
depends on X86 || ARM || ARM64 || COMPILE_TEST
help
This is a transitional Kconfig option and will be removed after
everyone enables the parts individually.
menuconfig CHROME_PLATFORMS menuconfig CHROME_PLATFORMS
bool "Platform support for Chrome hardware" bool "Platform support for Chrome hardware"
depends on X86 || ARM || ARM64 || COMPILE_TEST depends on X86 || ARM || ARM64 || COMPILE_TEST
......
...@@ -116,8 +116,10 @@ static int get_lightbar_version(struct cros_ec_dev *ec, ...@@ -116,8 +116,10 @@ static int get_lightbar_version(struct cros_ec_dev *ec,
param = (struct ec_params_lightbar *)msg->data; param = (struct ec_params_lightbar *)msg->data;
param->cmd = LIGHTBAR_CMD_VERSION; param->cmd = LIGHTBAR_CMD_VERSION;
msg->outsize = sizeof(param->cmd);
msg->result = sizeof(resp->version);
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
if (ret < 0) { if (ret < 0 && ret != -EINVAL) {
ret = 0; ret = 0;
goto exit; goto exit;
} }
...@@ -298,11 +300,9 @@ static ssize_t sequence_show(struct device *dev, ...@@ -298,11 +300,9 @@ static ssize_t sequence_show(struct device *dev,
goto exit; goto exit;
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
if (ret == -EPROTO) { if (ret < 0) {
ret = scnprintf(buf, PAGE_SIZE, ret = scnprintf(buf, PAGE_SIZE, "XFER / EC ERROR %d / %d\n",
"ERROR: EC returned %d\n", msg->result); ret, msg->result);
goto exit;
} else if (ret < 0) {
goto exit; goto exit;
} }
......
...@@ -15,6 +15,43 @@ ...@@ -15,6 +15,43 @@
#define EC_COMMAND_RETRIES 50 #define EC_COMMAND_RETRIES 50
static const int cros_ec_error_map[] = {
[EC_RES_INVALID_COMMAND] = -EOPNOTSUPP,
[EC_RES_ERROR] = -EIO,
[EC_RES_INVALID_PARAM] = -EINVAL,
[EC_RES_ACCESS_DENIED] = -EACCES,
[EC_RES_INVALID_RESPONSE] = -EPROTO,
[EC_RES_INVALID_VERSION] = -ENOPROTOOPT,
[EC_RES_INVALID_CHECKSUM] = -EBADMSG,
[EC_RES_IN_PROGRESS] = -EINPROGRESS,
[EC_RES_UNAVAILABLE] = -ENODATA,
[EC_RES_TIMEOUT] = -ETIMEDOUT,
[EC_RES_OVERFLOW] = -EOVERFLOW,
[EC_RES_INVALID_HEADER] = -EBADR,
[EC_RES_REQUEST_TRUNCATED] = -EBADR,
[EC_RES_RESPONSE_TOO_BIG] = -EFBIG,
[EC_RES_BUS_ERROR] = -EFAULT,
[EC_RES_BUSY] = -EBUSY,
[EC_RES_INVALID_HEADER_VERSION] = -EBADMSG,
[EC_RES_INVALID_HEADER_CRC] = -EBADMSG,
[EC_RES_INVALID_DATA_CRC] = -EBADMSG,
[EC_RES_DUP_UNAVAILABLE] = -ENODATA,
};
static int cros_ec_map_error(uint32_t result)
{
int ret = 0;
if (result != EC_RES_SUCCESS) {
if (result < ARRAY_SIZE(cros_ec_error_map) && cros_ec_error_map[result])
ret = cros_ec_error_map[result];
else
ret = -EPROTO;
}
return ret;
}
static int prepare_packet(struct cros_ec_device *ec_dev, static int prepare_packet(struct cros_ec_device *ec_dev,
struct cros_ec_command *msg) struct cros_ec_command *msg)
{ {
...@@ -512,19 +549,22 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev) ...@@ -512,19 +549,22 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev)
EXPORT_SYMBOL(cros_ec_query_all); EXPORT_SYMBOL(cros_ec_query_all);
/** /**
* cros_ec_cmd_xfer() - Send a command to the ChromeOS EC. * cros_ec_cmd_xfer_status() - Send a command to the ChromeOS EC.
* @ec_dev: EC device. * @ec_dev: EC device.
* @msg: Message to write. * @msg: Message to write.
* *
* Call this to send a command to the ChromeOS EC. This should be used * Call this to send a command to the ChromeOS EC. This should be used instead of calling the EC's
* instead of calling the EC's cmd_xfer() callback directly. * cmd_xfer() callback directly. It returns success status only if both the command was transmitted
* successfully and the EC replied with success status.
* *
* Return: 0 on success or negative error code. * Return:
* >=0 - The number of bytes transferred
* <0 - Linux error code
*/ */
static int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
struct cros_ec_command *msg) struct cros_ec_command *msg)
{ {
int ret; int ret, mapped;
mutex_lock(&ec_dev->lock); mutex_lock(&ec_dev->lock);
if (ec_dev->proto_version == EC_PROTO_VERSION_UNKNOWN) { if (ec_dev->proto_version == EC_PROTO_VERSION_UNKNOWN) {
...@@ -561,42 +601,15 @@ static int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, ...@@ -561,42 +601,15 @@ static int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
return -EMSGSIZE; return -EMSGSIZE;
} }
} }
ret = send_command(ec_dev, msg); ret = send_command(ec_dev, msg);
mutex_unlock(&ec_dev->lock); mutex_unlock(&ec_dev->lock);
return ret; mapped = cros_ec_map_error(msg->result);
} if (mapped) {
dev_dbg(ec_dev->dev, "Command result (err: %d [%d])\n",
/** msg->result, mapped);
* cros_ec_cmd_xfer_status() - Send a command to the ChromeOS EC. ret = mapped;
* @ec_dev: EC device.
* @msg: Message to write.
*
* This function is identical to cros_ec_cmd_xfer, except it returns success
* status only if both the command was transmitted successfully and the EC
* replied with success status. It's not necessary to check msg->result when
* using this function.
*
* Return:
* >=0 - The number of bytes transferred
* -ENOTSUPP - Operation not supported
* -EPROTO - Protocol error
*/
int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
struct cros_ec_command *msg)
{
int ret;
ret = cros_ec_cmd_xfer(ec_dev, msg);
if (ret < 0) {
dev_err(ec_dev->dev, "Command xfer error (err:%d)\n", ret);
} else if (msg->result == EC_RES_INVALID_VERSION) {
dev_dbg(ec_dev->dev, "Command invalid version (err:%d)\n",
msg->result);
return -ENOTSUPP;
} else if (msg->result != EC_RES_SUCCESS) {
dev_dbg(ec_dev->dev, "Command result (err: %d)\n", msg->result);
return -EPROTO;
} }
return ret; return ret;
...@@ -615,7 +628,7 @@ static int get_next_event_xfer(struct cros_ec_device *ec_dev, ...@@ -615,7 +628,7 @@ static int get_next_event_xfer(struct cros_ec_device *ec_dev,
msg->insize = size; msg->insize = size;
msg->outsize = 0; msg->outsize = 0;
ret = cros_ec_cmd_xfer(ec_dev, msg); ret = cros_ec_cmd_xfer_status(ec_dev, msg);
if (ret > 0) { if (ret > 0) {
ec_dev->event_size = ret - 1; ec_dev->event_size = ret - 1;
ec_dev->event_data = *event; ec_dev->event_data = *event;
...@@ -659,7 +672,7 @@ static int get_keyboard_state_event(struct cros_ec_device *ec_dev) ...@@ -659,7 +672,7 @@ static int get_keyboard_state_event(struct cros_ec_device *ec_dev)
msg->insize = sizeof(ec_dev->event_data.data); msg->insize = sizeof(ec_dev->event_data.data);
msg->outsize = 0; msg->outsize = 0;
ec_dev->event_size = cros_ec_cmd_xfer(ec_dev, msg); ec_dev->event_size = cros_ec_cmd_xfer_status(ec_dev, msg);
ec_dev->event_data.event_type = EC_MKBP_EVENT_KEY_MATRIX; ec_dev->event_data.event_type = EC_MKBP_EVENT_KEY_MATRIX;
memcpy(&ec_dev->event_data.data, msg->data, memcpy(&ec_dev->event_data.data, msg->data,
sizeof(ec_dev->event_data.data)); sizeof(ec_dev->event_data.data));
...@@ -848,11 +861,9 @@ int cros_ec_get_sensor_count(struct cros_ec_dev *ec) ...@@ -848,11 +861,9 @@ int cros_ec_get_sensor_count(struct cros_ec_dev *ec)
params = (struct ec_params_motion_sense *)msg->data; params = (struct ec_params_motion_sense *)msg->data;
params->cmd = MOTIONSENSE_CMD_DUMP; params->cmd = MOTIONSENSE_CMD_DUMP;
ret = cros_ec_cmd_xfer(ec->ec_dev, msg); ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
if (ret < 0) { if (ret < 0) {
sensor_count = ret; sensor_count = ret;
} else if (msg->result != EC_RES_SUCCESS) {
sensor_count = -EPROTO;
} else { } else {
resp = (struct ec_response_motion_sense *)msg->data; resp = (struct ec_response_motion_sense *)msg->data;
sensor_count = resp->dump.sensor_count; sensor_count = resp->dump.sensor_count;
...@@ -863,9 +874,7 @@ int cros_ec_get_sensor_count(struct cros_ec_dev *ec) ...@@ -863,9 +874,7 @@ int cros_ec_get_sensor_count(struct cros_ec_dev *ec)
* Check legacy mode: Let's find out if sensors are accessible * Check legacy mode: Let's find out if sensors are accessible
* via LPC interface. * via LPC interface.
*/ */
if (sensor_count == -EPROTO && if (sensor_count < 0 && ec->cmd_offset == 0 && ec_dev->cmd_readmem) {
ec->cmd_offset == 0 &&
ec_dev->cmd_readmem) {
ret = ec_dev->cmd_readmem(ec_dev, EC_MEMMAP_ACC_STATUS, ret = ec_dev->cmd_readmem(ec_dev, EC_MEMMAP_ACC_STATUS,
1, &status); 1, &status);
if (ret >= 0 && if (ret >= 0 &&
...@@ -880,9 +889,6 @@ int cros_ec_get_sensor_count(struct cros_ec_dev *ec) ...@@ -880,9 +889,6 @@ int cros_ec_get_sensor_count(struct cros_ec_dev *ec)
*/ */
sensor_count = 0; sensor_count = 0;
} }
} else if (sensor_count == -EPROTO) {
/* EC responded, but does not understand DUMP command. */
sensor_count = 0;
} }
return sensor_count; return sensor_count;
} }
......
...@@ -150,12 +150,10 @@ static ssize_t version_show(struct device *dev, ...@@ -150,12 +150,10 @@ static ssize_t version_show(struct device *dev,
msg->command = EC_CMD_GET_BUILD_INFO + ec->cmd_offset; msg->command = EC_CMD_GET_BUILD_INFO + ec->cmd_offset;
msg->insize = EC_HOST_PARAM_SIZE; msg->insize = EC_HOST_PARAM_SIZE;
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
if (ret == -EPROTO) { if (ret < 0) {
count += scnprintf(buf + count, PAGE_SIZE - count,
"Build info: EC error %d\n", msg->result);
} else if (ret < 0) {
count += scnprintf(buf + count, PAGE_SIZE - count, count += scnprintf(buf + count, PAGE_SIZE - count,
"Build info: XFER ERROR %d\n", ret); "Build info: XFER / EC ERROR %d / %d\n",
ret, msg->result);
} else { } else {
msg->data[EC_HOST_PARAM_SIZE - 1] = '\0'; msg->data[EC_HOST_PARAM_SIZE - 1] = '\0';
count += scnprintf(buf + count, PAGE_SIZE - count, count += scnprintf(buf + count, PAGE_SIZE - count,
...@@ -166,12 +164,10 @@ static ssize_t version_show(struct device *dev, ...@@ -166,12 +164,10 @@ static ssize_t version_show(struct device *dev,
msg->command = EC_CMD_GET_CHIP_INFO + ec->cmd_offset; msg->command = EC_CMD_GET_CHIP_INFO + ec->cmd_offset;
msg->insize = sizeof(*r_chip); msg->insize = sizeof(*r_chip);
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
if (ret == -EPROTO) { if (ret < 0) {
count += scnprintf(buf + count, PAGE_SIZE - count,
"Chip info: EC error %d\n", msg->result);
} else if (ret < 0) {
count += scnprintf(buf + count, PAGE_SIZE - count, count += scnprintf(buf + count, PAGE_SIZE - count,
"Chip info: XFER ERROR %d\n", ret); "Chip info: XFER / EC ERROR %d / %d\n",
ret, msg->result);
} else { } else {
r_chip = (struct ec_response_get_chip_info *)msg->data; r_chip = (struct ec_response_get_chip_info *)msg->data;
...@@ -190,12 +186,10 @@ static ssize_t version_show(struct device *dev, ...@@ -190,12 +186,10 @@ static ssize_t version_show(struct device *dev,
msg->command = EC_CMD_GET_BOARD_VERSION + ec->cmd_offset; msg->command = EC_CMD_GET_BOARD_VERSION + ec->cmd_offset;
msg->insize = sizeof(*r_board); msg->insize = sizeof(*r_board);
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
if (ret == -EPROTO) { if (ret < 0) {
count += scnprintf(buf + count, PAGE_SIZE - count,
"Board version: EC error %d\n", msg->result);
} else if (ret < 0) {
count += scnprintf(buf + count, PAGE_SIZE - count, count += scnprintf(buf + count, PAGE_SIZE - count,
"Board version: XFER ERROR %d\n", ret); "Board version: XFER / EC ERROR %d / %d\n",
ret, msg->result);
} else { } else {
r_board = (struct ec_response_board_version *)msg->data; r_board = (struct ec_response_board_version *)msg->data;
...@@ -326,7 +320,7 @@ static struct attribute *__ec_attrs[] = { ...@@ -326,7 +320,7 @@ static struct attribute *__ec_attrs[] = {
static umode_t cros_ec_ctrl_visible(struct kobject *kobj, static umode_t cros_ec_ctrl_visible(struct kobject *kobj,
struct attribute *a, int n) struct attribute *a, int n)
{ {
struct device *dev = container_of(kobj, struct device, kobj); struct device *dev = kobj_to_dev(kobj);
struct cros_ec_dev *ec = to_cros_ec_dev(dev); struct cros_ec_dev *ec = to_cros_ec_dev(dev);
if (a == &dev_attr_kb_wake_angle.attr && !ec->has_kb_wake_angle) if (a == &dev_attr_kb_wake_angle.attr && !ec->has_kb_wake_angle)
......
...@@ -23,14 +23,22 @@ TRACE_EVENT(cros_ec_request_start, ...@@ -23,14 +23,22 @@ TRACE_EVENT(cros_ec_request_start,
TP_ARGS(cmd), TP_ARGS(cmd),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(uint32_t, version) __field(uint32_t, version)
__field(uint32_t, offset)
__field(uint32_t, command) __field(uint32_t, command)
__field(uint32_t, outsize)
__field(uint32_t, insize)
), ),
TP_fast_assign( TP_fast_assign(
__entry->version = cmd->version; __entry->version = cmd->version;
__entry->command = cmd->command; __entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(1);
__entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(1);
__entry->outsize = cmd->outsize;
__entry->insize = cmd->insize;
), ),
TP_printk("version: %u, command: %s", __entry->version, TP_printk("version: %u, offset: %d, command: %s, outsize: %u, insize: %u",
__print_symbolic(__entry->command, EC_CMDS)) __entry->version, __entry->offset,
__print_symbolic(__entry->command, EC_CMDS),
__entry->outsize, __entry->insize)
); );
TRACE_EVENT(cros_ec_request_done, TRACE_EVENT(cros_ec_request_done,
...@@ -38,19 +46,26 @@ TRACE_EVENT(cros_ec_request_done, ...@@ -38,19 +46,26 @@ TRACE_EVENT(cros_ec_request_done,
TP_ARGS(cmd, retval), TP_ARGS(cmd, retval),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(uint32_t, version) __field(uint32_t, version)
__field(uint32_t, offset)
__field(uint32_t, command) __field(uint32_t, command)
__field(uint32_t, outsize)
__field(uint32_t, insize)
__field(uint32_t, result) __field(uint32_t, result)
__field(int, retval) __field(int, retval)
), ),
TP_fast_assign( TP_fast_assign(
__entry->version = cmd->version; __entry->version = cmd->version;
__entry->command = cmd->command; __entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(1);
__entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(1);
__entry->outsize = cmd->outsize;
__entry->insize = cmd->insize;
__entry->result = cmd->result; __entry->result = cmd->result;
__entry->retval = retval; __entry->retval = retval;
), ),
TP_printk("version: %u, command: %s, ec result: %s, retval: %d", TP_printk("version: %u, offset: %d, command: %s, outsize: %u, insize: %u, ec result: %s, retval: %u",
__entry->version, __entry->version, __entry->offset,
__print_symbolic(__entry->command, EC_CMDS), __print_symbolic(__entry->command, EC_CMDS),
__entry->outsize, __entry->insize,
__print_symbolic(__entry->result, EC_RESULT), __print_symbolic(__entry->result, EC_RESULT),
__entry->retval) __entry->retval)
); );
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/platform_data/cros_ec_proto.h> #include <linux/platform_data/cros_ec_proto.h>
#include <linux/platform_data/cros_usbpd_notify.h> #include <linux/platform_data/cros_usbpd_notify.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/usb/pd.h>
#include <linux/usb/typec.h> #include <linux/usb/typec.h>
#include <linux/usb/typec_altmode.h> #include <linux/usb/typec_altmode.h>
#include <linux/usb/typec_dp.h> #include <linux/usb/typec_dp.h>
...@@ -496,6 +497,34 @@ static int cros_typec_enable_dp(struct cros_typec_data *typec, ...@@ -496,6 +497,34 @@ static int cros_typec_enable_dp(struct cros_typec_data *typec,
return typec_mux_set(port->mux, &port->state); return typec_mux_set(port->mux, &port->state);
} }
static int cros_typec_enable_usb4(struct cros_typec_data *typec,
int port_num,
struct ec_response_usb_pd_control_v2 *pd_ctrl)
{
struct cros_typec_port *port = typec->ports[port_num];
struct enter_usb_data data;
data.eudo = EUDO_USB_MODE_USB4 << EUDO_USB_MODE_SHIFT;
/* Cable Speed */
data.eudo |= pd_ctrl->cable_speed << EUDO_CABLE_SPEED_SHIFT;
/* Cable Type */
if (pd_ctrl->control_flags & USB_PD_CTRL_OPTICAL_CABLE)
data.eudo |= EUDO_CABLE_TYPE_OPTICAL << EUDO_CABLE_TYPE_SHIFT;
else if (pd_ctrl->control_flags & USB_PD_CTRL_ACTIVE_CABLE)
data.eudo |= EUDO_CABLE_TYPE_RE_TIMER << EUDO_CABLE_TYPE_SHIFT;
data.active_link_training = !!(pd_ctrl->control_flags &
USB_PD_CTRL_ACTIVE_LINK_UNIDIR);
port->state.alt = NULL;
port->state.data = &data;
port->state.mode = TYPEC_MODE_USB4;
return typec_mux_set(port->mux, &port->state);
}
static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num, static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num,
uint8_t mux_flags, uint8_t mux_flags,
struct ec_response_usb_pd_control_v2 *pd_ctrl) struct ec_response_usb_pd_control_v2 *pd_ctrl)
...@@ -516,7 +545,15 @@ static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num, ...@@ -516,7 +545,15 @@ static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num,
if (ret) if (ret)
return ret; return ret;
if (mux_flags & USB_PD_MUX_TBT_COMPAT_ENABLED) { ret = usb_role_switch_set_role(typec->ports[port_num]->role_sw,
pd_ctrl->role & PD_CTRL_RESP_ROLE_DATA
? USB_ROLE_HOST : USB_ROLE_DEVICE);
if (ret)
return ret;
if (mux_flags & USB_PD_MUX_USB4_ENABLED) {
ret = cros_typec_enable_usb4(typec, port_num, pd_ctrl);
} else if (mux_flags & USB_PD_MUX_TBT_COMPAT_ENABLED) {
ret = cros_typec_enable_tbt(typec, port_num, pd_ctrl); ret = cros_typec_enable_tbt(typec, port_num, pd_ctrl);
} else if (mux_flags & USB_PD_MUX_DP_ENABLED) { } else if (mux_flags & USB_PD_MUX_DP_ENABLED) {
ret = cros_typec_enable_dp(typec, port_num, pd_ctrl); ret = cros_typec_enable_dp(typec, port_num, pd_ctrl);
...@@ -590,8 +627,7 @@ static int cros_typec_port_update(struct cros_typec_data *typec, int port_num) ...@@ -590,8 +627,7 @@ static int cros_typec_port_update(struct cros_typec_data *typec, int port_num)
if (ret) if (ret)
dev_warn(typec->dev, "Configure muxes failed, err = %d\n", ret); dev_warn(typec->dev, "Configure muxes failed, err = %d\n", ret);
return usb_role_switch_set_role(typec->ports[port_num]->role_sw, return ret;
!!(resp.role & PD_CTRL_RESP_ROLE_DATA));
} }
static int cros_typec_get_cmd_version(struct cros_typec_data *typec) static int cros_typec_get_cmd_version(struct cros_typec_data *typec)
......
...@@ -17,7 +17,7 @@ static ssize_t vboot_context_read(struct file *filp, struct kobject *kobj, ...@@ -17,7 +17,7 @@ static ssize_t vboot_context_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *att, char *buf, struct bin_attribute *att, char *buf,
loff_t pos, size_t count) loff_t pos, size_t count)
{ {
struct device *dev = container_of(kobj, struct device, kobj); struct device *dev = kobj_to_dev(kobj);
struct cros_ec_dev *ec = to_cros_ec_dev(dev); struct cros_ec_dev *ec = to_cros_ec_dev(dev);
struct cros_ec_device *ecdev = ec->ec_dev; struct cros_ec_device *ecdev = ec->ec_dev;
struct ec_params_vbnvcontext *params; struct ec_params_vbnvcontext *params;
...@@ -57,7 +57,7 @@ static ssize_t vboot_context_write(struct file *filp, struct kobject *kobj, ...@@ -57,7 +57,7 @@ static ssize_t vboot_context_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr, char *buf, struct bin_attribute *attr, char *buf,
loff_t pos, size_t count) loff_t pos, size_t count)
{ {
struct device *dev = container_of(kobj, struct device, kobj); struct device *dev = kobj_to_dev(kobj);
struct cros_ec_dev *ec = to_cros_ec_dev(dev); struct cros_ec_dev *ec = to_cros_ec_dev(dev);
struct cros_ec_device *ecdev = ec->ec_dev; struct cros_ec_device *ecdev = ec->ec_dev;
struct ec_params_vbnvcontext *params; struct ec_params_vbnvcontext *params;
......
...@@ -81,8 +81,7 @@ static int cros_ec_pwm_set_duty(struct cros_ec_device *ec, u8 index, u16 duty) ...@@ -81,8 +81,7 @@ static int cros_ec_pwm_set_duty(struct cros_ec_device *ec, u8 index, u16 duty)
return cros_ec_cmd_xfer_status(ec, msg); return cros_ec_cmd_xfer_status(ec, msg);
} }
static int __cros_ec_pwm_get_duty(struct cros_ec_device *ec, u8 index, static int cros_ec_pwm_get_duty(struct cros_ec_device *ec, u8 index)
u32 *result)
{ {
struct { struct {
struct cros_ec_command msg; struct cros_ec_command msg;
...@@ -107,19 +106,12 @@ static int __cros_ec_pwm_get_duty(struct cros_ec_device *ec, u8 index, ...@@ -107,19 +106,12 @@ static int __cros_ec_pwm_get_duty(struct cros_ec_device *ec, u8 index,
params->index = index; params->index = index;
ret = cros_ec_cmd_xfer_status(ec, msg); ret = cros_ec_cmd_xfer_status(ec, msg);
if (result)
*result = msg->result;
if (ret < 0) if (ret < 0)
return ret; return ret;
return resp->duty; return resp->duty;
} }
static int cros_ec_pwm_get_duty(struct cros_ec_device *ec, u8 index)
{
return __cros_ec_pwm_get_duty(ec, index, NULL);
}
static int cros_ec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, static int cros_ec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
const struct pwm_state *state) const struct pwm_state *state)
{ {
...@@ -204,29 +196,34 @@ static const struct pwm_ops cros_ec_pwm_ops = { ...@@ -204,29 +196,34 @@ static const struct pwm_ops cros_ec_pwm_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
/*
* Determine the number of supported PWMs. The EC does not return the number
* of PWMs it supports directly, so we have to read the pwm duty cycle for
* subsequent channels until we get an error.
*/
static int cros_ec_num_pwms(struct cros_ec_device *ec) static int cros_ec_num_pwms(struct cros_ec_device *ec)
{ {
int i, ret; int i, ret;
/* The index field is only 8 bits */ /* The index field is only 8 bits */
for (i = 0; i <= U8_MAX; i++) { for (i = 0; i <= U8_MAX; i++) {
u32 result = 0; ret = cros_ec_pwm_get_duty(ec, i);
ret = __cros_ec_pwm_get_duty(ec, i, &result);
/* We want to parse EC protocol errors */
if (ret < 0 && !(ret == -EPROTO && result))
return ret;
/* /*
* We look for SUCCESS, INVALID_COMMAND, or INVALID_PARAM * We look for SUCCESS, INVALID_COMMAND, or INVALID_PARAM
* responses; everything else is treated as an error. * responses; everything else is treated as an error.
* The EC error codes map to -EOPNOTSUPP and -EINVAL,
* so check for those.
*/ */
if (result == EC_RES_INVALID_COMMAND) switch (ret) {
case -EOPNOTSUPP: /* invalid command */
return -ENODEV; return -ENODEV;
else if (result == EC_RES_INVALID_PARAM) case -EINVAL: /* invalid parameter */
return i; return i;
else if (result) default:
return -EPROTO; if (ret < 0)
return ret;
break;
}
} }
return U8_MAX; return U8_MAX;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment