summaryrefslogtreecommitdiff
path: root/chip/stm32/i2c-stm32f3.c
diff options
context:
space:
mode:
Diffstat (limited to 'chip/stm32/i2c-stm32f3.c')
-rw-r--r--[l---------]chip/stm32/i2c-stm32f3.c655
1 files changed, 654 insertions, 1 deletions
diff --git a/chip/stm32/i2c-stm32f3.c b/chip/stm32/i2c-stm32f3.c
index ce8523ea90..acd4d3aca6 120000..100644
--- a/chip/stm32/i2c-stm32f3.c
+++ b/chip/stm32/i2c-stm32f3.c
@@ -1 +1,654 @@
-i2c-stm32f0.c \ No newline at end of file
+/* Copyright 2013 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "builtin/assert.h"
+#include "chipset.h"
+#include "clock.h"
+#include "common.h"
+#include "console.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "host_command.h"
+#include "hwtimer.h"
+#include "i2c.h"
+#include "i2c_private.h"
+#include "registers.h"
+#include "system.h"
+#include "task.h"
+#include "timer.h"
+#include "usb_pd_tcpc.h"
+#include "usb_pd_tcpm.h"
+#include "util.h"
+
+/* Console output macros */
+#define CPUTS(outstr) cputs(CC_I2C, outstr)
+#define CPRINTS(format, args...) cprints(CC_I2C, format, ##args)
+
+/* Transmit timeout in microseconds */
+#define I2C_TX_TIMEOUT_CONTROLLER (10 * MSEC)
+
+#ifdef CONFIG_HOSTCMD_I2C_ADDR_FLAGS
+#if (I2C_PORT_EC == STM32_I2C1_PORT)
+#define IRQ_PERIPHERAL STM32_IRQ_I2C1
+#else
+#define IRQ_PERIPHERAL STM32_IRQ_I2C2
+#endif
+#endif
+
+/* I2C port state data */
+struct i2c_port_data {
+ uint32_t timeout_us; /* Transaction timeout, or 0 to use default */
+ enum i2c_freq freq; /* Port clock speed */
+};
+static struct i2c_port_data pdata[I2C_PORT_COUNT];
+
+void i2c_set_timeout(int port, uint32_t timeout)
+{
+ pdata[port].timeout_us = timeout ? timeout : I2C_TX_TIMEOUT_CONTROLLER;
+}
+
+/* timingr register values for supported input clks / i2c clk rates */
+static const uint32_t busyloop_us[I2C_FREQ_COUNT] = {
+ [I2C_FREQ_1000KHZ] = 16, /* Enough for 2 bytes */
+ [I2C_FREQ_400KHZ] = 40, /* Enough for 2 bytes */
+ [I2C_FREQ_100KHZ] = 0, /* No busy looping at 100kHz (bus is slow) */
+};
+
+/**
+ * Wait for ISR register to contain the specified mask.
+ *
+ * Returns EC_SUCCESS, EC_ERROR_TIMEOUT if timed out waiting, or
+ * EC_ERROR_UNKNOWN if an error bit appeared in the status register.
+ */
+static int wait_isr(int port, int mask)
+{
+ uint32_t start = __hw_clock_source_read();
+ uint32_t delta = 0;
+
+ do {
+ int isr = STM32_I2C_ISR(port);
+
+ /* Check for errors */
+ if (isr & (STM32_I2C_ISR_ARLO | STM32_I2C_ISR_BERR |
+ STM32_I2C_ISR_NACK))
+ return EC_ERROR_UNKNOWN;
+
+ /* Check for desired mask */
+ if ((isr & mask) == mask)
+ return EC_SUCCESS;
+
+ delta = __hw_clock_source_read() - start;
+
+ /**
+ * Depending on the bus speed, busy loop for a while before
+ * sleeping and letting other things run.
+ */
+ if (delta >= busyloop_us[pdata[port].freq])
+ usleep(100);
+ } while (delta < pdata[port].timeout_us);
+
+ return EC_ERROR_TIMEOUT;
+}
+
+/* Supported i2c input clocks */
+enum stm32_i2c_clk_src {
+ I2C_CLK_SRC_48MHZ = 0,
+ I2C_CLK_SRC_8MHZ = 1,
+ I2C_CLK_SRC_COUNT,
+};
+
+/* timingr register values for supported input clks / i2c clk rates */
+static const uint32_t timingr_regs[I2C_CLK_SRC_COUNT][I2C_FREQ_COUNT] = {
+ [I2C_CLK_SRC_48MHZ] = {
+ [I2C_FREQ_1000KHZ] = 0x50100103,
+ [I2C_FREQ_400KHZ] = 0x50330609,
+ [I2C_FREQ_100KHZ] = 0xB0421214,
+ },
+ [I2C_CLK_SRC_8MHZ] = {
+ [I2C_FREQ_1000KHZ] = 0x00100306,
+ [I2C_FREQ_400KHZ] = 0x00310309,
+ [I2C_FREQ_100KHZ] = 0x10420f13,
+ },
+};
+
+int chip_i2c_set_freq(int port, enum i2c_freq freq)
+{
+ enum stm32_i2c_clk_src src = I2C_CLK_SRC_48MHZ;
+
+#if defined(CONFIG_HOSTCMD_I2C_ADDR_FLAGS) && \
+ defined(CONFIG_LOW_POWER_IDLE) && (I2C_PORT_EC == STM32_I2C1_PORT)
+ if (port == STM32_I2C1_PORT) {
+ /*
+ * Use HSI (8MHz) for i2c clock. This allows smooth wakeup
+ * from STOP mode since HSI is only clock running immediately
+ * upon exit from STOP mode.
+ */
+ src = I2C_CLK_SRC_8MHZ;
+ }
+#endif
+
+ /* Disable port */
+ STM32_I2C_CR1(port) = 0;
+ STM32_I2C_CR2(port) = 0;
+ /* Set clock frequency */
+ STM32_I2C_TIMINGR(port) = timingr_regs[src][freq];
+ /* Enable port */
+ STM32_I2C_CR1(port) = STM32_I2C_CR1_PE;
+
+ pdata[port].freq = freq;
+
+ return EC_SUCCESS;
+}
+
+enum i2c_freq chip_i2c_get_freq(int port)
+{
+ return pdata[port].freq;
+}
+
+/**
+ * Initialize on the specified I2C port.
+ *
+ * @param p the I2c port
+ */
+static int i2c_init_port(const struct i2c_port_t *p)
+{
+ int port = p->port;
+ int ret = EC_SUCCESS;
+ enum i2c_freq freq;
+
+ /* Enable clocks to I2C modules if necessary */
+ if (!(STM32_RCC_APB1ENR & (1 << (21 + port))))
+ STM32_RCC_APB1ENR |= 1 << (21 + port);
+
+ if (port == STM32_I2C1_PORT) {
+#if defined(CONFIG_HOSTCMD_I2C_ADDR_FLAGS) && \
+ defined(CONFIG_LOW_POWER_IDLE) && (I2C_PORT_EC == STM32_I2C1_PORT)
+ /*
+ * Use HSI (8MHz) for i2c clock. This allows smooth wakeup
+ * from STOP mode since HSI is only clock running immediately
+ * upon exit from STOP mode.
+ */
+ STM32_RCC_CFGR3 &= ~0x10;
+#else
+ /* Use SYSCLK for i2c clock. */
+ STM32_RCC_CFGR3 |= 0x10;
+#endif
+ }
+
+ /* Configure GPIOs */
+ gpio_config_module(MODULE_I2C, 1);
+
+ /* Set clock frequency */
+ switch (p->kbps) {
+ case 1000:
+ freq = I2C_FREQ_1000KHZ;
+ break;
+ case 400:
+ freq = I2C_FREQ_400KHZ;
+ break;
+ case 100:
+ freq = I2C_FREQ_100KHZ;
+ break;
+ default: /* unknown speed, defaults to 100kBps */
+ CPRINTS("I2C bad speed %d kBps", p->kbps);
+ freq = I2C_FREQ_100KHZ;
+ ret = EC_ERROR_INVAL;
+ }
+
+ /* Set up initial bus frequencies */
+ chip_i2c_set_freq(p->port, freq);
+
+ /* Set up default timeout */
+ i2c_set_timeout(port, 0);
+
+ return ret;
+}
+
+/*****************************************************************************/
+#ifdef CONFIG_HOSTCMD_I2C_ADDR_FLAGS
+/* Host command peripheral */
+/*
+ * Buffer for received host command packets (including prefix byte on request,
+ * and result/size on response). After any protocol-specific headers, the
+ * buffers must be 32-bit aligned.
+ */
+static uint8_t host_buffer_padded[I2C_MAX_HOST_PACKET_SIZE + 4 +
+ CONFIG_I2C_EXTRA_PACKET_SIZE] __aligned(4);
+static uint8_t *const host_buffer = host_buffer_padded + 2;
+static uint8_t params_copy[I2C_MAX_HOST_PACKET_SIZE] __aligned(4);
+static int host_i2c_resp_port;
+static int tx_pending;
+static int tx_index, tx_end;
+static struct host_packet i2c_packet;
+
+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 controller i2c
+ * doesn't need to snoop the response stream to abort transaction.
+ */
+ STM32_I2C_CR1(host_i2c_resp_port) |= STM32_I2C_CR1_TXIE;
+}
+
+/* Process the command in the i2c host buffer */
+static void i2c_process_command(void)
+{
+ char *buff = host_buffer;
+
+ /*
+ * TODO(crosbug.com/p/29241): Combine this functionality with the
+ * i2c_process_command function in chip/stm32/i2c-stm32f.c to make one
+ * host command i2c process function which handles all protocol
+ * versions.
+ */
+ i2c_packet.send_response = i2c_send_response_packet;
+
+ i2c_packet.request = (const void *)(&buff[1]);
+ i2c_packet.request_temp = params_copy;
+ i2c_packet.request_max = sizeof(params_copy);
+ /* Don't know the request size so pass in the entire buffer */
+ i2c_packet.request_size = I2C_MAX_HOST_PACKET_SIZE;
+
+ /*
+ * Stuff response at buff[2] to leave the first two bytes of
+ * buffer available for the result and size to send over i2c. Note
+ * that this 2-byte offset and the 2-byte offset from host_buffer
+ * add up to make the response buffer 32-bit aligned.
+ */
+ i2c_packet.response = (void *)(&buff[2]);
+ i2c_packet.response_max = I2C_MAX_HOST_PACKET_SIZE;
+ i2c_packet.response_size = 0;
+
+ if (*buff >= EC_COMMAND_PROTOCOL_3) {
+ i2c_packet.driver_result = EC_RES_SUCCESS;
+ } else {
+ /* Only host command protocol 3 is supported. */
+ i2c_packet.driver_result = EC_RES_INVALID_HEADER;
+ }
+ host_packet_receive(&i2c_packet);
+}
+
+#ifdef TCPCI_I2C_PERIPHERAL
+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 i2c_process_tcpc_command(int read, int addr, int len)
+{
+ tcpc_i2c_process(read, TCPC_ADDR_TO_PORT(addr), len, &host_buffer[0],
+ i2c_send_tcpc_response);
+}
+#endif
+
+static void i2c_event_handler(int port)
+{
+ int i2c_isr;
+ static int rx_pending, buf_idx;
+#ifdef TCPCI_I2C_PERIPHERAL
+ 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 peripheral 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 peripheral address */
+ if (i2c_isr & STM32_I2C_ISR_ADDR) {
+ if (i2c_isr & STM32_I2C_ISR_DIR) {
+ /* Transmitter peripheral */
+ /* 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 peripheral */
+ buf_idx = 0;
+ rx_pending = 1;
+ }
+
+ /* Clear ADDR bit by writing to ADDRCF bit */
+ STM32_I2C_ICR(port) |= STM32_I2C_ICR_ADDRCF;
+ /* Inhibit sleep mode when addressed until STOPF flag is set */
+ disable_sleep(SLEEP_MASK_I2C_PERIPHERAL);
+ }
+
+ /* Receiver full event */
+ if (i2c_isr & STM32_I2C_ISR_RXNE)
+ host_buffer[buf_idx++] = STM32_I2C_RXDR(port);
+
+ /* Stop condition on bus */
+ if (i2c_isr & STM32_I2C_ISR_STOP) {
+#ifdef TCPCI_I2C_PERIPHERAL
+ /*
+ * 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_PERIPHERAL);
+ }
+
+ /* Controller 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_PERIPHERAL
+ 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 void i2c2_event_interrupt(void)
+{
+ i2c_event_handler(I2C_PORT_EC);
+}
+DECLARE_IRQ(IRQ_PERIPHERAL, i2c2_event_interrupt, 2);
+#endif
+
+/*****************************************************************************/
+/* Interface */
+
+int chip_i2c_xfer(const int port, const uint16_t addr_flags, const uint8_t *out,
+ int out_bytes, uint8_t *in, int in_bytes, int flags)
+{
+ int addr_8bit = I2C_STRIP_FLAGS(addr_flags) << 1;
+ 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 &&
+ addr_flags == CONFIG_I2C_SCL_GATE_ADDR_FLAGS)
+ gpio_set_level(CONFIG_I2C_SCL_GATE_GPIO, 1);
+#endif
+
+ ASSERT(out || !out_bytes);
+ ASSERT(in || !in_bytes);
+
+ /* Clear status */
+ if (xfer_start) {
+ uint32_t cr2 = STM32_I2C_CR2(port);
+
+ STM32_I2C_ICR(port) = STM32_I2C_ICR_ALL;
+ STM32_I2C_CR2(port) = 0;
+ if (cr2 & STM32_I2C_CR2_RELOAD) {
+ /*
+ * If I2C_XFER_START flag is on and we've set RELOAD=1
+ * in previous chip_i2c_xfer() call. Then we are
+ * probably in the middle of an i2c transaction.
+ *
+ * In this case, we need to clear the RELOAD bit and
+ * wait for Transfer Complete (TC) flag, to make sure
+ * the chip is not expecting another NBYTES data, And
+ * send repeated-start correctly.
+ */
+ rv = wait_isr(port, STM32_I2C_ISR_TC);
+ if (rv)
+ goto xfer_exit;
+ }
+ }
+
+ 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) | addr_8bit |
+ ((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 |
+ addr_8bit | (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 peripherals 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 &&
+ addr_flags == CONFIG_I2C_SCL_GATE_ADDR_FLAGS)
+ gpio_set_level(CONFIG_I2C_SCL_GATE_GPIO, 0);
+#endif
+
+ return rv;
+}
+
+int i2c_raw_get_scl(int port)
+{
+ enum gpio_signal g;
+
+ if (get_scl_from_i2c_port(port, &g) == EC_SUCCESS)
+ return gpio_get_level(g);
+
+ /* If no SCL pin defined for this port, then return 1 to appear idle. */
+ return 1;
+}
+
+int i2c_raw_get_sda(int port)
+{
+ enum gpio_signal g;
+
+ if (get_sda_from_i2c_port(port, &g) == EC_SUCCESS)
+ return gpio_get_level(g);
+
+ /* If no SCL pin defined for this port, then return 1 to appear idle. */
+ return 1;
+}
+
+int i2c_get_line_levels(int port)
+{
+ return (i2c_raw_get_sda(port) ? I2C_LINE_SDA_HIGH : 0) |
+ (i2c_raw_get_scl(port) ? I2C_LINE_SCL_HIGH : 0);
+}
+
+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_ADDR_FLAGS
+ 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 | (I2C_STRIP_FLAGS(CONFIG_HOSTCMD_I2C_ADDR_FLAGS) << 1);
+#ifdef TCPCI_I2C_PERIPHERAL
+ /*
+ * 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 |
+ (I2C_STRIP_FLAGS(CONFIG_TCPC_I2C_BASE_ADDR_FLAGS) << 1);
+#endif
+ task_enable_irq(IRQ_PERIPHERAL);
+#endif
+}