static void i2c_init(void) { /* * TODO(crosbug.com/p/23763): Add config options to determine which * channels to init. */ i2c_init_port(I2C1); i2c_init_port(I2C2); /* Enable event and error interrupts */ task_enable_irq(STM32_IRQ_I2C2_EV); task_enable_irq(STM32_IRQ_I2C2_ER); }
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 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); }
static int i2c_write_raw_slave(int port, void *buf, int len) { stm32_dma_chan_t *chan; int rv; /* we don't want to race with TxE interrupt event */ disable_i2c_interrupt(port); /* Configuring DMA1 channel DMAC_SLAVE_TX */ enable_ack(port); chan = dma_get_channel(DMAC_SLAVE_TX); dma_prepare_tx(dma_tx_option + port, len, buf); /* Start the DMA */ dma_go(chan); /* Configuring i2c to use DMA */ STM32_I2C_CR2(port) |= (1 << 11); if (in_interrupt_context()) { /* Poll for the transmission complete flag */ dma_wait(DMAC_SLAVE_TX); dma_clear_isr(DMAC_SLAVE_TX); } else { /* Wait for the transmission complete Interrupt */ dma_enable_tc_interrupt(DMAC_SLAVE_TX); rv = task_wait_event(DMA_TRANSFER_TIMEOUT_US); dma_disable_tc_interrupt(DMAC_SLAVE_TX); if (!(rv & TASK_EVENT_WAKE)) { CPRINTS("Slave timeout, resetting i2c"); i2c_init_port(port); } } dma_disable(DMAC_SLAVE_TX); STM32_I2C_CR2(port) &= ~(1 << 11); enable_i2c_interrupt(port); return len; }
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; }