mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-27 18:25:05 +00:00
Initial commit of TCPM driver for FUSB302.
BUG=none BRANCH=none TEST=PD contract established with various devices Change-Id: I4b452befe9ccd9d67bd6ad5c8cf77ae58320f6af Signed-off-by: Gabe Noblesmith <gabe.noblesmith@fairchildsemi.com> Reviewed-on: https://chromium-review.googlesource.com/294924 Commit-Ready: Shawn N <shawnn@chromium.org> Tested-by: Shawn N <shawnn@chromium.org> Reviewed-by: Alec Berg <alecaberg@chromium.org>
This commit is contained in:
committed by
chrome-bot
parent
4f090ad68e
commit
e3554f39d7
@@ -74,6 +74,7 @@ driver-$(CONFIG_THERMISTOR_NCP15WB)+=temp_sensor/thermistor_ncp15wb.o
|
||||
# Type-C port controller (TCPC) drivers
|
||||
driver-$(CONFIG_USB_PD_TCPM_STUB)+=tcpm/stub.o
|
||||
driver-$(CONFIG_USB_PD_TCPM_TCPCI)+=tcpm/tcpci.o
|
||||
driver-$(CONFIG_USB_PD_TCPM_FUSB302)+=tcpm/fusb302.o
|
||||
|
||||
# USB switches
|
||||
driver-$(CONFIG_USB_SWITCH_PI3USB9281)+=usb_switch_pi3usb9281.o
|
||||
|
||||
952
driver/tcpm/fusb302.c
Normal file
952
driver/tcpm/fusb302.c
Normal file
@@ -0,0 +1,952 @@
|
||||
/* 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.
|
||||
*
|
||||
* Author: Gabe Noblesmith
|
||||
*/
|
||||
|
||||
/* Type-C port manager for Fairchild's FUSB302 */
|
||||
|
||||
#include "console.h"
|
||||
#include "fusb302.h"
|
||||
#include "i2c.h"
|
||||
#include "task.h"
|
||||
#include "hooks.h"
|
||||
#include "timer.h"
|
||||
#include "usb_pd.h"
|
||||
#include "usb_pd_tcpc.h"
|
||||
#include "usb_pd_tcpm.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Convert port number to tcpc i2c address */
|
||||
#define I2C_ADDR_TCPC(p) (CONFIG_TCPC_I2C_BASE_ADDR + 2*(p))
|
||||
|
||||
static struct fusb302_chip_state {
|
||||
int cc_polarity;
|
||||
int vconn_enabled;
|
||||
/* 1 = pulling up (DFP) 0 = pulling down (UFP) */
|
||||
int pulling_up;
|
||||
int rx_enable;
|
||||
int dfp_toggling_on;
|
||||
int previous_pull;
|
||||
int togdone_pullup_cc1;
|
||||
int togdone_pullup_cc2;
|
||||
int tx_hard_reset_req;
|
||||
} state[CONFIG_USB_PD_PORT_COUNT];
|
||||
|
||||
static int fusb302_i2c_write8(int port, int reg, int val)
|
||||
{
|
||||
return i2c_write8(I2C_PORT_TCPC, I2C_ADDR_TCPC(port), reg, val);
|
||||
}
|
||||
|
||||
static int fusb302_i2c_read8(int port, int reg, int *val)
|
||||
{
|
||||
return i2c_read8(I2C_PORT_TCPC, I2C_ADDR_TCPC(port), reg, val);
|
||||
}
|
||||
|
||||
/* bring the FUSB302 out of reset after Hard Reset signaling */
|
||||
static void fusb302_pd_reset(int port)
|
||||
{
|
||||
fusb302_i2c_write8(port, TCPC_REG_RESET, TCPC_REG_RESET_PD_RESET);
|
||||
}
|
||||
|
||||
static void fusb302_flush_rx_fifo(int port)
|
||||
{
|
||||
/*
|
||||
* other bits in the register _should_ be 0
|
||||
* until the day we support other SOP* types...
|
||||
* then we'll have to keep a shadow of what this register
|
||||
* value should be so we don't clobber it here!
|
||||
*/
|
||||
fusb302_i2c_write8(port, TCPC_REG_CONTROL1, TCPC_REG_CONTROL1_RX_FLUSH);
|
||||
}
|
||||
|
||||
static void fusb302_flush_tx_fifo(int port)
|
||||
{
|
||||
int reg;
|
||||
|
||||
fusb302_i2c_read8(port, TCPC_REG_CONTROL0, ®);
|
||||
reg |= TCPC_REG_CONTROL0_TX_FLUSH;
|
||||
fusb302_i2c_write8(port, TCPC_REG_CONTROL0, reg);
|
||||
}
|
||||
|
||||
static void fusb302_auto_goodcrc_enable(int port, int enable)
|
||||
{
|
||||
int reg;
|
||||
|
||||
fusb302_i2c_read8(port, TCPC_REG_SWITCHES1, ®);
|
||||
|
||||
if (enable)
|
||||
reg |= TCPC_REG_SWITCHES1_AUTO_GCRC;
|
||||
else
|
||||
reg &= ~TCPC_REG_SWITCHES1_AUTO_GCRC;
|
||||
|
||||
fusb302_i2c_write8(port, TCPC_REG_SWITCHES1, reg);
|
||||
}
|
||||
|
||||
/* Convert BC LVL values (in FUSB302) to Type-C CC Voltage Status */
|
||||
static int convert_bc_lvl(int port, int bc_lvl)
|
||||
{
|
||||
/* assume OPEN unless one of the following conditions is true... */
|
||||
int ret = TYPEC_CC_VOLT_OPEN;
|
||||
|
||||
if (state[port].pulling_up) {
|
||||
if (bc_lvl == 0x00)
|
||||
ret = TYPEC_CC_VOLT_RA;
|
||||
else if (bc_lvl < 0x3)
|
||||
ret = TYPEC_CC_VOLT_RD;
|
||||
} else {
|
||||
if (bc_lvl == 0x1)
|
||||
ret = TYPEC_CC_VOLT_SNK_DEF;
|
||||
else if (bc_lvl == 0x2)
|
||||
ret = TYPEC_CC_VOLT_SNK_1_5;
|
||||
else if (bc_lvl == 0x3)
|
||||
ret = TYPEC_CC_VOLT_SNK_3_0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Determine cc pin state for source */
|
||||
static void detect_cc_pin_source(int port, int *cc1_lvl, int *cc2_lvl)
|
||||
{
|
||||
int reg;
|
||||
|
||||
*cc1_lvl = TYPEC_CC_VOLT_OPEN;
|
||||
*cc2_lvl = TYPEC_CC_VOLT_OPEN;
|
||||
|
||||
if (state[port].togdone_pullup_cc1 == 1) {
|
||||
/* Measure CC1 */
|
||||
|
||||
/* Enable CC1 measurement switch and pullup */
|
||||
fusb302_i2c_write8(port, TCPC_REG_SWITCHES0,
|
||||
TCPC_REG_SWITCHES0_CC1_PU_EN |
|
||||
TCPC_REG_SWITCHES0_MEAS_CC1);
|
||||
|
||||
/* Set MDAC Value to High. MDAC Reg is 7:2 */
|
||||
fusb302_i2c_write8(port, TCPC_REG_MEASURE, 0x26 << 2);
|
||||
|
||||
/* CC1 is now being measured by FUSB302. */
|
||||
|
||||
/* Wait on measurement */
|
||||
usleep(250);
|
||||
|
||||
/* Read status register */
|
||||
fusb302_i2c_read8(port, TCPC_REG_STATUS0, ®);
|
||||
|
||||
if (reg & TCPC_REG_STATUS0_COMP) {
|
||||
*cc1_lvl = TYPEC_CC_VOLT_OPEN;
|
||||
} else {
|
||||
|
||||
/* Set MDAC Value to Low. MDAC Reg is 7:2 */
|
||||
fusb302_i2c_write8(port, TCPC_REG_MEASURE, 0x05 << 2);
|
||||
|
||||
/* Wait on measurement */
|
||||
usleep(250);
|
||||
|
||||
/* Read status register */
|
||||
fusb302_i2c_read8(port, TCPC_REG_STATUS0, ®);
|
||||
|
||||
if (reg & TCPC_REG_STATUS0_COMP)
|
||||
*cc1_lvl = TYPEC_CC_VOLT_RA;
|
||||
else
|
||||
*cc1_lvl = TYPEC_CC_VOLT_RD;
|
||||
}
|
||||
} else if (state[port].togdone_pullup_cc2 == 1) {
|
||||
/* Measure CC2 */
|
||||
|
||||
/* Enable CC2 measurement switch and pullup */
|
||||
fusb302_i2c_write8(port, TCPC_REG_SWITCHES0,
|
||||
TCPC_REG_SWITCHES0_CC2_PU_EN |
|
||||
TCPC_REG_SWITCHES0_MEAS_CC2);
|
||||
|
||||
/* Set MDAC Value to High. MDAC Reg is 7:2 */
|
||||
fusb302_i2c_write8(port, TCPC_REG_MEASURE, 0x26 << 2);
|
||||
|
||||
/* CC2 is now being measured by FUSB302. */
|
||||
|
||||
/* Wait on measurement */
|
||||
usleep(250);
|
||||
|
||||
/* Read status register */
|
||||
fusb302_i2c_read8(port, TCPC_REG_STATUS0, ®);
|
||||
|
||||
if (reg & TCPC_REG_STATUS0_COMP) {
|
||||
*cc2_lvl = TYPEC_CC_VOLT_OPEN;
|
||||
} else {
|
||||
|
||||
/* Set MDAC Value to Low. MDAC Reg is 7:2 */
|
||||
fusb302_i2c_write8(port, TCPC_REG_MEASURE, 0x05 << 2);
|
||||
|
||||
/* Wait on measurement */
|
||||
usleep(250);
|
||||
|
||||
/* Read status register */
|
||||
fusb302_i2c_read8(port, TCPC_REG_STATUS0, ®);
|
||||
|
||||
if (reg & TCPC_REG_STATUS0_COMP)
|
||||
*cc2_lvl = TYPEC_CC_VOLT_RA;
|
||||
else
|
||||
*cc2_lvl = TYPEC_CC_VOLT_RD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine cc pin state for sink */
|
||||
static void detect_cc_pin_sink(int port, int *cc1, int *cc2)
|
||||
{
|
||||
int reg;
|
||||
int orig_meas_cc1;
|
||||
int orig_meas_cc2;
|
||||
int bc_lvl_cc1;
|
||||
int bc_lvl_cc2;
|
||||
|
||||
/*
|
||||
* Measure CC1 first.
|
||||
*/
|
||||
fusb302_i2c_read8(port, TCPC_REG_SWITCHES0, ®);
|
||||
|
||||
/* save original state to be returned to later... */
|
||||
if (reg & TCPC_REG_SWITCHES0_MEAS_CC1)
|
||||
orig_meas_cc1 = 1;
|
||||
else
|
||||
orig_meas_cc1 = 0;
|
||||
|
||||
if (reg & TCPC_REG_SWITCHES0_MEAS_CC2)
|
||||
orig_meas_cc2 = 1;
|
||||
else
|
||||
orig_meas_cc2 = 0;
|
||||
|
||||
|
||||
/* Disable CC2 measurement switch, enable CC1 measurement switch */
|
||||
reg &= ~TCPC_REG_SWITCHES0_MEAS_CC2;
|
||||
reg |= TCPC_REG_SWITCHES0_MEAS_CC1;
|
||||
|
||||
fusb302_i2c_write8(port, TCPC_REG_SWITCHES0, reg);
|
||||
|
||||
/*
|
||||
* CC1 is now being measured by FUSB302.
|
||||
*/
|
||||
fusb302_i2c_read8(port, TCPC_REG_STATUS0, &bc_lvl_cc1);
|
||||
|
||||
/* mask away unwanted bits */
|
||||
bc_lvl_cc1 &= (TCPC_REG_STATUS0_BC_LVL0 | TCPC_REG_STATUS0_BC_LVL1);
|
||||
|
||||
/*
|
||||
* Measure CC2 next.
|
||||
*/
|
||||
|
||||
fusb302_i2c_read8(port, TCPC_REG_SWITCHES0, ®);
|
||||
|
||||
/* Disable CC1 measurement switch, enable CC2 measurement switch */
|
||||
reg &= ~TCPC_REG_SWITCHES0_MEAS_CC1;
|
||||
reg |= TCPC_REG_SWITCHES0_MEAS_CC2;
|
||||
|
||||
fusb302_i2c_write8(port, TCPC_REG_SWITCHES0, reg);
|
||||
|
||||
/*
|
||||
* CC2 is now being measured by FUSB302.
|
||||
*/
|
||||
fusb302_i2c_read8(port, TCPC_REG_STATUS0, &bc_lvl_cc2);
|
||||
|
||||
/* mask away unwanted bits */
|
||||
bc_lvl_cc2 &= (TCPC_REG_STATUS0_BC_LVL0 | TCPC_REG_STATUS0_BC_LVL1);
|
||||
|
||||
*cc1 = convert_bc_lvl(port, bc_lvl_cc1);
|
||||
*cc2 = convert_bc_lvl(port, bc_lvl_cc2);
|
||||
|
||||
/* return MEAS_CC1/2 switches to original state */
|
||||
fusb302_i2c_read8(port, TCPC_REG_SWITCHES0, ®);
|
||||
if (orig_meas_cc1)
|
||||
reg |= TCPC_REG_SWITCHES0_MEAS_CC1;
|
||||
else
|
||||
reg &= ~TCPC_REG_SWITCHES0_MEAS_CC1;
|
||||
if (orig_meas_cc2)
|
||||
reg |= TCPC_REG_SWITCHES0_MEAS_CC2;
|
||||
else
|
||||
reg &= ~TCPC_REG_SWITCHES0_MEAS_CC2;
|
||||
|
||||
fusb302_i2c_write8(port, TCPC_REG_SWITCHES0, reg);
|
||||
}
|
||||
|
||||
/* Parse header bytes for the size of packet */
|
||||
static int get_num_bytes(uint16_t header)
|
||||
{
|
||||
int rv;
|
||||
|
||||
/* Grab the Number of Data Objects field.*/
|
||||
rv = PD_HEADER_CNT(header);
|
||||
|
||||
/* Multiply by four to go from 32-bit words -> bytes */
|
||||
rv *= 4;
|
||||
|
||||
/* Plus 2 for header */
|
||||
rv += 2;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int fusb302_send_message(int port, uint16_t header, const uint32_t *data,
|
||||
uint8_t *buf, int buf_pos)
|
||||
{
|
||||
int rv;
|
||||
int reg;
|
||||
int len;
|
||||
|
||||
len = get_num_bytes(header);
|
||||
|
||||
/*
|
||||
* packsym tells the TXFIFO that the next X bytes are payload,
|
||||
* and should not be interpreted as special tokens.
|
||||
* The 5 LSBs represent X, the number of bytes.
|
||||
*/
|
||||
reg = FUSB302_TKN_PACKSYM;
|
||||
reg |= (len & 0x1F);
|
||||
|
||||
buf[buf_pos++] = reg;
|
||||
|
||||
/* write in the header */
|
||||
reg = header;
|
||||
buf[buf_pos++] = reg & 0xFF;
|
||||
|
||||
reg >>= 8;
|
||||
buf[buf_pos++] = reg & 0xFF;
|
||||
|
||||
/* header is done, subtract from length to make this for-loop simpler */
|
||||
len -= 2;
|
||||
|
||||
/* write data objects, if present */
|
||||
memcpy(&buf[buf_pos], data, len);
|
||||
buf_pos += len;
|
||||
|
||||
/* put in the CRC */
|
||||
buf[buf_pos++] = FUSB302_TKN_JAMCRC;
|
||||
|
||||
/* put in EOP */
|
||||
buf[buf_pos++] = FUSB302_TKN_EOP;
|
||||
|
||||
/* Turn transmitter off after sending message */
|
||||
buf[buf_pos++] = FUSB302_TKN_TXOFF;
|
||||
|
||||
/* Start transmission */
|
||||
reg = FUSB302_TKN_TXON;
|
||||
buf[buf_pos++] = FUSB302_TKN_TXON;
|
||||
|
||||
/* burst write for speed! */
|
||||
i2c_lock(I2C_PORT_TCPC, 1);
|
||||
rv = i2c_xfer(I2C_PORT_TCPC, I2C_ADDR_TCPC(port),
|
||||
buf, buf_pos, 0, 0, I2C_XFER_SINGLE);
|
||||
i2c_lock(I2C_PORT_TCPC, 0);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void tcpm_init_ports(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; i++)
|
||||
tcpm_init(i);
|
||||
}
|
||||
DECLARE_HOOK(HOOK_INIT, tcpm_init_ports, HOOK_PRIO_DEFAULT);
|
||||
|
||||
int tcpm_init(int port)
|
||||
{
|
||||
int reg;
|
||||
|
||||
/* set default */
|
||||
state[port].cc_polarity = -1;
|
||||
|
||||
state[port].previous_pull = TYPEC_CC_RD;
|
||||
|
||||
/* all other variables assumed to default to 0 */
|
||||
|
||||
/* Restore default settings */
|
||||
fusb302_i2c_write8(port, TCPC_REG_RESET, TCPC_REG_RESET_SW_RESET);
|
||||
|
||||
/* Turn on retries and set number of retries */
|
||||
fusb302_i2c_read8(port, TCPC_REG_CONTROL3, ®);
|
||||
reg |= TCPC_REG_CONTROL3_AUTO_RETRY;
|
||||
reg |= (PD_RETRY_COUNT & 0x3) <<
|
||||
TCPC_REG_CONTROL3_N_RETRIES_POS;
|
||||
fusb302_i2c_write8(port, TCPC_REG_CONTROL3, reg);
|
||||
|
||||
/* Create interrupt masks */
|
||||
reg = 0xFF;
|
||||
/* CC level changes */
|
||||
reg &= ~TCPC_REG_MASK_BC_LVL;
|
||||
/* collisions */
|
||||
reg &= ~TCPC_REG_MASK_COLLISION;
|
||||
/* misc alert */
|
||||
reg &= ~TCPC_REG_MASK_ALERT;
|
||||
fusb302_i2c_write8(port, TCPC_REG_MASK, reg);
|
||||
|
||||
reg = 0xFF;
|
||||
/* informs of attaches */
|
||||
reg &= ~TCPC_REG_MASKA_TOGDONE;
|
||||
/* when all pd message retries fail... */
|
||||
reg &= ~TCPC_REG_MASKA_RETRYFAIL;
|
||||
/* when fusb302 send a hard reset. */
|
||||
reg &= ~TCPC_REG_MASKA_HARDSENT;
|
||||
/* when fusb302 receives GoodCRC ack for a pd message */
|
||||
reg &= ~TCPC_REG_MASKA_TX_SUCCESS;
|
||||
/* when fusb302 receives a hard reset */
|
||||
reg &= ~TCPC_REG_MASKA_HARDRESET;
|
||||
fusb302_i2c_write8(port, TCPC_REG_MASKA, reg);
|
||||
|
||||
reg = 0xFF;
|
||||
/* when fusb302 sends GoodCRC to ack a pd message */
|
||||
reg &= ~TCPC_REG_MASKB_GCRCSENT;
|
||||
fusb302_i2c_write8(port, TCPC_REG_MASKB, reg);
|
||||
|
||||
/* Interrupt Enable */
|
||||
fusb302_i2c_read8(port, TCPC_REG_CONTROL0, ®);
|
||||
reg &= ~TCPC_REG_CONTROL0_INT_MASK;
|
||||
fusb302_i2c_write8(port, TCPC_REG_CONTROL0, reg);
|
||||
|
||||
/* Set VCONN switch defaults */
|
||||
tcpm_set_polarity(port, 0);
|
||||
tcpm_set_vconn(port, 0);
|
||||
|
||||
/* Turn on the power! */
|
||||
/* TODO: Reduce power consumption */
|
||||
fusb302_i2c_write8(port, TCPC_REG_POWER, TCPC_REG_POWER_PWR_ALL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpm_get_cc(int port, int *cc1, int *cc2)
|
||||
{
|
||||
/*
|
||||
* can't measure while doing DFP toggling -
|
||||
* FUSB302 takes control of the switches.
|
||||
* During this time, tell software that CCs are open -
|
||||
* at least until we get the TOGDONE interrupt...
|
||||
* which signals that the hardware found something.
|
||||
*/
|
||||
if (state[port].dfp_toggling_on) {
|
||||
*cc1 = TYPEC_CC_VOLT_OPEN;
|
||||
*cc2 = TYPEC_CC_VOLT_OPEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (state[port].pulling_up) {
|
||||
/* Source mode? */
|
||||
detect_cc_pin_source(port, cc1, cc2);
|
||||
} else {
|
||||
/* Sink mode? */
|
||||
detect_cc_pin_sink(port, cc1, cc2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpm_set_cc(int port, int pull)
|
||||
{
|
||||
int reg;
|
||||
|
||||
state[port].previous_pull = pull;
|
||||
|
||||
/* NOTE: FUSB302 toggles a single pull-up between CC1 and CC2 */
|
||||
/* NOTE: FUSB302 Does not support Ra. */
|
||||
switch (pull) {
|
||||
case TYPEC_CC_RP:
|
||||
|
||||
/* if fusb302 hasn't figured anything out yet */
|
||||
if (!state[port].togdone_pullup_cc1 &&
|
||||
!state[port].togdone_pullup_cc2) {
|
||||
|
||||
/* Enable DFP Toggle Mode */
|
||||
fusb302_i2c_read8(port, TCPC_REG_CONTROL2, ®);
|
||||
|
||||
/* turn on toggle */
|
||||
reg |= (TCPC_REG_CONTROL2_MODE_DFP <<
|
||||
TCPC_REG_CONTROL2_MODE_POS);
|
||||
reg |= TCPC_REG_CONTROL2_TOGGLE;
|
||||
fusb302_i2c_write8(port, TCPC_REG_CONTROL2, reg);
|
||||
|
||||
state[port].pulling_up = 1;
|
||||
state[port].dfp_toggling_on = 1;
|
||||
} else {
|
||||
|
||||
/* enable the pull-up we know to be necessary */
|
||||
fusb302_i2c_read8(port, TCPC_REG_SWITCHES0, ®);
|
||||
|
||||
reg &= ~(TCPC_REG_SWITCHES0_CC2_PU_EN);
|
||||
reg &= ~(TCPC_REG_SWITCHES0_CC1_PU_EN);
|
||||
reg &= ~TCPC_REG_SWITCHES0_CC1_PD_EN;
|
||||
reg &= ~TCPC_REG_SWITCHES0_CC2_PD_EN;
|
||||
|
||||
if (state[port].togdone_pullup_cc1)
|
||||
reg |= TCPC_REG_SWITCHES0_CC1_PU_EN;
|
||||
else
|
||||
reg |= TCPC_REG_SWITCHES0_CC2_PU_EN;
|
||||
|
||||
fusb302_i2c_write8(port, TCPC_REG_SWITCHES0, reg);
|
||||
|
||||
state[port].pulling_up = 1;
|
||||
state[port].dfp_toggling_on = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
case TYPEC_CC_RD:
|
||||
/* Enable UFP Mode */
|
||||
|
||||
/* turn off toggle */
|
||||
fusb302_i2c_read8(port, TCPC_REG_CONTROL2, ®);
|
||||
reg &= ~TCPC_REG_CONTROL2_TOGGLE;
|
||||
fusb302_i2c_write8(port, TCPC_REG_CONTROL2, reg);
|
||||
|
||||
/* enable pull-downs, disable pullups */
|
||||
fusb302_i2c_read8(port, TCPC_REG_SWITCHES0, ®);
|
||||
|
||||
reg &= ~(TCPC_REG_SWITCHES0_CC2_PU_EN);
|
||||
reg &= ~(TCPC_REG_SWITCHES0_CC1_PU_EN);
|
||||
reg |= (TCPC_REG_SWITCHES0_CC1_PD_EN);
|
||||
reg |= (TCPC_REG_SWITCHES0_CC2_PD_EN);
|
||||
fusb302_i2c_write8(port, TCPC_REG_SWITCHES0, reg);
|
||||
|
||||
state[port].pulling_up = 0;
|
||||
state[port].dfp_toggling_on = 0;
|
||||
break;
|
||||
case TYPEC_CC_OPEN:
|
||||
/* Disable toggling */
|
||||
fusb302_i2c_read8(port, TCPC_REG_CONTROL2, ®);
|
||||
reg &= ~TCPC_REG_CONTROL2_TOGGLE;
|
||||
fusb302_i2c_write8(port, TCPC_REG_CONTROL2, reg);
|
||||
|
||||
/* Ensure manual switches are opened */
|
||||
fusb302_i2c_read8(port, TCPC_REG_SWITCHES0, ®);
|
||||
reg &= ~TCPC_REG_SWITCHES0_CC1_PU_EN;
|
||||
reg &= ~TCPC_REG_SWITCHES0_CC2_PU_EN;
|
||||
reg &= ~TCPC_REG_SWITCHES0_CC1_PD_EN;
|
||||
reg &= ~TCPC_REG_SWITCHES0_CC2_PD_EN;
|
||||
fusb302_i2c_write8(port, TCPC_REG_SWITCHES0, reg);
|
||||
|
||||
state[port].pulling_up = 0;
|
||||
state[port].dfp_toggling_on = 0;
|
||||
break;
|
||||
default:
|
||||
/* Unsupported... */
|
||||
return EC_ERROR_UNIMPLEMENTED;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpm_set_polarity(int port, int polarity)
|
||||
{
|
||||
/* Port polarity : 0 => CC1 is CC line, 1 => CC2 is CC line */
|
||||
int reg;
|
||||
|
||||
fusb302_i2c_read8(port, TCPC_REG_SWITCHES0, ®);
|
||||
|
||||
/* clear VCONN switch bits */
|
||||
reg &= ~TCPC_REG_SWITCHES0_VCONN_CC1;
|
||||
reg &= ~TCPC_REG_SWITCHES0_VCONN_CC2;
|
||||
|
||||
if (state[port].vconn_enabled) {
|
||||
/* set VCONN switch to be non-CC line */
|
||||
if (polarity)
|
||||
reg |= TCPC_REG_SWITCHES0_VCONN_CC1;
|
||||
else
|
||||
reg |= TCPC_REG_SWITCHES0_VCONN_CC2;
|
||||
}
|
||||
|
||||
/* clear meas_cc bits (RX line select) */
|
||||
reg &= ~TCPC_REG_SWITCHES0_MEAS_CC1;
|
||||
reg &= ~TCPC_REG_SWITCHES0_MEAS_CC2;
|
||||
|
||||
/* set rx polarity */
|
||||
if (polarity)
|
||||
reg |= TCPC_REG_SWITCHES0_MEAS_CC2;
|
||||
else
|
||||
reg |= TCPC_REG_SWITCHES0_MEAS_CC1;
|
||||
|
||||
fusb302_i2c_write8(port, TCPC_REG_SWITCHES0, reg);
|
||||
|
||||
fusb302_i2c_read8(port, TCPC_REG_SWITCHES1, ®);
|
||||
|
||||
/* clear tx_cc bits */
|
||||
reg &= ~TCPC_REG_SWITCHES1_TXCC1_EN;
|
||||
reg &= ~TCPC_REG_SWITCHES1_TXCC2_EN;
|
||||
|
||||
/* set tx polarity */
|
||||
if (polarity)
|
||||
reg |= TCPC_REG_SWITCHES1_TXCC2_EN;
|
||||
else
|
||||
reg |= TCPC_REG_SWITCHES1_TXCC1_EN;
|
||||
|
||||
fusb302_i2c_write8(port, TCPC_REG_SWITCHES1, reg);
|
||||
|
||||
/* Save the polarity for later */
|
||||
state[port].cc_polarity = polarity;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpm_set_vconn(int port, int enable)
|
||||
{
|
||||
/*
|
||||
* FUSB302 does not have dedicated VCONN Enable switch.
|
||||
* We'll get through this by disabling both of the
|
||||
* VCONN - CC* switches to disable, and enabling the
|
||||
* saved polarity when enabling.
|
||||
* Therefore at startup, tcpm_set_polarity should be called first,
|
||||
* or else live with the default put into tcpm_init.
|
||||
*/
|
||||
int reg;
|
||||
|
||||
if (enable) {
|
||||
/* set to saved polarity */
|
||||
tcpm_set_polarity(port, state[port].cc_polarity);
|
||||
} else {
|
||||
|
||||
fusb302_i2c_read8(port, TCPC_REG_SWITCHES0, ®);
|
||||
|
||||
/* clear VCONN switch bits */
|
||||
reg &= ~TCPC_REG_SWITCHES0_VCONN_CC1;
|
||||
reg &= ~TCPC_REG_SWITCHES0_VCONN_CC2;
|
||||
|
||||
fusb302_i2c_write8(port, TCPC_REG_SWITCHES0, reg);
|
||||
}
|
||||
|
||||
/* save enable state for later use */
|
||||
state[port].vconn_enabled = enable;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpm_set_msg_header(int port, int power_role, int data_role)
|
||||
{
|
||||
int reg;
|
||||
|
||||
fusb302_i2c_read8(port, TCPC_REG_SWITCHES1, ®);
|
||||
|
||||
reg &= ~TCPC_REG_SWITCHES1_POWERROLE;
|
||||
reg &= ~TCPC_REG_SWITCHES1_DATAROLE;
|
||||
|
||||
if (power_role)
|
||||
reg |= TCPC_REG_SWITCHES1_POWERROLE;
|
||||
if (data_role)
|
||||
reg |= TCPC_REG_SWITCHES1_DATAROLE;
|
||||
|
||||
fusb302_i2c_write8(port, TCPC_REG_SWITCHES1, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpm_set_rx_enable(int port, int enable)
|
||||
{
|
||||
int reg;
|
||||
|
||||
state[port].rx_enable = enable;
|
||||
|
||||
/* Get current switch state */
|
||||
fusb302_i2c_read8(port, TCPC_REG_SWITCHES0, ®);
|
||||
|
||||
/* Clear CC1/CC2 measure bits */
|
||||
reg &= ~TCPC_REG_SWITCHES0_MEAS_CC1;
|
||||
reg &= ~TCPC_REG_SWITCHES0_MEAS_CC2;
|
||||
|
||||
if (enable) {
|
||||
switch (state[port].cc_polarity) {
|
||||
/* if CC polarity hasnt been determined, can't enable */
|
||||
case -1:
|
||||
return EC_ERROR_UNKNOWN;
|
||||
case 0:
|
||||
reg |= TCPC_REG_SWITCHES0_MEAS_CC1;
|
||||
break;
|
||||
case 1:
|
||||
reg |= TCPC_REG_SWITCHES0_MEAS_CC2;
|
||||
break;
|
||||
default:
|
||||
/* "shouldn't get here" */
|
||||
return EC_ERROR_UNKNOWN;
|
||||
}
|
||||
fusb302_i2c_write8(port, TCPC_REG_SWITCHES0, reg);
|
||||
|
||||
/* flush rx fifo in case messages have been coming our way */
|
||||
fusb302_flush_rx_fifo(port);
|
||||
|
||||
|
||||
} else {
|
||||
/*
|
||||
* bit of a hack here.
|
||||
* when this function is called to disable rx (enable=0)
|
||||
* using it as an indication of detach (gulp!)
|
||||
* to reset our knowledge of where
|
||||
* the toggle state machine landed.
|
||||
*/
|
||||
state[port].togdone_pullup_cc1 = 0;
|
||||
state[port].togdone_pullup_cc2 = 0;
|
||||
|
||||
tcpm_set_cc(port, state[port].previous_pull);
|
||||
|
||||
fusb302_i2c_write8(port, TCPC_REG_SWITCHES0, reg);
|
||||
}
|
||||
|
||||
fusb302_auto_goodcrc_enable(port, enable);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpm_get_message(int port, uint32_t *payload, int *head)
|
||||
{
|
||||
/*
|
||||
* this is the buffer that will get the burst-read data
|
||||
* from the fusb302.
|
||||
*
|
||||
* it's re-used in a couple different spots, the worst of which
|
||||
* is the PD packet (not header) and CRC.
|
||||
* maximum size necessary = 28 + 4 = 32
|
||||
*/
|
||||
uint8_t buf[32];
|
||||
int rv = 0;
|
||||
int len;
|
||||
|
||||
/* NOTE: Assuming enough memory has been allocated for payload. */
|
||||
|
||||
/*
|
||||
* PART 1 OF BURST READ: Write in register address.
|
||||
* Issue a START, no STOP.
|
||||
*/
|
||||
i2c_lock(I2C_PORT_TCPC, 1);
|
||||
buf[0] = TCPC_REG_FIFOS;
|
||||
rv |= i2c_xfer(I2C_PORT_TCPC, I2C_ADDR_TCPC(port),
|
||||
buf, 1, 0, 0, I2C_XFER_START);
|
||||
|
||||
/*
|
||||
* PART 2 OF BURST READ: Read up to the header.
|
||||
* Issue a repeated START, no STOP.
|
||||
* only grab three bytes so we can get the header
|
||||
* and determine how many more bytes we need to read.
|
||||
*/
|
||||
rv |= i2c_xfer(I2C_PORT_TCPC, I2C_ADDR_TCPC(port),
|
||||
0, 0, buf, 3, I2C_XFER_START);
|
||||
|
||||
/* Grab the header */
|
||||
*head = (buf[1] & 0xFF);
|
||||
*head |= ((buf[2] << 8) & 0xFF00);
|
||||
|
||||
/* figure out packet length, subtract header bytes */
|
||||
len = get_num_bytes(*head) - 2;
|
||||
|
||||
/*
|
||||
* PART 3 OF BURST READ: Read everything else.
|
||||
* No START, but do issue a STOP at the end.
|
||||
* add 4 to len to read CRC out
|
||||
*/
|
||||
rv |= i2c_xfer(I2C_PORT_TCPC, I2C_ADDR_TCPC(port),
|
||||
0, 0, buf, len+4, I2C_XFER_STOP);
|
||||
|
||||
i2c_lock(I2C_PORT_TCPC, 0);
|
||||
|
||||
/* return the data */
|
||||
memcpy(payload, buf, len);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int tcpm_transmit(int port, enum tcpm_transmit_type type, uint16_t header,
|
||||
const uint32_t *data)
|
||||
{
|
||||
/*
|
||||
* this is the buffer that will be burst-written into the fusb302
|
||||
* maximum size necessary =
|
||||
* 1: FIFO register address
|
||||
* 4: SOP* tokens
|
||||
* 1: Token that signifies "next X bytes are not tokens"
|
||||
* 30: 2 for header and up to 7*4 = 28 for rest of message
|
||||
* 1: "Insert CRC" Token
|
||||
* 1: EOP Token
|
||||
* 1: "Turn transmitter off" token
|
||||
* 1: "Star Transmission" Command
|
||||
* -
|
||||
* 40: 40 bytes worst-case
|
||||
*/
|
||||
uint8_t buf[40];
|
||||
int buf_pos = 0;
|
||||
|
||||
int reg;
|
||||
|
||||
/* Flush the TXFIFO */
|
||||
fusb302_flush_tx_fifo(port);
|
||||
|
||||
switch (type) {
|
||||
case TCPC_TX_SOP:
|
||||
|
||||
/* put register address first for of burst i2c write */
|
||||
buf[buf_pos++] = TCPC_REG_FIFOS;
|
||||
|
||||
/* Write the SOP Ordered Set into TX FIFO */
|
||||
buf[buf_pos++] = FUSB302_TKN_SYNC1;
|
||||
buf[buf_pos++] = FUSB302_TKN_SYNC1;
|
||||
buf[buf_pos++] = FUSB302_TKN_SYNC1;
|
||||
buf[buf_pos++] = FUSB302_TKN_SYNC2;
|
||||
|
||||
return fusb302_send_message(port, header, data, buf, buf_pos);
|
||||
case TCPC_TX_HARD_RESET:
|
||||
state[port].tx_hard_reset_req = 1;
|
||||
|
||||
/* Simply hit the SEND_HARD_RESET bit */
|
||||
fusb302_i2c_read8(port, TCPC_REG_CONTROL3, ®);
|
||||
reg |= TCPC_REG_CONTROL3_SEND_HARDRESET;
|
||||
fusb302_i2c_write8(port, TCPC_REG_CONTROL3, reg);
|
||||
|
||||
break;
|
||||
case TCPC_TX_BIST_MODE_2:
|
||||
/* Simply hit the BIST_MODE2 bit */
|
||||
fusb302_i2c_read8(port, TCPC_REG_CONTROL1, ®);
|
||||
reg |= TCPC_REG_CONTROL1_BIST_MODE2;
|
||||
fusb302_i2c_write8(port, TCPC_REG_CONTROL1, reg);
|
||||
break;
|
||||
default:
|
||||
return EC_ERROR_UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpm_get_vbus_level(int port)
|
||||
{
|
||||
int reg;
|
||||
|
||||
/* Read status register */
|
||||
fusb302_i2c_read8(port, TCPC_REG_STATUS0, ®);
|
||||
|
||||
return (reg & TCPC_REG_STATUS0_VBUSOK) ? 1 : 0;
|
||||
}
|
||||
|
||||
void tcpc_alert(int port)
|
||||
{
|
||||
/* interrupt has been received */
|
||||
int interrupt;
|
||||
int interrupta;
|
||||
int interruptb;
|
||||
int reg;
|
||||
int toggle_answer;
|
||||
|
||||
/* reading interrupt registers clears them */
|
||||
|
||||
fusb302_i2c_read8(port, TCPC_REG_INTERRUPT, &interrupt);
|
||||
fusb302_i2c_read8(port, TCPC_REG_INTERRUPTA, &interrupta);
|
||||
fusb302_i2c_read8(port, TCPC_REG_INTERRUPTB, &interruptb);
|
||||
|
||||
if (interrupt & TCPC_REG_INTERRUPT_BC_LVL) {
|
||||
/* CC Status change */
|
||||
task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0);
|
||||
}
|
||||
|
||||
if (interrupt & TCPC_REG_INTERRUPT_COLLISION) {
|
||||
/* packet sending collided */
|
||||
state[port].tx_hard_reset_req = 0;
|
||||
pd_transmit_complete(port, TCPC_TX_COMPLETE_FAILED);
|
||||
}
|
||||
|
||||
if (interrupta & TCPC_REG_INTERRUPTA_TX_SUCCESS) {
|
||||
/* sent packet was acknowledged with a GoodCRC */
|
||||
|
||||
/* flush out the GoodCRC message*/
|
||||
fusb302_flush_rx_fifo(port);
|
||||
|
||||
pd_transmit_complete(port, TCPC_TX_COMPLETE_SUCCESS);
|
||||
}
|
||||
|
||||
if (interrupta & TCPC_REG_INTERRUPTA_TOGDONE) {
|
||||
/* toggle done */
|
||||
state[port].dfp_toggling_on = 0;
|
||||
|
||||
/* read what 302 settled on for an answer...*/
|
||||
fusb302_i2c_read8(port, TCPC_REG_STATUS1A, ®);
|
||||
reg = reg >> TCPC_REG_STATUS1A_TOGSS_POS;
|
||||
reg = reg & TCPC_REG_STATUS1A_TOGSS_MASK;
|
||||
|
||||
toggle_answer = reg;
|
||||
|
||||
/* Turn off toggle so we can take over the switches again */
|
||||
fusb302_i2c_read8(port, TCPC_REG_CONTROL2, ®);
|
||||
reg &= ~TCPC_REG_CONTROL2_TOGGLE;
|
||||
fusb302_i2c_write8(port, TCPC_REG_CONTROL2, reg);
|
||||
|
||||
switch (toggle_answer) {
|
||||
case TCPC_REG_STATUS1A_TOGSS_SRC1:
|
||||
state[port].togdone_pullup_cc1 = 1;
|
||||
state[port].togdone_pullup_cc2 = 0;
|
||||
break;
|
||||
case TCPC_REG_STATUS1A_TOGSS_SRC2:
|
||||
state[port].togdone_pullup_cc1 = 0;
|
||||
state[port].togdone_pullup_cc2 = 1;
|
||||
break;
|
||||
case TCPC_REG_STATUS1A_TOGSS_SNK1:
|
||||
state[port].togdone_pullup_cc1 = 0;
|
||||
state[port].togdone_pullup_cc2 = 0;
|
||||
break;
|
||||
case TCPC_REG_STATUS1A_TOGSS_SNK2:
|
||||
state[port].togdone_pullup_cc1 = 0;
|
||||
state[port].togdone_pullup_cc2 = 0;
|
||||
break;
|
||||
case TCPC_REG_STATUS1A_TOGSS_AA:
|
||||
state[port].togdone_pullup_cc1 = 0;
|
||||
state[port].togdone_pullup_cc2 = 0;
|
||||
break;
|
||||
default:
|
||||
/* TODO: should never get here, but? */
|
||||
break;
|
||||
}
|
||||
|
||||
/* enable the pull-up we know to be necessary */
|
||||
fusb302_i2c_read8(port, TCPC_REG_SWITCHES0, ®);
|
||||
|
||||
reg &= ~(TCPC_REG_SWITCHES0_CC2_PU_EN);
|
||||
reg &= ~(TCPC_REG_SWITCHES0_CC1_PU_EN);
|
||||
reg &= ~TCPC_REG_SWITCHES0_CC1_PD_EN;
|
||||
reg &= ~TCPC_REG_SWITCHES0_CC2_PD_EN;
|
||||
|
||||
if (state[port].togdone_pullup_cc1)
|
||||
reg |= TCPC_REG_SWITCHES0_CC1_PU_EN;
|
||||
else
|
||||
reg |= TCPC_REG_SWITCHES0_CC2_PU_EN;
|
||||
|
||||
fusb302_i2c_write8(port, TCPC_REG_SWITCHES0, reg);
|
||||
}
|
||||
|
||||
if (interrupta & TCPC_REG_INTERRUPTA_RETRYFAIL) {
|
||||
/* all retries have failed to get a GoodCRC */
|
||||
pd_transmit_complete(port, TCPC_TX_COMPLETE_FAILED);
|
||||
}
|
||||
|
||||
if (interrupta & TCPC_REG_INTERRUPTA_HARDSENT) {
|
||||
/* hard reset has been sent */
|
||||
|
||||
if (state[port].tx_hard_reset_req) {
|
||||
state[port].tx_hard_reset_req = 0;
|
||||
/* bring FUSB302 out of reset */
|
||||
fusb302_pd_reset(port);
|
||||
|
||||
pd_transmit_complete(port, TCPC_TX_COMPLETE_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
if (interrupta & TCPC_REG_INTERRUPTA_HARDRESET) {
|
||||
/* hard reset has been received */
|
||||
|
||||
/* bring FUSB302 out of reset */
|
||||
fusb302_pd_reset(port);
|
||||
|
||||
pd_execute_hard_reset(port);
|
||||
|
||||
task_wake(PD_PORT_TO_TASK_ID(port));
|
||||
}
|
||||
|
||||
if (interruptb & TCPC_REG_INTERRUPTB_GCRCSENT) {
|
||||
/* Packet received and GoodCRC sent */
|
||||
/* (this interrupt fires after the GoodCRC finishes) */
|
||||
if (state[port].rx_enable) {
|
||||
task_set_event(PD_PORT_TO_TASK_ID(port),
|
||||
PD_EVENT_RX, 0);
|
||||
} else {
|
||||
/* flush rx fifo if rx isn't enabled */
|
||||
fusb302_flush_rx_fifo(port);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
198
driver/tcpm/fusb302.h
Normal file
198
driver/tcpm/fusb302.h
Normal file
@@ -0,0 +1,198 @@
|
||||
/* 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.
|
||||
*
|
||||
* Author: Gabe Noblesmith
|
||||
*/
|
||||
|
||||
/* USB Power delivery port management */
|
||||
/* For Fairchild FUSB302 */
|
||||
#ifndef __CROS_EC_DRIVER_TCPM_FUSB302_H
|
||||
#define __CROS_EC_DRIVER_TCPM_FUSB302_H
|
||||
|
||||
/* FUSB302 I2C Address */
|
||||
#define CONFIG_TCPC_I2C_BASE_ADDR 0x44
|
||||
|
||||
/* Default retry count for transmitting */
|
||||
#define PD_RETRY_COUNT 3
|
||||
|
||||
#define TCPC_REG_DEVICE_ID 0x01
|
||||
|
||||
#define TCPC_REG_SWITCHES0 0x02
|
||||
#define TCPC_REG_SWITCHES0_CC2_PU_EN (1<<7)
|
||||
#define TCPC_REG_SWITCHES0_CC1_PU_EN (1<<6)
|
||||
#define TCPC_REG_SWITCHES0_VCONN_CC2 (1<<5)
|
||||
#define TCPC_REG_SWITCHES0_VCONN_CC1 (1<<4)
|
||||
#define TCPC_REG_SWITCHES0_MEAS_CC2 (1<<3)
|
||||
#define TCPC_REG_SWITCHES0_MEAS_CC1 (1<<2)
|
||||
#define TCPC_REG_SWITCHES0_CC2_PD_EN (1<<1)
|
||||
#define TCPC_REG_SWITCHES0_CC1_PD_EN (1<<0)
|
||||
|
||||
#define TCPC_REG_SWITCHES1 0x03
|
||||
#define TCPC_REG_SWITCHES1_POWERROLE (1<<7)
|
||||
#define TCPC_REG_SWITCHES1_SPECREV1 (1<<6)
|
||||
#define TCPC_REG_SWITCHES1_SPECREV0 (1<<5)
|
||||
#define TCPC_REG_SWITCHES1_DATAROLE (1<<4)
|
||||
#define TCPC_REG_SWITCHES1_AUTO_GCRC (1<<2)
|
||||
#define TCPC_REG_SWITCHES1_TXCC2_EN (1<<1)
|
||||
#define TCPC_REG_SWITCHES1_TXCC1_EN (1<<0)
|
||||
|
||||
#define TCPC_REG_MEASURE 0x04
|
||||
#define TCPC_REG_MEASURE_MDAC5 (1<<7)
|
||||
#define TCPC_REG_MEASURE_MDAC4 (1<<6)
|
||||
#define TCPC_REG_MEASURE_MDAC3 (1<<5)
|
||||
#define TCPC_REG_MEASURE_MDAC2 (1<<4)
|
||||
#define TCPC_REG_MEASURE_MDAC1 (1<<3)
|
||||
#define TCPC_REG_MEASURE_MDAC0 (1<<2)
|
||||
#define TCPC_REG_MEASURE_VBUS (1<<1)
|
||||
#define TCPC_REG_MEASURE_XXXX5 (1<<0)
|
||||
|
||||
#define TCPC_REG_CONTROL0 0x06
|
||||
#define TCPC_REG_CONTROL0_TX_FLUSH (1<<6)
|
||||
#define TCPC_REG_CONTROL0_INT_MASK (1<<5)
|
||||
#define TCPC_REG_CONTROL0_TX_START (1<<0)
|
||||
|
||||
#define TCPC_REG_CONTROL1 0x07
|
||||
#define TCPC_REG_CONTROL1_ENSOP2DB (1<<6)
|
||||
#define TCPC_REG_CONTROL1_ENSOP1DB (1<<5)
|
||||
#define TCPC_REG_CONTROL1_BIST_MODE2 (1<<4)
|
||||
#define TCPC_REG_CONTROL1_RX_FLUSH (1<<2)
|
||||
#define TCPC_REG_CONTROL1_ENSOP2 (1<<1)
|
||||
#define TCPC_REG_CONTROL1_ENSOP1 (1<<0)
|
||||
|
||||
#define TCPC_REG_CONTROL2 0x08
|
||||
/* two-bit field, valid values below */
|
||||
#define TCPC_REG_CONTROL2_MODE (1<<1)
|
||||
#define TCPC_REG_CONTROL2_MODE_DFP (0x3)
|
||||
#define TCPC_REG_CONTROL2_MODE_UFP (0x2)
|
||||
#define TCPC_REG_CONTROL2_MODE_DRP (0x1)
|
||||
#define TCPC_REG_CONTROL2_MODE_POS (1)
|
||||
#define TCPC_REG_CONTROL2_TOGGLE (1<<0)
|
||||
|
||||
#define TCPC_REG_CONTROL3 0x09
|
||||
#define TCPC_REG_CONTROL3_SEND_HARDRESET (1<<6)
|
||||
#define TCPC_REG_CONTROL3_AUTO_HARDRESET (1<<4)
|
||||
#define TCPC_REG_CONTROL3_AUTO_SOFTRESET (1<<3)
|
||||
/* two-bit field */
|
||||
#define TCPC_REG_CONTROL3_N_RETRIES (1<<1)
|
||||
#define TCPC_REG_CONTROL3_N_RETRIES_POS (1)
|
||||
#define TCPC_REG_CONTROL3_N_RETRIES_SIZE (2)
|
||||
#define TCPC_REG_CONTROL3_AUTO_RETRY (1<<0)
|
||||
|
||||
#define TCPC_REG_MASK 0x0A
|
||||
#define TCPC_REG_MASK_VBUSOK (1<<7)
|
||||
#define TCPC_REG_MASK_ACTIVITY (1<<6)
|
||||
#define TCPC_REG_MASK_COMP_CHNG (1<<5)
|
||||
#define TCPC_REG_MASK_CRC_CHK (1<<4)
|
||||
#define TCPC_REG_MASK_ALERT (1<<3)
|
||||
#define TCPC_REG_MASK_WAKE (1<<2)
|
||||
#define TCPC_REG_MASK_COLLISION (1<<1)
|
||||
#define TCPC_REG_MASK_BC_LVL (1<<0)
|
||||
|
||||
#define TCPC_REG_POWER 0x0B
|
||||
#define TCPC_REG_POWER_PWR (1<<0) /* four-bit field */
|
||||
#define TCPC_REG_POWER_PWR_LOW 0x1 /* Bandgap + Wake circuitry */
|
||||
#define TCPC_REG_POWER_PWR_MEDIUM 0x3 /* LOW + Receiver + Current refs */
|
||||
#define TCPC_REG_POWER_PWR_HIGH 0x7 /* MEDIUM + Measure block */
|
||||
#define TCPC_REG_POWER_PWR_ALL 0xF /* HIGH + Internal Oscillator */
|
||||
|
||||
#define TCPC_REG_RESET 0x0C
|
||||
#define TCPC_REG_RESET_PD_RESET (1<<1)
|
||||
#define TCPC_REG_RESET_SW_RESET (1<<0)
|
||||
|
||||
#define TCPC_REG_MASKA 0x0E
|
||||
#define TCPC_REG_MASKA_OCP_TEMP (1<<7)
|
||||
#define TCPC_REG_MASKA_TOGDONE (1<<6)
|
||||
#define TCPC_REG_MASKA_SOFTFAIL (1<<5)
|
||||
#define TCPC_REG_MASKA_RETRYFAIL (1<<4)
|
||||
#define TCPC_REG_MASKA_HARDSENT (1<<3)
|
||||
#define TCPC_REG_MASKA_TX_SUCCESS (1<<2)
|
||||
#define TCPC_REG_MASKA_SOFTRESET (1<<1)
|
||||
#define TCPC_REG_MASKA_HARDRESET (1<<0)
|
||||
|
||||
#define TCPC_REG_MASKB 0x0F
|
||||
#define TCPC_REG_MASKB_GCRCSENT (1<<0)
|
||||
|
||||
#define TCPC_REG_STATUS0A 0x3C
|
||||
#define TCPC_REG_STATUS0A_SOFTFAIL (1<<5)
|
||||
#define TCPC_REG_STATUS0A_RETRYFAIL (1<<4)
|
||||
#define TCPC_REG_STATUS0A_POWER (1<<2) /* two-bit field */
|
||||
#define TCPC_REG_STATUS0A_RX_SOFT_RESET (1<<1)
|
||||
#define TCPC_REG_STATUS0A_RX_HARD_RESEt (1<<0)
|
||||
|
||||
#define TCPC_REG_STATUS1A 0x3D
|
||||
/* three-bit field, valid values below */
|
||||
#define TCPC_REG_STATUS1A_TOGSS (1<<3)
|
||||
#define TCPC_REG_STATUS1A_TOGSS_RUNNING 0x0
|
||||
#define TCPC_REG_STATUS1A_TOGSS_SRC1 0x1
|
||||
#define TCPC_REG_STATUS1A_TOGSS_SRC2 0x2
|
||||
#define TCPC_REG_STATUS1A_TOGSS_SNK1 0x5
|
||||
#define TCPC_REG_STATUS1A_TOGSS_SNK2 0x6
|
||||
#define TCPC_REG_STATUS1A_TOGSS_AA 0x7
|
||||
#define TCPC_REG_STATUS1A_TOGSS_POS (3)
|
||||
#define TCPC_REG_STATUS1A_TOGSS_MASK (0x7)
|
||||
|
||||
#define TCPC_REG_STATUS1A_RXSOP2DB (1<<2)
|
||||
#define TCPC_REG_STATUS1A_RXSOP1DB (1<<1)
|
||||
#define TCPC_REG_STATUS1A_RXSOP (1<<0)
|
||||
|
||||
#define TCPC_REG_INTERRUPTA 0x3E
|
||||
#define TCPC_REG_INTERRUPTA_OCP_TEMP (1<<7)
|
||||
#define TCPC_REG_INTERRUPTA_TOGDONE (1<<6)
|
||||
#define TCPC_REG_INTERRUPTA_SOFTFAIL (1<<5)
|
||||
#define TCPC_REG_INTERRUPTA_RETRYFAIL (1<<4)
|
||||
#define TCPC_REG_INTERRUPTA_HARDSENT (1<<3)
|
||||
#define TCPC_REG_INTERRUPTA_TX_SUCCESS (1<<2)
|
||||
#define TCPC_REG_INTERRUPTA_SOFTRESET (1<<1)
|
||||
#define TCPC_REG_INTERRUPTA_HARDRESET (1<<0)
|
||||
|
||||
#define TCPC_REG_INTERRUPTB 0x3F
|
||||
#define TCPC_REG_INTERRUPTB_GCRCSENT (1<<0)
|
||||
|
||||
#define TCPC_REG_STATUS0 0x40
|
||||
#define TCPC_REG_STATUS0_VBUSOK (1<<7)
|
||||
#define TCPC_REG_STATUS0_ACTIVITY (1<<6)
|
||||
#define TCPC_REG_STATUS0_COMP (1<<5)
|
||||
#define TCPC_REG_STATUS0_CRC_CHK (1<<4)
|
||||
#define TCPC_REG_STATUS0_ALERT (1<<3)
|
||||
#define TCPC_REG_STATUS0_WAKE (1<<2)
|
||||
#define TCPC_REG_STATUS0_BC_LVL1 (1<<1) /* two-bit field */
|
||||
#define TCPC_REG_STATUS0_BC_LVL0 (1<<0) /* two-bit field */
|
||||
|
||||
#define TCPC_REG_STATUS1 0x41
|
||||
#define TCPC_REG_STATUS1_RXSOP2 (1<<7)
|
||||
#define TCPC_REG_STATUS1_RXSOP1 (1<<6)
|
||||
#define TCPC_REG_STATUS1_RX_EMPTY (1<<5)
|
||||
#define TCPC_REG_STATUS1_RX_FULL (1<<4)
|
||||
#define TCPC_REG_STATUS1_TX_EMPTY (1<<3)
|
||||
#define TCPC_REG_STATUS1_TX_FULL (1<<2)
|
||||
|
||||
#define TCPC_REG_INTERRUPT 0x42
|
||||
#define TCPC_REG_INTERRUPT_VBUSOK (1<<7)
|
||||
#define TCPC_REG_INTERRUPT_ACTIVITY (1<<6)
|
||||
#define TCPC_REG_INTERRUPT_COMP_CHNG (1<<5)
|
||||
#define TCPC_REG_INTERRUPT_CRC_CHK (1<<4)
|
||||
#define TCPC_REG_INTERRUPT_ALERT (1<<3)
|
||||
#define TCPC_REG_INTERRUPT_WAKE (1<<2)
|
||||
#define TCPC_REG_INTERRUPT_COLLISION (1<<1)
|
||||
#define TCPC_REG_INTERRUPT_BC_LVL (1<<0)
|
||||
|
||||
#define TCPC_REG_FIFOS 0x43
|
||||
|
||||
/* Tokens defined for the FUSB302 TX FIFO */
|
||||
enum fusb302_txfifo_tokens {
|
||||
FUSB302_TKN_TXON = 0xA1,
|
||||
FUSB302_TKN_SYNC1 = 0x12,
|
||||
FUSB302_TKN_SYNC2 = 0x13,
|
||||
FUSB302_TKN_SYNC3 = 0x1B,
|
||||
FUSB302_TKN_RST1 = 0x15,
|
||||
FUSB302_TKN_RST2 = 0x16,
|
||||
FUSB302_TKN_PACKSYM = 0x80,
|
||||
FUSB302_TKN_JAMCRC = 0xFF,
|
||||
FUSB302_TKN_EOP = 0x14,
|
||||
FUSB302_TKN_TXOFF = 0xFE,
|
||||
};
|
||||
|
||||
|
||||
#endif /* __CROS_EC_DRIVER_TCPM_FUSB302_H */
|
||||
|
||||
@@ -1763,6 +1763,7 @@
|
||||
*/
|
||||
#undef CONFIG_USB_PD_TCPM_STUB
|
||||
#undef CONFIG_USB_PD_TCPM_TCPCI
|
||||
#undef CONFIG_USB_PD_TCPM_FUSB302
|
||||
|
||||
/*
|
||||
* Use this option if the TCPC port controller is on a seperate chip from
|
||||
|
||||
Reference in New Issue
Block a user