示例#1
0
int chip_i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_bytes,
		  uint8_t *in, int in_bytes, int flags)
{
	int rv = EC_SUCCESS;
	int i;
	int xfer_start = flags & I2C_XFER_START;
	int xfer_stop = flags & I2C_XFER_STOP;

#if defined(CONFIG_I2C_SCL_GATE_ADDR) && defined(CONFIG_I2C_SCL_GATE_PORT)
	if (port == CONFIG_I2C_SCL_GATE_PORT &&
	    slave_addr == CONFIG_I2C_SCL_GATE_ADDR)
		gpio_set_level(CONFIG_I2C_SCL_GATE_GPIO, 1);
#endif

	ASSERT(out || !out_bytes);
	ASSERT(in || !in_bytes);

	/* Clear status */
	if (xfer_start) {
		STM32_I2C_ICR(port) = STM32_I2C_ICR_ALL;
		STM32_I2C_CR2(port) = 0;
	}

	if (out_bytes || !in_bytes) {
		/*
		 * Configure the write transfer: if we are stopping then set
		 * AUTOEND bit to automatically set STOP bit after NBYTES.
		 * if we are not stopping, set RELOAD bit so that we can load
		 * NBYTES again. if we are starting, then set START bit.
		 */
		STM32_I2C_CR2(port) =  ((out_bytes & 0xFF) << 16)
			| slave_addr
			| ((in_bytes == 0 && xfer_stop) ?
				STM32_I2C_CR2_AUTOEND : 0)
			| ((in_bytes == 0 && !xfer_stop) ?
				STM32_I2C_CR2_RELOAD : 0)
			| (xfer_start ? STM32_I2C_CR2_START : 0);

		for (i = 0; i < out_bytes; i++) {
			rv = wait_isr(port, STM32_I2C_ISR_TXIS);
			if (rv)
				goto xfer_exit;
			/* Write next data byte */
			STM32_I2C_TXDR(port) = out[i];
		}
	}
	if (in_bytes) {
		if (out_bytes) { /* wait for completion of the write */
			rv = wait_isr(port, STM32_I2C_ISR_TC);
			if (rv)
				goto xfer_exit;
		}
		/*
		 * Configure the read transfer: if we are stopping then set
		 * AUTOEND bit to automatically set STOP bit after NBYTES.
		 * if we are not stopping, set RELOAD bit so that we can load
		 * NBYTES again. if we were just transmitting, we need to
		 * set START bit to send (re)start and begin read transaction.
		 */
		STM32_I2C_CR2(port) = ((in_bytes & 0xFF) << 16)
			| STM32_I2C_CR2_RD_WRN | slave_addr
			| (xfer_stop ? STM32_I2C_CR2_AUTOEND : 0)
			| (!xfer_stop ? STM32_I2C_CR2_RELOAD : 0)
			| (out_bytes || xfer_start ? STM32_I2C_CR2_START : 0);

		for (i = 0; i < in_bytes; i++) {
			/* Wait for receive buffer not empty */
			rv = wait_isr(port, STM32_I2C_ISR_RXNE);
			if (rv)
				goto xfer_exit;

			in[i] = STM32_I2C_RXDR(port);
		}
	}

	/*
	 * If we are stopping, then we already set AUTOEND and we should
	 * wait for the stop bit to be transmitted. Otherwise, we set
	 * the RELOAD bit and we should wait for transfer complete
	 * reload (TCR).
	 */
	rv = wait_isr(port, xfer_stop ? STM32_I2C_ISR_STOP : STM32_I2C_ISR_TCR);
	if (rv)
		goto xfer_exit;

xfer_exit:
	/* clear status */
	if (xfer_stop)
		STM32_I2C_ICR(port) = STM32_I2C_ICR_ALL;

	/* On error, queue a stop condition */
	if (rv) {
		/* queue a STOP condition */
		STM32_I2C_CR2(port) |= STM32_I2C_CR2_STOP;
		/* wait for it to take effect */
		/* Wait up to 100 us for bus idle */
		for (i = 0; i < 10; i++) {
			if (!(STM32_I2C_ISR(port) & STM32_I2C_ISR_BUSY))
				break;
			udelay(10);
		}

		/*
		 * Allow bus to idle for at least one 100KHz clock = 10 us.
		 * This allows slaves on the bus to detect bus-idle before
		 * the next start condition.
		 */
		udelay(10);
		/* re-initialize the controller */
		STM32_I2C_CR2(port) = 0;
		STM32_I2C_CR1(port) &= ~STM32_I2C_CR1_PE;
		udelay(10);
		STM32_I2C_CR1(port) |= STM32_I2C_CR1_PE;
	}

#ifdef CONFIG_I2C_SCL_GATE_ADDR
	if (port == CONFIG_I2C_SCL_GATE_PORT &&
	    slave_addr == CONFIG_I2C_SCL_GATE_ADDR)
		gpio_set_level(CONFIG_I2C_SCL_GATE_GPIO, 0);
#endif

	return rv;
}
示例#2
0
int i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_bytes,
	     uint8_t *in, int in_bytes, int flags)
{
	int rv = EC_SUCCESS;
	int i;

	ASSERT(out || !out_bytes);
	ASSERT(in || !in_bytes);

	/* Clear status */
	STM32_I2C_ICR(port) = 0x3F38;
	STM32_I2C_CR2(port) = 0;

	if (out_bytes || !in_bytes) {
		/* Configure the write transfer */
		STM32_I2C_CR2(port) =  ((out_bytes & 0xFF) << 16)
			| slave_addr
			| (in_bytes == 0 ? STM32_I2C_CR2_AUTOEND : 0);
		/* let's go ... */
		STM32_I2C_CR2(port) |= STM32_I2C_CR2_START;

		for (i = 0; i < out_bytes; i++) {
			rv = wait_isr(port, STM32_I2C_ISR_TXIS);
			if (rv)
				goto xfer_exit;
			/* Write next data byte */
			STM32_I2C_TXDR(port) = out[i];
		}
	}
	if (in_bytes) {
		if (out_bytes) { /* wait for completion of the write */
			rv = wait_isr(port, STM32_I2C_ISR_TC);
			if (rv)
				goto xfer_exit;
		}
		/* Configure the read transfer */
		STM32_I2C_CR2(port) = ((in_bytes & 0xFF) << 16)
				    | STM32_I2C_CR2_RD_WRN | slave_addr
				    | STM32_I2C_CR2_AUTOEND;
		/* START or repeated start */
		STM32_I2C_CR2(port) |= STM32_I2C_CR2_START;

		for (i = 0; i < in_bytes; i++) {
			/* Wait for receive buffer not empty */
			rv = wait_isr(port, STM32_I2C_ISR_RXNE);
			if (rv)
				goto xfer_exit;

			in[i] = STM32_I2C_RXDR(port);
		}
	}
	rv = wait_isr(port, STM32_I2C_ISR_STOP);
	if (rv)
		goto xfer_exit;

xfer_exit:
	/* clear status */
	STM32_I2C_ICR(port) = 0x3F38;
	/* On error, queue a stop condition */
	if (rv) {
		/* queue a STOP condition */
		STM32_I2C_CR2(port) |= STM32_I2C_CR2_STOP;
		/* wait for it to take effect */
		/* Wait up to 100 us for bus idle */
		for (i = 0; i < 10; i++) {
			if (!(STM32_I2C_ISR(port) & STM32_I2C_ISR_BUSY))
				break;
			udelay(10);
		}

		/*
		 * Allow bus to idle for at least one 100KHz clock = 10 us.
		 * This allows slaves on the bus to detect bus-idle before
		 * the next start condition.
		 */
		udelay(10);
		/* re-initialize the controller */
		STM32_I2C_CR2(port) = 0;
		STM32_I2C_CR1(port) &= ~STM32_I2C_CR1_PE;
		udelay(10);
		STM32_I2C_CR1(port) |= STM32_I2C_CR1_PE;
	}

	return rv;
}
示例#3
0
static void i2c_event_handler(int port)
{
	int i2c_isr;
	static int rx_pending, buf_idx;
#ifdef TCPCI_I2C_SLAVE
	int addr;
#endif

	i2c_isr = STM32_I2C_ISR(port);

	/*
	 * Check for error conditions. Note, arbitration loss and bus error
	 * are the only two errors we can get as a slave allowing clock
	 * stretching and in non-SMBus mode.
	 */
	if (i2c_isr & (STM32_I2C_ISR_ARLO | STM32_I2C_ISR_BERR)) {
		rx_pending = 0;
		tx_pending = 0;

		/* Make sure TXIS interrupt is disabled */
		STM32_I2C_CR1(port) &= ~STM32_I2C_CR1_TXIE;

		/* Clear error status bits */
		STM32_I2C_ICR(port) |= STM32_I2C_ICR_BERRCF |
				STM32_I2C_ICR_ARLOCF;
	}

	/* Transfer matched our slave address */
	if (i2c_isr & STM32_I2C_ISR_ADDR) {
		if (i2c_isr & STM32_I2C_ISR_DIR) {
			/* Transmitter slave */
			/* Clear transmit buffer */
			STM32_I2C_ISR(port) |= STM32_I2C_ISR_TXE;

			/* Enable txis interrupt to start response */
			STM32_I2C_CR1(port) |= STM32_I2C_CR1_TXIE;
		} else {
			/* Receiver slave */
			buf_idx = 0;
			rx_pending = 1;
		}

		/* Clear ADDR bit by writing to ADDRCF bit */
		STM32_I2C_ICR(port) |= STM32_I2C_ICR_ADDRCF;
		/* Inhibit stop mode when addressed until STOPF flag is set */
		disable_sleep(SLEEP_MASK_I2C_SLAVE);
	}

	/* Stop condition on bus */
	if (i2c_isr & STM32_I2C_ISR_STOP) {
#ifdef TCPCI_I2C_SLAVE
		/*
		 * if tcpc is being addressed, and we received a stop
		 * while rx is pending, then this is a write only to
		 * the tcpc.
		 */
		addr = STM32_I2C_ISR_ADDCODE(STM32_I2C_ISR(port));
		if (rx_pending && ADDR_IS_TCPC(addr))
			i2c_process_tcpc_command(0, addr, buf_idx);
#endif
		rx_pending = 0;
		tx_pending = 0;

		/* Make sure TXIS interrupt is disabled */
		STM32_I2C_CR1(port) &= ~STM32_I2C_CR1_TXIE;

		/* Clear STOPF bit by writing to STOPCF bit */
		STM32_I2C_ICR(port) |= STM32_I2C_ICR_STOPCF;

		/* No longer inhibit deep sleep after stop condition */
		enable_sleep(SLEEP_MASK_I2C_SLAVE);
	}

	/* Receiver full event */
	if (i2c_isr & STM32_I2C_ISR_RXNE)
		host_buffer[buf_idx++] = STM32_I2C_RXDR(port);

	/* Master requested STOP or RESTART */
	if (i2c_isr & STM32_I2C_ISR_NACK) {
		/* Make sure TXIS interrupt is disabled */
		STM32_I2C_CR1(port) &= ~STM32_I2C_CR1_TXIE;
		/* Clear NACK */
		STM32_I2C_ICR(port) |= STM32_I2C_ICR_NACKCF;
		/* Resend last byte on RESTART */
		if (port == I2C_PORT_EC && tx_index)
			tx_index--;
	}

	/* Transmitter empty event */
	if (i2c_isr & STM32_I2C_ISR_TXIS) {
		if (port == I2C_PORT_EC) { /* host is waiting for PD response */
			if (tx_pending) {
				if (tx_index < tx_end) {
					STM32_I2C_TXDR(port) =
						host_buffer[tx_index++];
				} else {
					STM32_I2C_TXDR(port) = 0xec;
					/*
					 * Set tx_index = 0 to prevent NACK
					 * handler resending last buffer byte.
					 */
					tx_index = 0;
					tx_end = 0;
					/* No pending data */
					tx_pending = 0;
				}
			} else if (rx_pending) {
				host_i2c_resp_port = port;
				/*
				 * Disable TXIS interrupt, transmission will
				 * be prepared by host command task.
				 */
				STM32_I2C_CR1(port) &= ~STM32_I2C_CR1_TXIE;

#ifdef TCPCI_I2C_SLAVE
				addr = STM32_I2C_ISR_ADDCODE(
					STM32_I2C_ISR(port));
				if (ADDR_IS_TCPC(addr))
					i2c_process_tcpc_command(1, addr,
								 buf_idx);
				else
#endif
					i2c_process_command();

				/* Reset host buffer after end of transfer */
				rx_pending = 0;
				tx_pending = 1;
			} else {
				STM32_I2C_TXDR(port) = 0xec;
			}
		}
	}
}