Host command for USB PD role and mux control

This allows us to control PD role and type-C mux through ectool.

BUG=None
TEST=Change role/mux on samus using ectool:
     $ ./ectool --interface=lpc --dev 1 usbpd 0 usb
     -> In EC console, 'typec 0' shows 'Superspeed USB1'
     $ ./ectool --interface=lpc --dev 1 usbpd 0 sink
     -> In EC console, 'pd 0 state' shows 'force sink'
BRANCH=None

Change-Id: I5b90fb53ea1c30e3bc269c12d61e4398c5dcee6c
Signed-off-by: Vic Yang <victoryang@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/209956
Reviewed-by: Alec Berg <alecaberg@chromium.org>
This commit is contained in:
Vic Yang
2014-07-24 15:23:16 -07:00
committed by chrome-internal-fetch
parent 9797f654d9
commit 139a9c6880
3 changed files with 162 additions and 0 deletions

View File

@@ -8,8 +8,10 @@
#include "common.h"
#include "console.h"
#include "crc.h"
#include "ec_commands.h"
#include "gpio.h"
#include "hooks.h"
#include "host_command.h"
#include "registers.h"
#include "task.h"
#include "timer.h"
@@ -1333,4 +1335,59 @@ DECLARE_CONSOLE_COMMAND(typec, command_typec,
NULL);
#endif /* CONFIG_USBC_SS_MUX */
static int hc_usb_pd_control(struct host_cmd_handler_args *args)
{
const struct ec_params_usb_pd_control *p = args->params;
if (p->role != USB_PD_CTRL_ROLE_NO_CHANGE) {
enum pd_dual_role_states role;
switch (p->role) {
case USB_PD_CTRL_ROLE_TOGGLE_ON:
role = PD_DRP_TOGGLE_ON;
break;
case USB_PD_CTRL_ROLE_TOGGLE_OFF:
role = PD_DRP_TOGGLE_OFF;
break;
case USB_PD_CTRL_ROLE_FORCE_SINK:
role = PD_DRP_FORCE_SINK;
break;
case USB_PD_CTRL_ROLE_FORCE_SOURCE:
role = PD_DRP_FORCE_SOURCE;
break;
default:
return EC_RES_INVALID_PARAM;
}
pd_set_dual_role(role);
}
#ifdef CONFIG_USBC_SS_MUX
if (p->mux != USB_PD_CTRL_MUX_NO_CHANGE) {
enum typec_mux mux;
switch (p->mux) {
case USB_PD_CTRL_MUX_NONE:
mux = TYPEC_MUX_NONE;
break;
case USB_PD_CTRL_MUX_USB:
mux = TYPEC_MUX_USB;
break;
case USB_PD_CTRL_MUX_AUTO:
case USB_PD_CTRL_MUX_DP:
mux = TYPEC_MUX_DP;
break;
case USB_PD_CTRL_MUX_DOCK:
mux = TYPEC_MUX_DOCK;
break;
default:
return EC_RES_INVALID_PARAM;
}
board_set_usb_mux(p->port, mux, pd_get_polarity(p->port));
}
#endif /* CONFIG_USBC_SS_MUX */
return EC_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_USB_PD_CONTROL,
hc_usb_pd_control,
EC_VER_MASK(0));
#endif /* CONFIG_COMMON_RUNTIME */

View File

@@ -2500,6 +2500,32 @@ struct ec_response_pd_status {
int8_t status; /* currently empty */
} __packed;
/* Set USB type-C port role and muxes */
#define EC_CMD_USB_PD_CONTROL 0x101
enum usb_pd_control_role {
USB_PD_CTRL_ROLE_NO_CHANGE = 0,
USB_PD_CTRL_ROLE_TOGGLE_ON = 1, /* == AUTO */
USB_PD_CTRL_ROLE_TOGGLE_OFF = 2,
USB_PD_CTRL_ROLE_FORCE_SINK = 3,
USB_PD_CTRL_ROLE_FORCE_SOURCE = 4,
};
enum usb_pd_control_mux {
USB_PD_CTRL_MUX_NO_CHANGE = 0,
USB_PD_CTRL_MUX_NONE = 1,
USB_PD_CTRL_MUX_USB = 2,
USB_PD_CTRL_MUX_DP = 3,
USB_PD_CTRL_MUX_DOCK = 4,
USB_PD_CTRL_MUX_AUTO = 5,
};
struct ec_params_usb_pd_control {
uint8_t port;
uint8_t role;
uint8_t mux;
} __packed;
/*****************************************************************************/
/*
* Passthru commands

View File

@@ -177,6 +177,9 @@ const char help_str[] =
" Set USB charging mode\n"
" usbmux <mux>\n"
" Set USB mux switch state\n"
" usbpd <port> <auto | "
"[toggle|toggle-off|sink|source] [none|usb|dp|dock]>\n"
" Control USB PD/type-C\n"
" version\n"
" Prints EC version\n"
" wireless <flags> [<mask> [<suspend_flags> <suspend_mask>]]\n"
@@ -2413,6 +2416,81 @@ int cmd_usb_mux(int argc, char *argv[])
}
int cmd_usb_pd(int argc, char *argv[])
{
const char *role_str[] = {"", "toggle", "toggle-off", "sink", "source"};
const char *mux_str[] = {"", "none", "usb", "dp", "dock"};
struct ec_params_usb_pd_control p;
int rv, i, j;
int option_ok;
char *e;
p.role = USB_PD_CTRL_ROLE_NO_CHANGE;
p.mux = USB_PD_CTRL_MUX_NO_CHANGE;
if (argc <= 2) {
fprintf(stderr, "No option specified.\n");
return -1;
}
p.port = strtol(argv[1], &e, 0);
if (e && *e) {
fprintf(stderr, "Invalid param (port)\n");
return -1;
}
for (i = 2; i < argc; ++i) {
option_ok = 0;
if (!strcmp(argv[i], "auto")) {
if (argc != 3) {
fprintf(stderr, "\"auto\" may not be used "
"with other options.\n");
return -1;
}
p.role = USB_PD_CTRL_ROLE_TOGGLE_ON;
p.mux = USB_PD_CTRL_MUX_AUTO;
continue;
}
for (j = 0; j < ARRAY_SIZE(role_str); ++j) {
if (!strcmp(argv[i], role_str[j])) {
if (p.role != USB_PD_CTRL_ROLE_NO_CHANGE) {
fprintf(stderr,
"Only one role allowed.\n");
return -1;
}
p.role = j;
option_ok = 1;
break;
}
}
if (option_ok)
continue;
for (j = 0; j < ARRAY_SIZE(mux_str); ++j) {
if (!strcmp(argv[i], mux_str[j])) {
if (p.mux != USB_PD_CTRL_MUX_NO_CHANGE) {
fprintf(stderr,
"Only one mux type allowed.\n");
return -1;
}
p.mux = j;
option_ok = 1;
break;
}
}
if (!option_ok) {
fprintf(stderr, "Unknown option: %s\n", argv[i]);
return -1;
}
}
rv = ec_command(EC_CMD_USB_PD_CONTROL, 0, &p, sizeof(p), NULL, 0);
return (rv < 0 ? rv : 0);
}
int cmd_kbpress(int argc, char *argv[])
{
struct ec_params_mkbp_simulate_key p;
@@ -4533,6 +4611,7 @@ const struct command commands[] = {
{"tmp006raw", cmd_tmp006raw},
{"usbchargemode", cmd_usb_charge_set_mode},
{"usbmux", cmd_usb_mux},
{"usbpd", cmd_usb_pd},
{"version", cmd_version},
{"wireless", cmd_wireless},
{NULL, NULL}