Ejemplo n.º 1
0
void anx74xx_tcpc_alert(int port)
{
	int status;

	/* Check the alert status */
	if (anx74xx_alert_status(port, &status))
		status = 0;
	if (status) {

		if (status & ANX74XX_REG_ALERT_CC_CHANGE) {
			/* CC status changed, wake task */
			task_set_event(PD_PORT_TO_TASK_ID(port),
					PD_EVENT_CC, 0);
		}

		/* If alert is to receive a message */
		if (status & ANX74XX_REG_ALERT_MSG_RECV) {
			/* Set a PD_EVENT_RX */
			task_set_event(PD_PORT_TO_TASK_ID(port),
						PD_EVENT_RX, 0);
		}
		if (status & ANX74XX_REG_ALERT_TX_ACK_RECV) {
			/* Inform PD about this TX success */
			pd_transmit_complete(port,
						TCPC_TX_COMPLETE_SUCCESS);
		}
		if (status & ANX74XX_REG_ALERT_TX_MSG_ERROR) {
			/* let PD does not wait for this */
			pd_transmit_complete(port,
					      TCPC_TX_COMPLETE_FAILED);
		}
		if (status & ANX74XX_REG_ALERT_TX_CABLE_RESETOK) {
			/* ANX hardware clears the request bit */
			pd_transmit_complete(port,
					      TCPC_TX_COMPLETE_SUCCESS);
		}
		if (status & ANX74XX_REG_ALERT_TX_HARD_RESETOK) {
			/* ANX hardware clears the request bit */
			pd_transmit_complete(port,
					     TCPC_TX_COMPLETE_SUCCESS);
		}
		if (status & ANX74XX_REG_ALERT_HARD_RST_RECV) {
			/* hard reset received */
			pd_execute_hard_reset(port);
			task_wake(PD_PORT_TO_TASK_ID(port));
		}
	}
}
Ejemplo n.º 2
0
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)
		i2c_write16(I2C_PORT_TCPC, I2C_ADDR_TCPC(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_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);
	}
}
Ejemplo n.º 3
0
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, &reg);

		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, &reg);
			/* 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);
	}
}
Ejemplo n.º 4
0
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, 0);
	}
	if (status & TCPC_REG_ALERT_RX_STATUS) {
		/*
		 * message received. since TCPC is compiled in, we
		 * already received PD_EVENT_RX from phy layer in
		 * pd_rx_event(), so we don't need to set another
		 * event.
		 */
	}
	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);
	}
}
Ejemplo n.º 5
0
void fusb302_tcpc_alert(int port)
{
	/* interrupt has been received */
	int interrupt;
	int interrupta;
	int interruptb;
	int reg;
	int toggle_answer;
	int head;
	uint32_t payload[7];

	/* reading interrupt registers clears them */

	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 */
		state[port].tx_hard_reset_req = 0;
		pd_transmit_complete(port, TCPC_TX_COMPLETE_FAILED);
	}

	if (interrupta & TCPC_REG_INTERRUPTA_TX_SUCCESS) {
		/*
		 * Sent packet was acknowledged with a GoodCRC,
		 * so remove GoodCRC message from FIFO.
		 */
		tcpm_get_message(port, payload, &head);

		pd_transmit_complete(port, TCPC_TX_COMPLETE_SUCCESS);
	}

	if (interrupta & TCPC_REG_INTERRUPTA_TOGDONE) {
		/* Don't allow other tasks to change CC PUs */
		mutex_lock(&state[port].set_cc_lock);
		/* If our toggle request is obsolete then we're done */
		if (state[port].dfp_toggling_on) {
			/* read what 302 settled on for an answer...*/
			tcpc_read(port, TCPC_REG_STATUS1A, &reg);
			reg = reg >> TCPC_REG_STATUS1A_TOGSS_POS;
			reg = reg & TCPC_REG_STATUS1A_TOGSS_MASK;

			toggle_answer = reg;

			/* Turn off toggle so we can take over the switches */
			tcpc_read(port, TCPC_REG_CONTROL2, &reg);
			reg &= ~TCPC_REG_CONTROL2_TOGGLE;
			tcpc_write(port, TCPC_REG_CONTROL2, reg);

			switch (toggle_answer) {
			case TCPC_REG_STATUS1A_TOGSS_SRC1:
				state[port].togdone_pullup_cc1 = 1;
				state[port].togdone_pullup_cc2 = 0;
				break;
			case TCPC_REG_STATUS1A_TOGSS_SRC2:
				state[port].togdone_pullup_cc1 = 0;
				state[port].togdone_pullup_cc2 = 1;
				break;
			case TCPC_REG_STATUS1A_TOGSS_SNK1:
			case TCPC_REG_STATUS1A_TOGSS_SNK2:
			case TCPC_REG_STATUS1A_TOGSS_AA:
				state[port].togdone_pullup_cc1 = 0;
				state[port].togdone_pullup_cc2 = 0;
				break;
			default:
				/* TODO: should never get here, but? */
				ASSERT(0);
				break;
			}

			/* enable the pull-up we know to be necessary */
			tcpc_read(port, TCPC_REG_SWITCHES0, &reg);

			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].togdone_pullup_cc1 ?
				       TCPC_REG_SWITCHES0_VCONN_CC2 :
				       TCPC_REG_SWITCHES0_VCONN_CC1;

			tcpc_write(port, TCPC_REG_SWITCHES0, reg);
			/* toggle done */
			state[port].dfp_toggling_on = 0;
		}