static int anx7688_init(int port) { int rv = 0; int mask = 0; /* * 7688 POWER_STATUS[6] is not reliable for tcpci_tcpm_init() to poll * due to it is default 0 in HW, and we cannot write TCPC until it is * ready, or something goes wrong. (Issue 52772) * Instead we poll TCPC 0x50:0xe7 bit6 here to make sure bootdone is * ready(50ms). Then PD main flow can process cc debounce in 50ms ~ * 100ms to follow cts. */ while (1) { rv = i2c_read8(I2C_PORT_TCPC, ANX7688_USBC_ADDR, ANX7688_REG_RAMCTRL, &mask); if (rv == EC_SUCCESS && (mask & ANX7688_REG_RAMCTRL_BOOT_DONE)) break; msleep(10); } rv = tcpci_tcpm_drv.init(port); if (rv) return rv; rv = tcpc_read16(port, TCPC_REG_ALERT_MASK, &mask); if (rv) return rv; /* enable vendor specific alert */ mask |= ANX7688_VENDOR_ALERT; rv = tcpc_write16(port, TCPC_REG_ALERT_MASK, mask); return rv; }
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); } }
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 tcpci_tcpm_transmit(int port, enum tcpm_transmit_type type, uint16_t header, const uint32_t *data) { int reg = TCPC_REG_TX_DATA; int rv, cnt = 4*PD_HEADER_CNT(header); /* TX_BYTE_CNT includes 2 bytes for message header */ rv = tcpc_write(port, TCPC_REG_TX_BYTE_CNT, cnt + 2); rv |= tcpc_write16(port, TCPC_REG_TX_HDR, header); /* If tcpc read fails, return error */ if (rv) return rv; if (cnt > 0) { tcpc_lock(port, 1); rv = tcpc_xfer(port, (uint8_t *)®, 1, NULL, 0, I2C_XFER_START); rv |= tcpc_xfer(port, (uint8_t *)data, cnt, NULL, 0, I2C_XFER_STOP); tcpc_lock(port, 0); } /* If tcpc read fails, return error */ if (rv) return rv; rv = tcpc_write(port, TCPC_REG_TRANSMIT, TCPC_REG_TRANSMIT_SET(type)); return rv; }
static int init_alert_mask(int port) { uint16_t mask; int rv; /* * Create mask of alert events that will cause the TCPC to * signal the TCPM via the Alert# gpio line. */ mask = TCPC_REG_ALERT_TX_SUCCESS | TCPC_REG_ALERT_TX_FAILED | TCPC_REG_ALERT_TX_DISCARDED | TCPC_REG_ALERT_RX_STATUS | TCPC_REG_ALERT_RX_HARD_RST | TCPC_REG_ALERT_CC_STATUS #ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC | TCPC_REG_ALERT_POWER_STATUS #endif ; /* Set the alert mask in TCPC */ rv = tcpc_write16(port, TCPC_REG_ALERT_MASK, mask); return rv; }
static int tcpci_tcpm_get_message(int port, uint32_t *payload, int *head) { int rv, cnt, reg = TCPC_REG_RX_DATA; rv = tcpc_read(port, TCPC_REG_RX_BYTE_CNT, &cnt); rv |= tcpc_read16(port, TCPC_REG_RX_HDR, (int *)head); if (rv == EC_SUCCESS && cnt > 0) { tcpc_lock(port, 1); rv = tcpc_xfer(port, (uint8_t *)®, 1, (uint8_t *)payload, cnt, I2C_XFER_SINGLE); tcpc_lock(port, 0); } /* Read complete, clear RX status alert bit */ tcpc_write16(port, TCPC_REG_ALERT, TCPC_REG_ALERT_RX_STATUS); return rv; }