Esempio n. 1
0
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, &reg);
	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, &reg);
	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, &reg);

	/* 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;
}
Esempio n. 2
0
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, &reg);
	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);
}
Esempio n. 3
0
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, &reg);
		if (rv)
			break;
		buf[i] = reg;
	}

	/* Clear receive message interrupt bit(bit-0) */
	rv |= tcpc_read(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, &reg);
	rv |= tcpc_write(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG,
			 reg & (~0x01));

	return rv;
}
Esempio n. 4
0
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, &reg);
	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, &reg);
	if (rv)
		return rv;
	reg |= ANX74XX_REG_TX_MODE_ENABLE;
	rv = tcpc_write(port, ANX74XX_REG_CC_SOFTWARE_CTRL, reg);

	return rv;
}
Esempio n. 5
0
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);
		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);
		reg |= TCPC_REG_CONTROL1_BIST_MODE2;
		tcpc_write(port, TCPC_REG_CONTROL1, reg);
		break;
	default:
		return EC_ERROR_UNIMPLEMENTED;
	}

	return 0;
}
Esempio n. 6
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, &reg);
	/* 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, &reg);

	/* 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, &reg);

		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;
}
Esempio n. 7
0
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, &reg);

	/* 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, &reg);

	/* 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;
}
Esempio n. 8
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);
		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);
		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, &reg);
		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;
}
Esempio n. 9
0
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, &reg);

		/* 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;
}
Esempio n. 10
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, &reg);
	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);
}
Esempio n. 11
0
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;
}
Esempio n. 12
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);
	}
}
Esempio n. 13
0
static int anx74xx_tcpm_get_vbus_level(int port)
{
	int reg = 0;

	tcpc_read(port, ANX74XX_REG_ANALOG_STATUS, &reg);
	return ((reg & ANX74XX_REG_VBUS_STATUS) ? 1 : 0);
}
Esempio n. 14
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);
	}
}
Esempio n. 15
0
static void fusb302_flush_tx_fifo(int port)
{
	int reg;

	tcpc_read(port, TCPC_REG_CONTROL0, &reg);
	reg |= TCPC_REG_CONTROL0_TX_FLUSH;
	tcpc_write(port, TCPC_REG_CONTROL0, reg);
}
Esempio n. 16
0
void anx74xx_tcpc_clear_hpd_status(int port)
{
	int reg;

	tcpc_read(port, ANX74XX_REG_HPD_CTRL_0, &reg);
	reg &= 0xcf;
	tcpc_write(port, ANX74XX_REG_HPD_CTRL_0, reg);
}
Esempio n. 17
0
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, &reg);
	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);
	}
}
Esempio n. 18
0
static int fusb302_tcpm_get_vbus_level(int port)
{
	int reg;

	/* Read status register */
	tcpc_read(port, TCPC_REG_STATUS0, &reg);

	return (reg & TCPC_REG_STATUS0_VBUSOK) ? 1 : 0;
}
Esempio n. 19
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, &reg);
	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);
		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);
	}
}
Esempio n. 20
0
void anx74xx_tcpc_discharge_vbus(int port, int enable)
{
	int reg;

	tcpc_read(port, ANX74XX_REG_HPD_CTRL_0, &reg);
	if (enable)
		reg |= ANX74XX_REG_DISCHARGE_CTRL;
	else
		reg &= ~ANX74XX_REG_DISCHARGE_CTRL;
	tcpc_write(port, ANX74XX_REG_HPD_CTRL_0, reg);
}
Esempio n. 21
0
void anx74xx_tcpc_set_vbus(int port, int enable)
{
	int reg;

	tcpc_read(port, ANX74XX_REG_GPIO_CTRL_4_5, &reg);
	if (enable)
		reg |= ANX74XX_REG_SET_VBUS;
	else
		reg &= ~ANX74XX_REG_SET_VBUS;
	tcpc_write(port, ANX74XX_REG_GPIO_CTRL_4_5, reg);
}
Esempio n. 22
0
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);
	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;
}
Esempio n. 23
0
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);
	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);
	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;
}
Esempio n. 24
0
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, &reg);
	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, &reg);
		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, &reg);
		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;
}
Esempio n. 25
0
static void fusb302_auto_goodcrc_enable(int port, int enable)
{
	int reg;

	tcpc_read(port,	TCPC_REG_SWITCHES1, &reg);

	if (enable)
		reg |= TCPC_REG_SWITCHES1_AUTO_GCRC;
	else
		reg &= ~TCPC_REG_SWITCHES1_AUTO_GCRC;

	tcpc_write(port, TCPC_REG_SWITCHES1, reg);
}
Esempio n. 26
0
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);
		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);
		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);
}
Esempio n. 27
0
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, &reg);
	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;
}
Esempio n. 28
0
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, &reg);
	if (rv) {
		*head = 0;
		/* Clear receive message interrupt bit(bit-0) */
		tcpc_read(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, &reg);
		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, &reg);
		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;
}
Esempio n. 29
0
static int anx74xx_set_mux(int port, int polarity)
{
	int reg, rv = EC_SUCCESS;

	rv = tcpc_read(port, ANX74XX_REG_ANALOG_CTRL_2, &reg);
	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;
}
Esempio n. 30
0
static int fusb302_tcpm_set_msg_header(int port, int power_role, int data_role)
{
	int reg;

	tcpc_read(port, TCPC_REG_SWITCHES1, &reg);

	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;
}