summaryrefslogtreecommitdiff
path: root/chip/stm32/i2c-stm32l4.c
diff options
context:
space:
mode:
Diffstat (limited to 'chip/stm32/i2c-stm32l4.c')
-rw-r--r--chip/stm32/i2c-stm32l4.c470
1 files changed, 0 insertions, 470 deletions
diff --git a/chip/stm32/i2c-stm32l4.c b/chip/stm32/i2c-stm32l4.c
deleted file mode 100644
index 5997ed5b70..0000000000
--- a/chip/stm32/i2c-stm32l4.c
+++ /dev/null
@@ -1,470 +0,0 @@
-/* Copyright 2013 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "printf.h"
-#include "chipset.h"
-#include "clock.h"
-#include "common.h"
-#include "console.h"
-#include "gpio.h"
-#include "hooks.h"
-#include "hwtimer.h"
-#include "i2c.h"
-#include "registers.h"
-
-#include "system.h"
-#include "task.h"
-#include "timer.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_MASTER (10 * MSEC)
-
-#ifdef CONFIG_HOSTCMD_I2C_ADDR_FLAGS
-#define I2C_SLAVE_ERROR_CODE 0xec
-#if (I2C_PORT_EC == STM32_I2C1_PORT)
-#define IRQ_SLAVE STM32_IRQ_I2C1
-#else
-#define IRQ_SLAVE 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_MASTER;
-}
-
-/* timing 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_16MHZ = 1,
- I2C_CLK_SRC_COUNT,
-};
-
-/* timing register values for supported input clks / i2c clk rates
- *
- * These values are calculated using ST's STM32cubeMX tool
- */
-static const uint32_t timingr_regs[I2C_CLK_SRC_COUNT][I2C_FREQ_COUNT] = {
- [I2C_CLK_SRC_48MHZ] = {
- [I2C_FREQ_1000KHZ] = 0x20000209,
- [I2C_FREQ_400KHZ] = 0x2010091A,
- [I2C_FREQ_100KHZ] = 0x20303E5D,
- },
- [I2C_CLK_SRC_16MHZ] = {
- [I2C_FREQ_1000KHZ] = 0x00000107,
- [I2C_FREQ_400KHZ] = 0x00100B15,
- [I2C_FREQ_100KHZ] = 0x00303D5B,
- },
-};
-
-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;
-
- /* 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;
-}
-
-/**
- * Initialize on the specified I2C port.
- *
- * @param p the I2c port
- */
-static void i2c_init_port(const struct i2c_port_t *p)
-{
- int port = p->port;
- uint32_t val;
- enum i2c_freq freq;
- enum stm32_i2c_clk_src src = I2C_CLK_SRC_16MHZ;
-
- /* Enable I2C clock */
- if (!(STM32_RCC_APB1ENR1 & (1 << (21 + port))))
- STM32_RCC_APB1ENR1 |= 1 << (21 + port);
-
- /* Select HSI 16MHz as I2C clock source */
- val = STM32_RCC_CCIPR;
- val &= ~(STM32_RCC_CCIPR_I2C1SEL_MASK << (port * 2));
- val |= STM32_RCC_CCIPR_I2C_HSI16
- << (STM32_RCC_CCIPR_I2C1SEL_SHIFT + port * 2);
- STM32_RCC_CCIPR = val;
-
- /* Configure GPIOs */
- gpio_config_module(MODULE_I2C, 1);
-
- /* Set clock frequency */
- switch (p->kbps) {
- case 1000:
- STM32_SYSCFG_CFGR1 |= STM32_SYSCFG_I2CFMP(port);
- 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;
- }
-
- /* Set up initial bus frequencies */
- i2c_set_freq_port(p, src, freq);
-
- /* Set up default timeout */
- i2c_set_timeout(port, 0);
-}
-
-/*****************************************************************************/
-
-#ifdef CONFIG_HOSTCMD_I2C_ADDR_FLAGS
-
-static void i2c_event_handler(int port)
-{
- /* Variables tracking the handler state.
- * TODO: Should have as many sets of these variables as the number
- * of slave ports.
- */
- static int rx_pending, rx_idx;
- static int tx_pending, tx_idx, tx_end;
- static uint8_t slave_buffer[I2C_MAX_HOST_PACKET_SIZE + 2];
- int 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 (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 (isr & STM32_I2C_ISR_ADDR) {
- if (isr & STM32_I2C_ISR_DIR) {
- /* Transmitter slave */
- /* Clear transmit buffer */
- STM32_I2C_ISR(port) |= STM32_I2C_ISR_TXE;
-
- if (rx_pending)
- /* RESTART */
- i2c_data_received(port, slave_buffer, rx_idx);
- tx_end = i2c_set_response(port, slave_buffer, rx_idx);
- tx_idx = 0;
- rx_pending = 0;
- tx_pending = 1;
-
- /* Enable txis interrupt to start response */
- STM32_I2C_CR1(port) |= STM32_I2C_CR1_TXIE;
- } else {
- /* Receiver slave */
- rx_idx = 0;
- rx_pending = 1;
- tx_pending = 0;
- }
-
- /* 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_PERIPHERAL);
- }
-
- /*
- * Receive buffer not empty
- *
- * When a master finishes sending data, it'll set STOP bit. It causes
- * the slave to receive RXNE and STOP interrupt at the same time. So,
- * we need to process RXNE first, then handle STOP.
- */
- if (isr & STM32_I2C_ISR_RXNE)
- slave_buffer[rx_idx++] = STM32_I2C_RXDR(port);
-
- /* Stop condition on bus */
- if (isr & STM32_I2C_ISR_STOP) {
- if (rx_pending)
- i2c_data_received(port, slave_buffer, rx_idx);
- tx_idx = 0;
- tx_end = 0;
- 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);
- }
-
- if (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;
- }
-
- /* Transmitter empty event */
- if (isr & STM32_I2C_ISR_TXIS) {
- if (port == I2C_PORT_EC) {
- if (tx_pending) {
- if (tx_idx < tx_end) {
- STM32_I2C_TXDR(port) =
- slave_buffer[tx_idx++];
- } else {
- STM32_I2C_TXDR(port)
- = I2C_SLAVE_ERROR_CODE;
- tx_idx = 0;
- tx_end = 0;
- tx_pending = 0;
- }
- } else {
- STM32_I2C_TXDR(port) = I2C_SLAVE_ERROR_CODE;
- }
- }
- }
-}
-
-void i2c_event_interrupt(void)
-{
- i2c_event_handler(I2C_PORT_EC);
-}
-DECLARE_IRQ(IRQ_SLAVE, i2c_event_interrupt, 2);
-#endif
-
-/*****************************************************************************/
-/* Interface */
-
-int chip_i2c_xfer(const int port, const uint16_t slave_addr_flags,
- const uint8_t *out, int out_bytes,
- uint8_t *in, int in_bytes, int flags)
-{
- int addr_8bit = I2C_STRIP_FLAGS(slave_addr_flags) << 1;
- int rv = EC_SUCCESS;
- int i;
- int xfer_start = flags & I2C_XFER_START;
- int xfer_stop = flags & I2C_XFER_STOP;
-
- 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)
- | 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 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_raw_get_scl(int port)
-{
- enum gpio_signal g;
-
- if (get_scl_from_i2c_port(port, &g))
- /* If no SCL pin is defined, return 1 to appear idle. */
- return 1;
-
- return gpio_get_level(g);
-}
-
-int i2c_raw_get_sda(int port)
-{
- enum gpio_signal g;
-
- if (get_sda_from_i2c_port(port, &g))
- /* If no SDA pin is defined, return 1 to appear idle. */
- return 1;
-
- return gpio_get_level(g);
-}
-
-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;
- STM32_I2C_OAR1(I2C_PORT_EC) = 0x8000
- | (I2C_STRIP_FLAGS(CONFIG_HOSTCMD_I2C_ADDR_FLAGS) << 1);
- task_enable_irq(IRQ_SLAVE);
-#endif
-}