Import existing FUSB302 library
This commit is contained in:
952
workspace/TS100/Core/Drivers/FUSB302/FUSB302.c
Normal file
952
workspace/TS100/Core/Drivers/FUSB302/FUSB302.c
Normal file
@@ -0,0 +1,952 @@
|
||||
/*
|
||||
FUSB302.c - Library for interacting with the FUSB302B chip.
|
||||
Copyright 2015 The Chromium OS Authors
|
||||
Copyright 2017 Jason Cerundolo
|
||||
Released under an MIT license. See LICENSE file.
|
||||
*/
|
||||
|
||||
#include "FUSB302.h"
|
||||
#include "usb_pd_tcpm.h"
|
||||
#include "USBC_TCPM/tcpm.h"
|
||||
#include "USBC_PD/usb_pd.h"
|
||||
|
||||
#define PACKET_IS_GOOD_CRC(head) (PD_HEADER_TYPE(head) == PD_CTRL_GOOD_CRC && \
|
||||
PD_HEADER_CNT(head) == 0)
|
||||
|
||||
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;
|
||||
uint8_t mdac_vnc;
|
||||
uint8_t mdac_rd;
|
||||
} state[CONFIG_USB_PD_PORT_COUNT];
|
||||
|
||||
/*
|
||||
* Bring the FUSB302 out of reset after Hard Reset signaling. This will
|
||||
* automatically flush both the Rx and Tx FIFOs.
|
||||
*/
|
||||
static void fusb302_pd_reset(int port) {
|
||||
|
||||
tcpc_write(port, TCPC_REG_RESET, TCPC_REG_RESET_PD_RESET);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush our Rx FIFO. To prevent packet framing issues, this function should
|
||||
* only be called when Rx is disabled.
|
||||
*/
|
||||
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!
|
||||
*/
|
||||
i2c_master_lock(tcpc_config[port].i2c_host_port);
|
||||
tcpc_write(port, TCPC_REG_CONTROL1, TCPC_REG_CONTROL1_RX_FLUSH);
|
||||
|
||||
}
|
||||
|
||||
static void fusb302_flush_tx_fifo(int port) {
|
||||
int reg;
|
||||
|
||||
i2c_master_lock(tcpc_config[port].i2c_host_port);
|
||||
tcpc_read(port, TCPC_REG_CONTROL0, ®);
|
||||
reg |= TCPC_REG_CONTROL0_TX_FLUSH;
|
||||
tcpc_write(port, TCPC_REG_CONTROL0, reg);
|
||||
|
||||
}
|
||||
|
||||
static void fusb302_auto_goodcrc_enable(int port, int enable) {
|
||||
int reg;
|
||||
|
||||
i2c_master_lock(tcpc_config[port].i2c_host_port);
|
||||
tcpc_read(port, TCPC_REG_SWITCHES1, ®);
|
||||
|
||||
if (enable)
|
||||
reg |= TCPC_REG_SWITCHES1_AUTO_GCRC;
|
||||
else
|
||||
reg &= ~TCPC_REG_SWITCHES1_AUTO_GCRC;
|
||||
|
||||
tcpc_write(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;
|
||||
}
|
||||
|
||||
static int measure_cc_pin_source(int port, int cc_measure) {
|
||||
int switches0_reg;
|
||||
int reg;
|
||||
int cc_lvl;
|
||||
|
||||
i2c_master_lock(tcpc_config[port].i2c_host_port);
|
||||
|
||||
/* Read status register */
|
||||
tcpc_read(port, TCPC_REG_SWITCHES0, ®);
|
||||
/* Save current value */
|
||||
switches0_reg = reg;
|
||||
/* Clear pull-up register settings and measure bits */
|
||||
reg &= ~(TCPC_REG_SWITCHES0_MEAS_CC1 | TCPC_REG_SWITCHES0_MEAS_CC2);
|
||||
/* Set desired pullup register bit */
|
||||
if (cc_measure == TCPC_REG_SWITCHES0_MEAS_CC1)
|
||||
reg |= TCPC_REG_SWITCHES0_CC1_PU_EN;
|
||||
else
|
||||
reg |= TCPC_REG_SWITCHES0_CC2_PU_EN;
|
||||
/* Set CC measure bit */
|
||||
reg |= cc_measure;
|
||||
|
||||
/* Set measurement switch */
|
||||
tcpc_write(port, TCPC_REG_SWITCHES0, reg);
|
||||
|
||||
/* Set MDAC for Open vs Rd/Ra comparison */
|
||||
tcpc_write(port, TCPC_REG_MEASURE, state[port].mdac_vnc);
|
||||
|
||||
/* Wait on measurement */
|
||||
usleep(250);
|
||||
|
||||
/* Read status register */
|
||||
tcpc_read(port, TCPC_REG_STATUS0, ®);
|
||||
|
||||
/* Assume open */
|
||||
cc_lvl = TYPEC_CC_VOLT_OPEN;
|
||||
|
||||
/* CC level is below the 'no connect' threshold (vOpen) */
|
||||
if ((reg & TCPC_REG_STATUS0_COMP) == 0) {
|
||||
/* Set MDAC for Rd vs Ra comparison */
|
||||
tcpc_write(port, TCPC_REG_MEASURE, state[port].mdac_rd);
|
||||
|
||||
/* Wait on measurement */
|
||||
usleep(250);
|
||||
|
||||
/* Read status register */
|
||||
tcpc_read(port, TCPC_REG_STATUS0, ®);
|
||||
|
||||
cc_lvl =
|
||||
(reg & TCPC_REG_STATUS0_COMP) ?
|
||||
TYPEC_CC_VOLT_RD : TYPEC_CC_VOLT_RA;
|
||||
}
|
||||
|
||||
/* Restore SWITCHES0 register to its value prior */
|
||||
tcpc_write(port, TCPC_REG_SWITCHES0, switches0_reg);
|
||||
|
||||
return cc_lvl;
|
||||
}
|
||||
|
||||
/* Determine cc pin state for source when in manual detect mode */
|
||||
static void detect_cc_pin_source_manual(int port, int *cc1_lvl, int *cc2_lvl) {
|
||||
int cc1_measure = TCPC_REG_SWITCHES0_MEAS_CC1;
|
||||
int cc2_measure = TCPC_REG_SWITCHES0_MEAS_CC2;
|
||||
|
||||
if (state[port].vconn_enabled) {
|
||||
/* If VCONN enabled, measure cc_pin that matches polarity */
|
||||
if (state[port].cc_polarity)
|
||||
*cc2_lvl = measure_cc_pin_source(port, cc2_measure);
|
||||
else
|
||||
*cc1_lvl = measure_cc_pin_source(port, cc1_measure);
|
||||
} else {
|
||||
/* If VCONN not enabled, measure both cc1 and cc2 */
|
||||
*cc1_lvl = measure_cc_pin_source(port, cc1_measure);
|
||||
*cc2_lvl = measure_cc_pin_source(port, cc2_measure);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
i2c_master_lock(tcpc_config[port].i2c_host_port);
|
||||
|
||||
/*
|
||||
* Measure CC1 first.
|
||||
*/
|
||||
tcpc_read(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;
|
||||
|
||||
tcpc_write(port, TCPC_REG_SWITCHES0, reg);
|
||||
|
||||
/* CC1 is now being measured by FUSB302. */
|
||||
|
||||
/* Wait on measurement */
|
||||
usleep(250);
|
||||
|
||||
tcpc_read(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.
|
||||
*/
|
||||
|
||||
tcpc_read(port, TCPC_REG_SWITCHES0, ®);
|
||||
|
||||
/* Disable CC1 measurement switch, enable CC2 measurement switch */
|
||||
reg &= ~TCPC_REG_SWITCHES0_MEAS_CC1;
|
||||
reg |= TCPC_REG_SWITCHES0_MEAS_CC2;
|
||||
|
||||
tcpc_write(port, TCPC_REG_SWITCHES0, reg);
|
||||
|
||||
/* CC2 is now being measured by FUSB302. */
|
||||
|
||||
/* Wait on measurement */
|
||||
usleep(250);
|
||||
|
||||
tcpc_read(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 */
|
||||
tcpc_read(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;
|
||||
|
||||
tcpc_write(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_master_lock(tcpc_config[port].i2c_host_port);
|
||||
rv = tcpc_xfer(port, buf, buf_pos, 0, 0, I2C_XFER_SINGLE);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int fusb302_tcpm_select_rp_value(int port, int rp) {
|
||||
int reg;
|
||||
int rv;
|
||||
uint8_t vnc, rd;
|
||||
|
||||
i2c_master_lock(tcpc_config[port].i2c_host_port);
|
||||
|
||||
rv = tcpc_read(port, TCPC_REG_CONTROL0, ®);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
/* Set the current source for Rp value */
|
||||
reg &= ~TCPC_REG_CONTROL0_HOST_CUR_MASK;
|
||||
switch (rp) {
|
||||
case TYPEC_RP_1A5:
|
||||
reg |= TCPC_REG_CONTROL0_HOST_CUR_1A5;
|
||||
vnc = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_1_5_VNC_MV);
|
||||
rd = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_1_5_RD_THRESH_MV);
|
||||
break;
|
||||
case TYPEC_RP_3A0:
|
||||
reg |= TCPC_REG_CONTROL0_HOST_CUR_3A0;
|
||||
vnc = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_3_0_VNC_MV);
|
||||
rd = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_3_0_RD_THRESH_MV);
|
||||
break;
|
||||
case TYPEC_RP_USB:
|
||||
default:
|
||||
reg |= TCPC_REG_CONTROL0_HOST_CUR_USB;
|
||||
vnc = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_DEF_VNC_MV);
|
||||
rd = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_DEF_RD_THRESH_MV);
|
||||
}
|
||||
state[port].mdac_vnc = vnc;
|
||||
state[port].mdac_rd = rd;
|
||||
rv = tcpc_write(port, TCPC_REG_CONTROL0, reg);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int fusb302_tcpm_init(int port) {
|
||||
int reg;
|
||||
|
||||
/* set default */
|
||||
state[port].cc_polarity = -1;
|
||||
|
||||
/* set the voltage threshold for no connect detection (vOpen) */
|
||||
state[port].mdac_vnc = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_DEF_VNC_MV);
|
||||
/* set the voltage threshold for Rd vs Ra detection */
|
||||
state[port].mdac_rd = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_DEF_RD_THRESH_MV);
|
||||
|
||||
/* all other variables assumed to default to 0 */
|
||||
|
||||
i2c_master_lock(tcpc_config[port].i2c_host_port);
|
||||
|
||||
/* Restore default settings */
|
||||
tcpc_write(port, TCPC_REG_RESET, TCPC_REG_RESET_SW_RESET);
|
||||
|
||||
/* Turn on retries and set number of retries */
|
||||
tcpc_read(port, TCPC_REG_CONTROL3, ®);
|
||||
reg |= TCPC_REG_CONTROL3_AUTO_RETRY;
|
||||
reg |= (PD_RETRY_COUNT & 0x3) <<
|
||||
TCPC_REG_CONTROL3_N_RETRIES_POS;
|
||||
tcpc_write(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;
|
||||
/* packet received with correct CRC */
|
||||
reg &= ~TCPC_REG_MASK_CRC_CHK;
|
||||
tcpc_write(port, TCPC_REG_MASK, reg);
|
||||
|
||||
reg = 0xFF;
|
||||
/* 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;
|
||||
tcpc_write(port, TCPC_REG_MASKA, reg);
|
||||
|
||||
reg = 0xFF;
|
||||
/* when fusb302 sends GoodCRC to ack a pd message */
|
||||
reg &= ~TCPC_REG_MASKB_GCRCSENT;
|
||||
tcpc_write(port, TCPC_REG_MASKB, reg);
|
||||
|
||||
/* Interrupt Enable */
|
||||
tcpc_read(port, TCPC_REG_CONTROL0, ®);
|
||||
reg &= ~TCPC_REG_CONTROL0_INT_MASK;
|
||||
tcpc_write(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 */
|
||||
tcpc_write(port, TCPC_REG_POWER, TCPC_REG_POWER_PWR_ALL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fusb302_tcpm_release(int port) {
|
||||
return EC_ERROR_UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
static int fusb302_tcpm_get_cc(int port, int *cc1, int *cc2) {
|
||||
if (state[port].pulling_up) {
|
||||
/* Source mode? */
|
||||
detect_cc_pin_source_manual(port, cc1, cc2);
|
||||
} else {
|
||||
/* Sink mode? */
|
||||
detect_cc_pin_sink(port, cc1, cc2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fusb302_tcpm_set_cc(int port, int pull) {
|
||||
int reg;
|
||||
|
||||
i2c_master_lock(tcpc_config[port].i2c_host_port);
|
||||
|
||||
/* NOTE: FUSB302 toggles a single pull-up between CC1 and CC2 */
|
||||
/* NOTE: FUSB302 Does not support Ra. */
|
||||
switch (pull) {
|
||||
case TYPEC_CC_RP:
|
||||
/* enable the pull-up we know to be necessary */
|
||||
tcpc_read(port, TCPC_REG_SWITCHES0, ®);
|
||||
|
||||
reg &= ~(TCPC_REG_SWITCHES0_CC2_PU_EN |
|
||||
TCPC_REG_SWITCHES0_CC1_PU_EN |
|
||||
TCPC_REG_SWITCHES0_CC1_PD_EN |
|
||||
TCPC_REG_SWITCHES0_CC2_PD_EN |
|
||||
TCPC_REG_SWITCHES0_VCONN_CC1 |
|
||||
TCPC_REG_SWITCHES0_VCONN_CC2);
|
||||
|
||||
reg |= TCPC_REG_SWITCHES0_CC1_PU_EN |
|
||||
TCPC_REG_SWITCHES0_CC2_PU_EN;
|
||||
|
||||
if (state[port].vconn_enabled)
|
||||
reg |= state[port].cc_polarity ?
|
||||
TCPC_REG_SWITCHES0_VCONN_CC1 :
|
||||
TCPC_REG_SWITCHES0_VCONN_CC2;
|
||||
|
||||
tcpc_write(port, TCPC_REG_SWITCHES0, reg);
|
||||
|
||||
state[port].pulling_up = 1;
|
||||
break;
|
||||
case TYPEC_CC_RD:
|
||||
/* Enable UFP Mode */
|
||||
|
||||
/* turn off toggle */
|
||||
tcpc_read(port, TCPC_REG_CONTROL2, ®);
|
||||
reg &= ~TCPC_REG_CONTROL2_TOGGLE;
|
||||
tcpc_write(port, TCPC_REG_CONTROL2, reg);
|
||||
|
||||
/* enable pull-downs, disable pullups */
|
||||
tcpc_read(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);
|
||||
tcpc_write(port, TCPC_REG_SWITCHES0, reg);
|
||||
|
||||
state[port].pulling_up = 0;
|
||||
break;
|
||||
case TYPEC_CC_OPEN:
|
||||
/* Disable toggling */
|
||||
tcpc_read(port, TCPC_REG_CONTROL2, ®);
|
||||
reg &= ~TCPC_REG_CONTROL2_TOGGLE;
|
||||
tcpc_write(port, TCPC_REG_CONTROL2, reg);
|
||||
|
||||
/* Ensure manual switches are opened */
|
||||
tcpc_read(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;
|
||||
tcpc_write(port, TCPC_REG_SWITCHES0, reg);
|
||||
|
||||
state[port].pulling_up = 0;
|
||||
break;
|
||||
default:
|
||||
/* Unsupported... */
|
||||
return EC_ERROR_UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fusb302_tcpm_set_polarity(int port, int polarity) {
|
||||
/* Port polarity : 0 => CC1 is CC line, 1 => CC2 is CC line */
|
||||
int reg;
|
||||
|
||||
i2c_master_lock(tcpc_config[port].i2c_host_port);
|
||||
|
||||
tcpc_read(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;
|
||||
|
||||
tcpc_write(port, TCPC_REG_SWITCHES0, reg);
|
||||
|
||||
tcpc_read(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;
|
||||
|
||||
tcpc_write(port, TCPC_REG_SWITCHES1, reg);
|
||||
|
||||
/* Save the polarity for later */
|
||||
state[port].cc_polarity = polarity;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fusb302_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;
|
||||
|
||||
/* save enable state for later use */
|
||||
state[port].vconn_enabled = enable;
|
||||
|
||||
if (enable) {
|
||||
/* set to saved polarity */
|
||||
tcpm_set_polarity(port, state[port].cc_polarity);
|
||||
} else {
|
||||
|
||||
i2c_master_lock(tcpc_config[port].i2c_host_port);
|
||||
|
||||
tcpc_read(port, TCPC_REG_SWITCHES0, ®);
|
||||
|
||||
/* clear VCONN switch bits */
|
||||
reg &= ~TCPC_REG_SWITCHES0_VCONN_CC1;
|
||||
reg &= ~TCPC_REG_SWITCHES0_VCONN_CC2;
|
||||
|
||||
tcpc_write(port, TCPC_REG_SWITCHES0, reg);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fusb302_tcpm_set_msg_header(int port, int power_role, int data_role) {
|
||||
int reg;
|
||||
|
||||
tcpc_read(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;
|
||||
|
||||
tcpc_write(port, TCPC_REG_SWITCHES1, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fusb302_tcpm_set_rx_enable(int port, int enable) {
|
||||
int reg;
|
||||
|
||||
state[port].rx_enable = enable;
|
||||
|
||||
i2c_master_lock(tcpc_config[port].i2c_host_port);
|
||||
|
||||
/* Get current switch state */
|
||||
tcpc_read(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;
|
||||
}
|
||||
tcpc_write(port, TCPC_REG_SWITCHES0, reg);
|
||||
|
||||
/* Disable BC_LVL interrupt when enabling PD comm */
|
||||
if (!tcpc_read(port, TCPC_REG_MASK, ®))
|
||||
tcpc_write(port, TCPC_REG_MASK, reg | TCPC_REG_MASK_BC_LVL);
|
||||
|
||||
/* flush rx fifo in case messages have been coming our way */
|
||||
fusb302_flush_rx_fifo(port);
|
||||
|
||||
} else {
|
||||
tcpc_write(port, TCPC_REG_SWITCHES0, reg);
|
||||
|
||||
/* Enable BC_LVL interrupt when disabling PD comm */
|
||||
if (!tcpc_read(port, TCPC_REG_MASK, ®))
|
||||
tcpc_write(port, TCPC_REG_MASK, reg & ~TCPC_REG_MASK_BC_LVL);
|
||||
}
|
||||
|
||||
fusb302_auto_goodcrc_enable(port, enable);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return true if our Rx FIFO is empty */
|
||||
static int fusb302_rx_fifo_is_empty(int port) {
|
||||
int reg, ret;
|
||||
|
||||
i2c_master_lock(tcpc_config[port].i2c_host_port);
|
||||
|
||||
ret = (!tcpc_read(port, TCPC_REG_STATUS1, ®))
|
||||
&& (reg & TCPC_REG_STATUS1_RX_EMPTY);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fusb302_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, len;
|
||||
|
||||
/* If our FIFO is empty then we have no packet */
|
||||
if (fusb302_rx_fifo_is_empty(port))
|
||||
return EC_ERROR_UNKNOWN;
|
||||
|
||||
/* Read until we have a non-GoodCRC packet or an empty FIFO */
|
||||
do {
|
||||
buf[0] = TCPC_REG_FIFOS;
|
||||
i2c_master_lock(tcpc_config[port].i2c_host_port);
|
||||
|
||||
/*
|
||||
* PART 1 OF BURST READ: Write in register address.
|
||||
* Issue a START, no STOP.
|
||||
*/
|
||||
rv = tcpc_xfer(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.
|
||||
* TODO: Check token to ensure valid packet.
|
||||
*/
|
||||
rv |= tcpc_xfer(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 |= tcpc_xfer(port, 0, 0, buf, len + 4, I2C_XFER_STOP);
|
||||
|
||||
} while (!rv && PACKET_IS_GOOD_CRC(*head) && !fusb302_rx_fifo_is_empty(port));
|
||||
|
||||
if (!rv) {
|
||||
/* Discard GoodCRC packets */
|
||||
if (PACKET_IS_GOOD_CRC(*head))
|
||||
rv = EC_ERROR_UNKNOWN;
|
||||
else
|
||||
memcpy(payload, buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* If our FIFO is non-empty then we may have a packet, we may get
|
||||
* fewer interrupts than packets due to interrupt latency.
|
||||
*/
|
||||
//if (!fusb302_rx_fifo_is_empty(port))
|
||||
// task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_RX, 0);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int fusb302_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 tcpc 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;
|
||||
|
||||
fusb302_send_message(port, header, data, buf, buf_pos);
|
||||
// wait for the GoodCRC to come back before we let the rest
|
||||
// of the code do stuff like change polarity and miss it
|
||||
delay_us(600);
|
||||
return;
|
||||
case TCPC_TX_HARD_RESET:
|
||||
i2c_master_lock(tcpc_config[port].i2c_host_port);
|
||||
/* Simply hit the SEND_HARD_RESET bit */
|
||||
tcpc_read(port, TCPC_REG_CONTROL3, ®);
|
||||
reg |= TCPC_REG_CONTROL3_SEND_HARDRESET;
|
||||
tcpc_write(port, TCPC_REG_CONTROL3, reg);
|
||||
|
||||
break;
|
||||
case TCPC_TX_BIST_MODE_2:
|
||||
i2c_master_lock(tcpc_config[port].i2c_host_port);
|
||||
/* Hit the BIST_MODE2 bit and start TX */
|
||||
tcpc_read(port, TCPC_REG_CONTROL1, ®);
|
||||
reg |= TCPC_REG_CONTROL1_BIST_MODE2;
|
||||
tcpc_write(port, TCPC_REG_CONTROL1, reg);
|
||||
|
||||
tcpc_read(port, TCPC_REG_CONTROL0, ®);
|
||||
reg |= TCPC_REG_CONTROL0_TX_START;
|
||||
tcpc_write(port, TCPC_REG_CONTROL0, reg);
|
||||
|
||||
//task_wait_event(PD_T_BIST_TRANSMIT);
|
||||
|
||||
/* Clear BIST mode bit, TX_START is self-clearing */
|
||||
tcpc_read(port, TCPC_REG_CONTROL1, ®);
|
||||
reg &= ~TCPC_REG_CONTROL1_BIST_MODE2;
|
||||
tcpc_write(port, TCPC_REG_CONTROL1, reg);
|
||||
|
||||
break;
|
||||
default:
|
||||
return EC_ERROR_UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC
|
||||
static int fusb302_tcpm_get_vbus_level(int port)
|
||||
{
|
||||
int reg;
|
||||
|
||||
/* Read status register */
|
||||
i2c_master_lock(tcpc_config[port].i2c_host_port);
|
||||
tcpc_read(port, TCPC_REG_STATUS0, ®);
|
||||
|
||||
|
||||
return (reg & TCPC_REG_STATUS0_VBUSOK) ? 1 : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void fusb302_tcpc_alert(int port) {
|
||||
/* interrupt has been received */
|
||||
int interrupt;
|
||||
int interrupta;
|
||||
int interruptb;
|
||||
|
||||
/* reading interrupt registers clears them */
|
||||
|
||||
i2c_master_lock(tcpc_config[port].i2c_host_port);
|
||||
tcpc_read(port, TCPC_REG_INTERRUPT, &interrupt);
|
||||
tcpc_read(port, TCPC_REG_INTERRUPTA, &interrupta);
|
||||
tcpc_read(port, TCPC_REG_INTERRUPTB, &interruptb);
|
||||
|
||||
/*
|
||||
* Ignore BC_LVL changes when transmitting / receiving PD,
|
||||
* since CC level will constantly change.
|
||||
*/
|
||||
if (state[port].rx_enable)
|
||||
interrupt &= ~TCPC_REG_INTERRUPT_BC_LVL;
|
||||
|
||||
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 */
|
||||
pd_transmit_complete(port, TCPC_TX_COMPLETE_FAILED);
|
||||
}
|
||||
|
||||
/* GoodCRC was received, our FIFO is now non-empty */
|
||||
if (interrupta & TCPC_REG_INTERRUPTA_TX_SUCCESS) {
|
||||
//task_set_event(PD_PORT_TO_TASK_ID(port),
|
||||
// PD_EVENT_RX, 0);
|
||||
|
||||
pd_transmit_complete(port, TCPC_TX_COMPLETE_SUCCESS);
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* For BIST receiving */
|
||||
void tcpm_set_bist_test_data(int port) {
|
||||
int reg;
|
||||
|
||||
i2c_master_lock(tcpc_config[port].i2c_host_port);
|
||||
|
||||
/* Read control3 register */
|
||||
tcpc_read(port, TCPC_REG_CONTROL3, ®);
|
||||
|
||||
/* Set the BIST_TMODE bit (Clears on Hard Reset) */
|
||||
reg |= TCPC_REG_CONTROL3_BIST_TMODE;
|
||||
|
||||
/* Write the updated value */
|
||||
tcpc_write(port, TCPC_REG_CONTROL3, reg);
|
||||
|
||||
}
|
||||
|
||||
const struct tcpm_drv fusb302_tcpm_drv = { .init = &fusb302_tcpm_init,
|
||||
.release = &fusb302_tcpm_release, .get_cc = &fusb302_tcpm_get_cc,
|
||||
#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC
|
||||
.get_vbus_level = &fusb302_tcpm_get_vbus_level,
|
||||
#endif
|
||||
.select_rp_value = &fusb302_tcpm_select_rp_value, .set_cc =
|
||||
&fusb302_tcpm_set_cc,
|
||||
.set_polarity = &fusb302_tcpm_set_polarity, .set_vconn =
|
||||
&fusb302_tcpm_set_vconn, .set_msg_header =
|
||||
&fusb302_tcpm_set_msg_header, .set_rx_enable =
|
||||
&fusb302_tcpm_set_rx_enable, .get_message =
|
||||
&fusb302_tcpm_get_message, .transmit = &fusb302_tcpm_transmit,
|
||||
.tcpc_alert = &fusb302_tcpc_alert, };
|
||||
250
workspace/TS100/Core/Drivers/FUSB302/FUSB302.h
Normal file
250
workspace/TS100/Core/Drivers/FUSB302/FUSB302.h
Normal file
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
FUSB302.h - Library for interacting with the FUSB302B chip.
|
||||
Copyright 2010 The Chromium OS Authors
|
||||
Copyright 2017 Jason Cerundolo
|
||||
Released under an MIT license. See LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef fusb302_H
|
||||
#define fusb302_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "usb_pd_tcpm.h"
|
||||
#include "USBC_PD/usb_pd.h"
|
||||
|
||||
/* Chip Device ID - 302A or 302B */
|
||||
#define fusb302_DEVID_302A 0x08
|
||||
#define fusb302_DEVID_302B 0x09
|
||||
|
||||
/* I2C slave address varies by part number */
|
||||
/* FUSB302BUCX / FUSB302BMPX */
|
||||
#define fusb302_I2C_SLAVE_ADDR 0x22 // 7-bit address for Arduino
|
||||
/* FUSB302B01MPX */
|
||||
#define fusb302_I2C_SLAVE_ADDR_B01 0x23
|
||||
/* FUSB302B10MPX */
|
||||
#define fusb302_I2C_SLAVE_ADDR_B10 0x24
|
||||
/* FUSB302B11MPX */
|
||||
#define fusb302_I2C_SLAVE_ADDR_B11 0x25
|
||||
|
||||
/* Default retry count for transmitting */
|
||||
#define PD_RETRY_COUNT 3
|
||||
|
||||
/* Time to wait for TCPC to complete transmit */
|
||||
#define PD_T_TCPC_TX_TIMEOUT (100*MSEC)
|
||||
|
||||
#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_VBUS (1<<6)
|
||||
#define TCPC_REG_MEASURE_MDAC_MV(mv) (((mv)/42) & 0x3f)
|
||||
|
||||
#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_HOST_CUR_MASK (3<<2)
|
||||
#define TCPC_REG_CONTROL0_HOST_CUR_3A0 (3<<2)
|
||||
#define TCPC_REG_CONTROL0_HOST_CUR_1A5 (2<<2)
|
||||
#define TCPC_REG_CONTROL0_HOST_CUR_USB (1<<2)
|
||||
#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_BIST_TMODE (1<<5) /* 302B Only */
|
||||
#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,
|
||||
};
|
||||
|
||||
extern const struct tcpm_drv fusb302_tcpm_drv;
|
||||
|
||||
/*
|
||||
// Common methods for TCPM implementations
|
||||
int fusb302_init(void);
|
||||
int fusb302_get_cc(int *cc1, int *cc2);
|
||||
int fusb302_get_vbus_level(void);
|
||||
int fusb302_select_rp_value(int rp);
|
||||
int fusb302_set_cc(int pull);
|
||||
int fusb302_set_polarity(int polarity);
|
||||
int fusb302_set_vconn(int enable);
|
||||
int fusb302_set_msg_header(int power_role, int data_role);
|
||||
int fusb302_set_rx_enable(int enable);
|
||||
int fusb302_get_message(uint32_t *payload, int *head);
|
||||
int fusb302_transmit(enum tcpm_transmit_type type,
|
||||
uint16_t header, const uint32_t *data);
|
||||
//int alert(void);
|
||||
void fusb302_pd_reset(int port);
|
||||
void fusb302_auto_goodcrc_enable(int enable);
|
||||
int fusb302_convert_bc_lvl(int bc_lvl);
|
||||
void fusb302_detect_cc_pin_source_manual(int *cc1_lvl, int *cc2_lvl);
|
||||
int fusb302_measure_cc_pin_source(int cc_measure);
|
||||
void fusb302_detect_cc_pin_sink(int *cc1, int *cc2);
|
||||
int fusb302_send_message(uint16_t header, const uint32_t *data,
|
||||
uint8_t *buf, int buf_pos);
|
||||
void fusb302_flush_rx_fifo(int port);
|
||||
void fusb302_flush_tx_fifo(int port);
|
||||
void fusb302_clear_int_pin(void);
|
||||
void fusb302_set_bist_test_data(void);
|
||||
int fusb302_get_chip_id(int *id);
|
||||
uint32_t fusb302_get_interrupt_reason(void);
|
||||
int fusb302_tcpc_write(int reg, int val);
|
||||
int fusb302_tcpc_read(int reg, int *val);
|
||||
int fusb302_tcpc_xfer(const uint8_t *out,
|
||||
int out_size, uint8_t *in,
|
||||
int in_size, int flags);
|
||||
*/
|
||||
|
||||
#endif /* fusb302_H */
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* FUSB302.hpp
|
||||
*
|
||||
* Created on: 11-06-2020
|
||||
* Author: Ralim
|
||||
*/
|
||||
|
||||
#ifndef FUSB302_H_
|
||||
#define FUSB302_H_
|
||||
#include "BSP.h"
|
||||
#include "FUSB302_includes.h"
|
||||
#include "I2C_Wrapper.hpp"
|
||||
//While the ST4500 is nice, the FUSB302 is _cheap_ so its what is used in the TS80P for example
|
||||
|
||||
class FUSB302 {
|
||||
public:
|
||||
//Returns true if the FUSB302 is detected on the I2C bus
|
||||
bool detect();
|
||||
|
||||
private:
|
||||
// Bring up out of reset and clear fifo's
|
||||
void fusb302_reset();
|
||||
void flush_rx_fifo();
|
||||
void flush_tx_fifo();
|
||||
void enable_auto_good_crc();
|
||||
int set_rp_value(int rp);
|
||||
int set_cc(int pull);
|
||||
struct fusb302_chip_state {
|
||||
int cc_polarity;
|
||||
int vconn_enabled;
|
||||
/* 1 = pulling up (DFP) 0 = pulling down (UFP) */
|
||||
int pulling_up;
|
||||
int rx_enable;
|
||||
uint8_t mdac_vnc;
|
||||
uint8_t mdac_rd;
|
||||
};
|
||||
fusb302_chip_state state;
|
||||
};
|
||||
|
||||
#endif /* LIS2DH12_HPP_ */
|
||||
@@ -1,204 +0,0 @@
|
||||
#ifndef FUSB302_INCLUDES_H_
|
||||
#define FUSB302_INCLUDES_H_
|
||||
|
||||
/* Whole bunch of includes to make working with the FUSB302 easier*/
|
||||
|
||||
/* Chip Device ID - 302A or 302B */
|
||||
#define fusb302_DEVID_302A 0x08
|
||||
#define fusb302_DEVID_302B 0x09
|
||||
|
||||
/* I2C slave address varies by part number */
|
||||
/* FUSB302BUCX / FUSB302BMPX */
|
||||
#define fusb302_I2C_SLAVE_ADDR 0x22 // 7-bit address for Arduino
|
||||
/* FUSB302B01MPX */
|
||||
#define fusb302_I2C_SLAVE_ADDR_B01 0x23
|
||||
/* FUSB302B10MPX */
|
||||
#define fusb302_I2C_SLAVE_ADDR_B10 0x24
|
||||
/* FUSB302B11MPX */
|
||||
#define fusb302_I2C_SLAVE_ADDR_B11 0x25
|
||||
|
||||
/* Default retry count for transmitting */
|
||||
#define PD_RETRY_COUNT 3
|
||||
|
||||
/* Time to wait for TCPC to complete transmit */
|
||||
#define PD_T_TCPC_TX_TIMEOUT (100 * MSEC)
|
||||
|
||||
#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_VBUS (1 << 6)
|
||||
#define TCPC_REG_MEASURE_MDAC_MV(mv) (((mv) / 42) & 0x3f)
|
||||
|
||||
#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_HOST_CUR_MASK (3 << 2)
|
||||
#define TCPC_REG_CONTROL0_HOST_CUR_3A0 (3 << 2)
|
||||
#define TCPC_REG_CONTROL0_HOST_CUR_1A5 (2 << 2)
|
||||
#define TCPC_REG_CONTROL0_HOST_CUR_USB (1 << 2)
|
||||
#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_BIST_TMODE (1 << 5) /* 302B Only */
|
||||
#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,
|
||||
};
|
||||
|
||||
#define PACKET_IS_GOOD_CRC(head) (PD_HEADER_TYPE(head) == PD_CTRL_GOOD_CRC && \
|
||||
PD_HEADER_CNT(head) == 0)
|
||||
#endif
|
||||
1799
workspace/TS100/Core/Drivers/FUSB302/USBC_PD/usb_pd.h
Normal file
1799
workspace/TS100/Core/Drivers/FUSB302/USBC_PD/usb_pd.h
Normal file
File diff suppressed because it is too large
Load Diff
1019
workspace/TS100/Core/Drivers/FUSB302/USBC_PD/usb_pd_policy.c
Normal file
1019
workspace/TS100/Core/Drivers/FUSB302/USBC_PD/usb_pd_policy.c
Normal file
File diff suppressed because it is too large
Load Diff
4276
workspace/TS100/Core/Drivers/FUSB302/USBC_PD/usb_pd_protocol.c
Normal file
4276
workspace/TS100/Core/Drivers/FUSB302/USBC_PD/usb_pd_protocol.c
Normal file
File diff suppressed because it is too large
Load Diff
276
workspace/TS100/Core/Drivers/FUSB302/USBC_TCPM/tcpm.h
Normal file
276
workspace/TS100/Core/Drivers/FUSB302/USBC_TCPM/tcpm.h
Normal file
@@ -0,0 +1,276 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
/* USB Power delivery port management - common header for TCPM drivers */
|
||||
|
||||
#ifndef __CROS_EC_USB_PD_TCPM_TCPM_H
|
||||
#define __CROS_EC_USB_PD_TCPM_TCPM_H
|
||||
|
||||
#include "tcpm_driver.h"
|
||||
#include "usb_pd_tcpm.h"
|
||||
|
||||
#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) && \
|
||||
!defined(CONFIG_USB_PD_DUAL_ROLE)
|
||||
#error "DRP auto toggle requires board to have DRP support"
|
||||
#error "Please upgrade your board configuration"
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USB_PD_TCPC
|
||||
extern const struct tcpc_config_t tcpc_config[];
|
||||
|
||||
/* I2C wrapper functions - get I2C port / slave addr from config struct. */
|
||||
int tcpc_write(int port, int reg, int val);
|
||||
int tcpc_write16(int port, int reg, int val);
|
||||
int tcpc_read(int port, int reg, int *val);
|
||||
int tcpc_read16(int port, int reg, int *val);
|
||||
int tcpc_xfer(int port,
|
||||
const uint8_t *out, int out_size,
|
||||
uint8_t *in, int in_size,
|
||||
int flags);
|
||||
|
||||
/* TCPM driver wrapper function */
|
||||
static inline int tcpm_init(int port)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = tcpc_config[port].drv->init(port);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
/* Board specific post TCPC init */
|
||||
if (board_tcpc_post_init)
|
||||
rv = board_tcpc_post_init(port);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static inline int tcpm_release(int port)
|
||||
{
|
||||
return tcpc_config[port].drv->release(port);
|
||||
}
|
||||
|
||||
static inline int tcpm_get_cc(int port, int *cc1, int *cc2)
|
||||
{
|
||||
return tcpc_config[port].drv->get_cc(port, cc1, cc2);
|
||||
}
|
||||
|
||||
static inline int tcpm_get_vbus_level(int port)
|
||||
{
|
||||
return tcpc_config[port].drv->get_vbus_level(port);
|
||||
}
|
||||
|
||||
static inline int tcpm_select_rp_value(int port, int rp)
|
||||
{
|
||||
return tcpc_config[port].drv->select_rp_value(port, rp);
|
||||
}
|
||||
|
||||
static inline int tcpm_set_cc(int port, int pull)
|
||||
{
|
||||
return tcpc_config[port].drv->set_cc(port, pull);
|
||||
}
|
||||
|
||||
static inline int tcpm_set_polarity(int port, int polarity)
|
||||
{
|
||||
return tcpc_config[port].drv->set_polarity(port, polarity);
|
||||
}
|
||||
|
||||
static inline int tcpm_set_vconn(int port, int enable)
|
||||
{
|
||||
return tcpc_config[port].drv->set_vconn(port, enable);
|
||||
}
|
||||
|
||||
static inline int tcpm_set_msg_header(int port, int power_role, int data_role)
|
||||
{
|
||||
return tcpc_config[port].drv->set_msg_header(port, power_role,
|
||||
data_role);
|
||||
}
|
||||
|
||||
static inline int tcpm_set_rx_enable(int port, int enable)
|
||||
{
|
||||
return tcpc_config[port].drv->set_rx_enable(port, enable);
|
||||
}
|
||||
|
||||
static inline int tcpm_get_message(int port, uint32_t *payload, int *head)
|
||||
{
|
||||
return tcpc_config[port].drv->get_message(port, payload, head);
|
||||
}
|
||||
|
||||
static inline int tcpm_transmit(int port, enum tcpm_transmit_type type,
|
||||
uint16_t header, const uint32_t *data)
|
||||
{
|
||||
return tcpc_config[port].drv->transmit(port, type, header, data);
|
||||
}
|
||||
|
||||
static inline void tcpc_alert(int port)
|
||||
{
|
||||
tcpc_config[port].drv->tcpc_alert(port);
|
||||
}
|
||||
|
||||
static inline void tcpc_discharge_vbus(int port, int enable)
|
||||
{
|
||||
tcpc_config[port].drv->tcpc_discharge_vbus(port, enable);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
|
||||
static inline int tcpm_auto_toggle_supported(int port)
|
||||
{
|
||||
return !!tcpc_config[port].drv->drp_toggle;
|
||||
}
|
||||
|
||||
static inline int tcpm_set_drp_toggle(int port, int enable)
|
||||
{
|
||||
return tcpc_config[port].drv->drp_toggle(port, enable);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CMD_I2C_STRESS_TEST_TCPC
|
||||
static inline int tcpc_i2c_read(const int port, const int addr,
|
||||
const int reg, int *data)
|
||||
{
|
||||
return tcpc_read(port, reg, data);
|
||||
}
|
||||
|
||||
static inline int tcpc_i2c_write(const int port, const int addr,
|
||||
const int reg, int data)
|
||||
{
|
||||
return tcpc_write(port, reg, data);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int tcpm_get_chip_info(int port, int renew,
|
||||
struct ec_response_pd_chip_info **info)
|
||||
{
|
||||
if (tcpc_config[port].drv->get_chip_info)
|
||||
return tcpc_config[port].drv->get_chip_info(port, renew, info);
|
||||
return EC_ERROR_UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/**
|
||||
* Initialize TCPM driver and wait for TCPC readiness.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int tcpm_init(int port);
|
||||
|
||||
/**
|
||||
* Read the CC line status.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param cc1 pointer to CC status for CC1
|
||||
* @param cc2 pointer to CC status for CC2
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int tcpm_get_cc(int port, int *cc1, int *cc2);
|
||||
|
||||
/**
|
||||
* Read VBUS
|
||||
*
|
||||
* @param port Type-C port number
|
||||
*
|
||||
* @return 0 => VBUS not detected, 1 => VBUS detected
|
||||
*/
|
||||
int tcpm_get_vbus_level(int port);
|
||||
|
||||
/**
|
||||
* Set the value of the CC pull-up used when we are a source.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param rp One of enum tcpc_rp_value
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int tcpm_select_rp_value(int port, int rp);
|
||||
|
||||
/**
|
||||
* Set the CC pull resistor. This sets our role as either source or sink.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param pull One of enum tcpc_cc_pull
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int tcpm_set_cc(int port, int pull);
|
||||
|
||||
/**
|
||||
* Set polarity
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param polarity 0=> transmit on CC1, 1=> transmit on CC2
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int tcpm_set_polarity(int port, int polarity);
|
||||
|
||||
/**
|
||||
* Set Vconn.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param polarity Polarity of the CC line to read
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int tcpm_set_vconn(int port, int enable);
|
||||
|
||||
/**
|
||||
* Set PD message header to use for goodCRC
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param power_role Power role to use in header
|
||||
* @param data_role Data role to use in header
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int tcpm_set_msg_header(int port, int power_role, int data_role);
|
||||
|
||||
/**
|
||||
* Set RX enable flag
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @enable true for enable, false for disable
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int tcpm_set_rx_enable(int port, int enable);
|
||||
|
||||
/**
|
||||
* Read last received PD message.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param payload Pointer to location to copy payload of message
|
||||
* @param header of message
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int tcpm_get_message(int port, uint32_t *payload, int *head);
|
||||
|
||||
/**
|
||||
* Transmit PD message
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param type Transmit type
|
||||
* @param header Packet header
|
||||
* @param cnt Number of bytes in payload
|
||||
* @param data Payload
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int tcpm_transmit(int port, enum tcpm_transmit_type type, uint16_t header,
|
||||
const uint32_t *data);
|
||||
|
||||
/**
|
||||
* TCPC is asserting alert
|
||||
*
|
||||
* @param port Type-C port number
|
||||
*/
|
||||
void tcpc_alert(int port);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
354
workspace/TS100/Core/Drivers/FUSB302/USBC_TCPM/usb_pd_tcpm.h
Normal file
354
workspace/TS100/Core/Drivers/FUSB302/USBC_TCPM/usb_pd_tcpm.h
Normal file
@@ -0,0 +1,354 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
/* USB Power delivery port management */
|
||||
|
||||
#ifndef __CROS_EC_USB_PD_TCPM_H
|
||||
#define __CROS_EC_USB_PD_TCPM_H
|
||||
|
||||
/* List of common error codes that can be returned */
|
||||
enum ec_error_list {
|
||||
/* Success - no error */
|
||||
EC_SUCCESS = 0,
|
||||
/* Unknown error */
|
||||
EC_ERROR_UNKNOWN = 1,
|
||||
/* Function not implemented yet */
|
||||
EC_ERROR_UNIMPLEMENTED = 2,
|
||||
/* Overflow error; too much input provided. */
|
||||
EC_ERROR_OVERFLOW = 3,
|
||||
/* Timeout */
|
||||
EC_ERROR_TIMEOUT = 4,
|
||||
/* Invalid argument */
|
||||
EC_ERROR_INVAL = 5,
|
||||
/* Already in use, or not ready yet */
|
||||
EC_ERROR_BUSY = 6,
|
||||
/* Access denied */
|
||||
EC_ERROR_ACCESS_DENIED = 7,
|
||||
/* Failed because component does not have power */
|
||||
EC_ERROR_NOT_POWERED = 8,
|
||||
/* Failed because component is not calibrated */
|
||||
EC_ERROR_NOT_CALIBRATED = 9,
|
||||
/* Failed because CRC error */
|
||||
EC_ERROR_CRC = 10,
|
||||
/* Invalid console command param (PARAMn means parameter n is bad) */
|
||||
EC_ERROR_PARAM1 = 11,
|
||||
EC_ERROR_PARAM2 = 12,
|
||||
EC_ERROR_PARAM3 = 13,
|
||||
EC_ERROR_PARAM4 = 14,
|
||||
EC_ERROR_PARAM5 = 15,
|
||||
EC_ERROR_PARAM6 = 16,
|
||||
EC_ERROR_PARAM7 = 17,
|
||||
EC_ERROR_PARAM8 = 18,
|
||||
EC_ERROR_PARAM9 = 19,
|
||||
/* Wrong number of params */
|
||||
EC_ERROR_PARAM_COUNT = 20,
|
||||
/* Interrupt event not handled */
|
||||
EC_ERROR_NOT_HANDLED = 21,
|
||||
/* Data has not changed */
|
||||
EC_ERROR_UNCHANGED = 22,
|
||||
/* Memory allocation */
|
||||
EC_ERROR_MEMORY_ALLOCATION = 23,
|
||||
|
||||
/* Verified boot errors */
|
||||
EC_ERROR_VBOOT_SIGNATURE = 0x1000, /* 4096 */
|
||||
EC_ERROR_VBOOT_SIG_MAGIC = 0x1001,
|
||||
EC_ERROR_VBOOT_SIG_SIZE = 0x1002,
|
||||
EC_ERROR_VBOOT_SIG_ALGORITHM = 0x1003,
|
||||
EC_ERROR_VBOOT_HASH_ALGORITHM = 0x1004,
|
||||
EC_ERROR_VBOOT_SIG_OFFSET = 0x1005,
|
||||
EC_ERROR_VBOOT_DATA_SIZE = 0x1006,
|
||||
|
||||
/* Verified boot key errors */
|
||||
EC_ERROR_VBOOT_KEY = 0x1100,
|
||||
EC_ERROR_VBOOT_KEY_MAGIC = 0x1101,
|
||||
EC_ERROR_VBOOT_KEY_SIZE = 0x1102,
|
||||
|
||||
/* Verified boot data errors */
|
||||
EC_ERROR_VBOOT_DATA = 0x1200,
|
||||
EC_ERROR_VBOOT_DATA_VERIFY = 0x1201,
|
||||
|
||||
/* Module-internal error codes may use this range. */
|
||||
EC_ERROR_INTERNAL_FIRST = 0x10000,
|
||||
EC_ERROR_INTERNAL_LAST = 0x1FFFF
|
||||
};
|
||||
|
||||
/* Flags for i2c_xfer() */
|
||||
#define I2C_XFER_START (1 << 0) /* Start smbus session from idle state */
|
||||
#define I2C_XFER_STOP (1 << 1) /* Terminate smbus session with stop bit */
|
||||
#define I2C_XFER_SINGLE (I2C_XFER_START | I2C_XFER_STOP) /* One transaction */
|
||||
|
||||
/* Default retry count for transmitting */
|
||||
#define PD_RETRY_COUNT 3
|
||||
|
||||
/* Time to wait for TCPC to complete transmit */
|
||||
#define PD_T_TCPC_TX_TIMEOUT (100*MSEC)
|
||||
|
||||
enum tcpc_cc_voltage_status {
|
||||
TYPEC_CC_VOLT_OPEN = 0,
|
||||
TYPEC_CC_VOLT_RA = 1,
|
||||
TYPEC_CC_VOLT_RD = 2,
|
||||
TYPEC_CC_VOLT_SNK_DEF = 5,
|
||||
TYPEC_CC_VOLT_SNK_1_5 = 6,
|
||||
TYPEC_CC_VOLT_SNK_3_0 = 7,
|
||||
};
|
||||
|
||||
enum tcpc_cc_pull {
|
||||
TYPEC_CC_RA = 0,
|
||||
TYPEC_CC_RP = 1,
|
||||
TYPEC_CC_RD = 2,
|
||||
TYPEC_CC_OPEN = 3,
|
||||
};
|
||||
|
||||
enum tcpc_rp_value {
|
||||
TYPEC_RP_USB = 0,
|
||||
TYPEC_RP_1A5 = 1,
|
||||
TYPEC_RP_3A0 = 2,
|
||||
TYPEC_RP_RESERVED = 3,
|
||||
};
|
||||
|
||||
enum tcpm_transmit_type {
|
||||
TCPC_TX_SOP = 0,
|
||||
TCPC_TX_SOP_PRIME = 1,
|
||||
TCPC_TX_SOP_PRIME_PRIME = 2,
|
||||
TCPC_TX_SOP_DEBUG_PRIME = 3,
|
||||
TCPC_TX_SOP_DEBUG_PRIME_PRIME = 4,
|
||||
TCPC_TX_HARD_RESET = 5,
|
||||
TCPC_TX_CABLE_RESET = 6,
|
||||
TCPC_TX_BIST_MODE_2 = 7
|
||||
};
|
||||
|
||||
enum tcpc_transmit_complete {
|
||||
TCPC_TX_COMPLETE_SUCCESS = 0,
|
||||
TCPC_TX_COMPLETE_DISCARDED = 1,
|
||||
TCPC_TX_COMPLETE_FAILED = 2,
|
||||
};
|
||||
|
||||
struct tcpm_drv {
|
||||
/**
|
||||
* Initialize TCPM driver and wait for TCPC readiness.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*init)(int port);
|
||||
|
||||
/**
|
||||
* Release the TCPM hardware and disconnect the driver.
|
||||
* Only .init() can be called after .release().
|
||||
*
|
||||
* @param port Type-C port number
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*release)(int port);
|
||||
|
||||
/**
|
||||
* Read the CC line status.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param cc1 pointer to CC status for CC1
|
||||
* @param cc2 pointer to CC status for CC2
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*get_cc)(int port, int *cc1, int *cc2);
|
||||
|
||||
/**
|
||||
* Read VBUS
|
||||
*
|
||||
* @param port Type-C port number
|
||||
*
|
||||
* @return 0 => VBUS not detected, 1 => VBUS detected
|
||||
*/
|
||||
int (*get_vbus_level)(int port);
|
||||
|
||||
/**
|
||||
* Set the value of the CC pull-up used when we are a source.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param rp One of enum tcpc_rp_value
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*select_rp_value)(int port, int rp);
|
||||
|
||||
/**
|
||||
* Set the CC pull resistor. This sets our role as either source or sink.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param pull One of enum tcpc_cc_pull
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*set_cc)(int port, int pull);
|
||||
|
||||
/**
|
||||
* Set polarity
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param polarity 0=> transmit on CC1, 1=> transmit on CC2
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*set_polarity)(int port, int polarity);
|
||||
|
||||
/**
|
||||
* Set Vconn.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param polarity Polarity of the CC line to read
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*set_vconn)(int port, int enable);
|
||||
|
||||
/**
|
||||
* Set PD message header to use for goodCRC
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param power_role Power role to use in header
|
||||
* @param data_role Data role to use in header
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*set_msg_header)(int port, int power_role, int data_role);
|
||||
|
||||
/**
|
||||
* Set RX enable flag
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @enable true for enable, false for disable
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*set_rx_enable)(int port, int enable);
|
||||
|
||||
/**
|
||||
* Read last received PD message.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param payload Pointer to location to copy payload of message
|
||||
* @param header of message
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*get_message)(int port, uint32_t *payload, int *head);
|
||||
|
||||
/**
|
||||
* Transmit PD message
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param type Transmit type
|
||||
* @param header Packet header
|
||||
* @param cnt Number of bytes in payload
|
||||
* @param data Payload
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*transmit)(int port, enum tcpm_transmit_type type, uint16_t header,
|
||||
const uint32_t *data);
|
||||
|
||||
/**
|
||||
* TCPC is asserting alert
|
||||
*
|
||||
* @param port Type-C port number
|
||||
*/
|
||||
void (*tcpc_alert)(int port);
|
||||
|
||||
/**
|
||||
* Discharge PD VBUS on src/sink disconnect & power role swap
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param enable Discharge enable or disable
|
||||
*/
|
||||
void (*tcpc_discharge_vbus)(int port, int enable);
|
||||
|
||||
#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
|
||||
/**
|
||||
* Enable TCPC auto DRP toggling.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param enable 1: Enable 0: Disable
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*drp_toggle)(int port, int enable);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get firmware version.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param renew Force renewal
|
||||
* @param info Pointer to pointer to PD chip info
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*get_chip_info)(int port, int renew,
|
||||
struct ec_response_pd_chip_info **info);
|
||||
};
|
||||
|
||||
enum tcpc_alert_polarity {
|
||||
TCPC_ALERT_ACTIVE_LOW,
|
||||
TCPC_ALERT_ACTIVE_HIGH,
|
||||
};
|
||||
|
||||
struct tcpc_config_t {
|
||||
int i2c_host_port;
|
||||
int i2c_slave_addr;
|
||||
const struct tcpm_drv *drv;
|
||||
enum tcpc_alert_polarity pol;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the PD_STATUS_TCPC_ALERT_* mask corresponding to the TCPC ports
|
||||
* that are currently asserting ALERT.
|
||||
*
|
||||
* @return PD_STATUS_TCPC_ALERT_* mask.
|
||||
*/
|
||||
uint16_t tcpc_get_alert_status(void);
|
||||
|
||||
/**
|
||||
* Optional, set the TCPC power mode.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param mode 0: off/sleep, 1: on/awake
|
||||
*/
|
||||
void board_set_tcpc_power_mode(int port, int mode) __attribute__((weak));
|
||||
|
||||
/**
|
||||
* Initialize TCPC.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
*/
|
||||
void tcpc_init(int port);
|
||||
|
||||
/**
|
||||
* TCPC is asserting alert
|
||||
*
|
||||
* @param port Type-C port number
|
||||
*/
|
||||
void tcpc_alert_clear(int port);
|
||||
|
||||
/**
|
||||
* Run TCPC task once. This checks for incoming messages, processes
|
||||
* any outgoing messages, and reads CC lines.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param evt Event type that woke up this task
|
||||
*/
|
||||
int tcpc_run(int port, int evt);
|
||||
|
||||
/**
|
||||
* Initialize board specific TCPC functions post TCPC initialization.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int board_tcpc_post_init(int port) __attribute__((weak));
|
||||
|
||||
#endif /* __CROS_EC_USB_PD_TCPM_H */
|
||||
69
workspace/TS100/Core/Drivers/FUSB302/tcpm_driver.cpp
Normal file
69
workspace/TS100/Core/Drivers/FUSB302/tcpm_driver.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* tcpm_driver.c
|
||||
*
|
||||
* Created: 11/11/2017 18:42:26
|
||||
* Author: jason
|
||||
*/
|
||||
|
||||
#include "tcpm_driver.h"
|
||||
#include "I2C_Wrapper.hpp"
|
||||
extern const struct tcpc_config_t tcpc_config[CONFIG_USB_PD_PORT_COUNT];
|
||||
#define STATUS_OK 0
|
||||
/* I2C wrapper functions - get I2C port / slave addr from config struct. */
|
||||
int tcpc_write(int port, int reg, int val) {
|
||||
|
||||
FRToSI2C::Mem_Write(tcpc_config[port].i2c_slave_addr, reg, (uint8_t*) &val,
|
||||
1);
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
int tcpc_write16(int port, int reg, int val) {
|
||||
uint8_t data[2];
|
||||
data[0] = (0xFF) & val;
|
||||
data[1] = (0xFF) & (val >> 8);
|
||||
FRToSI2C::Mem_Write(tcpc_config[port].i2c_slave_addr, reg, (uint8_t*) data,
|
||||
2);
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
int tcpc_read(int port, int reg, int *val) {
|
||||
uint8_t data[1];
|
||||
|
||||
FRToSI2C::Mem_Read(tcpc_config[port].i2c_slave_addr, reg, (uint8_t*) data,
|
||||
1);
|
||||
|
||||
*val = data[0];
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
int tcpc_read16(int port, int reg, int *val) {
|
||||
uint8_t data[2];
|
||||
FRToSI2C::Mem_Write(tcpc_config[port].i2c_slave_addr, reg, (uint8_t*) data,
|
||||
2);
|
||||
|
||||
*val = data[0];
|
||||
*val |= (data[1] << 8);
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
int tcpc_xfer(int port, const uint8_t *out, int out_size, uint8_t *in,
|
||||
int in_size, int flags) {
|
||||
// Write out the I2C port to the given slave address
|
||||
// Write out the out byte array to the device (sending a stop if the flag is set)
|
||||
// Then issue a read from the device
|
||||
|
||||
if (flags & I2C_XFER_STOP) {
|
||||
//Issuing a stop between the requests
|
||||
//Send as a Tx followed by a Rx
|
||||
FRToSI2C::Transmit(tcpc_config[port].i2c_slave_addr, (uint8_t*)out, out_size);
|
||||
FRToSI2C::Receive(tcpc_config[port].i2c_slave_addr, in, in_size);
|
||||
} else {
|
||||
//issue as a continious transmit & recieve
|
||||
FRToSI2C::TransmitReceive(tcpc_config[port].i2c_slave_addr, (uint8_t*)out,
|
||||
out_size, in, in_size);
|
||||
}
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
22
workspace/TS100/Core/Drivers/FUSB302/tcpm_driver.h
Normal file
22
workspace/TS100/Core/Drivers/FUSB302/tcpm_driver.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* tcpm_driver.h
|
||||
*
|
||||
* Created: 11/11/2017 18:42:39
|
||||
* Author: jason
|
||||
*/
|
||||
|
||||
|
||||
#ifndef TCPM_DRIVER_H_
|
||||
#define TCPM_DRIVER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// USB-C Stuff
|
||||
#include "USBC_TCPM/tcpm.h"
|
||||
#include "FUSB302.h"
|
||||
#define CONFIG_USB_PD_PORT_COUNT 1
|
||||
extern struct i2c_master_module i2c_master_instance;
|
||||
|
||||
|
||||
|
||||
#endif /* TCPM_DRIVER_H_ */
|
||||
414
workspace/TS100/Core/Drivers/FUSB302/usb_pd_driver.cpp
Normal file
414
workspace/TS100/Core/Drivers/FUSB302/usb_pd_driver.cpp
Normal file
@@ -0,0 +1,414 @@
|
||||
/*
|
||||
* usb_pd_driver.c
|
||||
*
|
||||
* Created: 11/11/2017 23:55:12
|
||||
* Author: jason
|
||||
*/
|
||||
|
||||
#include "usb_pd_driver.h"
|
||||
#include "USBC_PD/usb_pd.h"
|
||||
#include <string.h>
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(t) (sizeof(t) / sizeof(t[0]))
|
||||
#endif
|
||||
|
||||
extern struct tc_module tc_instance;
|
||||
extern uint32_t g_us_timestamp_upper_32bit;
|
||||
|
||||
uint32_t pd_task_set_event(uint32_t event, int wait_for_reply) {
|
||||
switch (event) {
|
||||
case PD_EVENT_TX:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint32_t pd_src_pdo[] = { PDO_FIXED(5000, 1500, PDO_FIXED_FLAGS), };
|
||||
const int pd_src_pdo_cnt = ARRAY_SIZE(pd_src_pdo);
|
||||
|
||||
const uint32_t pd_snk_pdo[] = { PDO_FIXED(5000, 500, PDO_FIXED_FLAGS),
|
||||
PDO_FIXED(9000, 500, PDO_FIXED_FLAGS), PDO_FIXED(20000, 500,
|
||||
PDO_FIXED_FLAGS), };
|
||||
const int pd_snk_pdo_cnt = ARRAY_SIZE(pd_snk_pdo);
|
||||
|
||||
void pd_set_input_current_limit(int port, uint32_t max_ma,
|
||||
uint32_t supply_voltage) {
|
||||
|
||||
}
|
||||
|
||||
int pd_is_valid_input_voltage(int mv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pd_snk_is_vbus_provided(int port) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
timestamp_t get_time(void) {
|
||||
timestamp_t t;
|
||||
//TODO
|
||||
//
|
||||
// system_interrupt_enter_critical_section();
|
||||
// t.le.lo = tc_get_count_value(&tc_instance);
|
||||
// t.le.hi = g_us_timestamp_upper_32bit;
|
||||
// system_interrupt_leave_critical_section();
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void pd_power_supply_reset(int port) {
|
||||
return;
|
||||
}
|
||||
|
||||
void pd_execute_data_swap(int port, int data_role) {
|
||||
/* Do nothing */
|
||||
}
|
||||
|
||||
int pd_check_data_swap(int port, int data_role) {
|
||||
// Never allow data swap
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pd_check_power_swap(int port) {
|
||||
/* Always refuse power swap */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pd_board_checks(void) {
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
int pd_set_power_supply_ready(int port) {
|
||||
#if 0
|
||||
/* Disable charging */
|
||||
gpio_set_level(GPIO_USB_C0_CHARGE_L, 1);
|
||||
|
||||
/* Enable VBUS source */
|
||||
gpio_set_level(GPIO_USB_C0_5V_EN, 1);
|
||||
|
||||
/* notify host of power info change */
|
||||
pd_send_host_event(PD_EVENT_POWER_CHANGE);
|
||||
#endif // if 0
|
||||
return EC_SUCCESS; /* we are ready */
|
||||
}
|
||||
|
||||
void pd_transition_voltage(int idx) {
|
||||
/* No-operation: we are always 5V */
|
||||
|
||||
#if 0
|
||||
timestamp_t deadline;
|
||||
uint32_t mv = src_pdo_charge[idx - 1].mv;
|
||||
|
||||
/* Is this a transition to a new voltage? */
|
||||
if (charge_port_is_active() && vbus[CHG].mv != mv) {
|
||||
/*
|
||||
* Alter voltage limit on charge port, this should cause
|
||||
* the port to select the desired PDO.
|
||||
*/
|
||||
pd_set_external_voltage_limit(CHG, mv);
|
||||
|
||||
/* Wait for CHG transition */
|
||||
deadline.val = get_time().val + PD_T_PS_TRANSITION;
|
||||
CPRINTS("Waiting for CHG port transition");
|
||||
while (charge_port_is_active() &&
|
||||
vbus[CHG].mv != mv &&
|
||||
get_time().val < deadline.val)
|
||||
msleep(10);
|
||||
|
||||
if (vbus[CHG].mv != mv) {
|
||||
CPRINTS("Missed CHG transition, resetting DUT");
|
||||
pd_power_supply_reset(DUT);
|
||||
return;
|
||||
}
|
||||
|
||||
CPRINTS("CHG transitioned");
|
||||
}
|
||||
|
||||
vbus[DUT].mv = vbus[CHG].mv;
|
||||
vbus[DUT].ma = vbus[CHG].ma;
|
||||
#endif // if 0
|
||||
|
||||
}
|
||||
|
||||
void pd_check_dr_role(int port, int dr_role, int flags) {
|
||||
#if 0
|
||||
/* If UFP, try to switch to DFP */
|
||||
if ((flags & PD_FLAGS_PARTNER_DR_DATA) && dr_role == PD_ROLE_UFP)
|
||||
pd_request_data_swap(port);
|
||||
#endif
|
||||
}
|
||||
|
||||
void pd_check_pr_role(int port, int pr_role, int flags) {
|
||||
#if 0
|
||||
/*
|
||||
* If partner is dual-role power and dualrole toggling is on, consider
|
||||
* if a power swap is necessary.
|
||||
*/
|
||||
if ((flags & PD_FLAGS_PARTNER_DR_POWER) &&
|
||||
pd_get_dual_role() == PD_DRP_TOGGLE_ON) {
|
||||
/*
|
||||
* If we are a sink and partner is not externally powered, then
|
||||
* swap to become a source. If we are source and partner is
|
||||
* externally powered, swap to become a sink.
|
||||
*/
|
||||
int partner_extpower = flags & PD_FLAGS_PARTNER_EXTPOWER;
|
||||
|
||||
if ((!partner_extpower && pr_role == PD_ROLE_SINK) ||
|
||||
(partner_extpower && pr_role == PD_ROLE_SOURCE))
|
||||
pd_request_power_swap(port);
|
||||
}
|
||||
#endif // if 0
|
||||
}
|
||||
|
||||
void pd_process_source_cap_callback(int port, int cnt, uint32_t *src_caps) {
|
||||
// char str[256];
|
||||
// int i;
|
||||
// uint32_t ma, mv, pdo;
|
||||
// uint8_t old_display;
|
||||
//
|
||||
// old_display = display_screen;
|
||||
// display_screen = SCREEN_POWER;
|
||||
// memset(display_buffer[SCREEN_POWER], 0x00, DISP_MEM_SIZE);
|
||||
//
|
||||
// sprintf(str, "Has Power Delivery");
|
||||
// UG_PutString(0, 8, str);
|
||||
//
|
||||
// for (i = 0; i < cnt; i++)
|
||||
// {
|
||||
// pd_extract_pdo_power(src_caps[i], &ma, &mv);
|
||||
// sprintf(str, "%5.2f V, %5.2f A", (float)mv/1000, (float)ma/1000);
|
||||
// UG_PutString(0, 8*(i+2), str);
|
||||
// }
|
||||
//
|
||||
// display_screen = old_display;
|
||||
// display_needs_update = 1;
|
||||
|
||||
//TODO Handle information on supported voltages?
|
||||
}
|
||||
|
||||
/* ----------------- Vendor Defined Messages ------------------ */
|
||||
/* Holds valid object position (opos) for entered mode */
|
||||
static int alt_mode[PD_AMODE_COUNT];
|
||||
|
||||
const uint32_t vdo_idh = VDO_IDH(0, /* data caps as USB host */
|
||||
1, /* data caps as USB device */
|
||||
IDH_PTYPE_AMA, /* Alternate mode */
|
||||
1, /* supports alt modes */
|
||||
USB_VID_GOOGLE);
|
||||
|
||||
const uint32_t vdo_product = VDO_PRODUCT(CONFIG_USB_PID, CONFIG_USB_BCD_DEV);
|
||||
|
||||
const uint32_t vdo_ama = VDO_AMA(CONFIG_USB_PD_IDENTITY_HW_VERS,
|
||||
CONFIG_USB_PD_IDENTITY_SW_VERS, 0, 0, 0, 0, /* SS[TR][12] */
|
||||
0, /* Vconn power */
|
||||
0, /* Vconn power required */
|
||||
1, /* Vbus power required */
|
||||
AMA_USBSS_BBONLY /* USB SS support */);
|
||||
|
||||
static int svdm_response_identity(int port, uint32_t *payload) {
|
||||
payload[VDO_I(IDH)] = vdo_idh;
|
||||
/* TODO(tbroch): Do we plan to obtain TID (test ID) */
|
||||
payload[VDO_I(CSTAT)] = VDO_CSTAT(0);
|
||||
payload[VDO_I(PRODUCT)] = vdo_product;
|
||||
payload[VDO_I(AMA)] = vdo_ama;
|
||||
return VDO_I(AMA) + 1;
|
||||
}
|
||||
|
||||
static int svdm_response_svids(int port, uint32_t *payload) {
|
||||
payload[1] = VDO_SVID(USB_SID_DISPLAYPORT, USB_VID_GOOGLE);
|
||||
payload[2] = 0;
|
||||
return 3;
|
||||
}
|
||||
|
||||
#define OPOS_DP 1
|
||||
#define OPOS_GFU 1
|
||||
|
||||
const uint32_t vdo_dp_modes[1] = { VDO_MODE_DP(0, /* UFP pin cfg supported : none */
|
||||
MODE_DP_PIN_C, /* DFP pin cfg supported */
|
||||
1, /* no usb2.0 signalling in AMode */
|
||||
CABLE_PLUG, /* its a plug */
|
||||
MODE_DP_V13, /* DPv1.3 Support, no Gen2 */
|
||||
MODE_DP_SNK) /* Its a sink only */
|
||||
};
|
||||
|
||||
const uint32_t vdo_goog_modes[1] = { VDO_MODE_GOOGLE(MODE_GOOGLE_FU) };
|
||||
|
||||
static int svdm_response_modes(int port, uint32_t *payload) {
|
||||
if (PD_VDO_VID(payload[0]) == USB_SID_DISPLAYPORT) {
|
||||
memcpy(payload + 1, vdo_dp_modes, sizeof(vdo_dp_modes));
|
||||
return ARRAY_SIZE(vdo_dp_modes) + 1;
|
||||
} else if (PD_VDO_VID(payload[0]) == USB_VID_GOOGLE) {
|
||||
memcpy(payload + 1, vdo_goog_modes, sizeof(vdo_goog_modes));
|
||||
return ARRAY_SIZE(vdo_goog_modes) + 1;
|
||||
} else {
|
||||
return 0; /* nak */
|
||||
}
|
||||
}
|
||||
|
||||
static int dp_status(int port, uint32_t *payload) {
|
||||
int opos = PD_VDO_OPOS(payload[0]);
|
||||
int hpd = 0; // gpio_get_level(GPIO_DP_HPD);
|
||||
if (opos != OPOS_DP)
|
||||
return 0; /* nak */
|
||||
|
||||
payload[1] = VDO_DP_STATUS(0, /* IRQ_HPD */
|
||||
(hpd == 1), /* HPD_HI|LOW */
|
||||
0, /* request exit DP */
|
||||
0, /* request exit USB */
|
||||
0, /* MF pref */
|
||||
0, //gpio_get_level(GPIO_PD_SBU_ENABLE),
|
||||
0, /* power low */
|
||||
0x2);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int dp_config(int port, uint32_t *payload) {
|
||||
if (PD_DP_CFG_DPON(payload[1]))
|
||||
0; //gpio_set_level(GPIO_PD_SBU_ENABLE, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int svdm_enter_mode(int port, uint32_t *payload) {
|
||||
int rv = 0; /* will generate a NAK */
|
||||
char str[256];
|
||||
uint8_t old_display;
|
||||
|
||||
/* SID & mode request is valid */
|
||||
if ((PD_VDO_VID(payload[0]) == USB_SID_DISPLAYPORT)
|
||||
&& (PD_VDO_OPOS(payload[0]) == OPOS_DP)) {
|
||||
alt_mode[PD_AMODE_DISPLAYPORT] = OPOS_DP;
|
||||
rv = 1;
|
||||
//pd_log_event(PD_EVENT_VIDEO_DP_MODE, 0, 1, NULL);
|
||||
} else if ((PD_VDO_VID(payload[0]) == USB_VID_GOOGLE)
|
||||
&& (PD_VDO_OPOS(payload[0]) == OPOS_GFU)) {
|
||||
alt_mode[PD_AMODE_GOOGLE] = OPOS_GFU;
|
||||
rv = 1;
|
||||
}
|
||||
|
||||
// if (rv)
|
||||
/*
|
||||
* If we failed initial mode entry we'll have enumerated the USB
|
||||
* Billboard class. If so we should disconnect.
|
||||
*/
|
||||
//usb_disconnect();
|
||||
// old_display = display_screen;
|
||||
// display_screen = SCREEN_ALTMODE;
|
||||
// memset(display_buffer[SCREEN_ALTMODE], 0x00, DISP_MEM_SIZE);
|
||||
//
|
||||
// sprintf(str, "Requested Alt Mode");
|
||||
// UG_PutString(0, 8, str);
|
||||
//
|
||||
// display_screen = old_display;
|
||||
// display_needs_update = 1;
|
||||
//TODO handle alt mode ?
|
||||
return rv;
|
||||
}
|
||||
|
||||
int pd_alt_mode(int port, uint16_t svid) {
|
||||
if (svid == USB_SID_DISPLAYPORT)
|
||||
return alt_mode[PD_AMODE_DISPLAYPORT];
|
||||
else if (svid == USB_VID_GOOGLE)
|
||||
return alt_mode[PD_AMODE_GOOGLE];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int svdm_exit_mode(int port, uint32_t *payload) {
|
||||
return 1; /* Must return ACK */
|
||||
}
|
||||
|
||||
static struct amode_fx dp_fx = { .status = &dp_status, .config = &dp_config, };
|
||||
|
||||
const struct svdm_response svdm_rsp = { &svdm_response_identity,
|
||||
&svdm_response_svids, &svdm_response_modes, &svdm_enter_mode,
|
||||
&svdm_exit_mode, &dp_fx, };
|
||||
|
||||
int pd_custom_vdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload) {
|
||||
int rsize;
|
||||
|
||||
if (PD_VDO_VID(payload[0]) != USB_VID_GOOGLE || !alt_mode[PD_AMODE_GOOGLE])
|
||||
return 0;
|
||||
|
||||
*rpayload = payload;
|
||||
|
||||
rsize = pd_custom_flash_vdm(port, cnt, payload);
|
||||
if (!rsize) {
|
||||
int cmd = PD_VDO_CMD(payload[0]);
|
||||
switch (cmd) {
|
||||
case VDO_CMD_GET_LOG:
|
||||
rsize = pd_vdm_get_log_entry(payload);
|
||||
break;
|
||||
default:
|
||||
/* Unknown : do not answer */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* respond (positively) to the request */
|
||||
payload[0] |= VDO_SRC_RESPONDER;
|
||||
|
||||
return rsize;
|
||||
}
|
||||
|
||||
int pd_custom_flash_vdm(int port, int cnt, uint32_t *payload) {
|
||||
static int flash_offset;
|
||||
int rsize = 1; /* default is just VDM header returned */
|
||||
|
||||
switch (PD_VDO_CMD(payload[0])) {
|
||||
#if 0
|
||||
case VDO_CMD_VERSION:
|
||||
memcpy(payload + 1, ¤t_image_data.version, 24);
|
||||
rsize = 7;
|
||||
break;
|
||||
case VDO_CMD_REBOOT:
|
||||
/* ensure the power supply is in a safe state */
|
||||
pd_power_supply_reset(0);
|
||||
system_reset(0);
|
||||
break;
|
||||
case VDO_CMD_READ_INFO:
|
||||
/* copy info into response */
|
||||
pd_get_info(payload + 1);
|
||||
rsize = 7;
|
||||
break;
|
||||
case VDO_CMD_FLASH_ERASE:
|
||||
/* do not kill the code under our feet */
|
||||
if (system_get_image_copy() != SYSTEM_IMAGE_RO)
|
||||
break;
|
||||
pd_log_event(PD_EVENT_ACC_RW_ERASE, 0, 0, NULL);
|
||||
flash_offset = CONFIG_EC_WRITABLE_STORAGE_OFF +
|
||||
CONFIG_RW_STORAGE_OFF;
|
||||
flash_physical_erase(CONFIG_EC_WRITABLE_STORAGE_OFF +
|
||||
CONFIG_RW_STORAGE_OFF, CONFIG_RW_SIZE);
|
||||
rw_flash_changed = 1;
|
||||
break;
|
||||
case VDO_CMD_FLASH_WRITE:
|
||||
/* do not kill the code under our feet */
|
||||
if ((system_get_image_copy() != SYSTEM_IMAGE_RO) ||
|
||||
(flash_offset < CONFIG_EC_WRITABLE_STORAGE_OFF +
|
||||
CONFIG_RW_STORAGE_OFF))
|
||||
break;
|
||||
flash_physical_write(flash_offset, 4*(cnt - 1),
|
||||
(const char *)(payload+1));
|
||||
flash_offset += 4*(cnt - 1);
|
||||
rw_flash_changed = 1;
|
||||
break;
|
||||
case VDO_CMD_ERASE_SIG:
|
||||
/* this is not touching the code area */
|
||||
{
|
||||
uint32_t zero = 0;
|
||||
int offset;
|
||||
/* zeroes the area containing the RSA signature */
|
||||
for (offset = FW_RW_END - RSANUMBYTES;
|
||||
offset < FW_RW_END; offset += 4)
|
||||
flash_physical_write(offset, 4,
|
||||
(const char *)&zero);
|
||||
}
|
||||
break;
|
||||
#endif // 0
|
||||
default:
|
||||
/* Unknown : do not answer */
|
||||
return 0;
|
||||
}
|
||||
return rsize;
|
||||
}
|
||||
104
workspace/TS100/Core/Drivers/FUSB302/usb_pd_driver.h
Normal file
104
workspace/TS100/Core/Drivers/FUSB302/usb_pd_driver.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* usb_pd_driver.h
|
||||
*
|
||||
* Created: 11/11/2017 23:55:25
|
||||
* Author: jason
|
||||
*/
|
||||
|
||||
|
||||
#ifndef USB_PD_DRIVER_H_
|
||||
#define USB_PD_DRIVER_H_
|
||||
|
||||
#include "USBC_PD/usb_pd.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
//#define CONFIG_BBRAM
|
||||
#define CONFIG_CHARGE_MANAGER
|
||||
//#define CONFIG_USBC_BACKWARDS_COMPATIBLE_DFP
|
||||
//#define CONFIG_USBC_VCONN_SWAP
|
||||
#define CONFIG_USB_PD_ALT_MODE
|
||||
//#define CONFIG_USB_PD_CHROMEOS
|
||||
#define CONFIG_USB_PD_DUAL_ROLE
|
||||
//#define CONFIG_USB_PD_GIVE_BACK
|
||||
//#define CONFIG_USB_PD_SIMPLE_DFP
|
||||
//#define CONFIG_USB_PD_TCPM_TCPCI
|
||||
#define PD_PREFER_HIGH_VOLTAGE
|
||||
|
||||
/* Default pull-up value on the USB-C ports when they are used as source. */
|
||||
#define CONFIG_USB_PD_PULLUP TYPEC_RP_USB
|
||||
|
||||
/* Override PD_ROLE_DEFAULT in usb_pd.h */
|
||||
#define PD_ROLE_DEFAULT(port) (PD_ROLE_SINK)
|
||||
|
||||
/* Don't automatically change roles */
|
||||
#undef CONFIG_USB_PD_INITIAL_DRP_STATE
|
||||
#define CONFIG_USB_PD_INITIAL_DRP_STATE PD_DRP_FREEZE
|
||||
|
||||
/* Prefer higher voltage, and more importantly, lower current */
|
||||
#define PD_PREFER_HIGH_VOLTAGE
|
||||
//#define PD_PREFER_LOW_VOLTAGE
|
||||
|
||||
/* board specific type-C power constants */
|
||||
/*
|
||||
* delay to turn on the power supply max is ~16ms.
|
||||
* delay to turn off the power supply max is about ~180ms.
|
||||
*/
|
||||
#define PD_POWER_SUPPLY_TURN_ON_DELAY 10000 /* us */
|
||||
#define PD_POWER_SUPPLY_TURN_OFF_DELAY 20000 /* us */
|
||||
|
||||
/* Define typical operating power and max power */
|
||||
#define PD_OPERATING_POWER_MW 15000
|
||||
#define PD_MAX_POWER_MW 100000
|
||||
#define PD_MAX_CURRENT_MA 5000
|
||||
#define PD_MAX_VOLTAGE_MV 20000
|
||||
|
||||
#define PDO_FIXED_FLAGS (PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP |\
|
||||
PDO_FIXED_COMM_CAP)
|
||||
|
||||
/* USB configuration */
|
||||
#define CONFIG_USB_PID 0x502f // Stolen, so should change for anything useful
|
||||
#define CONFIG_USB_BCD_DEV 0x0001 /* v 0.01 */
|
||||
|
||||
/* Optional features */
|
||||
#define CONFIG_USB_PD_IDENTITY_HW_VERS 1
|
||||
#define CONFIG_USB_PD_IDENTITY_SW_VERS 1
|
||||
|
||||
#define usleep(us) (delay_us(us))
|
||||
#define msleep(us) (delay_ms(us))
|
||||
|
||||
typedef union {
|
||||
uint64_t val;
|
||||
struct {
|
||||
uint32_t lo;
|
||||
uint32_t hi;
|
||||
} le /* little endian words */;
|
||||
} timestamp_t;
|
||||
|
||||
uint32_t pd_task_set_event(uint32_t event, int wait_for_reply);
|
||||
void pd_power_supply_reset(int port);
|
||||
|
||||
// Get the current timestamp from the system timer.
|
||||
timestamp_t get_time(void);
|
||||
|
||||
/* Standard macros / definitions */
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) \
|
||||
({ \
|
||||
__typeof__(a) temp_a = (a); \
|
||||
__typeof__(b) temp_b = (b); \
|
||||
\
|
||||
temp_a > temp_b ? temp_a : temp_b; \
|
||||
})
|
||||
#endif
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) \
|
||||
({ \
|
||||
__typeof__(a) temp_a = (a); \
|
||||
__typeof__(b) temp_b = (b); \
|
||||
\
|
||||
temp_a < temp_b ? temp_a : temp_b; \
|
||||
})
|
||||
#endif
|
||||
|
||||
#endif /* USB_PD_DRIVER_H_ */
|
||||
354
workspace/TS100/Core/Drivers/FUSB302/usb_pd_tcpm.h
Normal file
354
workspace/TS100/Core/Drivers/FUSB302/usb_pd_tcpm.h
Normal file
@@ -0,0 +1,354 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
/* USB Power delivery port management */
|
||||
|
||||
#ifndef __CROS_EC_USB_PD_TCPM_H
|
||||
#define __CROS_EC_USB_PD_TCPM_H
|
||||
|
||||
/* List of common error codes that can be returned */
|
||||
enum ec_error_list {
|
||||
/* Success - no error */
|
||||
EC_SUCCESS = 0,
|
||||
/* Unknown error */
|
||||
EC_ERROR_UNKNOWN = 1,
|
||||
/* Function not implemented yet */
|
||||
EC_ERROR_UNIMPLEMENTED = 2,
|
||||
/* Overflow error; too much input provided. */
|
||||
EC_ERROR_OVERFLOW = 3,
|
||||
/* Timeout */
|
||||
EC_ERROR_TIMEOUT = 4,
|
||||
/* Invalid argument */
|
||||
EC_ERROR_INVAL = 5,
|
||||
/* Already in use, or not ready yet */
|
||||
EC_ERROR_BUSY = 6,
|
||||
/* Access denied */
|
||||
EC_ERROR_ACCESS_DENIED = 7,
|
||||
/* Failed because component does not have power */
|
||||
EC_ERROR_NOT_POWERED = 8,
|
||||
/* Failed because component is not calibrated */
|
||||
EC_ERROR_NOT_CALIBRATED = 9,
|
||||
/* Failed because CRC error */
|
||||
EC_ERROR_CRC = 10,
|
||||
/* Invalid console command param (PARAMn means parameter n is bad) */
|
||||
EC_ERROR_PARAM1 = 11,
|
||||
EC_ERROR_PARAM2 = 12,
|
||||
EC_ERROR_PARAM3 = 13,
|
||||
EC_ERROR_PARAM4 = 14,
|
||||
EC_ERROR_PARAM5 = 15,
|
||||
EC_ERROR_PARAM6 = 16,
|
||||
EC_ERROR_PARAM7 = 17,
|
||||
EC_ERROR_PARAM8 = 18,
|
||||
EC_ERROR_PARAM9 = 19,
|
||||
/* Wrong number of params */
|
||||
EC_ERROR_PARAM_COUNT = 20,
|
||||
/* Interrupt event not handled */
|
||||
EC_ERROR_NOT_HANDLED = 21,
|
||||
/* Data has not changed */
|
||||
EC_ERROR_UNCHANGED = 22,
|
||||
/* Memory allocation */
|
||||
EC_ERROR_MEMORY_ALLOCATION = 23,
|
||||
|
||||
/* Verified boot errors */
|
||||
EC_ERROR_VBOOT_SIGNATURE = 0x1000, /* 4096 */
|
||||
EC_ERROR_VBOOT_SIG_MAGIC = 0x1001,
|
||||
EC_ERROR_VBOOT_SIG_SIZE = 0x1002,
|
||||
EC_ERROR_VBOOT_SIG_ALGORITHM = 0x1003,
|
||||
EC_ERROR_VBOOT_HASH_ALGORITHM = 0x1004,
|
||||
EC_ERROR_VBOOT_SIG_OFFSET = 0x1005,
|
||||
EC_ERROR_VBOOT_DATA_SIZE = 0x1006,
|
||||
|
||||
/* Verified boot key errors */
|
||||
EC_ERROR_VBOOT_KEY = 0x1100,
|
||||
EC_ERROR_VBOOT_KEY_MAGIC = 0x1101,
|
||||
EC_ERROR_VBOOT_KEY_SIZE = 0x1102,
|
||||
|
||||
/* Verified boot data errors */
|
||||
EC_ERROR_VBOOT_DATA = 0x1200,
|
||||
EC_ERROR_VBOOT_DATA_VERIFY = 0x1201,
|
||||
|
||||
/* Module-internal error codes may use this range. */
|
||||
EC_ERROR_INTERNAL_FIRST = 0x10000,
|
||||
EC_ERROR_INTERNAL_LAST = 0x1FFFF
|
||||
};
|
||||
|
||||
/* Flags for i2c_xfer() */
|
||||
#define I2C_XFER_START (1 << 0) /* Start smbus session from idle state */
|
||||
#define I2C_XFER_STOP (1 << 1) /* Terminate smbus session with stop bit */
|
||||
#define I2C_XFER_SINGLE (I2C_XFER_START | I2C_XFER_STOP) /* One transaction */
|
||||
|
||||
/* Default retry count for transmitting */
|
||||
#define PD_RETRY_COUNT 3
|
||||
|
||||
/* Time to wait for TCPC to complete transmit */
|
||||
#define PD_T_TCPC_TX_TIMEOUT (100*MSEC)
|
||||
|
||||
enum tcpc_cc_voltage_status {
|
||||
TYPEC_CC_VOLT_OPEN = 0,
|
||||
TYPEC_CC_VOLT_RA = 1,
|
||||
TYPEC_CC_VOLT_RD = 2,
|
||||
TYPEC_CC_VOLT_SNK_DEF = 5,
|
||||
TYPEC_CC_VOLT_SNK_1_5 = 6,
|
||||
TYPEC_CC_VOLT_SNK_3_0 = 7,
|
||||
};
|
||||
|
||||
enum tcpc_cc_pull {
|
||||
TYPEC_CC_RA = 0,
|
||||
TYPEC_CC_RP = 1,
|
||||
TYPEC_CC_RD = 2,
|
||||
TYPEC_CC_OPEN = 3,
|
||||
};
|
||||
|
||||
enum tcpc_rp_value {
|
||||
TYPEC_RP_USB = 0,
|
||||
TYPEC_RP_1A5 = 1,
|
||||
TYPEC_RP_3A0 = 2,
|
||||
TYPEC_RP_RESERVED = 3,
|
||||
};
|
||||
|
||||
enum tcpm_transmit_type {
|
||||
TCPC_TX_SOP = 0,
|
||||
TCPC_TX_SOP_PRIME = 1,
|
||||
TCPC_TX_SOP_PRIME_PRIME = 2,
|
||||
TCPC_TX_SOP_DEBUG_PRIME = 3,
|
||||
TCPC_TX_SOP_DEBUG_PRIME_PRIME = 4,
|
||||
TCPC_TX_HARD_RESET = 5,
|
||||
TCPC_TX_CABLE_RESET = 6,
|
||||
TCPC_TX_BIST_MODE_2 = 7
|
||||
};
|
||||
|
||||
enum tcpc_transmit_complete {
|
||||
TCPC_TX_COMPLETE_SUCCESS = 0,
|
||||
TCPC_TX_COMPLETE_DISCARDED = 1,
|
||||
TCPC_TX_COMPLETE_FAILED = 2,
|
||||
};
|
||||
|
||||
struct tcpm_drv {
|
||||
/**
|
||||
* Initialize TCPM driver and wait for TCPC readiness.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*init)(int port);
|
||||
|
||||
/**
|
||||
* Release the TCPM hardware and disconnect the driver.
|
||||
* Only .init() can be called after .release().
|
||||
*
|
||||
* @param port Type-C port number
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*release)(int port);
|
||||
|
||||
/**
|
||||
* Read the CC line status.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param cc1 pointer to CC status for CC1
|
||||
* @param cc2 pointer to CC status for CC2
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*get_cc)(int port, int *cc1, int *cc2);
|
||||
|
||||
/**
|
||||
* Read VBUS
|
||||
*
|
||||
* @param port Type-C port number
|
||||
*
|
||||
* @return 0 => VBUS not detected, 1 => VBUS detected
|
||||
*/
|
||||
int (*get_vbus_level)(int port);
|
||||
|
||||
/**
|
||||
* Set the value of the CC pull-up used when we are a source.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param rp One of enum tcpc_rp_value
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*select_rp_value)(int port, int rp);
|
||||
|
||||
/**
|
||||
* Set the CC pull resistor. This sets our role as either source or sink.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param pull One of enum tcpc_cc_pull
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*set_cc)(int port, int pull);
|
||||
|
||||
/**
|
||||
* Set polarity
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param polarity 0=> transmit on CC1, 1=> transmit on CC2
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*set_polarity)(int port, int polarity);
|
||||
|
||||
/**
|
||||
* Set Vconn.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param polarity Polarity of the CC line to read
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*set_vconn)(int port, int enable);
|
||||
|
||||
/**
|
||||
* Set PD message header to use for goodCRC
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param power_role Power role to use in header
|
||||
* @param data_role Data role to use in header
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*set_msg_header)(int port, int power_role, int data_role);
|
||||
|
||||
/**
|
||||
* Set RX enable flag
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @enable true for enable, false for disable
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*set_rx_enable)(int port, int enable);
|
||||
|
||||
/**
|
||||
* Read last received PD message.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param payload Pointer to location to copy payload of message
|
||||
* @param header of message
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*get_message)(int port, uint32_t *payload, int *head);
|
||||
|
||||
/**
|
||||
* Transmit PD message
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param type Transmit type
|
||||
* @param header Packet header
|
||||
* @param cnt Number of bytes in payload
|
||||
* @param data Payload
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*transmit)(int port, enum tcpm_transmit_type type, uint16_t header,
|
||||
const uint32_t *data);
|
||||
|
||||
/**
|
||||
* TCPC is asserting alert
|
||||
*
|
||||
* @param port Type-C port number
|
||||
*/
|
||||
void (*tcpc_alert)(int port);
|
||||
|
||||
/**
|
||||
* Discharge PD VBUS on src/sink disconnect & power role swap
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param enable Discharge enable or disable
|
||||
*/
|
||||
void (*tcpc_discharge_vbus)(int port, int enable);
|
||||
|
||||
#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
|
||||
/**
|
||||
* Enable TCPC auto DRP toggling.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param enable 1: Enable 0: Disable
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*drp_toggle)(int port, int enable);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get firmware version.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param renew Force renewal
|
||||
* @param info Pointer to pointer to PD chip info
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int (*get_chip_info)(int port, int renew,
|
||||
struct ec_response_pd_chip_info **info);
|
||||
};
|
||||
|
||||
enum tcpc_alert_polarity {
|
||||
TCPC_ALERT_ACTIVE_LOW,
|
||||
TCPC_ALERT_ACTIVE_HIGH,
|
||||
};
|
||||
|
||||
struct tcpc_config_t {
|
||||
int i2c_host_port;
|
||||
int i2c_slave_addr;
|
||||
const struct tcpm_drv *drv;
|
||||
enum tcpc_alert_polarity pol;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the PD_STATUS_TCPC_ALERT_* mask corresponding to the TCPC ports
|
||||
* that are currently asserting ALERT.
|
||||
*
|
||||
* @return PD_STATUS_TCPC_ALERT_* mask.
|
||||
*/
|
||||
uint16_t tcpc_get_alert_status(void);
|
||||
|
||||
/**
|
||||
* Optional, set the TCPC power mode.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param mode 0: off/sleep, 1: on/awake
|
||||
*/
|
||||
void board_set_tcpc_power_mode(int port, int mode) __attribute__((weak));
|
||||
|
||||
/**
|
||||
* Initialize TCPC.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
*/
|
||||
void tcpc_init(int port);
|
||||
|
||||
/**
|
||||
* TCPC is asserting alert
|
||||
*
|
||||
* @param port Type-C port number
|
||||
*/
|
||||
void tcpc_alert_clear(int port);
|
||||
|
||||
/**
|
||||
* Run TCPC task once. This checks for incoming messages, processes
|
||||
* any outgoing messages, and reads CC lines.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
* @param evt Event type that woke up this task
|
||||
*/
|
||||
int tcpc_run(int port, int evt);
|
||||
|
||||
/**
|
||||
* Initialize board specific TCPC functions post TCPC initialization.
|
||||
*
|
||||
* @param port Type-C port number
|
||||
*
|
||||
* @return EC_SUCCESS or error
|
||||
*/
|
||||
int board_tcpc_post_init(int port) __attribute__((weak));
|
||||
|
||||
#endif /* __CROS_EC_USB_PD_TCPM_H */
|
||||
@@ -40,6 +40,9 @@ public:
|
||||
static bool probe(uint16_t DevAddress);
|
||||
|
||||
static void Transmit(uint16_t DevAddress, uint8_t *pData, uint16_t Size);
|
||||
static void Receive(uint16_t DevAddress, uint8_t *pData, uint16_t Size);
|
||||
static void TransmitReceive(uint16_t DevAddress, uint8_t *pData_tx,
|
||||
uint16_t Size_tx, uint8_t *pData_rx, uint16_t Size_rx);
|
||||
static void I2C_RegisterWrite(uint8_t address, uint8_t reg, uint8_t data);
|
||||
static uint8_t I2C_RegisterRead(uint8_t address, uint8_t reg);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user