| /* Copyright 2017 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. |
| * |
| * Parade PS874X USB Type-C Redriving Switch for USB Host / DisplayPort. |
| */ |
| |
| #include "common.h" |
| #include "i2c.h" |
| #include "usb_mux_ps874x.h" |
| #include "usb_mux.h" |
| #include "util.h" |
| |
| static inline int ps874x_read(int i2c_addr, uint8_t reg, int *val) |
| { |
| return i2c_read8(I2C_PORT_USB_MUX, i2c_addr, reg, val); |
| } |
| |
| static inline int ps874x_write(int i2c_addr, uint8_t reg, uint8_t val) |
| { |
| return i2c_write8(I2C_PORT_USB_MUX, i2c_addr, reg, val); |
| } |
| |
| static int ps874x_init(int i2c_addr) |
| { |
| int val; |
| int res; |
| |
| /* Reset chip back to power-on state */ |
| res = ps874x_write(i2c_addr, PS874X_REG_MODE, PS874X_MODE_POWER_DOWN); |
| if (res) |
| return res; |
| |
| /* |
| * Verify revision / chip ID registers. |
| * From Parade: PS8743 may have REVISION_ID1 as 0 or 1, |
| * PS8740 may have REVISION_ID2 as 0 or 1, |
| * 1 is derived from 0 and have same functionality. |
| */ |
| res = ps874x_read(i2c_addr, PS874X_REG_REVISION_ID1, &val); |
| if (res) |
| return res; |
| if (val < PS874X_REVISION_ID1) |
| return EC_ERROR_UNKNOWN; |
| |
| res = ps874x_read(i2c_addr, PS874X_REG_REVISION_ID2, &val); |
| if (res) |
| return res; |
| if (val < PS874X_REVISION_ID2) |
| return EC_ERROR_UNKNOWN; |
| |
| res = ps874x_read(i2c_addr, PS874X_REG_CHIP_ID1, &val); |
| if (res) |
| return res; |
| if (val != PS874X_CHIP_ID1) |
| return EC_ERROR_UNKNOWN; |
| |
| res = ps874x_read(i2c_addr, PS874X_REG_CHIP_ID2, &val); |
| if (res) |
| return res; |
| if (val != PS874X_CHIP_ID2) |
| return EC_ERROR_UNKNOWN; |
| |
| return EC_SUCCESS; |
| } |
| |
| /* Writes control register to set switch mode */ |
| static int ps874x_set_mux(int i2c_addr, mux_state_t mux_state) |
| { |
| uint8_t reg = 0; |
| |
| if (mux_state & MUX_USB_ENABLED) |
| reg |= PS874X_MODE_USB_ENABLED; |
| if (mux_state & MUX_DP_ENABLED) |
| reg |= PS874X_MODE_DP_ENABLED; |
| if (mux_state & MUX_POLARITY_INVERTED) |
| reg |= PS874X_MODE_POLARITY_INVERTED; |
| |
| return ps874x_write(i2c_addr, PS874X_REG_MODE, reg); |
| } |
| |
| /* Reads control register and updates mux_state accordingly */ |
| static int ps874x_get_mux(int i2c_addr, mux_state_t *mux_state) |
| { |
| int reg; |
| int res; |
| |
| res = ps874x_read(i2c_addr, PS874X_REG_STATUS, ®); |
| if (res) |
| return res; |
| |
| *mux_state = 0; |
| if (reg & PS874X_STATUS_USB_ENABLED) |
| *mux_state |= MUX_USB_ENABLED; |
| if (reg & PS874X_STATUS_DP_ENABLED) |
| *mux_state |= MUX_DP_ENABLED; |
| if (reg & PS874X_STATUS_POLARITY_INVERTED) |
| *mux_state |= MUX_POLARITY_INVERTED; |
| |
| return EC_SUCCESS; |
| } |
| |
| /* Tune USB Tx/Rx Equalization */ |
| int ps874x_tune_usb_eq(int i2c_addr, uint8_t tx, uint8_t rx) |
| { |
| int ret; |
| |
| ret = ps874x_write(i2c_addr, PS874X_REG_USB_EQ_TX, tx); |
| ret |= ps874x_write(i2c_addr, PS874X_REG_USB_EQ_RX, rx); |
| |
| return ret; |
| } |
| |
| const struct usb_mux_driver ps874x_usb_mux_driver = { |
| .init = ps874x_init, |
| .set = ps874x_set_mux, |
| .get = ps874x_get_mux, |
| }; |