summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Berg <alecaberg@chromium.org>2014-10-15 13:09:38 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-10-30 04:31:34 +0000
commit498abf833cad27c5014cdb2d1511f3860703ba82 (patch)
treebee810af95220991f45cca57b52eebbee9da3ef4
parentcfbb9e51b2abfd562af865c0b11362d48d799cfd (diff)
downloadchrome-ec-498abf833cad27c5014cdb2d1511f3860703ba82.tar.gz
samus_pd: add host command to get type-c port power info
Get type-c port power info including power role, charger type, and charging info. Also added host command to get number of type-c ports. Also adds new charging suppliers for pericom identified chargers including DCP, CDP, SDP, proprietary, and other chargers. Priority of these for charging is set in samus board file. BUG=chrome-os-partner:32650 BRANCH=samus TEST=run 'ectool --name=cros_pd usbpdpower' and verify correct status with minimuffin, zinger, and type-C to type-A adapter. Change-Id: I1dabbe7de4185a23df5684a5ea9a2d944f1f6ff5 Signed-off-by: Alec Berg <alecaberg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/223523 Tested-by: Shawn Nematbakhsh <shawnn@chromium.org> Reviewed-by: Shawn Nematbakhsh <shawnn@chromium.org> Reviewed-by: Patrick Georgi <pgeorgi@chromium.org> Reviewed-by: Todd Broch <tbroch@chromium.org> Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--board/samus_pd/board.c50
-rw-r--r--board/samus_pd/board.h6
-rw-r--r--common/charge_manager.c97
-rw-r--r--common/usb_pd_protocol.c12
-rw-r--r--driver/pi3usb9281.h2
-rw-r--r--include/ec_commands.h39
-rw-r--r--include/usb.h2
-rw-r--r--util/ectool.c83
8 files changed, 281 insertions, 10 deletions
diff --git a/board/samus_pd/board.c b/board/samus_pd/board.c
index d57ce4704f..736b28360e 100644
--- a/board/samus_pd/board.c
+++ b/board/samus_pd/board.c
@@ -48,7 +48,11 @@ BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT);
const int supplier_priority[] = {
[CHARGE_SUPPLIER_PD] = 0,
[CHARGE_SUPPLIER_TYPEC] = 1,
- [CHARGE_SUPPLIER_BC12] = 1,
+ [CHARGE_SUPPLIER_PROPRIETARY] = 1,
+ [CHARGE_SUPPLIER_BC12_DCP] = 1,
+ [CHARGE_SUPPLIER_BC12_CDP] = 2,
+ [CHARGE_SUPPLIER_BC12_SDP] = 3,
+ [CHARGE_SUPPLIER_OTHER] = 3
};
BUILD_ASSERT(ARRAY_SIZE(supplier_priority) == CHARGE_SUPPLIER_COUNT);
@@ -72,23 +76,40 @@ static void board_usb_charger_update(int port)
{
int device_type, charger_status;
struct charge_port_info charge;
+ int type;
charge.voltage = USB_BC12_CHARGE_VOLTAGE;
/* Read interrupt register to clear*/
pi3usb9281_get_interrupts(port);
+
+ /* Set device type */
device_type = pi3usb9281_get_device_type(port);
charger_status = pi3usb9281_get_charger_status(port);
+ if (PI3USB9281_CHG_STATUS_ANY(charger_status))
+ type = CHARGE_SUPPLIER_PROPRIETARY;
+ else if (device_type & PI3USB9281_TYPE_CDP)
+ type = CHARGE_SUPPLIER_BC12_CDP;
+ else if (device_type & PI3USB9281_TYPE_DCP)
+ type = CHARGE_SUPPLIER_BC12_DCP;
+ else if (device_type & PI3USB9281_TYPE_SDP)
+ type = CHARGE_SUPPLIER_BC12_SDP;
+ else
+ type = CHARGE_SUPPLIER_OTHER;
/* Attachment: decode + update available charge */
- if (device_type || (charger_status & 0x1f))
+ if (device_type || PI3USB9281_CHG_STATUS_ANY(charger_status)) {
charge.current = pi3usb9281_get_ilim(device_type,
charger_status);
- /* Detachment: update available charge to 0 */
- else
+ charge_manager_update(type, port, &charge);
+ } else { /* Detachment: update available charge to 0 */
charge.current = 0;
-
- charge_manager_update(CHARGE_SUPPLIER_BC12, port, &charge);
-
+ charge_manager_update(CHARGE_SUPPLIER_PROPRIETARY, port,
+ &charge);
+ charge_manager_update(CHARGE_SUPPLIER_BC12_CDP, port, &charge);
+ charge_manager_update(CHARGE_SUPPLIER_BC12_DCP, port, &charge);
+ charge_manager_update(CHARGE_SUPPLIER_BC12_SDP, port, &charge);
+ charge_manager_update(CHARGE_SUPPLIER_OTHER, port, &charge);
+ }
}
/* Pericom USB deferred tasks -- called after USB device insert / removal */
@@ -176,9 +197,10 @@ void board_config_pre_init(void)
/* Initialize board. */
static void board_init(void)
{
- int pd_enable;
+ int pd_enable, i;
int slp_s5 = gpio_get_level(GPIO_PCH_SLP_S5_L);
int slp_s3 = gpio_get_level(GPIO_PCH_SLP_S3_L);
+ struct charge_port_info charge;
/*
* Enable CC lines after all GPIO have been initialized. Note, it is
@@ -191,6 +213,18 @@ static void board_init(void)
gpio_enable_interrupt(GPIO_USB_C0_VBUS_WAKE);
gpio_enable_interrupt(GPIO_USB_C1_VBUS_WAKE);
+ /* Initialize all pericom charge suppliers to 0 */
+ charge.voltage = USB_BC12_CHARGE_VOLTAGE;
+ charge.current = 0;
+ for (i = 0; i < PD_PORT_COUNT; i++) {
+ charge_manager_update(CHARGE_SUPPLIER_PROPRIETARY, i,
+ &charge);
+ charge_manager_update(CHARGE_SUPPLIER_BC12_CDP, i, &charge);
+ charge_manager_update(CHARGE_SUPPLIER_BC12_DCP, i, &charge);
+ charge_manager_update(CHARGE_SUPPLIER_BC12_SDP, i, &charge);
+ charge_manager_update(CHARGE_SUPPLIER_OTHER, i, &charge);
+ }
+
/* Enable pericom BC1.2 interrupts. */
gpio_enable_interrupt(GPIO_USB_C0_BC12_INT_L);
gpio_enable_interrupt(GPIO_USB_C1_BC12_INT_L);
diff --git a/board/samus_pd/board.h b/board/samus_pd/board.h
index 82e1993fa8..62805b6c07 100644
--- a/board/samus_pd/board.h
+++ b/board/samus_pd/board.h
@@ -90,7 +90,11 @@ enum pwm_channel {
enum charge_supplier {
CHARGE_SUPPLIER_PD,
CHARGE_SUPPLIER_TYPEC,
- CHARGE_SUPPLIER_BC12,
+ CHARGE_SUPPLIER_BC12_DCP,
+ CHARGE_SUPPLIER_BC12_CDP,
+ CHARGE_SUPPLIER_BC12_SDP,
+ CHARGE_SUPPLIER_PROPRIETARY,
+ CHARGE_SUPPLIER_OTHER,
CHARGE_SUPPLIER_COUNT
};
diff --git a/common/charge_manager.c b/common/charge_manager.c
index af648f2cfd..01552a7144 100644
--- a/common/charge_manager.c
+++ b/common/charge_manager.c
@@ -6,6 +6,8 @@
#include "charge_manager.h"
#include "console.h"
#include "hooks.h"
+#include "host_command.h"
+#include "usb_pd.h"
#include "usb_pd_config.h"
#include "util.h"
@@ -18,6 +20,7 @@ static struct charge_port_info available_charge[CHARGE_SUPPLIER_COUNT]
/* Store current state of port enable / charge current. */
static int charge_port = CHARGE_PORT_NONE;
static int charge_current = CHARGE_CURRENT_UNINITIALIZED;
+static int charge_supplier = CHARGE_SUPPLIER_NONE;
/**
* Initialize available charge. Run before board init, so board init can
@@ -113,6 +116,7 @@ static void charge_manager_refresh(void)
board_set_active_charge_port(new_port);
charge_current = new_charge_current;
+ charge_supplier = new_supplier;
charge_port = new_port;
}
}
@@ -154,3 +158,96 @@ void charge_manager_update(int supplier,
hook_call_deferred(charge_manager_refresh, 0);
}
}
+
+static int hc_pd_power_info(struct host_cmd_handler_args *args)
+{
+ const struct ec_params_usb_pd_power_info *p = args->params;
+ struct ec_response_usb_pd_power_info *r = args->response;
+ int port = p->port;
+ int sup = CHARGE_SUPPLIER_NONE;
+ int i;
+
+ /* If host is asking for the charging port, set port appropriately */
+ if (port == PD_POWER_CHARGING_PORT)
+ port = charge_port;
+
+ /* Determine supplier information to show */
+ if (port == charge_port) {
+ sup = charge_supplier;
+ } else {
+ /* Find highest priority supplier */
+ for (i = 0; i < CHARGE_SUPPLIER_COUNT; ++i) {
+ if (available_charge[i][port].current > 0 &&
+ available_charge[i][port].voltage > 0 &&
+ (sup == CHARGE_SUPPLIER_NONE ||
+ supplier_priority[i] <
+ supplier_priority[sup] ||
+ (supplier_priority[i] ==
+ supplier_priority[sup] &&
+ POWER(available_charge[i][port]) >
+ POWER(available_charge[sup]
+ [port]))))
+ sup = i;
+ }
+ }
+
+ /* Fill in power role */
+ if (charge_port == port)
+ r->role = USB_PD_PORT_POWER_SINK;
+ else if (sup != CHARGE_SUPPLIER_NONE)
+ r->role = USB_PD_PORT_POWER_SINK_NOT_CHARGING;
+ else if (pd_is_connected(port) && pd_get_role(port) == PD_ROLE_SOURCE)
+ r->role = USB_PD_PORT_POWER_SOURCE;
+ else
+ r->role = USB_PD_PORT_POWER_DISCONNECTED;
+
+ if (sup == CHARGE_SUPPLIER_NONE) {
+ r->type = USB_CHG_TYPE_NONE;
+ r->voltage_max = 0;
+ r->voltage_now = 0;
+ r->current_max = 0;
+ r->max_power = 0;
+ } else {
+ switch (sup) {
+ case CHARGE_SUPPLIER_PD:
+ r->type = USB_CHG_TYPE_PD;
+ break;
+ case CHARGE_SUPPLIER_TYPEC:
+ r->type = USB_CHG_TYPE_C;
+ break;
+ case CHARGE_SUPPLIER_PROPRIETARY:
+ r->type = USB_CHG_TYPE_PROPRIETARY;
+ break;
+ case CHARGE_SUPPLIER_BC12_DCP:
+ r->type = USB_CHG_TYPE_BC12_DCP;
+ break;
+ case CHARGE_SUPPLIER_BC12_CDP:
+ r->type = USB_CHG_TYPE_BC12_CDP;
+ break;
+ case CHARGE_SUPPLIER_BC12_SDP:
+ r->type = USB_CHG_TYPE_BC12_SDP;
+ break;
+ default:
+ r->type = USB_CHG_TYPE_OTHER;
+ }
+ r->voltage_max = available_charge[sup][port].voltage;
+ r->current_max = available_charge[sup][port].current;
+ r->max_power = POWER(available_charge[sup][port]);
+
+ /*
+ * If we are sourcing power, or sinking but not charging, then
+ * VBUS must be 5V. If we are charging, then read VBUS ADC.
+ */
+ if (r->role == USB_PD_PORT_POWER_SOURCE ||
+ r->role == USB_PD_PORT_POWER_SINK_NOT_CHARGING)
+ r->voltage_now = 5000;
+ else
+ r->voltage_now = adc_read_channel(ADC_BOOSTIN);
+ }
+
+ args->response_size = sizeof(*r);
+ return EC_RES_SUCCESS;
+}
+DECLARE_HOST_COMMAND(EC_CMD_USB_PD_POWER_INFO,
+ hc_pd_power_info,
+ EC_VER_MASK(0));
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 24cdf8e264..34ef385621 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -1985,6 +1985,18 @@ DECLARE_CONSOLE_COMMAND(typec, command_typec,
NULL);
#endif /* CONFIG_USBC_SS_MUX */
+static int hc_pd_ports(struct host_cmd_handler_args *args)
+{
+ struct ec_response_usb_pd_ports *r = args->response;
+ r->num_ports = PD_PORT_COUNT;
+
+ args->response_size = sizeof(*r);
+ return EC_RES_SUCCESS;
+}
+DECLARE_HOST_COMMAND(EC_CMD_USB_PD_PORTS,
+ hc_pd_ports,
+ EC_VER_MASK(0));
+
static const enum pd_dual_role_states dual_role_map[USB_PD_CTRL_ROLE_COUNT] = {
[USB_PD_CTRL_ROLE_TOGGLE_ON] = PD_DRP_TOGGLE_ON,
[USB_PD_CTRL_ROLE_TOGGLE_OFF] = PD_DRP_TOGGLE_OFF,
diff --git a/driver/pi3usb9281.h b/driver/pi3usb9281.h
index d26295b846..392c02ae52 100644
--- a/driver/pi3usb9281.h
+++ b/driver/pi3usb9281.h
@@ -46,6 +46,8 @@
#define PI3USB9281_CHG_APPLE_1A (1 << 2)
#define PI3USB9281_CHG_APPLE_2A (1 << 3)
#define PI3USB9281_CHG_APPLE_2_4A (1 << 4)
+/* Check if charge status has any connection */
+#define PI3USB9281_CHG_STATUS_ANY(x) (((x) & 0x1f) > 1)
/* Read PI3USB9281 register. */
uint8_t pi3usb9281_read(uint8_t chip_idx, uint8_t reg);
diff --git a/include/ec_commands.h b/include/ec_commands.h
index 52a0996b91..07bf6a5a43 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -2734,6 +2734,45 @@ struct ec_response_usb_pd_control {
uint8_t state;
} __packed;
+#define EC_CMD_USB_PD_PORTS 0x102
+
+struct ec_response_usb_pd_ports {
+ uint8_t num_ports;
+} __packed;
+
+#define EC_CMD_USB_PD_POWER_INFO 0x103
+
+#define PD_POWER_CHARGING_PORT 0xff
+struct ec_params_usb_pd_power_info {
+ uint8_t port;
+} __packed;
+
+enum usb_chg_type {
+ USB_CHG_TYPE_NONE,
+ USB_CHG_TYPE_PD,
+ USB_CHG_TYPE_C,
+ USB_CHG_TYPE_PROPRIETARY,
+ USB_CHG_TYPE_BC12_DCP,
+ USB_CHG_TYPE_BC12_CDP,
+ USB_CHG_TYPE_BC12_SDP,
+ USB_CHG_TYPE_OTHER
+};
+enum usb_power_roles {
+ USB_PD_PORT_POWER_DISCONNECTED,
+ USB_PD_PORT_POWER_SOURCE,
+ USB_PD_PORT_POWER_SINK,
+ USB_PD_PORT_POWER_SINK_NOT_CHARGING,
+};
+
+struct ec_response_usb_pd_power_info {
+ uint8_t role;
+ uint8_t type;
+ uint16_t voltage_max;
+ uint16_t voltage_now;
+ uint16_t current_max;
+ uint32_t max_power;
+} __packed;
+
/* Write USB-PD device FW */
#define EC_CMD_USB_PD_FW_UPDATE 0x110
diff --git a/include/usb.h b/include/usb.h
index bf2bb8fd6a..df6426fc64 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -190,7 +190,7 @@ struct usb_endpoint_descriptor {
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
-#define USB_BC12_CHARGE_VOLTAGE 5000 /* mA */
+#define USB_BC12_CHARGE_VOLTAGE 5000 /* mV */
/* Helpers for descriptors */
diff --git a/util/ectool.c b/util/ectool.c
index 2823ede20d..e9f0195077 100644
--- a/util/ectool.c
+++ b/util/ectool.c
@@ -191,6 +191,8 @@ const char help_str[] =
" usbpd <port> <auto | "
"[toggle|toggle-off|sink|source] [none|usb|dp|dock]>\n"
" Control USB PD/type-C\n"
+ " usbpdpower\n"
+ " Get USB PD power information\n"
" version\n"
" Prints EC version\n"
" wireless <flags> [<mask> [<suspend_flags> <suspend_mask>]]\n"
@@ -2880,6 +2882,86 @@ int cmd_usb_pd(int argc, char *argv[])
return (rv < 0 ? rv : 0);
}
+int cmd_usb_pd_power(int argc, char *argv[])
+{
+ struct ec_params_usb_pd_power_info p;
+ struct ec_response_usb_pd_power_info *r =
+ (struct ec_response_usb_pd_power_info *)ec_inbuf;
+ int num_ports, i, rv;
+
+ rv = ec_command(EC_CMD_USB_PD_PORTS, 0, NULL, 0,
+ ec_inbuf, ec_max_insize);
+ if (rv < 0)
+ return rv;
+ num_ports = ((struct ec_response_usb_pd_ports *)r)->num_ports;
+
+ for (i = 0; i < num_ports; i++) {
+ p.port = i;
+ rv = ec_command(EC_CMD_USB_PD_POWER_INFO, 0,
+ &p, sizeof(p),
+ ec_inbuf, ec_max_insize);
+ if (rv < 0)
+ return rv;
+
+ printf("Port %d:\n Power role: ", i);
+ switch (r->role) {
+ case USB_PD_PORT_POWER_DISCONNECTED:
+ printf("Disconnected\n");
+ break;
+ case USB_PD_PORT_POWER_SOURCE:
+ printf("Source\n");
+ break;
+ case USB_PD_PORT_POWER_SINK:
+ printf("Sink\n");
+ break;
+ case USB_PD_PORT_POWER_SINK_NOT_CHARGING:
+ printf("Sink (not charging)\n");
+ break;
+ default:
+ printf("Unknown\n");
+ }
+
+ printf(" Charger type: ");
+ switch (r->type) {
+ case USB_CHG_TYPE_PD:
+ printf("PD\n");
+ break;
+ case USB_CHG_TYPE_C:
+ printf("Type-c\n");
+ break;
+ case USB_CHG_TYPE_PROPRIETARY:
+ printf("Proprietary\n");
+ break;
+ case USB_CHG_TYPE_BC12_DCP:
+ printf("BC1.2 DCP\n");
+ break;
+ case USB_CHG_TYPE_BC12_CDP:
+ printf("BC1.2 CDP\n");
+ break;
+ case USB_CHG_TYPE_BC12_SDP:
+ printf("BC1.2 SDP\n");
+ break;
+ case USB_CHG_TYPE_OTHER:
+ printf("Other\n");
+ break;
+ default:
+ printf("None\n");
+ }
+
+ printf(" Max charging voltage: %dmV\n",
+ r->voltage_max);
+ printf(" Current charging voltage: %dmV\n",
+ r->voltage_now);
+ printf(" Max input current: %dmA\n",
+ r->current_max);
+ printf(" Max input power: %dmW\n",
+ r->max_power);
+
+ printf("\n");
+ }
+
+ return 0;
+}
int cmd_kbpress(int argc, char *argv[])
{
@@ -5096,6 +5178,7 @@ const struct command commands[] = {
{"usbchargemode", cmd_usb_charge_set_mode},
{"usbmux", cmd_usb_mux},
{"usbpd", cmd_usb_pd},
+ {"usbpdpower", cmd_usb_pd_power},
{"version", cmd_version},
{"wireless", cmd_wireless},
{NULL, NULL}