ucsi: Add usage of USB role switch functionality

This change adds usage of USB role switch framework to notify
USB role to start USB host/device stack to USB driver.

Change-Id: I9778e0e3d2db2aaccf2f19c6dfd2482dad6acbfc
Signed-off-by: Mayank Rana <mrana@codeaurora.org>
This commit is contained in:
Mayank Rana 2020-01-27 14:49:00 -08:00
commit a1d126aa4e
2 changed files with 35 additions and 0 deletions

View file

@ -473,15 +473,19 @@ static void ucsi_unregister_partner(struct ucsi_connector *con)
static void ucsi_partner_change(struct ucsi_connector *con)
{
int ret;
struct ucsi *ucsi = con->ucsi;
enum usb_role u_role = USB_ROLE_NONE;
if (!con->partner)
return;
switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) {
case UCSI_CONSTAT_PARTNER_TYPE_UFP:
u_role = USB_ROLE_HOST;
typec_set_data_role(con->port, TYPEC_HOST);
break;
case UCSI_CONSTAT_PARTNER_TYPE_DFP:
u_role = USB_ROLE_DEVICE;
typec_set_data_role(con->port, TYPEC_DEVICE);
break;
default:
@ -492,6 +496,11 @@ static void ucsi_partner_change(struct ucsi_connector *con)
if (!completion_done(&con->complete))
complete(&con->complete);
ret = usb_role_switch_set_role(ucsi->usb_role_sw, u_role);
if (ret)
dev_err(ucsi->dev, "%s(): failed to set role(%d):%d\n",
__func__, u_role, ret);
/* Can't rely on Partner Flags field. Always checking the alt modes. */
ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_SOP);
if (ret)
@ -510,6 +519,7 @@ static void ucsi_handle_connector_change(struct work_struct *work)
enum typec_role role;
u64 command;
int ret;
enum usb_role u_role = USB_ROLE_NONE;
mutex_lock(&con->lock);
@ -540,9 +550,11 @@ static void ucsi_handle_connector_change(struct work_struct *work)
switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) {
case UCSI_CONSTAT_PARTNER_TYPE_UFP:
u_role = USB_ROLE_HOST;
typec_set_data_role(con->port, TYPEC_HOST);
break;
case UCSI_CONSTAT_PARTNER_TYPE_DFP:
u_role = USB_ROLE_DEVICE;
typec_set_data_role(con->port, TYPEC_DEVICE);
break;
default:
@ -553,6 +565,11 @@ static void ucsi_handle_connector_change(struct work_struct *work)
ucsi_register_partner(con);
else
ucsi_unregister_partner(con);
ret = usb_role_switch_set_role(ucsi->usb_role_sw, u_role);
if (ret)
dev_err(ucsi->dev, "%s(): failed to set role(%d):%d\n",
__func__, u_role, ret);
}
if (con->status.change & UCSI_CONSTAT_CAM_CHANGE) {
@ -776,6 +793,7 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
enum typec_accessory *accessory = cap->accessory;
u64 command;
int ret;
enum usb_role role = USB_ROLE_NONE;
INIT_WORK(&con->work, ucsi_handle_connector_change);
init_completion(&con->complete);
@ -840,9 +858,11 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) {
case UCSI_CONSTAT_PARTNER_TYPE_UFP:
role = USB_ROLE_HOST;
typec_set_data_role(con->port, TYPEC_HOST);
break;
case UCSI_CONSTAT_PARTNER_TYPE_DFP:
role = USB_ROLE_DEVICE;
typec_set_data_role(con->port, TYPEC_DEVICE);
break;
default:
@ -857,6 +877,11 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
ucsi_register_partner(con);
}
ret = usb_role_switch_set_role(ucsi->usb_role_sw, role);
if (ret)
dev_err(ucsi->dev, "%s(): failed to set role(%d):%d\n",
__func__, role, ret);
if (con->partner) {
ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_SOP);
if (ret)
@ -920,6 +945,13 @@ int ucsi_init(struct ucsi *ucsi)
goto err_reset;
}
ucsi->usb_role_sw = fwnode_usb_role_switch_get(dev_fwnode(ucsi->dev));
if (IS_ERR_OR_NULL(ucsi->usb_role_sw)) {
dev_err(ucsi->dev, "%s(): Unable to find usb role switch\n",
__func__);
ucsi->usb_role_sw = NULL;
}
/* Register all connectors */
for (i = 0; i < ucsi->cap.num_connectors; i++) {
ret = ucsi_register_port(ucsi, i);

View file

@ -7,6 +7,7 @@
#include <linux/device.h>
#include <linux/types.h>
#include <linux/usb/typec.h>
#include <linux/usb/role.h>
/* -------------------------------------------------------------------------- */
@ -277,6 +278,8 @@ struct ucsi {
#define EVENT_PENDING 0
#define COMMAND_PENDING 1
#define ACK_PENDING 2
struct usb_role_switch *usb_role_sw;
};
#define UCSI_MAX_SVID 5