summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn Nematbakhsh <shawnn@chromium.org>2015-06-23 17:52:00 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-06-30 17:18:37 +0000
commit1ef8c7dc2096405e815797fd06dec628a39b4e33 (patch)
tree8c45cc6b372317d6b66dbdc11bc883802e208521
parent4114b7f1fe2274c0d1321cba8182ade8180599d9 (diff)
downloadchrome-ec-1ef8c7dc2096405e815797fd06dec628a39b4e33.tar.gz
usb_mux: Add driver interface for USB-C muxes
In preparation for adding support for additional USB-C mux chips, add a new high-level USB-C mux interface usb_mux.c. usb_mux functions are now called from pd code instead of board-level functions. usb_mux calls down into a mux chip-specific driver (currently pi3usb30532) or board-specific drivers which toggle GPIOs (for legacy boards). BUG=chrome-os-partner:41696 TEST=Manual on Glados in subsequent commit. Verify set() and get() functions set and return consistent values. Verify that USB SS device functions when muxes are set to dock or USB. Also, verify that DP dongle and USB SS device are functional on both PD ports on samus_pd. BRANCH=None Change-Id: Ib6477f489310f3be1430585ea09fea26f57e3752 Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/281435 Reviewed-by: Alec Berg <alecaberg@chromium.org>
-rw-r--r--board/honeybuns/board.c57
-rw-r--r--board/honeybuns/build.mk2
-rw-r--r--board/honeybuns/usb_mux.c84
-rw-r--r--board/honeybuns/usb_pd_policy.c3
-rw-r--r--board/oak/board.c70
-rw-r--r--board/oak/board.h12
-rw-r--r--board/oak/usb_pd_policy.c9
-rw-r--r--board/ryu/board.c62
-rw-r--r--board/ryu/build.mk2
-rw-r--r--board/ryu/usb_mux.c67
-rw-r--r--board/ryu/usb_pd_config.h3
-rw-r--r--board/ryu/usb_pd_policy.c7
-rw-r--r--board/ryu_p4p5/board.c130
-rw-r--r--board/ryu_p4p5/board.h4
-rw-r--r--board/ryu_p4p5/build.mk2
-rw-r--r--board/ryu_p4p5/usb_mux.c121
-rw-r--r--board/ryu_p4p5/usb_pd_config.h3
-rw-r--r--board/samus_pd/board.c114
-rw-r--r--board/samus_pd/board.h1
-rw-r--r--board/samus_pd/build.mk2
-rw-r--r--board/samus_pd/usb_mux.c117
-rw-r--r--board/samus_pd/usb_pd_config.h3
-rw-r--r--board/samus_pd/usb_pd_policy.c9
-rw-r--r--common/usb_pd_protocol.c86
-rw-r--r--driver/build.mk7
-rw-r--r--driver/pi3usb30532.h15
-rw-r--r--driver/usb_mux.c150
-rw-r--r--driver/usb_mux_pi3usb30532.c109
-rw-r--r--driver/usb_switch_pi3usb30532.c85
-rw-r--r--include/config.h4
-rw-r--r--include/usb_mux.h116
-rw-r--r--include/usb_pd.h41
32 files changed, 853 insertions, 644 deletions
diff --git a/board/honeybuns/board.c b/board/honeybuns/board.c
index bdcedf5599..b16b9b6ed3 100644
--- a/board/honeybuns/board.c
+++ b/board/honeybuns/board.c
@@ -164,62 +164,6 @@ const void * const usb_strings[] = {
};
BUILD_ASSERT(ARRAY_SIZE(usb_strings) == USB_STR_COUNT);
-void board_set_usb_mux(int port, enum typec_mux mux,
- enum usb_switch usb, int polarity)
-{
- if (mux == TYPEC_MUX_NONE) {
- /* put the mux in the high impedance state */
- gpio_set_level(GPIO_SS_MUX_OE_L, 1);
- /* Disable display hardware */
- gpio_set_level(GPIO_BRIDGE_RESET_L, 0);
- gpio_set_level(GPIO_SPLITTER_RESET_L, 0);
- /* Put the USB hub under reset */
- hx3_enable(0);
- return;
- }
-
- /* Trigger USB Hub configuration */
- hx3_enable(1);
-
- if ((mux == TYPEC_MUX_DOCK) || (mux == TYPEC_MUX_USB)) {
- /* Low selects USB Dock */
- gpio_set_level(GPIO_SS_MUX_SEL, 0);
- } else if (mux == TYPEC_MUX_DP) {
- /* high selects display port */
- gpio_set_level(GPIO_SS_MUX_SEL, 1);
- }
-
- /* clear OE line to make mux active */
- gpio_set_level(GPIO_SS_MUX_OE_L, 0);
-
- if (mux != TYPEC_MUX_USB) {
- /* Enable display hardware */
- gpio_set_level(GPIO_BRIDGE_RESET_L, 1);
- gpio_set_level(GPIO_SPLITTER_RESET_L, 1);
- }
-}
-
-int board_get_usb_mux(int port, const char **dp_str, const char **usb_str)
-{
- int oe_disabled = gpio_get_level(GPIO_SS_MUX_OE_L);
- int dp_4lanes = gpio_get_level(GPIO_SS_MUX_SEL);
-
- if (oe_disabled) {
- *usb_str = NULL;
- *dp_str = NULL;
- return 0;
- }
-
- if (dp_4lanes) {
- *dp_str = "DP_4LANE";
- *usb_str = NULL;
- } else {
- *dp_str = "DP_2LANE";
- *usb_str = "DOCK";
- }
- return 1;
-}
-
/**
* USB configuration
* Any type-C device with alternate mode capabilities must have the following
@@ -279,4 +223,3 @@ const struct bos_context bos_ctx = {
.descp = (void *)&bos_desc,
.size = sizeof(struct my_bos),
};
-
diff --git a/board/honeybuns/build.mk b/board/honeybuns/build.mk
index ff4b39a2ce..84b222d16a 100644
--- a/board/honeybuns/build.mk
+++ b/board/honeybuns/build.mk
@@ -11,4 +11,4 @@ CHIP_FAMILY:=stm32f0
CHIP_VARIANT:=stm32f07x
board-y=board.o hx3.o
-board-$(CONFIG_USB_POWER_DELIVERY)+=usb_pd_policy.o
+board-$(CONFIG_USB_POWER_DELIVERY)+=usb_mux.o usb_pd_policy.o
diff --git a/board/honeybuns/usb_mux.c b/board/honeybuns/usb_mux.c
new file mode 100644
index 0000000000..ea8a56910f
--- /dev/null
+++ b/board/honeybuns/usb_mux.c
@@ -0,0 +1,84 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Honeybuns-custom USB mux driver. */
+
+#include "common.h"
+#include "gpio.h"
+#include "usb_mux.h"
+#include "util.h"
+
+void board_set_usb_switches(int port, enum usb_switch setting)
+{
+ /* Not implemented */
+}
+
+static int board_init_usb_mux(int port)
+{
+ return EC_SUCCESS;
+}
+
+static int board_set_usb_mux(int port, mux_state_t mux_state)
+{
+ if (!(mux_state & (MUX_USB_ENABLED | MUX_DP_ENABLED))) {
+ /* put the mux in the high impedance state */
+ gpio_set_level(GPIO_SS_MUX_OE_L, 1);
+ /* Disable display hardware */
+ gpio_set_level(GPIO_BRIDGE_RESET_L, 0);
+ gpio_set_level(GPIO_SPLITTER_RESET_L, 0);
+ /* Put the USB hub under reset */
+ hx3_enable(0);
+ return EC_SUCCESS;
+ }
+
+ /* Trigger USB Hub configuration */
+ hx3_enable(1);
+
+ if (mux_state & MUX_USB_ENABLED)
+ /* Low selects USB Dock */
+ gpio_set_level(GPIO_SS_MUX_SEL, 0);
+ else
+ /* high selects display port */
+ gpio_set_level(GPIO_SS_MUX_SEL, 1);
+
+ /* clear OE line to make mux active */
+ gpio_set_level(GPIO_SS_MUX_OE_L, 0);
+
+ if (mux_state & MUX_DP_ENABLED) {
+ /* Enable display hardware */
+ gpio_set_level(GPIO_BRIDGE_RESET_L, 1);
+ gpio_set_level(GPIO_SPLITTER_RESET_L, 1);
+ }
+
+ return EC_SUCCESS;
+}
+
+static int board_get_usb_mux(int port, mux_state_t *mux_state)
+{
+ int oe_disabled = gpio_get_level(GPIO_SS_MUX_OE_L);
+ int dp_4lanes = gpio_get_level(GPIO_SS_MUX_SEL);
+
+ if (oe_disabled)
+ *mux_state = 0;
+ else if (dp_4lanes)
+ *mux_state = MUX_DP_ENABLED;
+ else
+ *mux_state = MUX_USB_ENABLED | MUX_DP_ENABLED;
+
+ return EC_SUCCESS;
+}
+
+const struct usb_mux_driver board_custom_usb_mux_driver = {
+ .init = board_init_usb_mux,
+ .set = board_set_usb_mux,
+ .get = board_get_usb_mux,
+};
+
+struct usb_mux usb_muxes[CONFIG_USB_PD_PORT_COUNT] = {
+ {
+ .port_addr = 0,
+ .driver = &board_custom_usb_mux_driver,
+ },
+};
diff --git a/board/honeybuns/usb_pd_policy.c b/board/honeybuns/usb_pd_policy.c
index 6f2f33505d..65c056f102 100644
--- a/board/honeybuns/usb_pd_policy.c
+++ b/board/honeybuns/usb_pd_policy.c
@@ -15,6 +15,7 @@
#include "timer.h"
#include "util.h"
#include "usb.h"
+#include "usb_mux.h"
#include "usb_pd.h"
@@ -253,7 +254,7 @@ static int dp_config(int port, uint32_t *payload)
if (PD_DP_CFG_DPON(payload[1]))
gpio_set_level(GPIO_PD_SBU_ENABLE, 1);
/* Get the DP lanes (or DP+USB SS depending on the mode) */
- board_set_usb_mux(port, mux, USB_SWITCH_CONNECT, pd_get_polarity(port));
+ usb_mux_set(port, mux, USB_SWITCH_CONNECT, pd_get_polarity(port));
return 1;
}
diff --git a/board/oak/board.c b/board/oak/board.c
index 26de4075d5..bf94c726e2 100644
--- a/board/oak/board.c
+++ b/board/oak/board.c
@@ -21,7 +21,6 @@
#include "i2c.h"
#include "keyboard_raw.h"
#include "lid_switch.h"
-#include "pi3usb30532.h"
#include "pi3usb9281.h"
#include "power.h"
#include "power_button.h"
@@ -33,6 +32,7 @@
#include "temp_sensor_chip.h"
#include "thermal.h"
#include "timer.h"
+#include "usb_mux.h"
#include "usb_pd.h"
#include "usb_pd_tcpm.h"
#include "util.h"
@@ -164,6 +164,17 @@ struct ec_thermal_config thermal_params[] = {
};
BUILD_ASSERT(ARRAY_SIZE(thermal_params) == TEMP_SENSOR_COUNT);
+struct usb_mux usb_muxes[CONFIG_USB_PD_PORT_COUNT] = {
+ {
+ .port_addr = 0x54 << 1,
+ .driver = &pi3usb30532_usb_mux_driver,
+ },
+ {
+ .port_addr = 0x55 << 1,
+ .driver = &pi3usb30532_usb_mux_driver,
+ },
+};
+
static int discharging_on_ac;
/**
@@ -172,7 +183,6 @@ static int discharging_on_ac;
*/
static int usb_switch_state[CONFIG_USB_PD_PORT_COUNT];
static struct mutex usb_switch_lock[CONFIG_USB_PD_PORT_COUNT];
-static uint8_t ss_mux_mode[CONFIG_USB_PD_PORT_COUNT];
/**
* Store the current DP hardware route.
@@ -350,62 +360,6 @@ void board_set_usb_switches(int port, enum usb_switch setting)
mutex_unlock(&usb_switch_lock[port]);
}
-/**
- * Set USB3.0/DP mux.
- *
- * @param port the type-C port to change
- * @param mux mux setting in enum typec_mux
- * @param usb USB2.0 switch
- * @param polarity 0 or 1
- */
-void board_set_usb_mux(int port, enum typec_mux mux,
- enum usb_switch usb, int polarity)
-{
- const uint8_t modes[] = {
- [TYPEC_MUX_NONE] = PI3USB30532_MODE_POWERON,
- [TYPEC_MUX_USB] = PI3USB30532_MODE_USB,
- [TYPEC_MUX_DP] = PI3USB30532_MODE_DP,
- [TYPEC_MUX_DOCK] = PI3USB30532_MODE_DP_USB,
- };
-
- /* Configure USB2.0 */
- board_set_usb_switches(port, usb);
-
- /* Configure superspeed lanes */
- ss_mux_mode[port] = modes[mux] | (polarity ? PI3USB30532_BIT_SWAP : 0);
- pi3usb30532_set_switch(port, ss_mux_mode[port]);
- CPRINTS("usb/dp mux: port(%d) typec_mux(%d) usb2(%d) polarity(%d)",
- port, mux, usb, polarity);
-}
-
-/**
- * Get USB/DP mux state.
- *
- * @param port the type-C port to check
- * @param dp_str return DP mux status in "DP1", "DP2" or NULL
- * @param usb_str return USB mux status in "USB1", "USB2" or NULL
- *
- * @return superspeed lane enable or not.
- */
-int board_get_usb_mux(int port, const char **dp_str, const char **usb_str)
-{
- const char *dp, *usb;
- int has_ss, has_dp, has_usb, polarity;
- int mode = ss_mux_mode[port];
-
- polarity = mode & PI3USB30532_BIT_SWAP;
- dp = polarity ? "DP2" : "DP1";
- usb = polarity ? "USB2" : "USB1";
-
- has_ss = mode & (PI3USB30532_BIT_DP | PI3USB30532_BIT_USB);
- has_dp = mode & PI3USB30532_BIT_DP;
- has_usb = mode & PI3USB30532_BIT_USB;
- *dp_str = has_dp ? dp : NULL;
- *usb_str = has_usb ? usb : NULL;
-
- return has_ss ? 1 : 0;
-}
-
static void hpd_irq_deferred(void)
{
gpio_set_level(GPIO_USB_DP_HPD, 1);
diff --git a/board/oak/board.h b/board/oak/board.h
index f653a344e9..940aa87b3d 100644
--- a/board/oak/board.h
+++ b/board/oak/board.h
@@ -93,15 +93,9 @@
#define CONFIG_CMD_HOSTCMD
/* Drivers */
-#define CONFIG_USB_SWITCH_PI3USB30532
-/*
- * 8-bit USB type-C switch I2C addresses:
- * port 0: 0x54 << 1
- * port 1: 0x55 << 1
- */
-#define CONFIG_USB_SWITCH_I2C_ADDRS {0x54 << 1, 0x55 << 1}
+/* USB Mux */
+#define CONFIG_USB_MUX_PI3USB30532
/* BC 1.2 charger */
-#define CONFIG_USB_SWITCH_PI3USB30532
#define CONFIG_USB_SWITCH_PI3USB9281
#define CONFIG_USB_SWITCH_PI3USB9281_CHIP_COUNT 2
@@ -120,7 +114,7 @@
#define I2C_PORT_PERICOM 0
#define I2C_PORT_THERMAL 0
#define I2C_PORT_PD_MCU 1
-#define I2C_PORT_USB_SWITCH 1
+#define I2C_PORT_USB_MUX 1
#define I2C_PORT_TCPC 1
/* Timer selection */
diff --git a/board/oak/usb_pd_policy.c b/board/oak/usb_pd_policy.c
index 26911a8e0f..e60f8745db 100644
--- a/board/oak/usb_pd_policy.c
+++ b/board/oak/usb_pd_policy.c
@@ -15,6 +15,7 @@
#include "task.h"
#include "timer.h"
#include "util.h"
+#include "usb_mux.h"
#include "usb_pd.h"
#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
@@ -246,8 +247,8 @@ static void svdm_safe_dp_mode(int port)
{
/* make DP interface safe until configure */
dp_flags[port] = 0;
- board_set_usb_mux(port, TYPEC_MUX_NONE,
- USB_SWITCH_CONNECT, pd_get_polarity(port));
+ usb_mux_set(port, TYPEC_MUX_NONE,
+ USB_SWITCH_CONNECT, pd_get_polarity(port));
}
static int svdm_enter_dp_mode(int port, uint32_t mode_caps)
@@ -280,8 +281,8 @@ static int svdm_dp_status(int port, uint32_t *payload)
static int svdm_dp_config(int port, uint32_t *payload)
{
int opos = pd_alt_mode(port, USB_SID_DISPLAYPORT);
- board_set_usb_mux(port, TYPEC_MUX_DP,
- USB_SWITCH_CONNECT, pd_get_polarity(port));
+ usb_mux_set(port, TYPEC_MUX_DP,
+ USB_SWITCH_CONNECT, pd_get_polarity(port));
payload[0] = VDO(USB_SID_DISPLAYPORT, 1,
CMD_DP_CONFIG | VDO_OPOS(opos));
payload[1] = VDO_DP_CFG(MODE_DP_PIN_E, /* pin mode */
diff --git a/board/ryu/board.c b/board/ryu/board.c
index 0cbfd80014..d7b3d2893d 100644
--- a/board/ryu/board.c
+++ b/board/ryu/board.c
@@ -346,68 +346,6 @@ void board_set_usb_switches(int port, enum usb_switch setting)
pi3usb9281_set_switches(port, usb_switch_state);
}
-void board_set_usb_mux(int port, enum typec_mux mux,
- enum usb_switch usb, int polarity)
-{
- /* reset everything */
- gpio_set_level(GPIO_USBC_MUX_CONF0, 0);
- gpio_set_level(GPIO_USBC_MUX_CONF1, 0);
- gpio_set_level(GPIO_USBC_MUX_CONF2, 0);
-
- /* Set D+/D- switch to appropriate level */
- board_set_usb_switches(port, usb);
-
- if (mux == TYPEC_MUX_NONE)
- /* everything is already disabled, we can return */
- return;
-
- gpio_set_level(GPIO_USBC_MUX_CONF0, polarity);
-
- if (mux == TYPEC_MUX_USB || mux == TYPEC_MUX_DOCK)
- /* USB 3.0 uses 2 superspeed lanes */
- gpio_set_level(GPIO_USBC_MUX_CONF2, 1);
-
- if (mux == TYPEC_MUX_DP || mux == TYPEC_MUX_DOCK)
- /* DP uses available superspeed lanes (x2 or x4) */
- gpio_set_level(GPIO_USBC_MUX_CONF1, 1);
-}
-
-int board_get_usb_mux(int port, const char **dp_str, const char **usb_str)
-{
- int has_usb, has_dp, polarity;
-
- has_usb = gpio_get_level(GPIO_USBC_MUX_CONF2);
- has_dp = gpio_get_level(GPIO_USBC_MUX_CONF1);
- polarity = gpio_get_level(GPIO_USBC_MUX_CONF0);
-
- if (has_dp)
- *dp_str = polarity ? "DP2" : "DP1";
- else
- *dp_str = NULL;
-
- if (has_usb)
- *usb_str = polarity ? "USB2" : "USB1";
- else
- *usb_str = NULL;
-
- return has_dp || has_usb;
-}
-
-void board_flip_usb_mux(int port)
-{
- int has_usb, has_dp, polarity;
- enum typec_mux mux;
-
- has_usb = gpio_get_level(GPIO_USBC_MUX_CONF2);
- has_dp = gpio_get_level(GPIO_USBC_MUX_CONF1);
- polarity = gpio_get_level(GPIO_USBC_MUX_CONF0);
- mux = has_usb && has_dp ? TYPEC_MUX_DOCK :
- (has_dp ? TYPEC_MUX_DP :
- (has_usb ? TYPEC_MUX_USB : TYPEC_MUX_NONE));
-
- board_set_usb_mux(port, mux, usb_switch_state, !polarity);
-}
-
/**
* Discharge battery when on AC power for factory test.
*/
diff --git a/board/ryu/build.mk b/board/ryu/build.mk
index 4671ea0c7c..7d6e69851d 100644
--- a/board/ryu/build.mk
+++ b/board/ryu/build.mk
@@ -10,4 +10,4 @@ CHIP_FAMILY:=stm32f3
CHIP_VARIANT:=stm32f373
board-y=board.o
-board-$(CONFIG_USB_POWER_DELIVERY)+=usb_pd_policy.o
+board-$(CONFIG_USB_POWER_DELIVERY)+=usb_mux.o usb_pd_policy.o
diff --git a/board/ryu/usb_mux.c b/board/ryu/usb_mux.c
new file mode 100644
index 0000000000..e77a8f228b
--- /dev/null
+++ b/board/ryu/usb_mux.c
@@ -0,0 +1,67 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Ryu-custom USB mux driver. */
+
+#include "common.h"
+#include "gpio.h"
+#include "usb_mux.h"
+#include "util.h"
+
+static int board_init_usb_mux(int port)
+{
+ return EC_SUCCESS;
+}
+
+static int board_set_usb_mux(int port, mux_state_t mux_state)
+{
+ /* reset everything */
+ gpio_set_level(GPIO_USBC_MUX_CONF0, 0);
+ gpio_set_level(GPIO_USBC_MUX_CONF1, 0);
+ gpio_set_level(GPIO_USBC_MUX_CONF2, 0);
+
+ if (!(mux_state & (MUX_USB_ENABLED | MUX_DP_ENABLED)))
+ /* everything is already disabled, we can return */
+ return EC_SUCCESS;
+
+ gpio_set_level(GPIO_USBC_MUX_CONF0, mux_state & MUX_POLARITY_INVERTED);
+
+ if (mux_state & MUX_USB_ENABLED)
+ /* USB 3.0 uses 2 superspeed lanes */
+ gpio_set_level(GPIO_USBC_MUX_CONF2, 1);
+
+ if (mux_state & MUX_DP_ENABLED)
+ /* DP uses available superspeed lanes (x2 or x4) */
+ gpio_set_level(GPIO_USBC_MUX_CONF1, 1);
+
+ return EC_SUCCESS;
+}
+
+static int board_get_usb_mux(int port, mux_state_t *mux_state)
+{
+ *mux_state = 0;
+
+ if (gpio_get_level(GPIO_USBC_MUX_CONF2))
+ *mux_state |= MUX_USB_ENABLED;
+ if (gpio_get_level(GPIO_USBC_MUX_CONF1))
+ *mux_state |= MUX_DP_ENABLED;
+ if (gpio_get_level(GPIO_USBC_MUX_CONF0))
+ *mux_state |= MUX_POLARITY_INVERTED;
+
+ return EC_SUCCESS;
+}
+
+const struct usb_mux_driver board_custom_usb_mux_driver = {
+ .init = board_init_usb_mux,
+ .set = board_set_usb_mux,
+ .get = board_get_usb_mux,
+};
+
+struct usb_mux usb_muxes[CONFIG_USB_PD_PORT_COUNT] = {
+ {
+ .port_addr = 0,
+ .driver = &board_custom_usb_mux_driver,
+ },
+};
diff --git a/board/ryu/usb_pd_config.h b/board/ryu/usb_pd_config.h
index c28a5469f5..2b7f89b9d8 100644
--- a/board/ryu/usb_pd_config.h
+++ b/board/ryu/usb_pd_config.h
@@ -13,6 +13,7 @@
#include "clock.h"
#include "gpio.h"
#include "registers.h"
+#include "usb_mux.h"
/* Timer selection for baseband PD communication */
#define TIM_CLOCK_PD_TX_C0 3
@@ -172,7 +173,7 @@ static inline void pd_config_init(int port, uint8_t power_role)
pd_tx_init();
/* Reset mux ... for NONE polarity doesn't matter */
- board_set_usb_mux(port, TYPEC_MUX_NONE, USB_SWITCH_DISCONNECT, 0);
+ usb_mux_set(port, TYPEC_MUX_NONE, USB_SWITCH_DISCONNECT, 0);
gpio_set_level(GPIO_USBC_VCONN1_EN_L, 1);
gpio_set_level(GPIO_USBC_VCONN2_EN_L, 1);
diff --git a/board/ryu/usb_pd_policy.c b/board/ryu/usb_pd_policy.c
index 2e9ad58bf0..6a22a76a16 100644
--- a/board/ryu/usb_pd_policy.c
+++ b/board/ryu/usb_pd_policy.c
@@ -16,6 +16,7 @@
#include "task.h"
#include "timer.h"
#include "util.h"
+#include "usb_mux.h"
#include "usb_pd.h"
#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
@@ -244,7 +245,7 @@ int pd_custom_vdm(int port, int cnt, uint32_t *payload,
CPRINTF("Current: %dmA\n", payload[1]);
break;
case VDO_CMD_FLIP:
- board_flip_usb_mux(port);
+ usb_mux_flip(port);
break;
#ifdef CONFIG_USB_PD_LOGGING
case VDO_CMD_GET_LOG:
@@ -263,7 +264,7 @@ static uint32_t dp_status;
static void svdm_safe_dp_mode(int port)
{
/* make DP interface safe until configure */
- board_set_usb_mux(port, TYPEC_MUX_NONE, USB_SWITCH_CONNECT, 0);
+ usb_mux_set(port, TYPEC_MUX_NONE, USB_SWITCH_CONNECT, 0);
dp_flags = 0;
dp_status = 0;
}
@@ -304,7 +305,7 @@ static int svdm_dp_config(int port, uint32_t *payload)
if (!pin_mode)
return 0;
- board_set_usb_mux(port, mf_pref ? TYPEC_MUX_DOCK : TYPEC_MUX_DP,
+ usb_mux_set(port, mf_pref ? TYPEC_MUX_DOCK : TYPEC_MUX_DP,
USB_SWITCH_CONNECT, pd_get_polarity(port));
payload[0] = VDO(USB_SID_DISPLAYPORT, 1,
diff --git a/board/ryu_p4p5/board.c b/board/ryu_p4p5/board.c
index 7a333610a1..2432eac06e 100644
--- a/board/ryu_p4p5/board.c
+++ b/board/ryu_p4p5/board.c
@@ -29,6 +29,7 @@
#include "spi.h"
#include "task.h"
#include "usb.h"
+#include "usb_mux.h"
#include "usb_pd.h"
#include "usb_spi.h"
#include "usb-stm32f3.h"
@@ -167,11 +168,22 @@ struct pi3usb9281_config pi3usb9281_chips[] = {
BUILD_ASSERT(ARRAY_SIZE(pi3usb9281_chips) ==
CONFIG_USB_SWITCH_PI3USB9281_CHIP_COUNT);
+struct usb_mux usb_muxes[CONFIG_USB_PD_PORT_COUNT] = {
+ {
+ .port_addr = 0,
+ .driver = &p5_board_custom_usb_mux_driver,
+ },
+};
+
/* Initialize board. */
static void board_init(void)
{
struct charge_port_info charge_none, charge_vbus;
+ /* Select P4 driver for old boards due to different GPIO config */
+ if (board_get_version() < 5)
+ usb_muxes[0].driver = &p4_board_custom_usb_mux_driver;
+
/* Initialize all pericom charge suppliers to 0 */
charge_none.voltage = USB_BC12_CHARGE_VOLTAGE;
charge_none.current = 0;
@@ -287,124 +299,6 @@ void board_set_usb_switches(int port, enum usb_switch setting)
pi3usb9281_set_switches(port, usb_switch_state);
}
-/* TODO(crosbug.com/p/38333) remove me */
-#define GPIO_USBC_SS1_USB_MODE_L GPIO_USBC_MUX_CONF0
-#define GPIO_USBC_SS2_USB_MODE_L GPIO_USBC_MUX_CONF1
-#define GPIO_USBC_SS_EN_L GPIO_USBC_MUX_CONF2
-
-void p4_board_set_usb_mux(int port, enum typec_mux mux,
- enum usb_switch usb, int polarity)
-{
- /* reset everything */
- gpio_set_level(GPIO_USBC_SS_EN_L, 1);
- gpio_set_level(GPIO_USBC_DP_MODE_L, 1);
- gpio_set_level(GPIO_USBC_DP_POLARITY, 1);
- gpio_set_level(GPIO_USBC_SS1_USB_MODE_L, 1);
- gpio_set_level(GPIO_USBC_SS2_USB_MODE_L, 1);
-
- /* Set D+/D- switch to appropriate level */
- board_set_usb_switches(port, usb);
-
- if (mux == TYPEC_MUX_NONE)
- /* everything is already disabled, we can return */
- return;
-
- if (mux == TYPEC_MUX_USB || mux == TYPEC_MUX_DOCK) {
- /* USB 3.0 uses 2 superspeed lanes */
- gpio_set_level(polarity ? GPIO_USBC_SS2_USB_MODE_L :
- GPIO_USBC_SS1_USB_MODE_L, 0);
- }
-
- if (mux == TYPEC_MUX_DP || mux == TYPEC_MUX_DOCK) {
- /* DP uses available superspeed lanes (x2 or x4) */
- gpio_set_level(GPIO_USBC_DP_POLARITY, polarity);
- gpio_set_level(GPIO_USBC_DP_MODE_L, 0);
- }
- /* switch on superspeed lanes */
- gpio_set_level(GPIO_USBC_SS_EN_L, 0);
-}
-
-void board_set_usb_mux(int port, enum typec_mux mux,
- enum usb_switch usb, int polarity)
-{
- if (board_get_version() < 5) {
- /* P4/EVT or older boards */
- /* TODO(crosbug.com/p/38333) remove this */
- p4_board_set_usb_mux(port, mux, usb, polarity);
- return;
- }
-
- /* reset everything */
- gpio_set_level(GPIO_USBC_MUX_CONF0, 0);
- gpio_set_level(GPIO_USBC_MUX_CONF1, 0);
- gpio_set_level(GPIO_USBC_MUX_CONF2, 0);
-
- /* Set D+/D- switch to appropriate level */
- board_set_usb_switches(port, usb);
-
- if (mux == TYPEC_MUX_NONE)
- /* everything is already disabled, we can return */
- return;
-
- gpio_set_level(GPIO_USBC_MUX_CONF0, polarity);
-
- if (mux == TYPEC_MUX_USB || mux == TYPEC_MUX_DOCK)
- /* USB 3.0 uses 2 superspeed lanes */
- gpio_set_level(GPIO_USBC_MUX_CONF2, 1);
-
- if (mux == TYPEC_MUX_DP || mux == TYPEC_MUX_DOCK)
- /* DP uses available superspeed lanes (x2 or x4) */
- gpio_set_level(GPIO_USBC_MUX_CONF1, 1);
-}
-
-int p4_board_get_usb_mux(int port, const char **dp_str, const char **usb_str)
-{
- int has_ss = !gpio_get_level(GPIO_USBC_SS_EN_L);
- int has_usb = !gpio_get_level(GPIO_USBC_SS1_USB_MODE_L) ||
- !gpio_get_level(GPIO_USBC_SS2_USB_MODE_L);
- int has_dp = !gpio_get_level(GPIO_USBC_DP_MODE_L);
-
- if (has_dp)
- *dp_str = gpio_get_level(GPIO_USBC_DP_POLARITY) ? "DP2" : "DP1";
- else
- *dp_str = NULL;
-
- if (has_usb)
- *usb_str = gpio_get_level(GPIO_USBC_SS1_USB_MODE_L) ?
- "USB2" : "USB1";
- else
- *usb_str = NULL;
-
- return has_ss;
-}
-
-int board_get_usb_mux(int port, const char **dp_str, const char **usb_str)
-{
- int has_usb, has_dp, polarity;
-
- if (board_get_version() < 5) {
- /* P4/EVT or older boards */
- /* TODO(crosbug.com/p/38333) remove this */
- return p4_board_get_usb_mux(port, dp_str, usb_str);
- }
-
- has_usb = gpio_get_level(GPIO_USBC_MUX_CONF2);
- has_dp = gpio_get_level(GPIO_USBC_MUX_CONF1);
- polarity = gpio_get_level(GPIO_USBC_MUX_CONF0);
-
- if (has_dp)
- *dp_str = polarity ? "DP2" : "DP1";
- else
- *dp_str = NULL;
-
- if (has_usb)
- *usb_str = polarity ? "USB2" : "USB1";
- else
- *usb_str = NULL;
-
- return has_dp || has_usb;
-}
-
/**
* Discharge battery when on AC power for factory test.
*/
diff --git a/board/ryu_p4p5/board.h b/board/ryu_p4p5/board.h
index c7c5a9193d..52bc499d47 100644
--- a/board/ryu_p4p5/board.h
+++ b/board/ryu_p4p5/board.h
@@ -208,6 +208,10 @@ enum usb_strings {
/* The lower the input voltage, the higher the power efficiency. */
#define PD_PREFER_LOW_VOLTAGE
+/* Mux driver functions differ by board revision */
+extern const struct usb_mux_driver p4_board_custom_usb_mux_driver;
+extern const struct usb_mux_driver p5_board_custom_usb_mux_driver;
+
/* Discharge battery when on AC power for factory test. */
int board_discharge_on_ac(int enable);
diff --git a/board/ryu_p4p5/build.mk b/board/ryu_p4p5/build.mk
index 4671ea0c7c..7d6e69851d 100644
--- a/board/ryu_p4p5/build.mk
+++ b/board/ryu_p4p5/build.mk
@@ -10,4 +10,4 @@ CHIP_FAMILY:=stm32f3
CHIP_VARIANT:=stm32f373
board-y=board.o
-board-$(CONFIG_USB_POWER_DELIVERY)+=usb_pd_policy.o
+board-$(CONFIG_USB_POWER_DELIVERY)+=usb_mux.o usb_pd_policy.o
diff --git a/board/ryu_p4p5/usb_mux.c b/board/ryu_p4p5/usb_mux.c
new file mode 100644
index 0000000000..03689fc468
--- /dev/null
+++ b/board/ryu_p4p5/usb_mux.c
@@ -0,0 +1,121 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Ryu-custom USB mux driver. */
+
+#include "common.h"
+#include "gpio.h"
+#include "usb_mux.h"
+#include "util.h"
+
+static int board_init_usb_mux(int port)
+{
+ return EC_SUCCESS;
+}
+
+static int board_set_usb_mux(int port, mux_state_t mux_state)
+{
+ /* reset everything */
+ gpio_set_level(GPIO_USBC_MUX_CONF0, 0);
+ gpio_set_level(GPIO_USBC_MUX_CONF1, 0);
+ gpio_set_level(GPIO_USBC_MUX_CONF2, 0);
+
+ if (!(mux_state & (MUX_USB_ENABLED | MUX_DP_ENABLED)))
+ /* everything is already disabled, we can return */
+ return EC_SUCCESS;
+
+ gpio_set_level(GPIO_USBC_MUX_CONF0, mux_state & MUX_POLARITY_INVERTED);
+
+ if (mux_state & MUX_USB_ENABLED)
+ /* USB 3.0 uses 2 superspeed lanes */
+ gpio_set_level(GPIO_USBC_MUX_CONF2, 1);
+
+ if (mux_state & MUX_DP_ENABLED)
+ /* DP uses available superspeed lanes (x2 or x4) */
+ gpio_set_level(GPIO_USBC_MUX_CONF1, 1);
+
+ return EC_SUCCESS;
+}
+
+/* TODO(crosbug.com/p/38333) remove me */
+#define GPIO_USBC_SS1_USB_MODE_L GPIO_USBC_MUX_CONF0
+#define GPIO_USBC_SS2_USB_MODE_L GPIO_USBC_MUX_CONF1
+#define GPIO_USBC_SS_EN_L GPIO_USBC_MUX_CONF2
+
+static int p4_board_set_usb_mux(int port, mux_state_t mux_state)
+{
+ int polarity = mux_state & MUX_POLARITY_INVERTED;
+
+ /* reset everything */
+ gpio_set_level(GPIO_USBC_SS_EN_L, 1);
+ gpio_set_level(GPIO_USBC_DP_MODE_L, 1);
+ gpio_set_level(GPIO_USBC_DP_POLARITY, 1);
+ gpio_set_level(GPIO_USBC_SS1_USB_MODE_L, 1);
+ gpio_set_level(GPIO_USBC_SS2_USB_MODE_L, 1);
+
+ if (!(mux_state & (MUX_USB_ENABLED | MUX_DP_ENABLED)))
+ /* everything is already disabled, we can return */
+ return EC_SUCCESS;
+
+ if (mux_state & MUX_USB_ENABLED)
+ /* USB 3.0 uses 2 superspeed lanes */
+ gpio_set_level(polarity ? GPIO_USBC_SS2_USB_MODE_L :
+ GPIO_USBC_SS1_USB_MODE_L, 0);
+
+ if (mux_state & MUX_DP_ENABLED) {
+ /* DP uses available superspeed lanes (x2 or x4) */
+ gpio_set_level(GPIO_USBC_DP_POLARITY, polarity);
+ gpio_set_level(GPIO_USBC_DP_MODE_L, 0);
+ }
+
+ /* switch on superspeed lanes */
+ gpio_set_level(GPIO_USBC_SS_EN_L, 0);
+
+ return EC_SUCCESS;
+}
+
+static int board_get_usb_mux(int port, mux_state_t *mux_state)
+{
+ *mux_state = 0;
+
+ if (gpio_get_level(GPIO_USBC_MUX_CONF2))
+ *mux_state |= MUX_USB_ENABLED;
+ if (gpio_get_level(GPIO_USBC_MUX_CONF1))
+ *mux_state |= MUX_DP_ENABLED;
+ if (gpio_get_level(GPIO_USBC_MUX_CONF0))
+ *mux_state |= MUX_POLARITY_INVERTED;
+
+ return EC_SUCCESS;
+}
+
+static int p4_board_get_usb_mux(int port, mux_state_t *mux_state)
+{
+ *mux_state = 0;
+
+ if (!gpio_get_level(GPIO_USBC_SS1_USB_MODE_L) ||
+ !gpio_get_level(GPIO_USBC_SS2_USB_MODE_L))
+ *mux_state |= MUX_USB_ENABLED;
+
+ if (!gpio_get_level(GPIO_USBC_DP_MODE_L))
+ *mux_state |= MUX_DP_ENABLED;
+
+ if (gpio_get_level(GPIO_USBC_DP_POLARITY))
+ *mux_state |= MUX_POLARITY_INVERTED;
+
+ return EC_SUCCESS;
+}
+
+const struct usb_mux_driver p4_board_custom_usb_mux_driver = {
+ .init = board_init_usb_mux,
+ .set = p4_board_set_usb_mux,
+ .get = p4_board_get_usb_mux,
+};
+
+const struct usb_mux_driver p5_board_custom_usb_mux_driver = {
+ .init = board_init_usb_mux,
+ .set = board_set_usb_mux,
+ .get = board_get_usb_mux,
+};
+
diff --git a/board/ryu_p4p5/usb_pd_config.h b/board/ryu_p4p5/usb_pd_config.h
index 31e675eb55..7a4df7a6a1 100644
--- a/board/ryu_p4p5/usb_pd_config.h
+++ b/board/ryu_p4p5/usb_pd_config.h
@@ -13,6 +13,7 @@
#include "clock.h"
#include "gpio.h"
#include "registers.h"
+#include "usb_mux.h"
/* Timer selection for baseband PD communication */
#define TIM_CLOCK_PD_TX_C0 3
@@ -171,7 +172,7 @@ static inline void pd_config_init(int port, uint8_t power_role)
pd_tx_init();
/* Reset mux ... for NONE polarity doesn't matter */
- board_set_usb_mux(port, TYPEC_MUX_NONE, USB_SWITCH_DISCONNECT, 0);
+ usb_mux_set(port, TYPEC_MUX_NONE, USB_SWITCH_DISCONNECT, 0);
gpio_set_level(GPIO_USBC_VCONN1_EN_L, 1);
gpio_set_level(GPIO_USBC_VCONN2_EN_L, 1);
diff --git a/board/samus_pd/board.c b/board/samus_pd/board.c
index 161fc135fc..c162f760a1 100644
--- a/board/samus_pd/board.c
+++ b/board/samus_pd/board.c
@@ -403,36 +403,6 @@ const struct i2c_port_t i2c_ports[] = {
};
const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports);
-struct usb_port_mux
-{
- enum gpio_signal ss1_en_l;
- enum gpio_signal ss2_en_l;
- enum gpio_signal dp_mode_l;
- enum gpio_signal dp_polarity;
- enum gpio_signal ss1_dp_mode;
- enum gpio_signal ss2_dp_mode;
-};
-
-const struct usb_port_mux usb_muxes[] = {
- {
- .ss1_en_l = GPIO_USB_C0_SS1_EN_L,
- .ss2_en_l = GPIO_USB_C0_SS2_EN_L,
- .dp_mode_l = GPIO_USB_C0_DP_MODE_L,
- .dp_polarity = GPIO_USB_C0_DP_POLARITY,
- .ss1_dp_mode = GPIO_USB_C0_SS1_DP_MODE,
- .ss2_dp_mode = GPIO_USB_C0_SS2_DP_MODE,
- },
- {
- .ss1_en_l = GPIO_USB_C1_SS1_EN_L,
- .ss2_en_l = GPIO_USB_C1_SS2_EN_L,
- .dp_mode_l = GPIO_USB_C1_DP_MODE_L,
- .dp_polarity = GPIO_USB_C1_DP_POLARITY,
- .ss1_dp_mode = GPIO_USB_C1_SS1_DP_MODE,
- .ss2_dp_mode = GPIO_USB_C1_SS2_DP_MODE,
- },
-};
-BUILD_ASSERT(ARRAY_SIZE(usb_muxes) == CONFIG_USB_PD_PORT_COUNT);
-
void board_set_usb_switches(int port, enum usb_switch setting)
{
/* If switch is not changing then return */
@@ -446,90 +416,6 @@ void board_set_usb_switches(int port, enum usb_switch setting)
mutex_unlock(&usb_switch_lock[port]);
}
-void board_set_usb_mux(int port, enum typec_mux mux,
- enum usb_switch usb, int polarity)
-{
- const struct usb_port_mux *usb_mux = usb_muxes + port;
-
- /* reset everything */
- gpio_set_level(usb_mux->ss1_en_l, 1);
- gpio_set_level(usb_mux->ss2_en_l, 1);
- gpio_set_level(usb_mux->dp_mode_l, 1);
- gpio_set_level(usb_mux->dp_polarity, 1);
- gpio_set_level(usb_mux->ss1_dp_mode, 1);
- gpio_set_level(usb_mux->ss2_dp_mode, 1);
-
- /* Set D+/D- switch to appropriate level */
- board_set_usb_switches(port, usb);
-
- if (mux == TYPEC_MUX_NONE)
- /* everything is already disabled, we can return */
- return;
-
- if (mux == TYPEC_MUX_USB || mux == TYPEC_MUX_DOCK) {
- /* USB 3.0 uses 2 superspeed lanes */
- gpio_set_level(polarity ? usb_mux->ss2_dp_mode :
- usb_mux->ss1_dp_mode, 0);
- }
-
- if (mux == TYPEC_MUX_DP || mux == TYPEC_MUX_DOCK) {
- /* DP uses available superspeed lanes (x2 or x4) */
- gpio_set_level(usb_mux->dp_polarity, polarity);
- gpio_set_level(usb_mux->dp_mode_l, 0);
- }
- /* switch on superspeed lanes */
- gpio_set_level(usb_mux->ss1_en_l, 0);
- gpio_set_level(usb_mux->ss2_en_l, 0);
-}
-
-int board_get_usb_mux(int port, const char **dp_str, const char **usb_str)
-{
- const struct usb_port_mux *usb_mux = usb_muxes + port;
- int has_ss, has_usb, has_dp;
- const char *dp, *usb;
-
- has_ss = !gpio_get_level(usb_mux->ss1_en_l);
- has_usb = !gpio_get_level(usb_mux->ss1_dp_mode) ||
- !gpio_get_level(usb_mux->ss2_dp_mode);
- has_dp = !gpio_get_level(usb_mux->dp_mode_l);
- dp = gpio_get_level(usb_mux->dp_polarity) ?
- "DP2" : "DP1";
- usb = gpio_get_level(usb_mux->ss1_dp_mode) ?
- "USB2" : "USB1";
-
- *dp_str = has_dp ? dp : NULL;
- *usb_str = has_usb ? usb : NULL;
-
- return has_ss;
-}
-
-void board_flip_usb_mux(int port)
-{
- const struct usb_port_mux *usb_mux = usb_muxes + port;
- int usb_polarity;
-
- /* Flip DP polarity */
- gpio_set_level(usb_mux->dp_polarity,
- !gpio_get_level(usb_mux->dp_polarity));
-
- /* Flip USB polarity if enabled */
- if (gpio_get_level(usb_mux->ss1_dp_mode) &&
- gpio_get_level(usb_mux->ss2_dp_mode))
- return;
- usb_polarity = gpio_get_level(usb_mux->ss1_dp_mode);
-
- /*
- * Disable both sides first so that we don't enable both at the
- * same time accidentally.
- */
- gpio_set_level(usb_mux->ss1_dp_mode, 1);
- gpio_set_level(usb_mux->ss2_dp_mode, 1);
-
- gpio_set_level(usb_mux->ss1_dp_mode, !usb_polarity);
- gpio_set_level(usb_mux->ss2_dp_mode, usb_polarity);
-}
-
-
int board_get_battery_soc(void)
{
return batt_soc;
diff --git a/board/samus_pd/board.h b/board/samus_pd/board.h
index 84401ad9fa..1d54501e61 100644
--- a/board/samus_pd/board.h
+++ b/board/samus_pd/board.h
@@ -22,7 +22,6 @@
#define CONFIG_CHARGE_MANAGER
#define CONFIG_CHARGE_RAMP
#undef CONFIG_CMD_HASH
-#undef CONFIG_CMD_TYPEC
#undef CONFIG_CMD_I2C_SCAN
#undef CONFIG_CMD_I2C_XFER
/* Minimum ilim = 500 mA */
diff --git a/board/samus_pd/build.mk b/board/samus_pd/build.mk
index af7ff42076..fa58b7833e 100644
--- a/board/samus_pd/build.mk
+++ b/board/samus_pd/build.mk
@@ -11,4 +11,4 @@ CHIP_FAMILY:=stm32f0
CHIP_VARIANT:=stm32f07x
board-y=board.o
-board-$(CONFIG_USB_POWER_DELIVERY)+=usb_pd_policy.o
+board-$(CONFIG_USB_POWER_DELIVERY)+=usb_mux.o usb_pd_policy.o
diff --git a/board/samus_pd/usb_mux.c b/board/samus_pd/usb_mux.c
new file mode 100644
index 0000000000..e37dd08037
--- /dev/null
+++ b/board/samus_pd/usb_mux.c
@@ -0,0 +1,117 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Samus PD-custom USB mux driver. */
+
+#include "common.h"
+#include "gpio.h"
+#include "usb_mux.h"
+#include "util.h"
+
+struct usb_port_mux {
+ enum gpio_signal ss1_en_l;
+ enum gpio_signal ss2_en_l;
+ enum gpio_signal dp_mode_l;
+ enum gpio_signal dp_polarity;
+ enum gpio_signal ss1_dp_mode;
+ enum gpio_signal ss2_dp_mode;
+};
+
+static const struct usb_port_mux mux_gpios[] = {
+ {
+ .ss1_en_l = GPIO_USB_C0_SS1_EN_L,
+ .ss2_en_l = GPIO_USB_C0_SS2_EN_L,
+ .dp_mode_l = GPIO_USB_C0_DP_MODE_L,
+ .dp_polarity = GPIO_USB_C0_DP_POLARITY,
+ .ss1_dp_mode = GPIO_USB_C0_SS1_DP_MODE,
+ .ss2_dp_mode = GPIO_USB_C0_SS2_DP_MODE,
+ },
+ {
+ .ss1_en_l = GPIO_USB_C1_SS1_EN_L,
+ .ss2_en_l = GPIO_USB_C1_SS2_EN_L,
+ .dp_mode_l = GPIO_USB_C1_DP_MODE_L,
+ .dp_polarity = GPIO_USB_C1_DP_POLARITY,
+ .ss1_dp_mode = GPIO_USB_C1_SS1_DP_MODE,
+ .ss2_dp_mode = GPIO_USB_C1_SS2_DP_MODE,
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(mux_gpios) == CONFIG_USB_PD_PORT_COUNT);
+
+
+static int board_init_usb_mux(int port)
+{
+ return EC_SUCCESS;
+}
+
+static int board_set_usb_mux(int port, mux_state_t mux_state)
+{
+ const struct usb_port_mux *usb_mux = mux_gpios + port;
+ int polarity = mux_state & MUX_POLARITY_INVERTED;
+
+ /* reset everything */
+ gpio_set_level(usb_mux->ss1_en_l, 1);
+ gpio_set_level(usb_mux->ss2_en_l, 1);
+ gpio_set_level(usb_mux->dp_mode_l, 1);
+ gpio_set_level(usb_mux->dp_polarity, 1);
+ gpio_set_level(usb_mux->ss1_dp_mode, 1);
+ gpio_set_level(usb_mux->ss2_dp_mode, 1);
+
+ if (!(mux_state & (MUX_USB_ENABLED | MUX_DP_ENABLED)))
+ /* everything is already disabled, we can return */
+ return EC_SUCCESS;
+
+ if (mux_state & MUX_USB_ENABLED)
+ /* USB 3.0 uses 2 superspeed lanes */
+ gpio_set_level(polarity ? usb_mux->ss2_dp_mode :
+ usb_mux->ss1_dp_mode, 0);
+
+ if (mux_state & MUX_DP_ENABLED) {
+ /* DP uses available superspeed lanes (x2 or x4) */
+ gpio_set_level(usb_mux->dp_polarity, polarity);
+ gpio_set_level(usb_mux->dp_mode_l, 0);
+ }
+
+ /* switch on superspeed lanes */
+ gpio_set_level(usb_mux->ss1_en_l, 0);
+ gpio_set_level(usb_mux->ss2_en_l, 0);
+
+ return EC_SUCCESS;
+}
+
+static int board_get_usb_mux(int port, mux_state_t *mux_state)
+{
+ const struct usb_port_mux *usb_mux = mux_gpios + port;
+
+ *mux_state = 0;
+
+ if (!gpio_get_level(usb_mux->ss1_dp_mode) ||
+ !gpio_get_level(usb_mux->ss2_dp_mode))
+ *mux_state |= MUX_USB_ENABLED;
+
+ if (!gpio_get_level(usb_mux->dp_mode_l))
+ *mux_state |= MUX_DP_ENABLED;
+
+ if (gpio_get_level(usb_mux->dp_polarity))
+ *mux_state |= MUX_POLARITY_INVERTED;
+
+ return EC_SUCCESS;
+}
+
+const struct usb_mux_driver board_custom_usb_mux_driver = {
+ .init = board_init_usb_mux,
+ .set = board_set_usb_mux,
+ .get = board_get_usb_mux,
+};
+
+struct usb_mux usb_muxes[CONFIG_USB_PD_PORT_COUNT] = {
+ {
+ .port_addr = 0,
+ .driver = &board_custom_usb_mux_driver,
+ },
+ {
+ .port_addr = 1,
+ .driver = &board_custom_usb_mux_driver,
+ },
+};
diff --git a/board/samus_pd/usb_pd_config.h b/board/samus_pd/usb_pd_config.h
index 43272bfbaf..d303ae3a51 100644
--- a/board/samus_pd/usb_pd_config.h
+++ b/board/samus_pd/usb_pd_config.h
@@ -6,6 +6,7 @@
#include "adc.h"
#include "chip/stm32/registers.h"
#include "gpio.h"
+#include "usb_mux.h"
/* USB Power delivery board configuration */
@@ -242,7 +243,7 @@ static inline void pd_config_init(int port, uint8_t power_role)
pd_tx_init();
/* Reset mux ... for NONE polarity doesn't matter */
- board_set_usb_mux(port, TYPEC_MUX_NONE, USB_SWITCH_DISCONNECT, 0);
+ usb_mux_set(port, TYPEC_MUX_NONE, USB_SWITCH_DISCONNECT, 0);
if (port == 0) {
gpio_set_level(GPIO_USB_C0_CC1_VCONN1_EN_L, 1);
diff --git a/board/samus_pd/usb_pd_policy.c b/board/samus_pd/usb_pd_policy.c
index b196e3f9d3..119c1ccc32 100644
--- a/board/samus_pd/usb_pd_policy.c
+++ b/board/samus_pd/usb_pd_policy.c
@@ -15,6 +15,7 @@
#include "task.h"
#include "timer.h"
#include "util.h"
+#include "usb_mux.h"
#include "usb_pd.h"
#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
@@ -252,7 +253,7 @@ int pd_custom_vdm(int port, int cnt, uint32_t *payload,
CPRINTF("Current: %dmA\n", payload[1]);
break;
case VDO_CMD_FLIP:
- board_flip_usb_mux(port);
+ usb_mux_flip(port);
break;
case VDO_CMD_GET_LOG:
pd_log_recv_vdm(port, cnt, payload);
@@ -269,7 +270,7 @@ static uint32_t dp_status[CONFIG_USB_PD_PORT_COUNT];
static void svdm_safe_dp_mode(int port)
{
/* make DP interface safe until configure */
- board_set_usb_mux(port, TYPEC_MUX_NONE, USB_SWITCH_CONNECT, 0);
+ usb_mux_set(port, TYPEC_MUX_NONE, USB_SWITCH_CONNECT, 0);
dp_flags[port] = 0;
dp_status[port] = 0;
}
@@ -310,8 +311,8 @@ static int svdm_dp_config(int port, uint32_t *payload)
if (!pin_mode)
return 0;
- board_set_usb_mux(port, mf_pref ? TYPEC_MUX_DOCK : TYPEC_MUX_DP,
- USB_SWITCH_CONNECT, pd_get_polarity(port));
+ usb_mux_set(port, mf_pref ? TYPEC_MUX_DOCK : TYPEC_MUX_DP,
+ USB_SWITCH_CONNECT, pd_get_polarity(port));
payload[0] = VDO(USB_SID_DISPLAYPORT, 1,
CMD_DP_CONFIG | VDO_OPOS(opos));
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 1d1f71dbbb..25774cd62e 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -19,6 +19,7 @@
#include "task.h"
#include "timer.h"
#include "util.h"
+#include "usb_mux.h"
#include "usb_pd.h"
#include "usb_pd_tcpm.h"
#include "version.h"
@@ -271,8 +272,8 @@ static inline void set_state(int port, enum pd_states next_state)
pd_dfp_exit_mode(port, 0, 0);
#endif
#ifdef CONFIG_USBC_SS_MUX
- board_set_usb_mux(port, TYPEC_MUX_NONE, USB_SWITCH_DISCONNECT,
- pd[port].polarity);
+ usb_mux_set(port, TYPEC_MUX_NONE, USB_SWITCH_DISCONNECT,
+ pd[port].polarity);
#endif
#ifdef CONFIG_USBC_VCONN
tcpm_set_vconn(port, 0);
@@ -787,14 +788,14 @@ static void pd_set_data_role(int port, int role)
* If new data role is UFP, then disconnect the SS mux.
*/
if (role == PD_ROLE_DFP)
- board_set_usb_mux(port, TYPEC_MUX_USB, USB_SWITCH_CONNECT,
- pd[port].polarity);
+ usb_mux_set(port, TYPEC_MUX_USB, USB_SWITCH_CONNECT,
+ pd[port].polarity);
else
- board_set_usb_mux(port, TYPEC_MUX_NONE, USB_SWITCH_DISCONNECT,
- pd[port].polarity);
+ usb_mux_set(port, TYPEC_MUX_NONE, USB_SWITCH_DISCONNECT,
+ pd[port].polarity);
#else
- board_set_usb_mux(port, TYPEC_MUX_USB, USB_SWITCH_CONNECT,
- pd[port].polarity);
+ usb_mux_set(port, TYPEC_MUX_USB, USB_SWITCH_CONNECT,
+ pd[port].polarity);
#endif
#endif
pd_update_roles(port);
@@ -1333,6 +1334,11 @@ void pd_task(void)
/* Disable TCPC RX until connection is established */
tcpm_set_rx_enable(port, 0);
+#ifdef CONFIG_USBC_SS_MUX
+ /* Initialize USB mux to its default state */
+ usb_mux_init(port);
+#endif
+
/* Initialize PD protocol state variables for each port. */
pd[port].power_role = PD_ROLE_DEFAULT;
pd[port].vdm_state = VDM_STATE_DONE;
@@ -1473,9 +1479,9 @@ void pd_task(void)
/* Enable VBUS */
if (pd_set_power_supply_ready(port)) {
#ifdef CONFIG_USBC_SS_MUX
- board_set_usb_mux(port, TYPEC_MUX_NONE,
- USB_SWITCH_DISCONNECT,
- pd[port].polarity);
+ usb_mux_set(port, TYPEC_MUX_NONE,
+ USB_SWITCH_DISCONNECT,
+ pd[port].polarity);
#endif
break;
}
@@ -2801,54 +2807,6 @@ DECLARE_CONSOLE_COMMAND(pd, command_pd,
"USB PD",
NULL);
-#ifdef CONFIG_USBC_SS_MUX
-#ifdef CONFIG_CMD_TYPEC
-static int command_typec(int argc, char **argv)
-{
- const char * const mux_name[] = {"none", "usb", "dp", "dock"};
- char *e;
- int port;
- enum typec_mux mux = TYPEC_MUX_NONE;
- int i;
-
- if (argc < 2)
- return EC_ERROR_PARAM_COUNT;
-
- port = strtoi(argv[1], &e, 10);
- if (*e || port >= CONFIG_USB_PD_PORT_COUNT)
- return EC_ERROR_PARAM1;
-
- if (argc < 3) {
- const char *dp_str, *usb_str;
- ccprintf("Port C%d: polarity:CC%d\n",
- port, pd_get_polarity(port) + 1);
- if (board_get_usb_mux(port, &dp_str, &usb_str))
- ccprintf("Superspeed %s%s%s\n",
- dp_str ? dp_str : "",
- dp_str && usb_str ? "+" : "",
- usb_str ? usb_str : "");
- else
- ccprintf("No Superspeed connection\n");
-
- return EC_SUCCESS;
- }
-
- for (i = 0; i < ARRAY_SIZE(mux_name); i++)
- if (!strcasecmp(argv[2], mux_name[i]))
- mux = i;
- board_set_usb_mux(port, mux, mux == TYPEC_MUX_NONE ?
- USB_SWITCH_DISCONNECT :
- USB_SWITCH_CONNECT,
- pd_get_polarity(port));
- return EC_SUCCESS;
-}
-DECLARE_CONSOLE_COMMAND(typec, command_typec,
- "<port> [none|usb|dp|dock]",
- "Control type-C connector muxing",
- NULL);
-#endif /* CONFIG_CMD_TYPEC */
-#endif /* CONFIG_USBC_SS_MUX */
-
#ifdef HAS_TASK_HOSTCMD
static int hc_pd_ports(struct host_cmd_handler_args *args)
@@ -2898,11 +2856,11 @@ static int hc_usb_pd_control(struct host_cmd_handler_args *args)
#ifdef CONFIG_USBC_SS_MUX
if (p->mux != USB_PD_CTRL_MUX_NO_CHANGE)
- board_set_usb_mux(p->port, typec_mux_map[p->mux],
- typec_mux_map[p->mux] == TYPEC_MUX_NONE ?
- USB_SWITCH_DISCONNECT :
- USB_SWITCH_CONNECT,
- pd_get_polarity(p->port));
+ usb_mux_set(p->port, typec_mux_map[p->mux],
+ typec_mux_map[p->mux] == TYPEC_MUX_NONE ?
+ USB_SWITCH_DISCONNECT :
+ USB_SWITCH_CONNECT,
+ pd_get_polarity(p->port));
#endif /* CONFIG_USBC_SS_MUX */
if (args->version == 0) {
diff --git a/driver/build.mk b/driver/build.mk
index 998cd9cbce..97d80521b3 100644
--- a/driver/build.mk
+++ b/driver/build.mk
@@ -60,9 +60,14 @@ driver-$(CONFIG_USB_PD_TCPM_TCPCI)+=tcpm/tcpci.o
# USB switches
driver-$(CONFIG_USB_SWITCH_PI3USB9281)+=usb_switch_pi3usb9281.o
-driver-$(CONFIG_USB_SWITCH_PI3USB30532)+=usb_switch_pi3usb30532.o
driver-$(CONFIG_USB_SWITCH_TSU6721)+=usb_switch_tsu6721.o
+# USB mux high-level driver
+driver-$(CONFIG_USBC_SS_MUX)+=usb_mux.o
+
+# USB muxes
+driver-$(CONFIG_USB_MUX_PI3USB30532)+=usb_mux_pi3usb30532.o
+
# Firmware Update
driver-$(CONFIG_SB_FIRMWARE_UPDATE)+=battery/sb_fw_update.o
diff --git a/driver/pi3usb30532.h b/driver/pi3usb30532.h
index c24edeb976..96c963204b 100644
--- a/driver/pi3usb30532.h
+++ b/driver/pi3usb30532.h
@@ -10,6 +10,8 @@
#include <inttypes.h>
+#include "usb_pd.h"
+
/* USB switch registers */
#define PI3USB30532_REG_ADDR 0x00
#define PI3USB30532_REG_VENDOR 0x01
@@ -62,17 +64,4 @@
#define PI3USB30532_MODE_DP_USB_SWAP (PI3USB30532_MODE_DP_USB | \
PI3USB30532_BIT_SWAP)
-
-/* Reads PI3USB30532 register */
-int pi3usb30532_read(uint8_t chip_idx, uint8_t reg);
-
-/* Writes PI3USB30532 register */
-int pi3usb30532_write(uint8_t chip_idx, uint8_t reg, uint8_t val);
-
-/* Writes PI3USB30532 control register */
-int pi3usb30532_set_switch(uint8_t chip_idx, uint8_t mode);
-
-/* Resets PI3USB30532 to power on default value */
-int pi3usb30532_reset(uint8_t chip_idx);
-
#endif /* __CROS_EC_PI3USB30532_H */
diff --git a/driver/usb_mux.c b/driver/usb_mux.c
new file mode 100644
index 0000000000..04427f7615
--- /dev/null
+++ b/driver/usb_mux.c
@@ -0,0 +1,150 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* USB mux high-level driver. */
+
+#include "common.h"
+#include "console.h"
+#include "usb_mux.h"
+#include "util.h"
+
+#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args)
+
+static int enable_debug_prints;
+
+void usb_mux_init(int port)
+{
+ const struct usb_mux *mux = &usb_muxes[port];
+ int res;
+
+ ASSERT(port >= 0 && port < CONFIG_USB_PD_PORT_COUNT);
+ res = mux->driver->init(mux->port_addr);
+ if (res)
+ CPRINTS("Error initializing mux port(%d): %d", port, res);
+}
+
+/*
+ * TODO(crbug.com/505480): Setting muxes often involves I2C transcations,
+ * which can block. Consider implementing an asynchronous task.
+ */
+void usb_mux_set(int port, enum typec_mux mux_mode,
+ enum usb_switch usb_mode, int polarity)
+{
+ const struct usb_mux *mux = &usb_muxes[port];
+ int res;
+ mux_state_t mux_state;
+
+ /* Configure USB2.0 */
+ board_set_usb_switches(port, usb_mode);
+
+ /* Configure superspeed lanes */
+ mux_state = polarity ? mux_mode | MUX_POLARITY_INVERTED : mux_mode;
+ res = mux->driver->set(mux->port_addr, mux_state);
+ if (res) {
+ CPRINTS("Error setting mux port(%d): %d", port, res);
+ return;
+ }
+
+ if (enable_debug_prints)
+ CPRINTS(
+ "usb/dp mux: port(%d) typec_mux(%d) usb2(%d) polarity(%d)",
+ port, mux_mode, usb_mode, polarity);
+}
+
+int usb_mux_get(int port, const char **dp_str, const char **usb_str)
+{
+ const struct usb_mux *mux = &usb_muxes[port];
+ int res;
+ mux_state_t mux_state;
+ const char *dp, *usb;
+
+ res = mux->driver->get(mux->port_addr, &mux_state);
+ if (res) {
+ CPRINTS("Error setting mux port(%d): %d", port, res);
+ return 0;
+ }
+
+ dp = mux_state & MUX_POLARITY_INVERTED ? "DP2" : "DP1";
+ usb = mux_state & MUX_POLARITY_INVERTED ? "USB2" : "USB1";
+
+ *dp_str = mux_state & MUX_DP_ENABLED ? dp : NULL;
+ *usb_str = mux_state & MUX_USB_ENABLED ? usb : NULL;
+
+ return *dp_str || *usb_str;
+}
+
+void usb_mux_flip(int port)
+{
+ const struct usb_mux *mux = &usb_muxes[port];
+ int res;
+ mux_state_t mux_state;
+
+ res = mux->driver->get(mux->port_addr, &mux_state);
+ if (res) {
+ CPRINTS("Error getting mux port(%d): %d", port, res);
+ return;
+ }
+
+ if (mux_state & MUX_POLARITY_INVERTED)
+ mux_state &= ~MUX_POLARITY_INVERTED;
+ else
+ mux_state |= MUX_POLARITY_INVERTED;
+
+ res = mux->driver->set(mux->port_addr, mux_state);
+ if (res)
+ CPRINTS("Error setting mux port(%d): %d", port, res);
+}
+
+#ifdef CONFIG_CMD_TYPEC
+static int command_typec(int argc, char **argv)
+{
+ const char * const mux_name[] = {"none", "usb", "dp", "dock"};
+ char *e;
+ int port;
+ enum typec_mux mux = TYPEC_MUX_NONE;
+ int i;
+
+ if (argc == 2 && !strcasecmp(argv[1], "debug")) {
+ enable_debug_prints = 1;
+ return EC_SUCCESS;
+ }
+
+ if (argc < 2)
+ return EC_ERROR_PARAM_COUNT;
+
+ port = strtoi(argv[1], &e, 10);
+ if (*e || port >= CONFIG_USB_PD_PORT_COUNT)
+ return EC_ERROR_PARAM1;
+
+ if (argc < 3) {
+ const char *dp_str, *usb_str;
+ ccprintf("Port C%d: polarity:CC%d\n",
+ port, pd_get_polarity(port) + 1);
+ if (usb_mux_get(port, &dp_str, &usb_str))
+ ccprintf("Superspeed %s%s%s\n",
+ dp_str ? dp_str : "",
+ dp_str && usb_str ? "+" : "",
+ usb_str ? usb_str : "");
+ else
+ ccprintf("No Superspeed connection\n");
+
+ return EC_SUCCESS;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mux_name); i++)
+ if (!strcasecmp(argv[2], mux_name[i]))
+ mux = i;
+ usb_mux_set(port, mux, mux == TYPEC_MUX_NONE ?
+ USB_SWITCH_DISCONNECT :
+ USB_SWITCH_CONNECT,
+ pd_get_polarity(port));
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(typec, command_typec,
+ "[port|debug] [none|usb|dp|dock]",
+ "Control type-C connector muxing",
+ NULL);
+#endif
diff --git a/driver/usb_mux_pi3usb30532.c b/driver/usb_mux_pi3usb30532.c
new file mode 100644
index 0000000000..ceb80c9368
--- /dev/null
+++ b/driver/usb_mux_pi3usb30532.c
@@ -0,0 +1,109 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Pericom PI3USB30532 USB port switch driver.
+ */
+
+#include "common.h"
+#include "i2c.h"
+#include "pi3usb30532.h"
+#include "usb_mux.h"
+#include "util.h"
+
+static int pi3usb30532_read(int i2c_addr, uint8_t reg, uint8_t *val)
+{
+ int read, res;
+
+ /*
+ * First byte read will be slave address (ignored).
+ * Second byte read will be vendor ID.
+ * Third byte read will be selection control.
+ */
+ res = i2c_read16(I2C_PORT_USB_MUX, i2c_addr, 0, &read);
+ if (res)
+ return res;
+
+ if (reg == PI3USB30532_REG_VENDOR)
+ *val = read & 0xff;
+ else if (reg == PI3USB30532_REG_CONTROL)
+ *val = (read >> 8) & 0xff;
+
+ return EC_SUCCESS;
+}
+
+static int pi3usb30532_write(int i2c_addr, uint8_t reg, uint8_t val)
+{
+ if (reg != PI3USB30532_REG_CONTROL)
+ return EC_ERROR_UNKNOWN;
+
+ return i2c_write8(I2C_PORT_USB_MUX, i2c_addr, 0, val);
+}
+
+static int pi3usb30532_reset(int i2c_addr)
+{
+ return pi3usb30532_write(
+ i2c_addr,
+ PI3USB30532_REG_CONTROL,
+ (PI3USB30532_MODE_POWERDOWN & PI3USB30532_CTRL_MASK) |
+ PI3USB30532_CTRL_RSVD);
+}
+
+static int pi3usb30532_init(int i2c_addr)
+{
+ uint8_t val;
+ int res;
+
+ res = pi3usb30532_reset(i2c_addr);
+ if (res)
+ return res;
+ res = pi3usb30532_read(i2c_addr, PI3USB30532_REG_VENDOR, &val);
+ if (res)
+ return res;
+ if (val != PI3USB30532_VENDOR_ID)
+ return EC_ERROR_UNKNOWN;
+
+ return EC_SUCCESS;
+}
+
+/* Writes control register to set switch mode */
+static int pi3usb30532_set_mux(int i2c_addr, mux_state_t mux_state)
+{
+ uint8_t reg = 0;
+
+ if (mux_state & MUX_USB_ENABLED)
+ reg |= PI3USB30532_MODE_USB;
+ if (mux_state & MUX_DP_ENABLED)
+ reg |= PI3USB30532_MODE_DP;
+ if (mux_state & MUX_POLARITY_INVERTED)
+ reg |= PI3USB30532_BIT_SWAP;
+
+ return pi3usb30532_write(i2c_addr, PI3USB30532_REG_CONTROL,
+ reg | PI3USB30532_CTRL_RSVD);
+}
+
+/* Reads control register and updates mux_state accordingly */
+static int pi3usb30532_get_mux(int i2c_addr, mux_state_t *mux_state)
+{
+ uint8_t reg, res;
+
+ *mux_state = 0;
+ res = pi3usb30532_read(i2c_addr, PI3USB30532_REG_CONTROL, &reg);
+ if (res)
+ return res;
+
+ if (reg & PI3USB30532_MODE_USB)
+ *mux_state |= MUX_USB_ENABLED;
+ if (reg & PI3USB30532_MODE_DP)
+ *mux_state |= MUX_DP_ENABLED;
+ if (reg & PI3USB30532_BIT_SWAP)
+ *mux_state |= MUX_POLARITY_INVERTED;
+
+ return EC_SUCCESS;
+}
+
+const struct usb_mux_driver pi3usb30532_usb_mux_driver = {
+ .init = pi3usb30532_init,
+ .set = pi3usb30532_set_mux,
+ .get = pi3usb30532_get_mux,
+};
diff --git a/driver/usb_switch_pi3usb30532.c b/driver/usb_switch_pi3usb30532.c
deleted file mode 100644
index 1688278ae6..0000000000
--- a/driver/usb_switch_pi3usb30532.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Copyright 2015 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- * Pericom PI3USB30532 USB port switch driver.
- */
-
-#include "common.h"
-#include "console.h"
-#include "gpio.h"
-#include "hooks.h"
-#include "i2c.h"
-#include "task.h"
-#include "timer.h"
-#include "pi3usb30532.h"
-#include "util.h"
-
-/* Console output macros */
-#define CPUTS(outstr) cputs(CC_USBCHARGE, outstr)
-#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args)
-
-#define INTERNAL_READ_ERROR(code) (EC_ERROR_INTERNAL_FIRST + code)
-#define IS_READ_ERROR(code) ((code) > EC_ERROR_INTERNAL_FIRST)
-
-/* 8-bit I2C address */
-static const int pi3usb30532_addrs[] = CONFIG_USB_SWITCH_I2C_ADDRS;
-
-int pi3usb30532_read(uint8_t chip_idx, uint8_t reg)
-{
- int res, val;
- int addr = pi3usb30532_addrs[chip_idx];
-
- res = i2c_read8(I2C_PORT_USB_SWITCH, addr, reg, &val);
- if (res)
- return INTERNAL_READ_ERROR(res);
-
- return val;
-}
-
-int pi3usb30532_write(uint8_t chip_idx, uint8_t reg, uint8_t val)
-{
- int res;
- int addr = pi3usb30532_addrs[chip_idx];
-
- res = i2c_write8(I2C_PORT_USB_SWITCH, addr, reg, val);
- if (res)
- CPUTS("PI3USB30532 I2C write failed");
-
- return res;
-}
-
-/* Writes control register to set switch mode */
-int pi3usb30532_set_switch(uint8_t chip_idx, uint8_t mode)
-{
- return pi3usb30532_write(chip_idx, PI3USB30532_REG_CONTROL,
- (mode & PI3USB30532_CTRL_MASK) |
- PI3USB30532_CTRL_RSVD);
-}
-
-int pi3usb30532_reset(uint8_t chip_idx)
-{
- return pi3usb30532_set_switch(chip_idx, PI3USB30532_MODE_POWERDOWN);
-}
-
-static void pi3usb30532_init(void)
-{
- int i, res, val;
-
- for (i = 0; i < ARRAY_SIZE(pi3usb30532_addrs); i++) {
- res = pi3usb30532_reset(i);
- if (res)
- CPRINTS("PI3USB30532 [%d] init failed", i);
-
- val = pi3usb30532_read(i, PI3USB30532_REG_VENDOR);
- if (IS_READ_ERROR(val)) {
- CPRINTS("PI3USB30532 [%d] read failed", i);
- continue;
- }
-
- if (val != PI3USB30532_VENDOR_ID)
- CPRINTS("PI3USB30532 [%d] invalid ID 0x%02x", i, val);
-
- }
-}
-DECLARE_HOOK(HOOK_INIT, pi3usb30532_init, HOOK_PRIO_LAST);
diff --git a/include/config.h b/include/config.h
index f7af2ba28b..76436708ca 100644
--- a/include/config.h
+++ b/include/config.h
@@ -1630,8 +1630,8 @@
/* Number of Pericom PI3USB9281 chips present in system */
#undef CONFIG_USB_SWITCH_PI3USB9281_CHIP_COUNT
-/* Support the Pericom PI3USB30532. */
-#undef CONFIG_USB_SWITCH_PI3USB30532
+/* Support the Pericom PI3USB30532 USB3.0/DP1.2 Matrix Switch */
+#undef CONFIG_USB_MUX_PI3USB30532
/*****************************************************************************/
/* USB GPIO config */
diff --git a/include/usb_mux.h b/include/usb_mux.h
new file mode 100644
index 0000000000..d451e9cf1c
--- /dev/null
+++ b/include/usb_mux.h
@@ -0,0 +1,116 @@
+/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* USB mux driver */
+
+#ifndef __CROS_EC_USB_MUX_H
+#define __CROS_EC_USB_MUX_H
+
+#include "usb_pd.h"
+
+/* USB-C mux state */
+typedef uint8_t mux_state_t;
+
+/* Mux state attributes */
+#define MUX_USB_ENABLED (1 << 0) /* USB is enabled */
+#define MUX_DP_ENABLED (1 << 1) /* DP is enabled */
+#define MUX_POLARITY_INVERTED (1 << 2) /* Polarity is inverted */
+
+/* Mux modes, decoded to attributes */
+enum typec_mux {
+ TYPEC_MUX_NONE = 0, /* Open switch */
+ TYPEC_MUX_USB = MUX_USB_ENABLED, /* USB only */
+ TYPEC_MUX_DP = MUX_DP_ENABLED, /* DP only */
+ TYPEC_MUX_DOCK = MUX_USB_ENABLED | /* Both USB and DP */
+ MUX_DP_ENABLED,
+};
+
+/* Mux driver function pointers */
+struct usb_mux_driver {
+ /**
+ * Initialize USB mux.
+ *
+ * @param port_addr Port/address driver-defined parameter.
+ * @return EC_SUCCESS on success, non-zero error code on failure.
+ */
+ int (*init)(int port_addr);
+
+ /**
+ * Set USB mux state.
+ *
+ * @param port_addr Port/address driver-defined parameter.
+ * @param mux_state State to set mux to.
+ * @return EC_SUCCESS on success, non-zero error code on failure.
+ */
+ int (*set)(int port_addr, mux_state_t mux_state);
+
+ /**
+ * Get current state of USB mux.
+ *
+ * @param port_addr Port / address driver-defined parameter.
+ * @param mux_state Gets set to current state of mux.
+ * @return EC_SUCCESS on success, non-zero error code on failure.
+ */
+ int (*get)(int port_addr, mux_state_t *mux_state);
+};
+
+/* Describes a USB mux present in the system */
+struct usb_mux {
+ /*
+ * Driver-defined parameter, typically an i2c slave address
+ * (for i2c muxes) or a port number (for GPIO 'muxes').
+ */
+ const int port_addr;
+ /* Mux driver */
+ const struct usb_mux_driver *driver;
+};
+
+/* Supported USB mux drivers */
+extern const struct usb_mux_driver pi3usb30532_usb_mux_driver;
+
+/* USB muxes present in system, ordered by PD port #, defined at board-level */
+extern struct usb_mux usb_muxes[];
+
+/**
+ * Initialize USB mux to its default state.
+ *
+ * @param port Port number.
+ */
+void usb_mux_init(int port);
+
+/**
+ * Configure superspeed muxes on type-C port.
+ *
+ * @param port port number.
+ * @param mux_mode mux selected function.
+ * @param usb_config usb2.0 selected function.
+ * @param polarity plug polarity (0=CC1, 1=CC2).
+ */
+void usb_mux_set(int port, enum typec_mux mux_mode,
+ enum usb_switch usb_config, int polarity);
+
+/**
+ * Query superspeed mux status on type-C port.
+ *
+ * @param port port number.
+ * @param dp_str pointer to the DP string to return.
+ * @param usb_str pointer to the USB string to return.
+ * @return Non-zero if superspeed connection is enabled; otherwise, zero.
+ */
+int usb_mux_get(int port, const char **dp_str, const char **usb_str);
+
+/**
+ * Flip the superspeed muxes on type-C port.
+ *
+ * This is used for factory test automation. Note that this function should
+ * only flip the superspeed muxes and leave CC lines alone. Without further
+ * changes, this function MUST ONLY be used for testing purpose, because
+ * the protocol layer loses track of the superspeed polarity and DP/USB3.0
+ * connection may break.
+ *
+ * @param port port number.
+ */
+void usb_mux_flip(int port);
+#endif
diff --git a/include/usb_pd.h b/include/usb_pd.h
index 8b915a14c4..e9edebb526 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -1186,14 +1186,6 @@ extern const int pd_snk_pdo_cnt;
*/
int pd_get_source_pdo(const uint32_t **src_pdo);
-/* Muxing for the USB type C */
-enum typec_mux {
- TYPEC_MUX_NONE,
- TYPEC_MUX_USB,
- TYPEC_MUX_DP,
- TYPEC_MUX_DOCK,
-};
-
enum usb_switch {
USB_SWITCH_CONNECT,
USB_SWITCH_DISCONNECT,
@@ -1209,39 +1201,6 @@ enum usb_switch {
void board_set_usb_switches(int port, enum usb_switch setting);
/**
- * Configure superspeed muxes on type-C port.
- *
- * @param port port number.
- * @param mux selected function.
- * @param polarity plug polarity (0=CC1, 1=CC2).
- */
-void board_set_usb_mux(int port, enum typec_mux mux,
- enum usb_switch usb, int polarity);
-
-/**
- * Query superspeed mux status on type-C port.
- *
- * @param port port number.
- * @param dp_str pointer to the DP string to return.
- * @param usb_str pointer to the USB string to return.
- * @return Non-zero if superspeed connection is enabled; otherwise, zero.
- */
-int board_get_usb_mux(int port, const char **dp_str, const char **usb_str);
-
-/**
- * Flip the superspeed muxes on type-C port.
- *
- * This is used for factory test automation. Note that this function should
- * only flip the superspeed muxes and leave CC lines alone. Without further
- * changes, this function MUST ONLY be used for testing purpose, because
- * the protocol layer loses track of the superspeed polarity and DP/USB3.0
- * connection may break.
- *
- * @param port port number.
- */
-void board_flip_usb_mux(int port);
-
-/**
* Request that a host event be sent to notify the AP of a PD power event.
*
* @param mask host event mask.