| /* Copyright 2020 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. |
| * |
| * TI TUSB544 USB Type-C Multi-Protocol Linear Redriver |
| */ |
| #include "i2c.h" |
| #include "tusb544.h" |
| #include "usb_mux.h" |
| |
| static int tusb544_write(const struct usb_mux *me, int offset, int data) |
| { |
| return i2c_write8(me->i2c_port, |
| me->i2c_addr_flags, |
| offset, data); |
| } |
| |
| static int tusb544_read(const struct usb_mux *me, int offset, int *data) |
| { |
| return i2c_read8(me->i2c_port, |
| me->i2c_addr_flags, |
| offset, data); |
| } |
| |
| int tusb544_i2c_field_update8(const struct usb_mux *me, int offset, |
| uint8_t field_mask, uint8_t set_value) |
| { |
| int rv; |
| |
| rv = i2c_field_update8(me->i2c_port, |
| me->i2c_addr_flags, |
| offset, |
| field_mask, |
| set_value); |
| |
| return rv; |
| } |
| |
| static int tusb544_enter_low_power_mode(const struct usb_mux *me) |
| { |
| int reg; |
| int rv; |
| |
| rv = tusb544_read(me, TUSB544_REG_GENERAL4, ®); |
| if (rv) |
| return rv; |
| |
| /* Setting CTL_SEL[0,1] to 0 powers down, per Table 5 */ |
| reg &= ~TUSB544_GEN4_CTL_SEL; |
| /* Clear HPD */ |
| reg &= ~TUSB544_GEN4_HPDIN; |
| |
| return tusb544_write(me, TUSB544_REG_GENERAL4, reg); |
| } |
| |
| static int tusb544_init(const struct usb_mux *me) |
| { |
| return EC_SUCCESS; |
| } |
| |
| static int tusb544_set_mux(const struct usb_mux *me, mux_state_t mux_state) |
| { |
| int reg; |
| int rv; |
| |
| if (mux_state == USB_PD_MUX_NONE) |
| return tusb544_enter_low_power_mode(me); |
| |
| rv = tusb544_read(me, TUSB544_REG_GENERAL4, ®); |
| if (rv) |
| return rv; |
| |
| if (mux_state & USB_PD_MUX_POLARITY_INVERTED) |
| reg |= TUSB544_GEN4_FLIP_SEL; |
| else |
| reg &= ~TUSB544_GEN4_FLIP_SEL; |
| |
| reg &= ~TUSB544_GEN4_CTL_SEL; |
| |
| if (IS_ENABLED(CONFIG_TUSB544_EQ_BY_REGISTER)) |
| reg |= TUSB544_GEN4_EQ_OVRD; |
| |
| if ((mux_state & USB_PD_MUX_USB_ENABLED) && |
| (mux_state & USB_PD_MUX_DP_ENABLED)) { |
| reg |= TUSB544_CTL_SEL_DP_USB; |
| reg |= TUSB544_GEN4_HPDIN; |
| } else if (mux_state & USB_PD_MUX_DP_ENABLED) { |
| reg |= TUSB544_CTL_SEL_DP_ONLY; |
| reg |= TUSB544_GEN4_HPDIN; |
| } else if (mux_state & USB_PD_MUX_USB_ENABLED) |
| reg |= TUSB544_CTL_SEL_USB_ONLY; |
| |
| rv = tusb544_write(me, TUSB544_REG_GENERAL4, reg); |
| if (rv) |
| return rv; |
| |
| rv = tusb544_read(me, TUSB544_REG_GENERAL6, ®); |
| if (rv) |
| return rv; |
| |
| reg &= ~TUSB544_GEN6_DIR_SEL; |
| /* All chromebooks are DP SRC */ |
| reg |= TUSB544_DIR_SEL_USB_DP_SRC; |
| |
| return tusb544_write(me, TUSB544_REG_GENERAL6, reg); |
| } |
| |
| const struct usb_mux_driver tusb544_drv = { |
| .enter_low_power_mode = &tusb544_enter_low_power_mode, |
| .init = &tusb544_init, |
| .set = &tusb544_set_mux, |
| }; |