static int anx74xx_alert_status(int port, int *alert) { int reg, rv = EC_SUCCESS; /* Clear soft irq bit */ rv |= tcpc_write(port, ANX74XX_REG_IRQ_EXT_SOURCE_3, ANX74XX_REG_CLEAR_SOFT_IRQ); /* Read TCPC Alert register1 */ rv |= tcpc_read(port, ANX74XX_REG_IRQ_EXT_SOURCE_1, ®); if (rv) return EC_ERROR_UNKNOWN; /* Clears interrupt bits */ rv |= tcpc_write(port, ANX74XX_REG_IRQ_EXT_SOURCE_1, reg); *alert = reg; rv = tcpc_read(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, ®); if (rv) return EC_ERROR_UNKNOWN; if (reg & ANX74XX_REG_IRQ_CC_MSG_INT) *alert |= ANX74XX_REG_ALERT_MSG_RECV; else *alert &= (~ANX74XX_REG_ALERT_MSG_RECV); if (reg & ANX74XX_REG_IRQ_CC_STATUS_INT) { *alert |= ANX74XX_REG_ALERT_CC_CHANGE; rv |= tcpc_write(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, reg & 0xfd); } else { *alert &= (~ANX74XX_REG_ALERT_CC_CHANGE); } if (reg & ANX74XX_REG_IRQ_GOOD_CRC_INT) { *alert |= ANX74XX_REG_ALERT_TX_ACK_RECV; rv |= tcpc_write(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, reg & 0xfb); } else { *alert &= (~ANX74XX_REG_ALERT_TX_ACK_RECV); } if (reg & ANX74XX_REG_IRQ_TX_FAIL_INT) { *alert |= ANX74XX_REG_ALERT_TX_MSG_ERROR; rv |= tcpc_write(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, reg & 0xf7); } /* Read TCPC Alert register2 */ rv |= tcpc_read(port, ANX74XX_REG_IRQ_EXT_SOURCE_2, ®); /* Clears interrupt bits */ rv |= tcpc_write(port, ANX74XX_REG_IRQ_EXT_SOURCE_2, reg); if (reg & ANX74XX_REG_EXT_HARD_RST) *alert |= ANX74XX_REG_ALERT_HARD_RST_RECV; else *alert &= (~ANX74XX_REG_ALERT_HARD_RST_RECV); return rv; }
static int anx7688_mux_set(int i2c_addr, mux_state_t mux_state) { int reg = 0; int rv, polarity; int port = i2c_addr; /* use port index in port_addr field */ rv = tcpc_read(port, TCPC_REG_CONFIG_STD_OUTPUT, ®); if (rv != EC_SUCCESS) return rv; reg &= ~TCPC_REG_CONFIG_STD_OUTPUT_MUX_MASK; if (mux_state & MUX_USB_ENABLED) reg |= TCPC_REG_CONFIG_STD_OUTPUT_MUX_USB; if (mux_state & MUX_DP_ENABLED) reg |= TCPC_REG_CONFIG_STD_OUTPUT_MUX_DP; /* ANX7688 needs to set bit0 */ rv = tcpc_read(port, TCPC_REG_TCPC_CTRL, &polarity); if (rv != EC_SUCCESS) return rv; /* copy the polarity from TCPC_CTRL[0], take care clear then set */ reg &= ~TCPC_REG_TCPC_CTRL_POLARITY(1); reg |= TCPC_REG_TCPC_CTRL_POLARITY(polarity); return tcpc_write(port, TCPC_REG_CONFIG_STD_OUTPUT, reg); }
static int anx74xx_read_pd_obj(int port, uint8_t *buf, int plen) { int rv = EC_SUCCESS, i; int reg, addr = ANX74XX_REG_PD_RX_DATA_OBJ; /* Read PD data objects from ANX */ for (i = 0; i < plen ; i++) { /* Register sequence changes for last two bytes, if * plen is greater than 26 */ if (i == 26) addr = ANX74XX_REG_PD_RX_DATA_OBJ_M; rv = tcpc_read(port, addr + i, ®); if (rv) break; buf[i] = reg; } /* Clear receive message interrupt bit(bit-0) */ rv |= tcpc_read(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, ®); rv |= tcpc_write(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, reg & (~0x01)); return rv; }
static int anx74xx_init_analog(int port) { int reg, rv = EC_SUCCESS; /* Analog settings for chip */ rv |= tcpc_write(port, ANX74XX_REG_HPD_CONTROL, ANX74XX_REG_HPD_OP_MODE); rv |= tcpc_write(port, ANX74XX_REG_HPD_CTRL_0, ANX74XX_REG_HPD_DEFAULT); if (rv) return rv; rv = tcpc_read(port, ANX74XX_REG_GPIO_CTRL_4_5, ®); if (rv) return rv; reg &= ANX74XX_REG_VBUS_GPIO_MODE; reg |= ANX74XX_REG_VBUS_OP_ENABLE; rv = tcpc_write(port, ANX74XX_REG_GPIO_CTRL_4_5, reg); if (rv) return rv; rv = tcpc_read(port, ANX74XX_REG_CC_SOFTWARE_CTRL, ®); if (rv) return rv; reg |= ANX74XX_REG_TX_MODE_ENABLE; rv = tcpc_write(port, ANX74XX_REG_CC_SOFTWARE_CTRL, reg); 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; return fusb302_send_message(port, header, data, buf, buf_pos); case TCPC_TX_HARD_RESET: state[port].tx_hard_reset_req = 1; /* Simply hit the SEND_HARD_RESET bit */ 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: /* Simply hit the BIST_MODE2 bit */ 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; }
static int measure_cc_pin_source(int port, int cc_measure) { int switches0_reg; int reg; int cc_lvl; /* 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; }
static int fusb302_tcpm_set_polarity(int port, int polarity) { /* Port polarity : 0 => CC1 is CC line, 1 => CC2 is CC line */ int reg; 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 anx74xx_tcpm_transmit(int port, enum tcpm_transmit_type type, uint16_t header, const uint32_t *data) { uint8_t len = 0; int ret = 0, reg = 0; switch (type) { /* ANX is aware of type */ case TCPC_TX_SOP: case TCPC_TX_SOP_PRIME: case TCPC_TX_SOP_PRIME_PRIME: len = PD_HEADER_CNT(header) * 4 + 2; ret = anx74xx_send_message(port, header, data, type, len); break; case TCPC_TX_HARD_RESET: /* Request HARD RESET */ tcpc_read(port, ANX74XX_REG_TX_CTRL_1, ®); reg |= ANX74XX_REG_TX_HARD_RESET_REQ; ret = tcpc_write(port, ANX74XX_REG_TX_CTRL_1, reg); break; case TCPC_TX_CABLE_RESET: /* Request CABLE RESET */ tcpc_read(port, ANX74XX_REG_TX_CTRL_1, ®); reg |= ANX74XX_REG_TX_CABLE_RESET_REQ; ret = tcpc_write(port, ANX74XX_REG_TX_CTRL_1, reg); break; case TCPC_TX_BIST_MODE_2: /* Request BIST MODE 2 */ reg = ANX74XX_REG_TX_BIST_START | ANX74XX_REG_TX_BIXT_FOREVER | (0x02 << 4); ret = tcpc_write(port, ANX74XX_REG_TX_BIST_CTRL, reg); msleep(1); ret = tcpc_write(port, ANX74XX_REG_TX_BIST_CTRL, reg | ANX74XX_REG_TX_BIST_ENABLE); msleep(30); tcpc_read(port, ANX74XX_REG_TX_BIST_CTRL, ®); ret = tcpc_write(port, ANX74XX_REG_TX_BIST_CTRL, reg | ANX74XX_REG_TX_BIST_STOP); ret = tcpc_write(port, ANX74XX_REG_TX_BIST_CTRL, reg & (~ANX74XX_REG_TX_BIST_STOP)); ret = tcpc_write(port, ANX74XX_REG_TX_BIST_CTRL, 0); break; default: return EC_ERROR_UNIMPLEMENTED; } return ret; }
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 { 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_select_rp_value(int port, int rp) { int reg; int rv; uint8_t vnc, rd; 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; return tcpc_write(port, TCPC_REG_CONTROL0, reg); }
static int tcpci_tcpm_get_cc(int port, int *cc1, int *cc2) { int status; int rv; rv = tcpc_read(port, TCPC_REG_CC_STATUS, &status); /* If tcpc read fails, return error */ if (rv) return rv; *cc1 = TCPC_REG_CC_STATUS_CC1(status); *cc2 = TCPC_REG_CC_STATUS_CC2(status); /* * If status is not open, then OR in termination to convert to * enum tcpc_cc_voltage_status. */ if (*cc1 != TYPEC_CC_VOLT_OPEN) *cc1 |= TCPC_REG_CC_STATUS_TERM(status) << 2; if (*cc2 != TYPEC_CC_VOLT_OPEN) *cc2 |= TCPC_REG_CC_STATUS_TERM(status) << 2; return rv; }
void tcpci_tcpc_alert(int port) { int status; /* Read the Alert register from the TCPC */ tcpm_alert_status(port, &status); /* * Clear alert status for everything except RX_STATUS, which shouldn't * be cleared until we have successfully retrieved message. */ if (status & ~TCPC_REG_ALERT_RX_STATUS) tcpc_write16(port, TCPC_REG_ALERT, status & ~TCPC_REG_ALERT_RX_STATUS); if (status & TCPC_REG_ALERT_CC_STATUS) { /* CC status changed, wake task */ task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0); } if (status & TCPC_REG_ALERT_POWER_STATUS) { int reg = 0; tcpc_read(port, TCPC_REG_POWER_STATUS_MASK, ®); if (reg == TCPC_REG_POWER_STATUS_MASK_ALL) { /* * If power status mask has been reset, then the TCPC * has reset. */ task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_TCPC_RESET, 0); } else { /* Read Power Status register */ tcpci_tcpm_get_power_status(port, ®); /* Update VBUS status */ tcpc_vbus[port] = reg & TCPC_REG_POWER_STATUS_VBUS_PRES ? 1 : 0; #if defined(CONFIG_USB_PD_VBUS_DETECT_TCPC) && defined(CONFIG_USB_CHARGER) /* Update charge manager with new VBUS state */ usb_charger_vbus_change(port, tcpc_vbus[port]); task_wake(PD_PORT_TO_TASK_ID(port)); #endif /* CONFIG_USB_PD_VBUS_DETECT_TCPC && CONFIG_USB_CHARGER */ } } if (status & TCPC_REG_ALERT_RX_STATUS) { /* message received */ task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_RX, 0); } if (status & TCPC_REG_ALERT_RX_HARD_RST) { /* hard reset received */ pd_execute_hard_reset(port); task_wake(PD_PORT_TO_TASK_ID(port)); } if (status & TCPC_REG_ALERT_TX_COMPLETE) { /* transmit complete */ pd_transmit_complete(port, status & TCPC_REG_ALERT_TX_SUCCESS ? TCPC_TX_COMPLETE_SUCCESS : TCPC_TX_COMPLETE_FAILED); } }
static int anx74xx_tcpm_get_vbus_level(int port) { int reg = 0; tcpc_read(port, ANX74XX_REG_ANALOG_STATUS, ®); return ((reg & ANX74XX_REG_VBUS_STATUS) ? 1 : 0); }
int tcpci_tcpm_init(int port) { int rv; int power_status; while (1) { rv = tcpc_read(port, TCPC_REG_POWER_STATUS, &power_status); /* * If read succeeds and the uninitialized bit is clear, then * initalization is complete, clear all alert bits and write * the initial alert mask. */ if (rv == EC_SUCCESS && !(power_status & TCPC_REG_POWER_STATUS_UNINIT)) { tcpc_write16(port, TCPC_REG_ALERT, 0xffff); /* Initialize power_status_mask */ init_power_status_mask(port); /* Update VBUS status */ tcpc_vbus[port] = power_status & TCPC_REG_POWER_STATUS_VBUS_PRES ? 1 : 0; return init_alert_mask(port); } msleep(10); } }
static void fusb302_flush_tx_fifo(int port) { int reg; tcpc_read(port, TCPC_REG_CONTROL0, ®); reg |= TCPC_REG_CONTROL0_TX_FLUSH; tcpc_write(port, TCPC_REG_CONTROL0, reg); }
void anx74xx_tcpc_clear_hpd_status(int port) { int reg; tcpc_read(port, ANX74XX_REG_HPD_CTRL_0, ®); reg &= 0xcf; tcpc_write(port, ANX74XX_REG_HPD_CTRL_0, reg); }
static void anx7688_update_hpd_enable(int port) { int status, reg, rv; rv = tcpc_read(port, ANX7688_REG_STATUS, &status); rv |= tcpc_read(port, ANX7688_REG_HPD, ®); if (rv) return; if (!(reg & ANX7688_REG_HPD_ENABLE) || !(status & ANX7688_REG_STATUS_LINK)) { reg &= ~ANX7688_REG_HPD_IRQ; tcpc_write(port, ANX7688_REG_HPD, (status & ANX7688_REG_STATUS_LINK) ? reg | ANX7688_REG_HPD_ENABLE : reg & ~ANX7688_REG_HPD_ENABLE); } }
static int fusb302_tcpm_get_vbus_level(int port) { int reg; /* Read status register */ tcpc_read(port, TCPC_REG_STATUS0, ®); return (reg & TCPC_REG_STATUS0_VBUSOK) ? 1 : 0; }
void anx74xx_tcpc_update_hpd_status(int port, int hpd_lvl, int hpd_irq) { int reg; tcpc_read(port, ANX74XX_REG_HPD_CTRL_0, ®); if (hpd_lvl) reg |= ANX74XX_REG_HPD_OUT_DATA; else reg &= ~ANX74XX_REG_HPD_OUT_DATA; tcpc_write(port, ANX74XX_REG_HPD_CTRL_0, reg); if (hpd_irq) { tcpc_read(port, ANX74XX_REG_HPD_CTRL_0, ®); reg &= ~ANX74XX_REG_HPD_OUT_DATA; tcpc_write(port, ANX74XX_REG_HPD_CTRL_0, reg); msleep(1); reg |= ANX74XX_REG_HPD_OUT_DATA; tcpc_write(port, ANX74XX_REG_HPD_CTRL_0, reg); } }
void anx74xx_tcpc_discharge_vbus(int port, int enable) { int reg; tcpc_read(port, ANX74XX_REG_HPD_CTRL_0, ®); if (enable) reg |= ANX74XX_REG_DISCHARGE_CTRL; else reg &= ~ANX74XX_REG_DISCHARGE_CTRL; tcpc_write(port, ANX74XX_REG_HPD_CTRL_0, reg); }
void anx74xx_tcpc_set_vbus(int port, int enable) { int reg; tcpc_read(port, ANX74XX_REG_GPIO_CTRL_4_5, ®); if (enable) reg |= ANX74XX_REG_SET_VBUS; else reg &= ~ANX74XX_REG_SET_VBUS; tcpc_write(port, ANX74XX_REG_GPIO_CTRL_4_5, reg); }
static int anx74xx_tcpm_set_msg_header(int port, int power_role, int data_role) { int rv = 0, reg; rv |= tcpc_read(port, ANX74XX_REG_TX_MSG_HEADER, ®); reg |= ((!!power_role) << ANX74XX_REG_PWR_ROLE_BIT_POS); reg |= ((!!data_role) << ANX74XX_REG_DATA_ROLE_BIT_POS); rv |= tcpc_write(port, ANX74XX_REG_TX_MSG_HEADER, reg); return rv; }
int anx74xx_tcpm_init(int port) { int rv = 0, reg; memset(anx, 0, CONFIG_USB_PD_PORT_COUNT*sizeof(struct anx_state)); /* Bring chip in normal mode to work */ anx74xx_set_power_mode(port, ANX74XX_NORMAL_MODE); /* Set Pd dual role mode */ pd_set_dual_role(PD_DRP_TOGGLE_ON); /* Initialize analog section of ANX */ rv |= anx74xx_init_analog(port); /* disable all interrupts */ rv |= tcpc_write(port, ANX74XX_REG_IRQ_EXT_MASK_1, ANX74XX_REG_CLEAR_SET_BITS); /* Initialize interrupt polarity */ rv |= tcpc_write(port, ANX74XX_REG_IRQ_STATUS, ANX74XX_INT_ACTIVE_POLARITY); /* unmask interrupts */ rv |= tcpc_read(port, ANX74XX_REG_IRQ_EXT_MASK_1, ®); reg &= (~ANX74XX_REG_ALERT_TX_MSG_ERROR); reg &= (~ANX74XX_REG_ALERT_TX_CABLE_RESETOK); reg &= (~ANX74XX_REG_ALERT_TX_HARD_RESETOK); rv |= tcpc_write(port, ANX74XX_REG_IRQ_EXT_MASK_1, reg); rv |= tcpc_read(port, ANX74XX_REG_IRQ_EXT_MASK_2, ®); reg &= (~ANX74XX_REG_EXT_HARD_RST); rv |= tcpc_write(port, ANX74XX_REG_IRQ_EXT_MASK_2, reg); /* HPD pin output enable*/ rv |= tcpc_write(port, ANX74XX_REG_HPD_CTRL_0, ANX74XX_REG_HPD_DEFAULT); if (rv) return EC_ERROR_UNKNOWN; return EC_SUCCESS; }
static int anx74xx_tcpm_set_cc(int port, int pull) { int rv = EC_SUCCESS; int reg; /* Enable CC software Control */ rv |= tcpc_read(port, ANX74XX_REG_CC_SOFTWARE_CTRL, ®); if (rv) return EC_ERROR_UNKNOWN; reg |= ANX74XX_REG_CC_SW_CTRL_ENABLE; rv |= tcpc_write(port, ANX74XX_REG_CC_SOFTWARE_CTRL, reg); if (rv) return EC_ERROR_UNKNOWN; switch (pull) { case TYPEC_CC_RP: /* Enable Rp */ rv |= tcpc_read(port, ANX74XX_REG_ANALOG_STATUS, ®); if (rv) return EC_ERROR_UNKNOWN; reg |= ANX74XX_REG_CC_PULL_RP; rv |= tcpc_write(port, ANX74XX_REG_ANALOG_STATUS, reg); anx[port].pull = 1; break; case TYPEC_CC_RD: /* Enable Rd */ rv |= tcpc_read(port, ANX74XX_REG_ANALOG_STATUS, ®); if (rv) return EC_ERROR_UNKNOWN; reg &= ANX74XX_REG_CC_PULL_RD; rv |= tcpc_write(port, ANX74XX_REG_ANALOG_STATUS, reg); anx[port].pull = 0; break; default: rv = EC_ERROR_UNKNOWN; break; } return rv; }
static void fusb302_auto_goodcrc_enable(int port, int enable) { int reg; 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); }
static void anx74xx_tcpm_set_auto_good_crc(int port, int enable) { int reg; if (enable) { /* Set default header for Good CRC auto reply */ tcpc_read(port, ANX74XX_REG_TX_MSG_HEADER, ®); reg |= (PD_REV20 << ANX74XX_REG_SPEC_REV_BIT_POS); reg |= ANX74XX_REG_AUTO_GOODCRC_EN; tcpc_write(port, ANX74XX_REG_TX_MSG_HEADER, reg); reg = ANX74XX_REG_ENABLE_GOODCRC; tcpc_write(port, ANX74XX_REG_TX_AUTO_GOODCRC_2, reg); /* Set bit-0 if enable, reset bit-0 if disable */ tcpc_read(port, ANX74XX_REG_TX_AUTO_GOODCRC_1, ®); reg |= ANX74XX_REG_AUTO_GOODCRC_EN; } else { reg &= ~ANX74XX_REG_AUTO_GOODCRC_EN; tcpc_write(port, ANX74XX_REG_TX_AUTO_GOODCRC_2, 0); } tcpc_write(port, ANX74XX_REG_TX_AUTO_GOODCRC_1, reg); }
static int anx74xx_tcpm_set_rx_enable(int port, int enable) { int reg, rv = 0; rv |= tcpc_read(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG_MASK, ®); if (enable) reg &= ~(ANX74XX_REG_IRQ_CC_MSG_INT); else/* Disable RX message by masking interrupt */ reg |= (ANX74XX_REG_IRQ_CC_MSG_INT); anx74xx_tcpm_set_auto_good_crc(port, enable); rv |= tcpc_write(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG_MASK, reg); return rv; }
static int anx74xx_tcpm_get_message(int port, uint32_t *payload, int *head) { int reg = 0, rv = EC_SUCCESS; int len = 0; /* Fetch the header */ rv |= tcpc_read16(port, ANX74XX_REG_PD_HEADER, ®); if (rv) { *head = 0; /* Clear receive message interrupt bit(bit-0) */ tcpc_read(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, ®); tcpc_write(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, reg & (~0x01)); return EC_ERROR_UNKNOWN; } *head = reg; len = PD_HEADER_CNT(*head) * 4; if (!len) { /* Clear receive message interrupt bit(bit-0) */ tcpc_read(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, ®); tcpc_write(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, reg & (~0x01)); return EC_SUCCESS; } /* Receive message : assuming payload have enough * memory allocated */ rv |= anx74xx_read_pd_obj(port, (uint8_t *)payload, len); if (rv) { *head = 0; return EC_ERROR_UNKNOWN; } return rv; }
static int anx74xx_set_mux(int port, int polarity) { int reg, rv = EC_SUCCESS; rv = tcpc_read(port, ANX74XX_REG_ANALOG_CTRL_2, ®); if (rv) return EC_ERROR_UNKNOWN; if (polarity) { reg |= ANX74XX_REG_AUX_SWAP_SET_CC2; reg &= ~ANX74XX_REG_AUX_SWAP_SET_CC1; } else { reg |= ANX74XX_REG_AUX_SWAP_SET_CC1; reg &= ~ANX74XX_REG_AUX_SWAP_SET_CC2; } rv = tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_2, reg); return rv; }
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; }