summaryrefslogtreecommitdiff
path: root/driver
diff options
context:
space:
mode:
authorDenis Brockus <dbrockus@chromium.org>2019-11-05 14:51:56 -0700
committerCommit Bot <commit-bot@chromium.org>2019-11-14 00:12:44 +0000
commita4972e187c6ce582aa54dbfce6039fd2239e4bbd (patch)
tree2dfffcb6b3b457b8abdbc6f4a0acc267cb9209d2 /driver
parentf5633029509350cf7254ab14c440d14e8e73f729 (diff)
downloadchrome-ec-a4972e187c6ce582aa54dbfce6039fd2239e4bbd.tar.gz
usbc: retimer pi3dpx1207
BUG=b:139428185 BRANCH=none TEST=verify mode is set correctly when switching devices Change-Id: Ic9d460a94bb8007f17168ac5237a4dcbc24cfb2b Signed-off-by: Denis Brockus <dbrockus@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1900123 Reviewed-by: Edward Hill <ecgh@chromium.org>
Diffstat (limited to 'driver')
-rw-r--r--driver/build.mk1
-rw-r--r--driver/retimer/pi3dpx1207.c115
-rw-r--r--driver/retimer/pi3dpx1207.h44
-rw-r--r--driver/usb_mux/usb_mux.c38
4 files changed, 191 insertions, 7 deletions
diff --git a/driver/build.mk b/driver/build.mk
index edd97a09a9..e912c3d33a 100644
--- a/driver/build.mk
+++ b/driver/build.mk
@@ -139,6 +139,7 @@ driver-$(CONFIG_USB_PD_TCPM_NCT38XX)+=tcpm/nct38xx.o
# Type-C Retimer drivers
driver-$(CONFIG_USBC_RETIMER_INTEL_BB)+=retimer/bb_retimer.o
+driver-$(CONFIG_USBC_RETIMER_PI3DPX1207)+=retimer/pi3dpx1207.o
# USB mux high-level driver
driver-$(CONFIG_USBC_SS_MUX)+=usb_mux/usb_mux.o
diff --git a/driver/retimer/pi3dpx1207.c b/driver/retimer/pi3dpx1207.c
new file mode 100644
index 0000000000..f1f1e19b54
--- /dev/null
+++ b/driver/retimer/pi3dpx1207.c
@@ -0,0 +1,115 @@
+/* Copyright 2019 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.
+ *
+ * PI3DPX1207 retimer.
+ */
+
+#include "pi3dpx1207.h"
+#include "common.h"
+#include "console.h"
+#include "gpio.h"
+#include "i2c.h"
+#include "ioexpander.h"
+#include "usb_mux.h"
+
+#define I2C_MAX_RETRIES 2
+
+/* Stack space is limited, so put the buffer somewhere else */
+static uint8_t buf[PI3DPX1207_NUM_REGISTERS];
+
+static int pi3dpx1207_i2c_write(int i2c_port,
+ uint16_t addr_flags,
+ uint8_t offset,
+ uint8_t val)
+{
+ int rv = EC_SUCCESS;
+ int attempt;
+
+ if (offset >= PI3DPX1207_NUM_REGISTERS)
+ return EC_ERROR_INVAL;
+
+ /*
+ * PI3DPX1207 does not support device register offset in
+ * the typical I2C sense. Have to read the values starting
+ * from 0, modify the byte and then write the block.
+ *
+ * NOTE: The device may not respond correctly if it was
+ * just powered or has gone to sleep. Allow for retries
+ * in case this happens.
+ */
+ if (offset > 0) {
+ attempt = 0;
+ do {
+ attempt++;
+ rv = i2c_xfer(i2c_port, addr_flags,
+ NULL, 0, buf, offset);
+ } while ((rv != EC_SUCCESS) && (attempt < I2C_MAX_RETRIES));
+ }
+
+ if (rv == EC_SUCCESS) {
+ buf[offset] = val;
+
+ attempt = 0;
+ do {
+ attempt++;
+ rv = i2c_xfer(i2c_port, addr_flags,
+ buf, offset + 1, NULL, 0);
+ } while ((rv != EC_SUCCESS) && (attempt < I2C_MAX_RETRIES));
+ }
+ return rv;
+}
+
+static int pi3dpx1207_set_mux(int port, mux_state_t mux_state)
+{
+ int rv = EC_SUCCESS;
+ uint8_t mode_val = PI3DPX1207_MODE_WATCHDOG_EN;
+
+ const int i2c_port = usb_retimers[port].i2c_port;
+ const uint16_t i2c_addr_flags = usb_retimers[port].i2c_addr_flags;
+ const int gpio_enable = usb_retimers[port].gpio_enable;
+ const int gpio_dp_enable = usb_retimers[port].gpio_dp_enable;
+
+ /* USB */
+ if (mux_state & MUX_USB_ENABLED) {
+ gpio_or_ioex_set_level(gpio_enable, 1);
+ /* USB with DP */
+ if (mux_state & MUX_DP_ENABLED) {
+ gpio_or_ioex_set_level(gpio_dp_enable, 1);
+ mode_val |= (mux_state & MUX_POLARITY_INVERTED)
+ ? PI3DPX1207_MODE_CONF_USB_DP_FLIP
+ : PI3DPX1207_MODE_CONF_USB_DP;
+ }
+ /* USB without DP */
+ else {
+ gpio_or_ioex_set_level(gpio_dp_enable, 0);
+ mode_val |= (mux_state & MUX_POLARITY_INVERTED)
+ ? PI3DPX1207_MODE_CONF_USB_FLIP
+ : PI3DPX1207_MODE_CONF_USB;
+ }
+ }
+ /* DP without USB */
+ else if (mux_state & MUX_DP_ENABLED) {
+ gpio_or_ioex_set_level(gpio_enable, 1);
+ gpio_or_ioex_set_level(gpio_dp_enable, 1);
+ mode_val |= (mux_state & MUX_POLARITY_INVERTED)
+ ? PI3DPX1207_MODE_CONF_DP_FLIP
+ : PI3DPX1207_MODE_CONF_DP;
+ }
+ /* Nothing enabled, power down the retimer */
+ else {
+ gpio_or_ioex_set_level(gpio_enable, 0);
+ gpio_or_ioex_set_level(gpio_dp_enable, 0);
+ return EC_SUCCESS;
+ }
+
+ /* Write the retimer config byte */
+ rv = pi3dpx1207_i2c_write(i2c_port, i2c_addr_flags,
+ PI3DPX1207_MODE_OFFSET,
+ mode_val);
+ return rv;
+}
+
+const struct usb_retimer_driver pi3dpx1207_usb_retimer = {
+ .set = pi3dpx1207_set_mux,
+};
diff --git a/driver/retimer/pi3dpx1207.h b/driver/retimer/pi3dpx1207.h
new file mode 100644
index 0000000000..7b3c3047f2
--- /dev/null
+++ b/driver/retimer/pi3dpx1207.h
@@ -0,0 +1,44 @@
+/* Copyright 2019 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.
+ *
+ * PI3DPX1207 retimer.
+ */
+
+#ifndef __CROS_EC_USB_RETIMER_PI3PDX1207_H
+#define __CROS_EC_USB_RETIMER_PI3PDX1207_H
+
+#define PI3DPX1207_I2C_ADDR_FLAGS 0x57
+#define PI3DPX1207_NUM_REGISTERS 32
+
+/* Register Offset 0 - Revision and Vendor ID */
+#define PI3DPX1207_VID_OFFSET 0
+
+#define PI3DPX1207B_VID 0x03
+#define PI3DPX1207C_VID 0x13
+
+/* Register Offset 1 - Device Type/ID */
+#define PI3DPX1207_DID_OFFSET 1
+
+#define PI3DPX1207_DID_ACTIVE_MUX 0x11
+
+/* Register Offset 3 - Mode Control */
+#define PI3DPX1207_MODE_OFFSET 3
+
+#define PI3DPX1207_MODE_WATCHDOG_EN 0x02
+
+#define PI3DPX1207B_MODE_GEN_APP_EN 0x08
+
+#define PI3DPX1207_MODE_CONF_SAFE 0x00
+#define PI3DPX1207_MODE_CONF_DP 0x20
+#define PI3DPX1207_MODE_CONF_DP_FLIP 0x30
+#define PI3DPX1207_MODE_CONF_USB 0x40
+#define PI3DPX1207_MODE_CONF_USB_FLIP 0x50
+#define PI3DPX1207_MODE_CONF_USB_DP 0x60
+#define PI3DPX1207_MODE_CONF_USB_DP_FLIP 0x70
+#define PI3DPX1207_MODE_CONF_USB_SUPER 0xC0
+
+/* Supported USB retimer drivers */
+extern const struct usb_retimer_driver pi3dpx1207_usb_retimer;
+
+#endif /* __CROS_EC_USB_RETIMER_PI3PDX1207_H */
diff --git a/driver/usb_mux/usb_mux.c b/driver/usb_mux/usb_mux.c
index 122f71d773..be150c8741 100644
--- a/driver/usb_mux/usb_mux.c
+++ b/driver/usb_mux/usb_mux.c
@@ -68,6 +68,19 @@ void usb_mux_init(int port)
return;
}
+ if (IS_ENABLED(CONFIG_USBC_MUX_RETIMER)) {
+ const struct usb_retimer *retimer = &usb_retimers[port];
+
+ if (retimer->driver && retimer->driver->init) {
+ res = retimer->driver->init(port);
+ if (res) {
+ CPRINTS("Err: init retimer port(%d): %d",
+ port, res);
+ return;
+ }
+ }
+ }
+
/* Device is always out of LPM after initialization. */
flags[port] &= ~USB_MUX_FLAG_IN_LPM;
@@ -93,10 +106,9 @@ void usb_mux_set(int port, enum typec_mux mux_mode,
const int should_enter_low_power_mode =
mux_mode == TYPEC_MUX_NONE && usb_mode == USB_SWITCH_DISCONNECT;
-#ifdef CONFIG_USB_CHARGER
/* Configure USB2.0 */
- usb_charger_set_switches(port, usb_mode);
-#endif
+ if (IS_ENABLED(CONFIG_USB_CHARGER))
+ usb_charger_set_switches(port, usb_mode);
/*
* Don't wake device up just to put it back to sleep. Low power mode
@@ -116,6 +128,19 @@ void usb_mux_set(int port, enum typec_mux mux_mode,
return;
}
+ if (IS_ENABLED(CONFIG_USBC_MUX_RETIMER)) {
+ const struct usb_retimer *retimer = &usb_retimers[port];
+
+ if (retimer->driver && retimer->driver->set) {
+ res = retimer->driver->set(port, mux_state);
+ if (res) {
+ CPRINTS("Err: set retimer port(%d): %d",
+ port, res);
+ return;
+ }
+ }
+ }
+
if (enable_debug_prints)
CPRINTS(
"usb/dp mux: port(%d) typec_mux(%d) usb2(%d) polarity(%d)",
@@ -241,12 +266,11 @@ static enum ec_status hc_usb_pd_mux_info(struct host_cmd_handler_args *args)
if (mux->driver->get(port, &r->flags) != EC_SUCCESS)
return EC_RES_ERROR;
-#ifdef CONFIG_USB_MUX_VIRTUAL
/* Clear HPD IRQ event since we're about to inform host of it. */
- if ((r->flags & USB_PD_MUX_HPD_IRQ) &&
- mux->hpd_update == &virtual_hpd_update)
+ if (IS_ENABLED(CONFIG_USB_MUX_VIRTUAL) &&
+ (r->flags & USB_PD_MUX_HPD_IRQ) &&
+ (mux->hpd_update == &virtual_hpd_update))
mux->hpd_update(port, r->flags & USB_PD_MUX_HPD_LVL, 0);
-#endif
args->response_size = sizeof(*r);
return EC_RES_SUCCESS;