| /* Copyright 2015 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. |
| * |
| * Pericom PI3USB30532 USB port switch driver. |
| */ |
| |
| #include "common.h" |
| #include "i2c.h" |
| #include "pi3usb30532.h" |
| #include "usb_mux.h" |
| #include "util.h" |
| |
| static int pi3usb30532_read(int i2c_addr, uint8_t reg, uint8_t *val) |
| { |
| int read, res; |
| |
| /* |
| * First byte read will be slave address (ignored). |
| * Second byte read will be vendor ID. |
| * Third byte read will be selection control. |
| */ |
| res = i2c_read16(I2C_PORT_USB_MUX, i2c_addr, 0, &read); |
| if (res) |
| return res; |
| |
| if (reg == PI3USB30532_REG_VENDOR) |
| *val = read & 0xff; |
| else /* reg == PI3USB30532_REG_CONTROL */ |
| *val = (read >> 8) & 0xff; |
| |
| return EC_SUCCESS; |
| } |
| |
| static int pi3usb30532_write(int i2c_addr, uint8_t reg, uint8_t val) |
| { |
| if (reg != PI3USB30532_REG_CONTROL) |
| return EC_ERROR_UNKNOWN; |
| |
| return i2c_write8(I2C_PORT_USB_MUX, i2c_addr, 0, val); |
| } |
| |
| static int pi3usb30532_reset(int i2c_addr) |
| { |
| return pi3usb30532_write( |
| i2c_addr, |
| PI3USB30532_REG_CONTROL, |
| (PI3USB30532_MODE_POWERDOWN & PI3USB30532_CTRL_MASK) | |
| PI3USB30532_CTRL_RSVD); |
| } |
| |
| static int pi3usb30532_init(int i2c_addr) |
| { |
| uint8_t val; |
| int res; |
| |
| res = pi3usb30532_reset(i2c_addr); |
| if (res) |
| return res; |
| res = pi3usb30532_read(i2c_addr, PI3USB30532_REG_VENDOR, &val); |
| if (res) |
| return res; |
| if (val != PI3USB30532_VENDOR_ID) |
| return EC_ERROR_UNKNOWN; |
| |
| return EC_SUCCESS; |
| } |
| |
| /* Writes control register to set switch mode */ |
| static int pi3usb30532_set_mux(int i2c_addr, mux_state_t mux_state) |
| { |
| uint8_t reg = 0; |
| |
| if (mux_state & MUX_USB_ENABLED) |
| reg |= PI3USB30532_MODE_USB; |
| if (mux_state & MUX_DP_ENABLED) |
| reg |= PI3USB30532_MODE_DP; |
| if (mux_state & MUX_POLARITY_INVERTED) |
| reg |= PI3USB30532_BIT_SWAP; |
| |
| return pi3usb30532_write(i2c_addr, PI3USB30532_REG_CONTROL, |
| reg | PI3USB30532_CTRL_RSVD); |
| } |
| |
| /* Reads control register and updates mux_state accordingly */ |
| static int pi3usb30532_get_mux(int i2c_addr, mux_state_t *mux_state) |
| { |
| uint8_t reg = 0; |
| uint8_t res; |
| |
| *mux_state = 0; |
| res = pi3usb30532_read(i2c_addr, PI3USB30532_REG_CONTROL, ®); |
| if (res) |
| return res; |
| |
| if (reg & PI3USB30532_MODE_USB) |
| *mux_state |= MUX_USB_ENABLED; |
| if (reg & PI3USB30532_MODE_DP) |
| *mux_state |= MUX_DP_ENABLED; |
| if (reg & PI3USB30532_BIT_SWAP) |
| *mux_state |= MUX_POLARITY_INVERTED; |
| |
| return EC_SUCCESS; |
| } |
| |
| const struct usb_mux_driver pi3usb30532_usb_mux_driver = { |
| .init = pi3usb30532_init, |
| .set = pi3usb30532_set_mux, |
| .get = pi3usb30532_get_mux, |
| }; |