summaryrefslogtreecommitdiff
path: root/driver/retimer/pi3dpx1207.c
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/retimer/pi3dpx1207.c
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/retimer/pi3dpx1207.c')
-rw-r--r--driver/retimer/pi3dpx1207.c115
1 files changed, 115 insertions, 0 deletions
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,
+};