USB Type-C Connector System Software Interface (UCSI) is specification that defines the registers and data structures that can be used to control USB Type-C ports on a system. UCSI is used on several Intel Broxton SoC based platforms. Things that UCSI can be used to control include at least USB Data Role swapping, Power Role swapping and controlling of Alternate Modes on top of providing general details about the port and the partners that are attached to it. The initial purpose of the UCSI driver is to allow the user to define a preferred USB Data Role - Host or Device - which will be used on the port in cases where both the USB Type-C port on the running system and the partner are Dual Role capable. In those cases with USB Type-C ports the role will get selected randomly. Most mobile systems will want to use USB in peripheral (device) mode by default, and in many cases Desktop systems, Linux distributions etc., want to use USB in Host mode. The preferred data role is delivered to the driver with a simple module parameter "usb_data_role". The goal is to integrate the driver later to an USB Type-C framework for Linux kernel, and at the same time add support for more extensive USB Type-C port control that UCSI offers, for example Power Role swapping, Alternate Mode control etc. The UCSI specification is public can be obtained from here: http://www.intel.com/content/www/us/en/io/universal-serial-bus/usb-type-c-ucsi-spec.html Signed-off-by: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx> --- Documentation/kernel-parameters.txt | 13 ++ drivers/usb/misc/Kconfig | 24 ++ drivers/usb/misc/Makefile | 1 + drivers/usb/misc/ucsi.c | 430 ++++++++++++++++++++++++++++++++++++ drivers/usb/misc/ucsi.h | 198 +++++++++++++++++ 5 files changed, 666 insertions(+) create mode 100644 drivers/usb/misc/ucsi.c create mode 100644 drivers/usb/misc/ucsi.h Hi guys, I'm not going to be able to give any users for the USB Type-C Class yet so I'm proposing this separated UCSI driver for now. It will provide control over the USB data role and nothing else at this point. We would need the driver to support the Broxton SoC based products that are coming soon to the market. With the mobile products, being able to control the data role is important. The default mode should really be device mode with those. That is what the user will expect. The user will definitely not like it if he/she has to unplug/replug the cable in order to attempt to get the USB into device mode so he/she can charge his/her phone or tablet. Thanks, diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index f4109de..53c4bee 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -4039,6 +4039,19 @@ bytes respectively. Such letter suffixes can also be entirely omitted. <port#>,<js1>,<js2>,<js3>,<js4>,<js5>,<js6>,<js7> See also Documentation/input/joystick-parport.txt + ucsi.usb_data_role= + [USB] On dual role capable systems, select the preferred + USB Data Role for the USB Type-C ports - host or device. + + After connection to an other dual role capable system, + if the partner gets the preferred role, UCSI driver + executes data role swap as defined in USB Type-C + specification. + + On desktop systems host role is often preferred, and on + mobile systems device role is usually preferred as the + default data role. + udbg-immortal [PPC] When debugging early kernel crashes that happen after console_init() and before a proper console driver takes over, this boot options might diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index f7a7fc2..7cd5cbc 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -268,3 +268,27 @@ config USB_CHAOSKEY To compile this driver as a module, choose M here: the module will be called chaoskey. + +config UCSI + tristate "USB Type-C Connector System Software Interface driver" + depends on ACPI + help + USB Type-C Connector System Software Interface (UCSI) is a + specification for an interface that allows the Operating System to + control the USB Type-C ports on a system. Things the need controlling + include the USB Data Role (host or device), and when USB Power + Delivery is supported, the Power Role (source or sink). With USB + Type-C Connectors, when two Dual Role capable devices are attached + together, the Data Role is selected randomly. Therefore it is + important to give the OS a way to select the role. Otherwise the user + would have to unplug and replug in order in order to attempt to swap + the Data and Power Role. + + The UCSI interface is initially used on various Intel based platforms + for example on many Intel Broxton SoC based products. + + The UCSI specification can be downloaded from: + http://www.intel.com/content/www/us/en/io/universal-serial-bus/usb-type-c-ucsi-spec.html + + To compile the driver as a module, choose M here: the module will be + called ucsi. diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 45fd4ac..2769cf6 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_USB_SEVSEG) += usbsevseg.o obj-$(CONFIG_USB_YUREX) += yurex.o obj-$(CONFIG_USB_HSIC_USB3503) += usb3503.o obj-$(CONFIG_USB_CHAOSKEY) += chaoskey.o +obj-$(CONFIG_UCSI) += ucsi.o obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ obj-$(CONFIG_USB_LINK_LAYER_TEST) += lvstest.o diff --git a/drivers/usb/misc/ucsi.c b/drivers/usb/misc/ucsi.c new file mode 100644 index 0000000..13939ab --- /dev/null +++ b/drivers/usb/misc/ucsi.c @@ -0,0 +1,430 @@ +/* + * USB Type-C Connector System Software Interface driver + * + * Copyright (C) 2016, Intel Corporation + * Author: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/acpi.h> + +#include "ucsi.h" + +#define PPM_TIMEOUT 50 +#define UCSI_ERROR 1 +#define UCSI_BUSY 2 + +#define cci_to_connector(_ucsi_, cci) \ + (_ucsi_->connector + UCSI_CCI_CONNECTOR_CHANGE(cci) - 1) + +struct ucsi_connector { + int num; + struct ucsi *ucsi; + struct work_struct work; + struct ucsi_connector_capability cap; +}; + +struct ucsi { + struct device *dev; + struct ucsi_data __iomem *data; + + int status; + struct completion complete; + struct ucsi_capability cap; + struct ucsi_connector *connector; + + struct mutex ppm_lock; + atomic_t event_pending; +}; + +static char data_role[7]; +module_param_string(usb_data_role, data_role, sizeof(data_role), 0644); +MODULE_PARM_DESC(usb_data_role, " USB Data Role - host or device"); + +static int ucsi_acpi_cmd(struct ucsi *ucsi, u64 ctrl) +{ + static const u8 ucsi_uuid[] = { + 0xc2, 0x98, 0x83, 0x6f, 0xa4, 0x7c, 0xe4, 0x11, + 0xad, 0x36, 0x63, 0x10, 0x42, 0xb5, 0x00, 0x8f, + }; + union acpi_object *obj; + + ucsi->data->control = ctrl; + + obj = acpi_evaluate_dsm(ACPI_HANDLE(ucsi->dev), ucsi_uuid, 1, 1, NULL); + if (!obj) { + dev_err(ucsi->dev, "%s: failed to evaluate _DSM\n", __func__); + return -EIO; + } + + ACPI_FREE(obj); + return 0; +} + +static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data) +{ + struct ucsi *ucsi = data; + u32 cci = ucsi->data->cci; + + dev_dbg(ucsi->dev, "%s: cci 0x%x\n", __func__, cci); + + if (!cci) { + if (atomic_read(&ucsi->event_pending)) + complete(&ucsi->complete); + return; + } + + ucsi->status = 0; + + if (UCSI_CCI_CONNECTOR_CHANGE(cci)) { + struct ucsi_connector *con = cci_to_connector(ucsi, cci); + + if (!ucsi->connector) + goto no_connector; + + if (!atomic_read(&ucsi->event_pending)) { + atomic_inc(&ucsi->event_pending); + schedule_work(&con->work); + return; + } + } +no_connector: + if (cci & UCSI_CCI_BUSY) + ucsi->status = UCSI_BUSY; + + if (cci & UCSI_CCI_ERROR) + ucsi->status = UCSI_ERROR; + + if (cci & UCSI_CCI_ACK_CMD || cci & UCSI_CCI_CMD_COMPLETED) { + ucsi->data->control = 0; + complete(&ucsi->complete); + } +} + +static int ucsi_ack(struct ucsi *ucsi, u8 cmd) +{ + struct ucsi_control *ctrl; + u64 control; + int ret; + + ctrl = (void *)&control; + + ctrl->cmd = UCSI_ACK_CC_CI; + ctrl->data = cmd; + + ret = ucsi_acpi_cmd(ucsi, control); + if (ret) + return ret; + + /* Waiting for ACK also with ACK CMD for now */ + wait_for_completion(&ucsi->complete); + return 0; +} + +static int ucsi_run_cmd(struct ucsi *ucsi, u64 *ctrl, void *data, size_t size) +{ + int status; + int ret; + + dev_dbg(ucsi->dev, "%s control 0x%llx\n", __func__, *ctrl); + + ret = ucsi_acpi_cmd(ucsi, *ctrl); + if (ret) + return ret; + + /* REVISIT: We may need to set UCSI_CCI_CMD_COMPLETE flag here */ + if (!wait_for_completion_timeout(&ucsi->complete, + msecs_to_jiffies(PPM_TIMEOUT))) + return -ETIMEDOUT; + + status = ucsi->status; + if (status != UCSI_ERROR && size) + memcpy(data, ucsi->data->message_in, size); + + ret = ucsi_ack(ucsi, UCSI_ACK_CMD); + if (ret) + goto err; + + if (status == UCSI_ERROR) { + u16 error = 0; + + ret = ucsi_acpi_cmd(ucsi, UCSI_GET_ERROR_STATUS); + if (ret) + goto err; + + wait_for_completion(&ucsi->complete); + + memcpy(&error, ucsi->data->message_in, sizeof(error)); + + /* Something has really gone wrong */ + if (ucsi->status == UCSI_ERROR) { + ret = -ENODEV; + goto err; + } + + ret = ucsi_ack(ucsi, UCSI_ACK_CMD); + if (ret) + goto err; + + switch (error) { + case UCSI_ERROR_INCOMPATIBLE_PARTNER: + ret = -EOPNOTSUPP; + break; + case UCSI_ERROR_CC_COMMUNICATION_ERR: + ret = -ECOMM; + break; + case UCSI_ERROR_CONTRACT_NEGOTIATION_FAIL: + ret = -EIO; + break; + case UCSI_ERROR_DEAD_BATTERY: + dev_warn(ucsi->dev, "Dead Battery Condition!\n"); + ret = -EPERM; + break; + /* The following mean a bug in this driver */ + case UCSI_ERROR_INVALID_CON_NUM: + case UCSI_ERROR_UNREGONIZED_CMD: + case UCSI_ERROR_INVALID_CMD_ARGUMENT: + default: + dev_warn(ucsi->dev, + "possible UCSI driver bug - error %hu\n", + error); + ret = -EINVAL; + break; + } + } +err: + *ctrl = 0; + return ret; +} + +static void ucsi_connector_change(struct work_struct *work) +{ + struct ucsi_connector *con = container_of(work, struct ucsi_connector, + work); + struct ucsi_connector_status constat; + struct ucsi *ucsi = con->ucsi; + struct ucsi_control *ctrl; + u64 control = 0; + int role; + int ret; + + if (!data_role[0]) + return; + + mutex_lock(&ucsi->ppm_lock); + + ctrl = (void *)&control; + ctrl->cmd = UCSI_GET_CONNECTOR_STATUS; + ctrl->data = con->num; + + ret = ucsi_run_cmd(con->ucsi, &control, &constat, sizeof(constat)); + if (ret) { + dev_err(ucsi->dev, "%s: failed to read connector status (%d)\n", + __func__, ret); + goto out; + } + + /* Ignoring disconnections and Alternate Modes */ + if (!constat.connected || !(constat.change & + (UCSI_CONSTAT_PARTNER_CHANGE | UCSI_CONSTAT_CONNECT_CHANGE)) || + constat.partner_flags & UCSI_CONSTAT_PARTNER_FLAG_ALT_MODE) + goto out; + + if (!strcmp(data_role, "host")) { + role = UCSI_UOR_ROLE_DFP; + } else if (!strcmp(data_role, "device")) { + role = UCSI_UOR_ROLE_UFP; + } else { + dev_warn(ucsi->dev, "no USB Data Role \"%s\"", + data_role); + goto out; + } + + /* If the partner got our preferred data role, attempting swap */ + if (role == (constat.partner_type & 0x3)) { + struct ucsi_uor_cmd *uor = (void *)&control; + + uor->cmd = UCSI_SET_UOR; + uor->con_num = con->num; + uor->role = role; + ret = ucsi_run_cmd(ucsi, &control, NULL, 0); + if (ret) + dev_err(ucsi->dev, "%s: failed to swap role (%d)\n", + __func__, ret); + } +out: + ucsi_ack(ucsi, UCSI_ACK_EVENT); + atomic_dec(&ucsi->event_pending); + mutex_unlock(&ucsi->ppm_lock); +} + +static int ucsi_init(struct ucsi *ucsi) +{ + struct ucsi_connector *con; + struct ucsi_control ctrl; + int ret; + int i; + + atomic_set(&ucsi->event_pending, 0); + init_completion(&ucsi->complete); + mutex_init(&ucsi->ppm_lock); + + mutex_lock(&ucsi->ppm_lock); + + /* Reset */ + ret = ucsi_acpi_cmd(ucsi, UCSI_PPM_RESET); + if (ret) + return ret; + + msleep(20); + + /* + * REVISIT: Executing second reset to WA an issue seen on some of the + * Broxton base platforms, where the first reset puts the PPM into a + * state where it's unable to respond to all of the commands send to it + */ + ret = ucsi_acpi_cmd(ucsi, UCSI_PPM_RESET); + if (ret) + return ret; + + msleep(20); + + /* Enable basic notifications */ + ctrl.cmd = UCSI_SET_NOTIFICATION_ENABLE; + ctrl.length = 0; + ctrl.data = UCSI_ENABLE_NTFY_CMD_COMPLETE | UCSI_ENABLE_NTFY_ERROR; + ret = ucsi_run_cmd(ucsi, (void *)&ctrl, NULL, 0); + if (ret < 0) + return ret; + + /* Get PPM capabilities */ + ctrl.cmd = UCSI_GET_CAPABILITY; + ret = ucsi_run_cmd(ucsi, (void *)&ctrl, &ucsi->cap, sizeof(ucsi->cap)); + if (ret < 0) + return ret; + + if (!ucsi->cap.num_connectors) + return -ENODEV; + + ucsi->connector = kcalloc(ucsi->cap.num_connectors, + sizeof(struct ucsi_connector), GFP_KERNEL); + if (!ucsi->connector) + return -ENOMEM; + + for (i = 0, con = ucsi->connector; i < ucsi->cap.num_connectors; + i++, con++) { + /* Get connector capability */ + ctrl.cmd = UCSI_GET_CONNECTOR_CAPABILITY; + ctrl.data = i + 1; + ret = ucsi_run_cmd(ucsi, (void *)&ctrl, &con->cap, + sizeof(con->cap)); + if (ret < 0) + goto err; + + con->num = i + 1; + con->ucsi = ucsi; + INIT_WORK(&con->work, ucsi_connector_change); + } + + /* Enable all notifications */ + ctrl.cmd = UCSI_SET_NOTIFICATION_ENABLE; + ctrl.data = UCSI_ENABLE_NTFY_ALL; + ret = ucsi_run_cmd(ucsi, (void *)&ctrl, NULL, 0); + if (ret < 0) + goto err; + + mutex_unlock(&ucsi->ppm_lock); + return 0; +err: + /* Disable all notifications */ + ucsi_acpi_cmd(ucsi, UCSI_SET_NOTIFICATION_ENABLE); + + mutex_unlock(&ucsi->ppm_lock); + + kfree(ucsi->connector); + ucsi->connector = NULL; + + return ret; +} + +static int ucsi_acpi_probe(struct platform_device *pdev) +{ + struct resource *res; + acpi_status status; + struct ucsi *ucsi; + int ret; + + ucsi = devm_kzalloc(&pdev->dev, sizeof(*ucsi), GFP_KERNEL); + if (!ucsi) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "missing memory resource\n"); + return -ENODEV; + } + + ucsi->data = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!ucsi->data) + return -ENOMEM; + + ucsi->dev = &pdev->dev; + + status = acpi_install_notify_handler(ACPI_HANDLE(&pdev->dev), + ACPI_ALL_NOTIFY, + ucsi_acpi_notify, ucsi); + if (ACPI_FAILURE(status)) + return -ENODEV; + + ret = ucsi_init(ucsi); + if (ret) { + acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), + ACPI_ALL_NOTIFY, + ucsi_acpi_notify); + return ret; + } + + platform_set_drvdata(pdev, ucsi); + return 0; +} + +static int ucsi_acpi_remove(struct platform_device *pdev) +{ + struct ucsi *ucsi = platform_get_drvdata(pdev); + + acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), + ACPI_ALL_NOTIFY, ucsi_acpi_notify); + + /* Disable all notifications */ + ucsi_acpi_cmd(ucsi, UCSI_SET_NOTIFICATION_ENABLE); + + kfree(ucsi->connector); + return 0; +} + +static const struct acpi_device_id ucsi_acpi_match[] = { + { "PNP0CA0", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, ucsi_acpi_match); + +static struct platform_driver ucsi_acpi_platform_driver = { + .driver = { + .name = "ucsi_acpi", + .acpi_match_table = ACPI_PTR(ucsi_acpi_match), + }, + .probe = ucsi_acpi_probe, + .remove = ucsi_acpi_remove, +}; + +module_platform_driver(ucsi_acpi_platform_driver); + +MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("USB Type-C System Software Interface (UCSI) driver"); diff --git a/drivers/usb/misc/ucsi.h b/drivers/usb/misc/ucsi.h new file mode 100644 index 0000000..c6336ac --- /dev/null +++ b/drivers/usb/misc/ucsi.h @@ -0,0 +1,198 @@ + +#include <linux/types.h> + +/* -------------------------------------------------------------------------- */ + +struct ucsi_data { + __u16 version; + __u16 RESERVED; + __u32 cci; + __u64 control; + __u32 message_in[4]; + __u32 message_out[4]; +} __packed; + +struct ucsi_control { + __u8 cmd; + __u8 length; + __u64 data:48; +} __packed; + +/* Command Status and Connector Change Indication (CCI) bits */ +#define UCSI_CCI_CONNECTOR_CHANGE(c) ((c >> 1) & 0x7f) +#define UCSI_CCI_DATA_LENGTH(c) ((c >> 8) & 0xff) +#define UCSI_CCI_NOT_SUPPORTED BIT(25) +#define UCSI_CCI_CANCEL_COMPLETED BIT(26) +#define UCSI_CCI_RESET_COMPLETED BIT(27) +#define UCSI_CCI_BUSY BIT(28) +#define UCSI_CCI_ACK_CMD BIT(29) +#define UCSI_CCI_ERROR BIT(30) +#define UCSI_CCI_CMD_COMPLETED BIT(31) + +/* Commands */ +#define UCSI_PPM_RESET 0x01 +#define UCSI_CANCEL 0x02 +#define UCSI_CONNECTOR_RESET 0x03 +#define UCSI_ACK_CC_CI 0x04 +#define UCSI_SET_NOTIFICATION_ENABLE 0x05 +#define UCSI_GET_CAPABILITY 0x06 +#define UCSI_GET_CONNECTOR_CAPABILITY 0x07 +#define UCSI_SET_UOM 0x08 +#define UCSI_SET_UOR 0x09 +#define UCSI_SET_PDM 0x0A +#define UCSI_SET_PDR 0x0B +#define UCSI_GET_ALTERNATE_MODES 0x0C +#define UCSI_GET_CAM_SUPPORTED 0x0D +#define UCSI_GET_CURRENT_CAM 0x0E +#define UCSI_SET_NEW_CAM 0x0F +#define UCSI_GET_PDOS 0x10 +#define UCSI_GET_CABLE_PROPERTY 0x11 +#define UCSI_GET_CONNECTOR_STATUS 0x12 +#define UCSI_GET_ERROR_STATUS 0x13 + +/* ACK_CC_CI commands */ +#define UCSI_ACK_EVENT 1 +#define UCSI_ACK_CMD 2 + +/* Bits for SET_NOTIFICATION_ENABLE command */ +#define UCSI_ENABLE_NTFY_CMD_COMPLETE BIT(0) +#define UCSI_ENABLE_NTFY_EXT_PWR_SRC_CHANGE BIT(1) +#define UCSI_ENABLE_NTFY_PWR_OPMODE_CHANGE BIT(2) +#define UCSI_ENABLE_NTFY_CAP_CHANGE BIT(5) +#define UCSI_ENABLE_NTFY_PWR_LEVEL_CHANGE BIT(6) +#define UCSI_ENABLE_NTFY_PD_RESET_COMPLETE BIT(7) +#define UCSI_ENABLE_NTFY_CAM_CHANGE BIT(8) +#define UCSI_ENABLE_NTFY_BAT_STATUS_CHANGE BIT(9) +#define UCSI_ENABLE_NTFY_PARTNER_CHANGE BIT(11) +#define UCSI_ENABLE_NTFY_PWR_DIR_CHANGE BIT(12) +#define UCSI_ENABLE_NTFY_CONNECTOR_CHANGE BIT(14) +#define UCSI_ENABLE_NTFY_ERROR BIT(15) +#define UCSI_ENABLE_NTFY_ALL 0xdbe7 + +/* Error information returned by PPM in response to GET_ERROR_STATUS command. */ +#define UCSI_ERROR_UNREGONIZED_CMD BIT(0) +#define UCSI_ERROR_INVALID_CON_NUM BIT(1) +#define UCSI_ERROR_INVALID_CMD_ARGUMENT BIT(2) +#define UCSI_ERROR_INCOMPATIBLE_PARTNER BIT(3) +#define UCSI_ERROR_CC_COMMUNICATION_ERR BIT(4) +#define UCSI_ERROR_DEAD_BATTERY BIT(5) +#define UCSI_ERROR_CONTRACT_NEGOTIATION_FAIL BIT(6) + +/* Data structure filled by PPM in response to GET_CAPABILITY command. */ +struct ucsi_capability { + __u32 attributes; +#define UCSI_CAP_ATTR_DISABLE_STATE BIT(0) +#define UCSI_CAP_ATTR_BATTERY_CHARGING BIT(1) +#define UCSI_CAP_ATTR_USB_PD BIT(2) +#define UCSI_CAP_ATTR_TYPEC_CURRENT BIT(6) +#define UCSI_CAP_ATTR_POWER_AC_SUPPLY BIT(8) +#define UCSI_CAP_ATTR_POWER_OTHER BIT(10) +#define UCSI_CAP_ATTR_POWER_VBUS BIT(14) + __u8 num_connectors; + __u32 features:24; +#define UCSI_CAP_SET_UOM BIT(0) +#define UCSI_CAP_SET_PDM BIT(1) +#define UCSI_CAP_ALT_MODE_DETAILS BIT(2) +#define UCSI_CAP_ALT_MODE_OVERRIDE BIT(3) +#define UCSI_CAP_PDO_DETAILS BIT(4) +#define UCSI_CAP_CABLE_DETAILS BIT(5) +#define UCSI_CAP_EXT_SUPPLY_NOTIFICATIONS BIT(6) +#define UCSI_CAP_PD_RESET BIT(7) + __u8 num_alt_modes; + __u8 RESERVED; + __u16 bc_version; + __u16 pd_version; + __u16 typec_version; +} __packed; + +/* Data structure filled by PPM in response to GET_CONNECTOR_CAPABILITY cmd. */ +struct ucsi_connector_capability { + __u8 op_mode; +#define UCSI_CONCAP_OPMODE_DFP BIT(0) +#define UCSI_CONCAP_OPMODE_UFP BIT(1) +#define UCSI_CONCAP_OPMODE_DRP BIT(2) +#define UCSI_CONCAP_OPMODE_AUDIO_ACCESSORY BIT(3) +#define UCSI_CONCAP_OPMODE_DEBUG_ACCESSORY BIT(4) +#define UCSI_CONCAP_OPMODE_USB2 BIT(5) +#define UCSI_CONCAP_OPMODE_USB3 BIT(6) +#define UCSI_CONCAP_OPMODE_ALT_MODE BIT(7) + __u8 provider:1; + __u8 consumer:1; +} __packed; + +/* Data structure filled by PPM in response to GET_CABLE_PROPERTY command. */ +struct ucsi_cable_property { + __u16 speed_supported; + __u8 current_capability; + __u8 vbus_in_cable:1; + __u8 active_cable:1; + __u8 directionality:1; + __u8 plug_type:2; +#define UCSI_CABLE_PROPERTY_PLUG_TYPE_A 0 +#define UCSI_CABLE_PROPERTY_PLUG_TYPE_B 1 +#define UCSI_CABLE_PROPERTY_PLUG_TYPE_C 2 +#define UCSI_CABLE_PROPERTY_PLUG_OTHER 3 + __u8 mode_support:1; + __u8 RESERVED_2:2; + __u8 latency:4; + __u8 RESERVED_4:4; +} __packed; + +/* Data structure filled by PPM in response to GET_CONNECTOR_STATUS command. */ +struct ucsi_connector_status { + __u16 change; +#define UCSI_CONSTAT_EXT_SUPPLY_CHANGE BIT(1) +#define UCSI_CONSTAT_POWER_OPMODE_CHANGE BIT(2) +#define UCSI_CONSTAT_PDOS_CHANGE BIT(5) +#define UCSI_CONSTAT_POWER_LEVEL_CHANGE BIT(6) +#define UCSI_CONSTAT_PD_RESET_COMPLETE BIT(7) +#define UCSI_CONSTAT_CAM_CHANGE BIT(8) +#define UCSI_CONSTAT_BC_CHANGE BIT(9) +#define UCSI_CONSTAT_PARTNER_CHANGE BIT(11) +#define UCSI_CONSTAT_POWER_DIR_CHANGE BIT(12) +#define UCSI_CONSTAT_CONNECT_CHANGE BIT(14) +#define UCSI_CONSTAT_ERROR BIT(15) + __u16 pwr_op_mode:3; +#define UCSI_CONSTAT_PWR_OPMODE_NONE 0 +#define UCSI_CONSTAT_PWR_OPMODE_DEFAULT 1 +#define UCSI_CONSTAT_PWR_OPMODE_BC 2 +#define UCSI_CONSTAT_PWR_OPMODE_PD 3 +#define UCSI_CONSTAT_PWR_OPMODE_TYPEC1_3 4 +#define UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0 5 + __u16 connected:1; + __u16 pwr_dir:1; + __u16 partner_flags:8; +#define UCSI_CONSTAT_PARTNER_FLAG_USB BIT(0) +#define UCSI_CONSTAT_PARTNER_FLAG_ALT_MODE BIT(1) + __u16 partner_type:3; +#define UCSI_CONSTAT_PARTNER_TYPE_DFP 1 +#define UCSI_CONSTAT_PARTNER_TYPE_UFP 2 +#define UCSI_CONSTAT_PARTNER_TYPE_CABLE_NO_UFP 3 /* Powered Cable */ +#define UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP 4 /* Powered Cable */ +#define UCSI_CONSTAT_PARTNER_TYPE_DEBUG 5 +#define UCSI_CONSTAT_PARTNER_TYPE_AUDIO 6 + __u32 request_data_obj; + __u8 bc_status:2; +#define UCSI_CONSTAT_BC_NOT_CHARGING 0 +#define UCSI_CONSTAT_BC_NOMINAL_CHARGING 1 +#define UCSI_CONSTAT_BC_SLOW_CHARGING 2 +#define UCSI_CONSTAT_BC_TRICKLE_CHARGING 3 + __u8 provider_cap_limit_reason:4; +#define UCSI_CONSTAT_CAP_PWR_LOWERED 0 +#define UCSI_CONSTAT_CAP_PWR_BUDGET_LIMIT 1 + __u8 RESERVED:2; +} __packed; + +/* -------------------------------------------------------------------------- */ + +/* Set USB Operation Mode Command structure */ +struct ucsi_uor_cmd { + __u8 cmd; + __u8 length; + __u64 con_num:7; + __u64 role:3; +#define UCSI_UOR_ROLE_DFP BIT(0) +#define UCSI_UOR_ROLE_UFP BIT(1) +#define UCSI_UOR_ROLE_DRP BIT(2) + __u64 data:38; +} __packed; -- 2.8.0.rc3 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html