static void i2c_init_port(unsigned int port) { const int i2c_clock_bit[] = {21, 22}; if (!(STM32_RCC_APB1ENR & (1 << i2c_clock_bit[port]))) { /* Only unwedge the bus if the clock is off */ if (i2c_claim(port) == EC_SUCCESS) { i2c_release(port); } /* enable I2C2 clock */ STM32_RCC_APB1ENR |= 1 << i2c_clock_bit[port]; } /* force reset of the i2c peripheral */ STM32_I2C_CR1(port) = 0x8000; STM32_I2C_CR1(port) = 0x0000; /* set clock configuration : standard mode (100kHz) */ STM32_I2C_CCR(port) = I2C_CCR; /* set slave address */ if (port == I2C2) STM32_I2C_OAR1(port) = I2C_ADDRESS; /* configuration : I2C mode / Periphal enabled, ACK enabled */ STM32_I2C_CR1(port) = (1 << 10) | (1 << 0); /* error and event interrupts enabled / input clock is 16Mhz */ STM32_I2C_CR2(port) = (1 << 9) | (1 << 8) | 0x10; /* clear status */ STM32_I2C_SR1(port) = 0; board_i2c_post_init(port); }
static void i2c_init(void) { const struct i2c_port_t *p = i2c_ports; int i; for (i = 0; i < i2c_ports_used; i++, p++) i2c_init_port(p); #ifdef CONFIG_HOSTCMD_I2C_SLAVE_ADDR STM32_I2C_CR1(I2C_PORT_EC) |= STM32_I2C_CR1_RXIE | STM32_I2C_CR1_ERRIE | STM32_I2C_CR1_ADDRIE | STM32_I2C_CR1_STOPIE | STM32_I2C_CR1_NACKIE; #if defined(CONFIG_LOW_POWER_IDLE) && (I2C_PORT_EC == STM32_I2C1_PORT) /* * If using low power idle and EC port is I2C1, then set I2C1 to wake * from STOP mode on address match. Note, this only works on I2C1 and * only if the clock to I2C1 is HSI 8MHz. */ STM32_I2C_CR1(I2C_PORT_EC) |= STM32_I2C_CR1_WUPEN; #endif STM32_I2C_OAR1(I2C_PORT_EC) = 0x8000 | CONFIG_HOSTCMD_I2C_SLAVE_ADDR; #ifdef TCPCI_I2C_SLAVE /* * Configure TCPC address with OA2[1] masked so that we respond * to CONFIG_TCPC_I2C_BASE_ADDR and CONFIG_TCPC_I2C_BASE_ADDR + 2. */ STM32_I2C_OAR2(I2C_PORT_EC) = 0x8100 | CONFIG_TCPC_I2C_BASE_ADDR; #endif task_enable_irq(IRQ_SLAVE); #endif }
static int wait_until_stop_sent(int port) { timestamp_t deadline; timestamp_t slow_cutoff; uint8_t is_slow; deadline = slow_cutoff = get_time(); deadline.val += TIMEOUT_STOP_SENT_US; slow_cutoff.val += SLOW_STOP_SENT_US; while (STM32_I2C_CR1(port) & (1 << 9)) { if (timestamp_expired(deadline, NULL)) { ccprintf("Stop event deadline passed:\ttask=%d" "\tCR1=%016b\n", (int)task_get_current(), STM32_I2C_CR1(port)); return EC_ERROR_TIMEOUT; } if (is_slow) { /* If we haven't gotten a fast response, sleep */ usleep(STOP_SENT_RETRY_US); } else { /* Check to see if this request is taking a while */ if (timestamp_expired(slow_cutoff, NULL)) { ccprintf("Stop event taking a while: task=%d", (int)task_get_current()); is_slow = 1; } } } return EC_SUCCESS; }
static void i2c_set_freq_port(const struct i2c_port_t *p) { int port = p->port; /* Disable port */ STM32_I2C_CR1(port) = 0; STM32_I2C_CR2(port) = 0; /* Set clock frequency */ switch (p->kbps) { case 1000: STM32_I2C_TIMINGR(port) = 0x50110103; break; case 400: STM32_I2C_TIMINGR(port) = 0x50330309; break; case 100: STM32_I2C_TIMINGR(port) = 0xB0420F13; break; default: /* unknown speed, defaults to 100kBps */ CPRINTS("I2C bad speed %d kBps", p->kbps); STM32_I2C_TIMINGR(port) = 0xB0420F13; } /* Enable port */ STM32_I2C_CR1(port) = STM32_I2C_CR1_PE; }
static void i2c_event_handler(int port) { /* save and clear status */ i2c_sr1[port] = STM32_I2C_SR1(port); STM32_I2C_SR1(port) = 0; /* Confirm that you are not in master mode */ if (STM32_I2C_SR2(port) & (1 << 0)) { CPRINTS("slave ISR triggered in master mode, ignoring"); return; } /* transfer matched our slave address */ if (i2c_sr1[port] & (1 << 1)) { /* If it's a receiver slave */ if (!(STM32_I2C_SR2(port) & (1 << 2))) { dma_start_rx(dma_rx_option + port, sizeof(host_buffer), host_buffer); STM32_I2C_CR2(port) |= (1 << 11); rx_pending = 1; } /* cleared by reading SR1 followed by reading SR2 */ STM32_I2C_SR1(port); STM32_I2C_SR2(port); } else if (i2c_sr1[port] & (1 << 4)) { /* If it's a receiver slave */ if (!(STM32_I2C_SR2(port) & (1 << 2))) { /* Disable, and clear the DMA transfer complete flag */ dma_disable(DMAC_SLAVE_RX); dma_clear_isr(DMAC_SLAVE_RX); /* Turn off i2c's DMA flag */ STM32_I2C_CR2(port) &= ~(1 << 11); } /* clear STOPF bit by reading SR1 and then writing CR1 */ STM32_I2C_SR1(port); STM32_I2C_CR1(port) = STM32_I2C_CR1(port); } /* TxE event */ if (i2c_sr1[port] & (1 << 7)) { if (port == I2C2) { /* AP is waiting for EC response */ if (rx_pending) { i2c_process_command(); /* reset host buffer after end of transfer */ rx_pending = 0; } else { /* spurious read : return dummy value */ STM32_I2C_DR(port) = 0xec; } } } }
static void i2c_set_freq_port(const struct i2c_port_t *p, enum stm32_i2c_clk_src src, enum i2c_freq freq) { int port = p->port; const uint32_t *regs = timingr_regs[src]; /* Disable port */ STM32_I2C_CR1(port) = 0; STM32_I2C_CR2(port) = 0; /* Set clock frequency */ STM32_I2C_TIMINGR(port) = regs[freq]; /* Enable port */ STM32_I2C_CR1(port) = STM32_I2C_CR1_PE; }
static void i2c_set_freq_port(const struct i2c_port_t *p) { int port = p->port; int freq = clock_get_freq(); /* Force peripheral reset and disable port */ STM32_I2C_CR1(port) = STM32_I2C_CR1_SWRST; STM32_I2C_CR1(port) = 0; /* Set clock frequency */ STM32_I2C_CCR(port) = freq / (2 * MSEC * p->kbps); STM32_I2C_CR2(port) = freq / SECOND; STM32_I2C_TRISE(port) = freq / SECOND + 1; /* Enable port */ STM32_I2C_CR1(port) |= STM32_I2C_CR1_PE; }
static void i2c_send_tcpc_response(int len) { /* host_buffer data range, beyond this length, will return 0xec */ tx_index = 0; tx_end = len; /* enable transmit interrupt and use irq to send data back */ STM32_I2C_CR1(host_i2c_resp_port) |= STM32_I2C_CR1_TXIE; }
static void dump_i2c_reg(int port, const char *what) { CPRINTS("i2c CR1=%04x CR2=%04x SR1=%04x SR2=%04x %s", STM32_I2C_CR1(port), STM32_I2C_CR2(port), STM32_I2C_SR1(port), STM32_I2C_SR2(port), what); }
static int master_start(int port, int slave_addr) { int rv; /* Change to master send mode, reset stop bit, send start bit */ STM32_I2C_CR1(port) = (STM32_I2C_CR1(port) & ~(1 << 9)) | (1 << 8); /* Wait for start bit sent event */ rv = wait_status(port, SR1_SB, WAIT_MASTER_START); if (rv) return rv; /* Send address */ STM32_I2C_DR(port) = slave_addr; /* Wait for addr ready */ rv = wait_status(port, SR1_ADDR, WAIT_ADDR_READY); if (rv) return rv; read_clear_status(port); return EC_SUCCESS; }
static inline void dump_i2c_reg(int port) { #ifdef CONFIG_I2C_DEBUG CPRINTF("CR1 : %016b\n", STM32_I2C_CR1(port)); CPRINTF("CR2 : %016b\n", STM32_I2C_CR2(port)); CPRINTF("SR2 : %016b\n", STM32_I2C_SR2(port)); CPRINTF("SR1 : %016b\n", STM32_I2C_SR1(port)); CPRINTF("OAR1 : %016b\n", STM32_I2C_OAR1(port)); CPRINTF("OAR2 : %016b\n", STM32_I2C_OAR2(port)); CPRINTF("DR : %016b\n", STM32_I2C_DR(port)); CPRINTF("CCR : %016b\n", STM32_I2C_CCR(port)); CPRINTF("TRISE: %016b\n", STM32_I2C_TRISE(port)); #endif /* CONFIG_I2C_DEBUG */ }
/** * Send a start condition and slave address on the specified port. * * @param port I2C port * @param slave_addr Slave address, with LSB set for receive-mode * * @return Non-zero if error. */ static int send_start(int port, int slave_addr) { int rv; /* Send start bit */ STM32_I2C_CR1(port) |= STM32_I2C_CR1_START; dump_i2c_reg(port, "sent start"); rv = wait_sr1(port, STM32_I2C_SR1_SB); if (rv) return I2C_ERROR_FAILED_START; /* Write slave address */ STM32_I2C_DR(port) = slave_addr & 0xff; rv = wait_sr1(port, STM32_I2C_SR1_ADDR); if (rv) return rv; /* Read SR2 to clear ADDR bit */ rv = STM32_I2C_SR2(port); dump_i2c_reg(port, "wrote addr"); return EC_SUCCESS; }
static void i2c_send_response_packet(struct host_packet *pkt) { int size = pkt->response_size; uint8_t *out = host_buffer; /* Ignore host command in-progress */ if (pkt->driver_result == EC_RES_IN_PROGRESS) return; /* Write result and size to first two bytes. */ *out++ = pkt->driver_result; *out++ = size; /* host_buffer data range */ tx_index = 0; tx_end = size + 2; /* * Set the transmitter to be in 'not full' state to keep sending * '0xec' in the event loop. Because of this, the master i2c * doesn't need to snoop the response stream to abort transaction. */ STM32_I2C_CR1(host_i2c_resp_port) |= STM32_I2C_CR1_TXIE; }
static void master_stop(int port) { STM32_I2C_CR1(port) |= (1 << 9); }
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; }
int i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_bytes, uint8_t *in, int in_bytes, int flags) { int started = (flags & I2C_XFER_START) ? 0 : 1; int rv = EC_SUCCESS; int i; ASSERT(out || !out_bytes); ASSERT(in || !in_bytes); dump_i2c_reg(port, "xfer start"); /* * Clear status * * TODO(crosbug.com/p/29314): should check for any leftover error * status, and reset the port if present. */ STM32_I2C_SR1(port) = 0; /* Clear start, stop, POS, ACK bits to get us in a known state */ STM32_I2C_CR1(port) &= ~(STM32_I2C_CR1_START | STM32_I2C_CR1_STOP | STM32_I2C_CR1_POS | STM32_I2C_CR1_ACK); /* No out bytes and no in bytes means just check for active */ if (out_bytes || !in_bytes) { if (!started) { rv = send_start(port, slave_addr); if (rv) goto xfer_exit; } /* Write data, if any */ for (i = 0; i < out_bytes; i++) { /* Write next data byte */ STM32_I2C_DR(port) = out[i]; dump_i2c_reg(port, "wrote data"); rv = wait_sr1(port, STM32_I2C_SR1_BTF); if (rv) goto xfer_exit; } /* Need repeated start condition before reading */ started = 0; /* If no input bytes, queue stop condition */ if (!in_bytes && (flags & I2C_XFER_STOP)) STM32_I2C_CR1(port) |= STM32_I2C_CR1_STOP; } if (in_bytes) { /* Setup ACK/POS before sending start as per user manual */ if (in_bytes == 2) STM32_I2C_CR1(port) |= STM32_I2C_CR1_POS; else if (in_bytes != 1) STM32_I2C_CR1(port) |= STM32_I2C_CR1_ACK; if (!started) { rv = send_start(port, slave_addr | 0x01); if (rv) goto xfer_exit; } if (in_bytes == 1) { /* Set stop immediately after ADDR cleared */ if (flags & I2C_XFER_STOP) STM32_I2C_CR1(port) |= STM32_I2C_CR1_STOP; rv = wait_sr1(port, STM32_I2C_SR1_RXNE); if (rv) goto xfer_exit; in[0] = STM32_I2C_DR(port); } else if (in_bytes == 2) { /* Wait till the shift register is full */ rv = wait_sr1(port, STM32_I2C_SR1_BTF); if (rv) goto xfer_exit; if (flags & I2C_XFER_STOP) STM32_I2C_CR1(port) |= STM32_I2C_CR1_STOP; in[0] = STM32_I2C_DR(port); in[1] = STM32_I2C_DR(port); } else { /* Read all but last three */ for (i = 0; i < in_bytes - 3; i++) { /* Wait for receive buffer not empty */ rv = wait_sr1(port, STM32_I2C_SR1_RXNE); if (rv) goto xfer_exit; dump_i2c_reg(port, "read data"); in[i] = STM32_I2C_DR(port); dump_i2c_reg(port, "post read data"); } /* Wait for BTF (data N-2 in DR, N-1 in shift) */ rv = wait_sr1(port, STM32_I2C_SR1_BTF); if (rv) goto xfer_exit; /* No more acking */ STM32_I2C_CR1(port) &= ~STM32_I2C_CR1_ACK; in[i++] = STM32_I2C_DR(port); /* Wait for BTF (data N-1 in DR, N in shift) */ rv = wait_sr1(port, STM32_I2C_SR1_BTF); if (rv) goto xfer_exit; /* If this is the last byte, queue stop condition */ if (flags & I2C_XFER_STOP) STM32_I2C_CR1(port) |= STM32_I2C_CR1_STOP; /* Read the last two bytes */ in[i++] = STM32_I2C_DR(port); in[i++] = STM32_I2C_DR(port); } } xfer_exit: /* On error, queue a stop condition */ if (rv) { flags |= I2C_XFER_STOP; STM32_I2C_CR1(port) |= STM32_I2C_CR1_STOP; dump_i2c_reg(port, "stop after error"); /* * If failed at sending start, try resetting the port * to unwedge the bus. */ if (rv == I2C_ERROR_FAILED_START) { const struct i2c_port_t *p = i2c_ports; CPRINTS("i2c_xfer start error; " "unwedging and resetting i2c %d", port); i2c_unwedge(port); for (i = 0; i < i2c_ports_used; i++, p++) { if (p->port == port) { i2c_init_port(p); break; } } } } /* If a stop condition is queued, wait for it to take effect */ if (flags & I2C_XFER_STOP) { /* Wait up to 100 us for bus idle */ for (i = 0; i < 10; i++) { if (!(STM32_I2C_SR2(port) & STM32_I2C_SR2_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); } return rv; }
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; }
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; } } } }
static inline void enable_ack(int port) { STM32_I2C_CR1(port) |= (1 << 10); }
static inline void disable_ack(int port) { STM32_I2C_CR1(port) &= ~(1 << 10); }