lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1455037283-106479-3-git-send-email-heikki.krogerus@linux.intel.com>
Date:	Tue,  9 Feb 2016 19:01:22 +0200
From:	Heikki Krogerus <heikki.krogerus@...ux.intel.com>
To:	Greg KH <gregkh@...uxfoundation.org>
Cc:	linux-usb@...r.kernel.org, linux-kernel@...r.kernel.org,
	Mathias Nyman <mathias.nyman@...ux.intel.com>,
	Felipe Balbi <balbi@...nel.org>
Subject: [PATCH 2/3] usb: type-c: USB Type-C Connector System Software Interface

USB Type-C Connector System Software Interface (UCSI) is a
specification that defines registers and data structures
used to interface with the USB Type-C connectors on a system.

The specification is public and available at:
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@...ux.intel.com>
---
 drivers/usb/type-c/Kconfig  |   8 +
 drivers/usb/type-c/Makefile |   1 +
 drivers/usb/type-c/ucsi.c   | 450 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/type-c/ucsi.h   | 219 +++++++++++++++++++++
 4 files changed, 678 insertions(+)
 create mode 100644 drivers/usb/type-c/ucsi.c
 create mode 100644 drivers/usb/type-c/ucsi.h

diff --git a/drivers/usb/type-c/Kconfig b/drivers/usb/type-c/Kconfig
index b229fb9..02abd74 100644
--- a/drivers/usb/type-c/Kconfig
+++ b/drivers/usb/type-c/Kconfig
@@ -4,4 +4,12 @@ menu "USB PD and Type-C drivers"
 config TYPEC
 	tristate
 
+config TYPEC_UCSI
+	tristate "USB Type-C Connector System Software Interface"
+	select TYPEC
+	help
+	  USB Type-C Connector System Software Interface (UCSI) describes the
+	  registers and data structures used to interface with the USB Type-C
+	  connectors on a system.
+
 endmenu
diff --git a/drivers/usb/type-c/Makefile b/drivers/usb/type-c/Makefile
index 1012a8b..ab974ba 100644
--- a/drivers/usb/type-c/Makefile
+++ b/drivers/usb/type-c/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_TYPEC)		+= typec.o
+obj-$(CONFIG_TYPEC_UCSI)	+= ucsi.o
diff --git a/drivers/usb/type-c/ucsi.c b/drivers/usb/type-c/ucsi.c
new file mode 100644
index 0000000..0107a85
--- /dev/null
+++ b/drivers/usb/type-c/ucsi.c
@@ -0,0 +1,450 @@
+/*
+ * ucsi.c - USB Type-C Connector System Software Interface
+ *
+ * Copyright (C) 2016, Intel Corporation
+ * Author: Heikki Krogerus <heikki.krogerus@...ux.intel.com>
+ *
+ * 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/completion.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb/typec.h>
+
+#include "ucsi.h"
+
+#define UCSI_ERROR 1
+#define UCSI_BUSY 2
+
+#define to_ucsi_connector(_port_) container_of(_port_->cap,                    \
+					       struct ucsi_connector,          \
+					       typec_cap)
+
+#define cci_to_connector(_ucsi_, cci) (_ucsi_->connector +		       \
+					UCSI_CCI_CONNECTOR_CHANGE(cci) - 1)
+
+struct ucsi_connector {
+	unsigned num;
+	struct ucsi *ucsi;
+	struct work_struct work;
+	struct typec_port *port;
+	struct typec_capability typec_cap;
+	struct ucsi_connector_capability cap;
+};
+
+struct ucsi {
+	struct device *dev;
+	struct ucsi_ppm *ppm;
+
+	int status;
+	struct completion complete;
+	struct ucsi_capability cap;
+	struct ucsi_connector *connector;
+};
+
+static int ucsi_ack(struct ucsi *ucsi, u8 cmd)
+{
+	struct ucsi_control *ctrl = (void *)&ucsi->ppm->data->control;
+	int ret;
+
+	ucsi->ppm->data->control = 0;
+	ctrl->cmd = UCSI_ACK_CC_CI;
+	ctrl->data = cmd;
+
+	ret = ucsi->ppm->cmd(ucsi->ppm);
+	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, void *data, size_t size)
+{
+	int status;
+	int ret;
+
+	dev_vdbg(ucsi->dev, "%s control 0x%llx\n", __func__,
+		 ucsi->ppm->data->control);
+
+	ret = ucsi->ppm->cmd(ucsi->ppm);
+	if (ret)
+		return ret;
+
+	/* REVISIT: We may need to set UCSI_CCI_CMD_COMPLETE flag here */
+	wait_for_completion(&ucsi->complete);
+
+	status = ucsi->status;
+	if (status != UCSI_ERROR && size)
+		memcpy(data, ucsi->ppm->data->message_in, size);
+
+	ret = ucsi_ack(ucsi, UCSI_ACK_CMD);
+	if (ret)
+		goto out;
+
+	if (status == UCSI_ERROR) {
+		u16 error;
+
+		ucsi->ppm->data->control = UCSI_GET_ERROR_STATUS;
+		ret = ucsi->ppm->cmd(ucsi->ppm);
+		if (ret)
+			goto out;
+
+		wait_for_completion(&ucsi->complete);
+
+		/* Something has really gone wrong */
+		if (ucsi->status == UCSI_ERROR) {
+			ret = -ENODEV;
+			goto out;
+		}
+
+		memcpy(&error, ucsi->ppm->data->message_in, sizeof(error));
+
+		ret = ucsi_ack(ucsi, UCSI_ACK_CMD);
+		if (ret)
+			goto out;
+
+		switch (error) {
+		case UCSI_ERROR_INVALID_CON_NUM:
+			ret = -ENXIO;
+			break;
+		case UCSI_ERROR_INCOMPATIBLE_PARTNER:
+		case UCSI_ERROR_CC_COMMUNICATION_ERR:
+		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;
+		case UCSI_ERROR_UNREGONIZED_CMD:
+		case UCSI_ERROR_INVALID_CMD_ARGUMENT:
+		default:
+			ret = -EINVAL;
+			break;
+		}
+	}
+out:
+	ucsi->ppm->data->control = 0;
+	return ret;
+}
+
+static int ucsi_dr_swap(struct typec_port *port)
+{
+	struct ucsi_connector *con = to_ucsi_connector(port);
+	struct ucsi_uor_cmd *ctrl = (void *)&con->ucsi->ppm->data->control;
+
+	ctrl->cmd = UCSI_SET_UOR;
+	ctrl->con_num = con->num;
+	ctrl->role = port->data_role == TYPEC_HOST ?
+			UCSI_UOR_ROLE_UFP : UCSI_UOR_ROLE_DFP;
+	if (port->cap->type == TYPEC_PORT_DRP)
+		ctrl->role |= UCSI_UOR_ROLE_DRP;
+
+	return ucsi_run_cmd(con->ucsi, NULL, 0);
+}
+
+static int ucsi_pr_swap(struct typec_port *port)
+{
+	struct ucsi_connector *con = to_ucsi_connector(port);
+	struct ucsi_uor_cmd *ctrl = (void *)&con->ucsi->ppm->data->control;
+
+	/* The command structure is identical to SET_UOR command structure */
+	ctrl->cmd = UCSI_SET_PDR;
+	ctrl->con_num = con->num;
+	ctrl->role = port->pwr_role == TYPEC_PWR_SOURCE ?
+			UCSI_UOR_ROLE_UFP : UCSI_UOR_ROLE_DFP;
+	/* Always accepting power swap requests from partner for now */
+	ctrl->role |= UCSI_UOR_ROLE_DRP;
+
+	return ucsi_run_cmd(con->ucsi, NULL, 0);
+}
+
+static int ucsi_get_constat(struct ucsi_connector *con,
+			    struct ucsi_connector_status *constat)
+{
+	struct ucsi_control *ctrl = (void *)&con->ucsi->ppm->data->control;
+
+	ctrl->cmd = UCSI_GET_CONNECTOR_STATUS;
+	ctrl->data = con->num;
+
+	return ucsi_run_cmd(con->ucsi, constat, sizeof(*constat));
+}
+
+static int
+ucsi_connect(struct ucsi_connector *con, struct ucsi_connector_status *constat)
+{
+	struct typec_port *port = con->port;
+
+	port->connected = true;
+
+	if (constat->partner_flags & UCSI_CONSTAT_PARTNER_FLAG_ALT_MODE)
+		port->partner_type = TYPEC_PARTNER_ALTMODE;
+	else
+		port->partner_type = TYPEC_PARTNER_USB;
+
+	switch (constat->partner_type) {
+	case UCSI_CONSTAT_PARTNER_TYPE_CABLE_NO_UFP:
+		/* REVISIT: We don't care about just the cable for now */
+		return 0;
+	case UCSI_CONSTAT_PARTNER_TYPE_DFP:
+	case UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP:
+		port->pwr_role = TYPEC_PWR_SINK;
+		port->data_role = TYPEC_DEVICE;
+		break;
+	case UCSI_CONSTAT_PARTNER_TYPE_UFP:
+		port->pwr_role = TYPEC_PWR_SOURCE;
+		port->data_role = TYPEC_HOST;
+		break;
+	case UCSI_CONSTAT_PARTNER_TYPE_DEBUG:
+		port->partner_type = TYPEC_PARTNER_DEBUG;
+		goto out;
+	case UCSI_CONSTAT_PARTNER_TYPE_AUDIO:
+		port->partner_type = TYPEC_PARTNER_AUDIO;
+		goto out;
+	}
+
+	switch (constat->pwr_op_mode) {
+	case UCSI_CONSTAT_PWR_OPMODE_NONE:
+	case UCSI_CONSTAT_PWR_OPMODE_DEFAULT:
+		port->pwr_opmode = TYPEC_PWR_MODE_USB;
+		break;
+	case UCSI_CONSTAT_PWR_OPMODE_BC:
+		port->partner_type = TYPEC_PARTNER_CHARGER;
+		port->pwr_opmode = TYPEC_PWR_MODE_BC1_2;
+		break;
+	case UCSI_CONSTAT_PWR_OPMODE_PD:
+		port->pwr_opmode = TYPEC_PWR_MODE_PD;
+		break;
+	case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_3:
+		port->pwr_opmode = TYPEC_PWR_MODE_1_5A;
+		break;
+	case UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0:
+		port->pwr_opmode = TYPEC_PWR_MODE_3_0A;
+		break;
+	default:
+		break;
+	}
+out:
+	return typec_connect(port);
+}
+
+static void ucsi_disconnect(struct ucsi_connector *con)
+{
+	con->port->partner_type = TYPEC_PARTNER_NONE;
+	con->port->connected = false;
+	typec_disconnect(con->port);
+}
+
+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;
+
+	ucsi_ack(con->ucsi, UCSI_ACK_EVENT);
+
+	if (WARN_ON(ucsi_get_constat(con, &constat) != 0))
+		return;
+
+	if (constat.constat_change & UCSI_CONSTAT_CONNECT_CHANGE) {
+		if (constat.connected)
+			ucsi_connect(con, &constat);
+		else
+			ucsi_disconnect(con);
+	}
+}
+
+/**
+ * ucsi_interrupt - UCSI Notification Handler
+ * @ucsi: Source UCSI Interface for the notifications
+ *
+ * Handle notifications from @ucsi.
+ */
+int ucsi_interrupt(struct ucsi *ucsi)
+{
+	u32 cci = ucsi->ppm->data->cci;
+
+	if (!cci)
+		return 0;
+
+	if (UCSI_CCI_CONNECTOR_CHANGE(cci)) {
+		struct ucsi_connector *con = cci_to_connector(ucsi, cci);
+
+		schedule_work(&con->work);
+		return 1;
+	}
+
+	ucsi->status = 0;
+
+	/* REVISIT: We don't actually do anything with this for now */
+	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)
+		complete(&ucsi->complete);
+
+	return 1;
+}
+EXPORT_SYMBOL_GPL(ucsi_interrupt);
+
+/**
+ * ucsi_init - Initialize an UCSI Interface
+ * @ucsi: The UCSI Interface
+ *
+ * Registers all the USB Type-C ports governed by the PPM of @ucsi and enables
+ * all the notifications from the PPM.
+ */
+int ucsi_init(struct ucsi *ucsi)
+{
+	struct ucsi_control *ctrl = (void *)&ucsi->ppm->data->control;
+	struct ucsi_connector *con;
+	int ret;
+	int i;
+
+	/* Enable basic notifications */
+	ctrl->cmd = UCSI_SET_NOTIFICATION_ENABLE;
+	ctrl->data = UCSI_ENABLE_NTFY_CMD_COMPLETE | UCSI_ENABLE_NTFY_ERROR;
+	ret = ucsi_run_cmd(ucsi, NULL, 0);
+	if (ret)
+		return ret;
+
+	/* Get PPM capabilities */
+	ctrl->cmd = UCSI_GET_CAPABILITY;
+	ret = ucsi_run_cmd(ucsi, &ucsi->cap, sizeof(ucsi->cap));
+	if (ret)
+		return ret;
+
+	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++) {
+		struct typec_capability *cap = &con->typec_cap;
+		struct ucsi_connector_status constat;
+
+		/* Get connector capability */
+		ctrl->cmd = UCSI_GET_CONNECTOR_CAPABILITY;
+		ctrl->data = i + 1;
+		ret = ucsi_run_cmd(ucsi, &con->cap, sizeof(con->cap));
+		if (ret)
+			goto err;
+
+		/* Register the connector */
+
+		if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DRP)
+			cap->type = TYPEC_PORT_DRP;
+		else if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DFP)
+			cap->type = TYPEC_PORT_DFP;
+		else if (con->cap.op_mode & UCSI_CONCAP_OPMODE_UFP)
+			cap->type = TYPEC_PORT_UFP;
+
+		cap->usb_pd = !!(ucsi->cap.attributes &
+				       UCSI_CAP_ATTR_USB_PD);
+		cap->audio_accessory = !!(con->cap.op_mode &
+					  UCSI_CONCAP_OPMODE_AUDIO_ACCESSORY);
+		cap->debug_accessory = !!(con->cap.op_mode &
+					  UCSI_CONCAP_OPMODE_DEBUG_ACCESSORY);
+
+		/* TODO: Alt modes */
+
+		cap->dr_swap = ucsi_dr_swap;
+		cap->pr_swap = ucsi_pr_swap;
+
+		con->port = typec_register_port(ucsi->dev, cap);
+		if (IS_ERR(con->port)) {
+			ret = PTR_ERR(con->port);
+			goto err;
+		}
+
+		con->num = i + 1;
+		con->ucsi = ucsi;
+		INIT_WORK(&con->work, ucsi_connector_change);
+
+		/* Check if the connector is connected */
+		if (WARN_ON(ucsi_get_constat(con, &constat) != 0))
+			continue;
+
+		if (constat.connected)
+			ucsi_connect(con, &constat);
+	}
+
+	/* Enable all notifications */
+	ctrl->cmd = UCSI_SET_NOTIFICATION_ENABLE;
+	ctrl->data = UCSI_ENABLE_NTFY_ALL;
+	ret = ucsi_run_cmd(ucsi, NULL, 0);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	if (i > 0)
+		for (; i >= 0; i--, con--)
+			typec_unregister_port(con->port);
+
+	kfree(ucsi->connector);
+	return ret;
+}
+EXPORT_SYMBOL(ucsi_init);
+
+/**
+ * ucsi_register_ppm - Register UCSI PPM Interface
+ * @dev: Device interface to the PPM
+ * @ppm: The PPM interface
+ *
+ * Allocates an UCSI instance, associates it with @ppm and returns it to the
+ * caller.
+ */
+struct ucsi *ucsi_register_ppm(struct device *dev, struct ucsi_ppm *ppm)
+{
+	struct ucsi *ucsi;
+
+	ucsi = kzalloc(sizeof(*ucsi), GFP_KERNEL);
+	if (!ucsi)
+		return ERR_PTR(-ENOMEM);
+
+	init_completion(&ucsi->complete);
+	ucsi->dev = dev;
+	ucsi->ppm = ppm;
+
+	return ucsi;
+}
+EXPORT_SYMBOL_GPL(ucsi_register_ppm);
+
+/**
+ * ucsi_unregister_ppm - Unregister UCSI PPM Interface
+ * @ucsi: struct ucsi associated with the PPM
+ *
+ * Unregister an UCSI PPM that was created with ucsi_register().
+ */
+void ucsi_unregister_ppm(struct ucsi *ucsi)
+{
+	struct ucsi_connector *con;
+	int i;
+
+	/* Disable all notifications */
+	ucsi->ppm->data->control = UCSI_SET_NOTIFICATION_ENABLE;
+	ucsi->ppm->cmd(ucsi->ppm);
+
+	for (i = 0, con = ucsi->connector; i < ucsi->cap.num_connectors;
+	     i++, con++)
+		typec_unregister_port(con->port);
+
+	kfree(ucsi->connector);
+	kfree(ucsi);
+}
+EXPORT_SYMBOL_GPL(ucsi_unregister_ppm);
+
+MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@...ux.intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("USB Type-C System Software Interface driver");
diff --git a/drivers/usb/type-c/ucsi.h b/drivers/usb/type-c/ucsi.h
new file mode 100644
index 0000000..0ec6366
--- /dev/null
+++ b/drivers/usb/type-c/ucsi.h
@@ -0,0 +1,219 @@
+
+#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_CMD		BIT(26)
+#define UCSI_CCI_RESET_CMD		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			0xdbf3
+
+/* 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)
+
+/* Set USB Operation Role Command structure */
+struct ucsi_uor_cmd {
+	__u8 cmd;
+	__u8 length;
+	__u8 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;
+
+/* 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_ALTERNATE_MODES command. */
+struct ucsi_alt_modes {
+	__u32 svid0;
+	__u16 mid0;
+	__u32 svid1;
+	__u16 mid1;
+} __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 constat_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;
+#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_TRICLE_CHARGING		3
+} __packed;
+
+/* -------------------------------------------------------------------------- */
+
+struct ucsi;
+
+/*
+ * struct ucsi_ppm - Interface to an UCSI Platform Policy Manager
+ * @data: memory location to the UCSI data structures
+ * @cmd: UCSI command execution routine
+ */
+struct ucsi_ppm {
+	struct ucsi_data *data;
+	int (*cmd)(struct ucsi_ppm *);
+};
+
+struct ucsi *ucsi_register_ppm(struct device *, struct ucsi_ppm *);
+void ucsi_unregister_ppm(struct ucsi *);
+int ucsi_init(struct ucsi *);
+int ucsi_interrupt(struct ucsi *);
-- 
2.7.0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ