blob: c407e099fb94ada5f9f90fb11e0f9335957c7a30 [file] [log] [blame]
/* 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 "tcpci.h"
#include "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);
}
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 tcpm_transmit_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);
}
}