/* 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. */ /* TCPM for MCU also running TCPC */ #include "task.h" #include "tcpm/tcpci.h" #include "tcpm/tcpm.h" #include "usb_pd.h" #include "usb_pd_tcpc.h" #include "usb_pd_tcpm.h" 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; /* Set the alert mask in TCPC */ rv = tcpc_alert_mask_set(port, mask); return rv; } static int init_power_status_mask(int port) { return tcpc_set_power_status_mask(port, 0); } int tcpm_init(int port) { int rv; tcpc_init(port); rv = init_alert_mask(port); if (rv) return rv; return init_power_status_mask(port); } int tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1, enum tcpc_cc_voltage_status *cc2) { return tcpc_get_cc(port, cc1, cc2); } int tcpm_select_rp_value(int port, int rp) { return tcpc_select_rp_value(port, rp); } int tcpm_set_cc(int port, int pull) { return tcpc_set_cc(port, pull); } int tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity) { return tcpc_set_polarity(port, polarity_rm_dts(polarity)); } int tcpm_set_vconn(int port, int enable) { return tcpc_set_vconn(port, enable); } int tcpm_set_msg_header(int port, int power_role, int data_role) { return tcpc_set_msg_header(port, power_role, data_role); } static int tcpm_alert_status(int port, int *alert) { /* Read TCPC Alert register */ return tcpc_alert_status(port, alert); } int tcpm_set_rx_enable(int port, int enable) { return tcpc_set_rx_enable(port, enable); } void tcpm_enable_auto_discharge_disconnect(int port, int enable) { } int tcpm_has_pending_message(int port) { return !rx_buf_is_empty(port); } int tcpm_dequeue_message(int port, uint32_t *payload, int *head) { int ret = tcpc_get_message(port, payload, head); /* Read complete, clear RX status alert bit */ tcpc_alert_status_clear(port, TCPC_REG_ALERT_RX_STATUS); return ret; } void tcpm_clear_pending_messages(int port) { rx_buf_clear(port); } int tcpm_transmit(int port, enum tcpci_msg_type type, uint16_t header, const uint32_t *data) { return tcpc_transmit(port, type, header, data); } void 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_alert_status_clear(port, 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); } if (status & TCPC_REG_ALERT_RX_STATUS) { /* * message received. since TCPC is compiled in, we * already woke the PD task up from the phy layer via * pd_rx_event(), so we don't need to wake it again. */ } if (status & TCPC_REG_ALERT_RX_HARD_RST) { /* hard reset received */ task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_RX_HARD_RESET); } 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); } }