/* Copyright 2020 The ChromiumOS Authors * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Parade PS8740 (and PS8742) * USB Type-C Redriving Switch for USB Host / DisplayPort. */ #include "common.h" #include "i2c.h" #include "ps8740.h" #include "usb_mux.h" #include "util.h" int ps8740_read(const struct usb_mux *me, uint8_t reg, int *val) { return i2c_read8(me->i2c_port, me->i2c_addr_flags, reg, val); } int ps8740_write(const struct usb_mux *me, uint8_t reg, uint8_t val) { return i2c_write8(me->i2c_port, me->i2c_addr_flags, reg, val); } static int ps8740_init(const struct usb_mux *me) { int id1; int id2; int res; /* Reset chip back to power-on state */ res = ps8740_write(me, PS8740_REG_MODE, PS8740_MODE_POWER_DOWN); if (res) return res; /* * Verify chip ID registers. */ res = ps8740_read(me, PS8740_REG_CHIP_ID1, &id1); if (res) return res; res = ps8740_read(me, PS8740_REG_CHIP_ID2, &id2); if (res) return res; if (id1 != PS8740_CHIP_ID1 || id2 != PS8740_CHIP_ID2) return EC_ERROR_UNKNOWN; /* * Verify revision ID registers. */ res = ps8740_read(me, PS8740_REG_REVISION_ID1, &id1); if (res) return res; res = ps8740_read(me, PS8740_REG_REVISION_ID2, &id2); if (res) return res; if (id1 != PS8740_REVISION_ID1) return EC_ERROR_UNKNOWN; /* PS8740 may have REVISION_ID2 as 0xa or 0xb */ if (id2 != PS8740_REVISION_ID2_0 && id2 != PS8740_REVISION_ID2_1) return EC_ERROR_UNKNOWN; return EC_SUCCESS; } /* Writes control register to set switch mode */ static int ps8740_set_mux(const struct usb_mux *me, mux_state_t mux_state, bool *ack_required) { uint8_t reg = 0; /* This driver does not use host command ACKs */ *ack_required = false; /* This driver treats safe mode as none */ if (mux_state == USB_PD_MUX_SAFE_MODE) mux_state = USB_PD_MUX_NONE; if (mux_state & USB_PD_MUX_USB_ENABLED) reg |= PS8740_MODE_USB_ENABLED; if (mux_state & USB_PD_MUX_DP_ENABLED) reg |= PS8740_MODE_DP_ENABLED; if (mux_state & USB_PD_MUX_POLARITY_INVERTED) reg |= PS8740_MODE_POLARITY_INVERTED; return ps8740_write(me, PS8740_REG_MODE, reg); } /* Reads control register and updates mux_state accordingly */ static int ps8740_get_mux(const struct usb_mux *me, mux_state_t *mux_state) { int reg; int res; res = ps8740_read(me, PS8740_REG_STATUS, ®); if (res) return res; *mux_state = 0; if (reg & PS8740_STATUS_USB_ENABLED) *mux_state |= USB_PD_MUX_USB_ENABLED; if (reg & PS8740_STATUS_DP_ENABLED) *mux_state |= USB_PD_MUX_DP_ENABLED; if (reg & PS8740_STATUS_POLARITY_INVERTED) *mux_state |= USB_PD_MUX_POLARITY_INVERTED; return EC_SUCCESS; } /* Tune USB Tx/Rx Equalization */ int ps8740_tune_usb_eq(const struct usb_mux *me, uint8_t tx, uint8_t rx) { int ret; ret = ps8740_write(me, PS8740_REG_USB_EQ_TX, tx); ret |= ps8740_write(me, PS8740_REG_USB_EQ_RX, rx); return ret; } const struct usb_mux_driver ps8740_usb_mux_driver = { .init = ps8740_init, .set = ps8740_set_mux, .get = ps8740_get_mux, };