diff options
-rw-r--r-- | chip/lm4/i2c.c | 246 | ||||
-rw-r--r-- | chip/stm32/i2c.c | 53 |
2 files changed, 149 insertions, 150 deletions
diff --git a/chip/lm4/i2c.c b/chip/lm4/i2c.c index de04bcf727..0fdefc15d9 100644 --- a/chip/lm4/i2c.c +++ b/chip/lm4/i2c.c @@ -37,7 +37,12 @@ static task_id_t task_waiting_on_port[NUM_PORTS]; static struct mutex port_mutex[NUM_PORTS]; extern const struct i2c_port_t i2c_ports[I2C_PORTS_USED]; - +/** + * Wait for port to go idle + * + * @param port Port to check + * @return EC_SUCCESS if port is idle; non-zero if error. + */ static int wait_idle(int port) { int i; @@ -48,7 +53,8 @@ static int wait_idle(int port) /* Port is busy, so wait for the interrupt */ task_waiting_on_port[port] = task_get_current(); LM4_I2C_MIMR(port) = 0x03; - /* We want to wait here quietly until the I2C interrupt comes + /* + * We want to wait here quietly until the I2C interrupt comes * along, but we don't want to lose any pending events that * will be needed by the task that started the I2C transaction * in the first place. So we save them up and restore them when @@ -68,7 +74,8 @@ static int wait_idle(int port) i = LM4_I2C_MCS(port); } - /* Restore any events that we saw while waiting. TASK_EVENT_TIMER isn't + /* + * Restore any events that we saw while waiting. TASK_EVENT_TIMER isn't * one, because we've handled it above. */ task_set_event(task_get_current(), event, 0); @@ -80,28 +87,35 @@ static int wait_idle(int port) return EC_SUCCESS; } - -/* Transmit one block of raw data, then receive one block of raw data. - * <start> flag indicates this smbus session start from idle state. - * <stop> flag means this session can be termicate with smbus stop bit +/** + * Transmit one block of raw data, then receive one block of raw data. + * + * @param port Port to access + * @param slave_addr Slave device address + * @param out Data to send + * @param out_size Number of bytes to send + * @param in Destination buffer for received data + * @param in_size Number of bytes to receive + * @param start Did smbus session started from idle state? + * @param stop Can session be terminated with smbus stop bit? + * @return EC_SUCCESS, or non-zero if error. */ -static int i2c_transmit_receive(int port, int slave_addr, - uint8_t *transmit_data, int transmit_size, - uint8_t *receive_data, int receive_size, - int start, int stop) +static int i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_size, + uint8_t *in, int in_size, int start, int stop) { int rv, i; int started = start ? 0 : 1; uint32_t reg_mcs; - if (transmit_size == 0 && receive_size == 0) + if (out_size == 0 && in_size == 0) return EC_SUCCESS; - if (transmit_data) { + if (out) { LM4_I2C_MSA(port) = slave_addr & 0xff; - for (i = 0; i < transmit_size; i++) { - LM4_I2C_MDR(port) = transmit_data[i]; - /* Setup master control/status register + for (i = 0; i < out_size; i++) { + LM4_I2C_MDR(port) = out[i]; + /* + * Set up master control/status register * MCS sequence on multi-byte write: * 0x3 0x1 0x1 ... 0x1 0x5 * Single byte write: @@ -113,12 +127,11 @@ static int i2c_transmit_receive(int port, int slave_addr, started = 1; reg_mcs |= LM4_I2C_MCS_START; } - /* Send stop bit if the stop flag is on, - * and caller doesn't expect to receive - * data. + /* + * Send stop bit if the stop flag is on, and caller + * doesn't expect to receive data. */ - if (stop && receive_size == 0 && i == - (transmit_size - 1)) + if (stop && in_size == 0 && i == (out_size - 1)) reg_mcs |= LM4_I2C_MCS_STOP; LM4_I2C_MCS(port) = reg_mcs; @@ -129,15 +142,16 @@ static int i2c_transmit_receive(int port, int slave_addr, } } - if (receive_size) { - if (transmit_size) + if (in_size) { + if (out_size) /* resend start bit when change direction */ started = 0; LM4_I2C_MSA(port) = (slave_addr & 0xff) | 0x01; - for (i = 0; i < receive_size; i++) { - LM4_I2C_MDR(port) = receive_data[i]; - /* MCS receive sequence on multi-byte read: + for (i = 0; i < in_size; i++) { + LM4_I2C_MDR(port) = in[i]; + /* + * MCS receive sequence on multi-byte read: * 0xb 0x9 0x9 ... 0x9 0x5 * Single byte read: * 0x7 @@ -148,7 +162,7 @@ static int i2c_transmit_receive(int port, int slave_addr, reg_mcs |= LM4_I2C_MCS_START; } /* ACK all bytes except the last one */ - if (stop && i == (receive_size - 1)) + if (stop && i == (in_size - 1)) reg_mcs |= LM4_I2C_MCS_STOP; else reg_mcs |= LM4_I2C_MCS_ACK; @@ -157,26 +171,22 @@ static int i2c_transmit_receive(int port, int slave_addr, rv = wait_idle(port); if (rv) return rv; - receive_data[i] = LM4_I2C_MDR(port) & 0xff; + in[i] = LM4_I2C_MDR(port) & 0xff; } } return EC_SUCCESS; } - int i2c_read16(int port, int slave_addr, int offset, int *data) { int rv; uint8_t reg, buf[2]; reg = offset & 0xff; - /* I2C read 16-bit word: - * Transmit 8-bit offset, and read 16bits - */ + /* I2C read 16-bit word: transmit 8-bit offset, and read 16bits */ mutex_lock(port_mutex + port); - rv = i2c_transmit_receive(port, slave_addr, ®, 1, buf, 2, - START, STOP); + rv = i2c_xfer(port, slave_addr, ®, 1, buf, 2, START, STOP); mutex_unlock(port_mutex + port); if (rv) @@ -190,7 +200,6 @@ int i2c_read16(int port, int slave_addr, int offset, int *data) return EC_SUCCESS; } - int i2c_write16(int port, int slave_addr, int offset, int data) { int rv; @@ -207,14 +216,12 @@ int i2c_write16(int port, int slave_addr, int offset, int data) } mutex_lock(port_mutex + port); - rv = i2c_transmit_receive(port, slave_addr, buf, 3, 0, 0, - START, STOP); + rv = i2c_xfer(port, slave_addr, buf, 3, 0, 0, START, STOP); mutex_unlock(port_mutex + port); return rv; } - int i2c_read8(int port, int slave_addr, int offset, int* data) { int rv; @@ -223,8 +230,7 @@ int i2c_read8(int port, int slave_addr, int offset, int* data) reg = offset; mutex_lock(port_mutex + port); - rv = i2c_transmit_receive(port, slave_addr, ®, 1, &val, 1, - START, STOP); + rv = i2c_xfer(port, slave_addr, ®, 1, &val, 1, START, STOP); mutex_unlock(port_mutex + port); if (!rv) @@ -233,7 +239,6 @@ int i2c_read8(int port, int slave_addr, int offset, int* data) return rv; } - int i2c_write8(int port, int slave_addr, int offset, int data) { int rv; @@ -243,16 +248,14 @@ int i2c_write8(int port, int slave_addr, int offset, int data) buf[1] = data; mutex_lock(port_mutex + port); - rv = i2c_transmit_receive(port, slave_addr, buf, 2, 0, 0, - START, STOP); + rv = i2c_xfer(port, slave_addr, buf, 2, 0, 0, START, STOP); mutex_unlock(port_mutex + port); return rv; } - int i2c_read_string(int port, int slave_addr, int offset, uint8_t *data, - int len) + int len) { int rv; uint8_t reg, block_length; @@ -260,18 +263,20 @@ int i2c_read_string(int port, int slave_addr, int offset, uint8_t *data, mutex_lock(port_mutex + port); reg = offset; - /* Send device reg space offset, and read back block length. - * Keep this session open without a stop */ - rv = i2c_transmit_receive(port, slave_addr, ®, 1, &block_length, 1, - START, NO_STOP); + /* + * Send device reg space offset, and read back block length. Keep this + * session open without a stop. + */ + rv = i2c_xfer(port, slave_addr, ®, 1, &block_length, 1, + START, NO_STOP); if (rv) goto exit; if (len && block_length > (len - 1)) block_length = len - 1; - rv = i2c_transmit_receive(port, slave_addr, 0, 0, data, block_length, - NO_START, STOP); + rv = i2c_xfer(port, slave_addr, 0, 0, data, block_length, + NO_START, STOP); data[block_length] = 0; exit: @@ -279,13 +284,41 @@ exit: return rv; } +/** + * Configure GPIOs for the module. + */ +static void configure_gpio(void) +{ +#ifdef BOARD_link + /* PA6:7 = I2C1 SCL/SDA; PB2:3 = I2C0 SCL/SDA; PB6:7 = I2C5 SCL/SDA */ + gpio_set_alternate_function(LM4_GPIO_A, 0xc0, 3); + gpio_set_alternate_function(LM4_GPIO_B, 0xcc, 3); + + /* Configure SDA as open-drain. SCL should not be open-drain, + * since it has an internal pull-up. */ + LM4_GPIO_ODR(LM4_GPIO_A) |= 0x80; + LM4_GPIO_ODR(LM4_GPIO_B) |= 0x88; +#else + /* PG6:7 = I2C5 SCL/SDA */ + gpio_set_alternate_function(LM4_GPIO_G, 0xc0, 3); + + /* Configure SDA as open-drain. SCL should not be open-drain, + * since it has an internal pull-up. */ + LM4_GPIO_ODR(LM4_GPIO_G) |= 0x80; +#endif +} + +/*****************************************************************************/ +/* Hooks */ + static void i2c_freq_changed(void) { int freq = clock_get_freq(); int i; for (i = 0; i < I2C_PORTS_USED; i++) { - /* From datasheet: + /* + * From datasheet: * SCL_PRD = 2 * (1 + TPR) * (SCL_LP + SCL_HP) * CLK_PRD * * so: @@ -310,10 +343,47 @@ static void i2c_freq_changed(void) } DECLARE_HOOK(HOOK_FREQ_CHANGE, i2c_freq_changed, HOOK_PRIO_DEFAULT + 1); -/*****************************************************************************/ -/* Interrupt handlers */ +static void i2c_init(void) +{ + uint32_t mask = 0; + int i; + + /* Enable I2C modules and delay a few clocks */ + for (i = 0; i < I2C_PORTS_USED; i++) + mask |= 1 << i2c_ports[i].port; + + LM4_SYSTEM_RCGCI2C |= mask; + clock_wait_cycles(3); + + /* Configure GPIOs */ + configure_gpio(); + + /* No tasks are waiting on ports */ + for (i = 0; i < NUM_PORTS; i++) + task_waiting_on_port[i] = TASK_ID_INVALID; + + /* Initialize ports as master, with interrupts enabled */ + for (i = 0; i < I2C_PORTS_USED; i++) + LM4_I2C_MCR(i2c_ports[i].port) = 0x10; + + /* Set initial clock frequency */ + i2c_freq_changed(); + + /* Enable irqs */ + task_enable_irq(LM4_IRQ_I2C0); + task_enable_irq(LM4_IRQ_I2C1); + task_enable_irq(LM4_IRQ_I2C2); + task_enable_irq(LM4_IRQ_I2C3); + task_enable_irq(LM4_IRQ_I2C4); + task_enable_irq(LM4_IRQ_I2C5); +} +DECLARE_HOOK(HOOK_INIT, i2c_init, HOOK_PRIO_DEFAULT); -/* Handles an interrupt on the specified port. */ +/** + * Handle an interrupt on the specified port. + * + * @param port I2C port generating interrupt + */ static void handle_interrupt(int port) { int id = task_waiting_on_port[port]; @@ -326,7 +396,6 @@ static void handle_interrupt(int port) task_set_event(id, TASK_EVENT_I2C_IDLE, 0); } - static void i2c0_interrupt(void) { handle_interrupt(0); } static void i2c1_interrupt(void) { handle_interrupt(1); } static void i2c2_interrupt(void) { handle_interrupt(2); } @@ -377,7 +446,6 @@ static void scan_bus(int port, const char *desc) ccputs("\n"); } - static int command_i2cread(int argc, char **argv) { int port, addr, count = 1; @@ -432,7 +500,6 @@ DECLARE_CONSOLE_COMMAND(i2cread, command_i2cread, "Read from I2C", NULL); - static int command_scan(int argc, char **argv) { int i; @@ -445,66 +512,3 @@ DECLARE_CONSOLE_COMMAND(i2cscan, command_scan, NULL, "Scan I2C ports for devices", NULL); - - -/*****************************************************************************/ -/* Initialization */ - -/* Configures GPIOs for the module. */ -static void configure_gpio(void) -{ -#ifdef BOARD_link - /* PA6:7 = I2C1 SCL/SDA; PB2:3 = I2C0 SCL/SDA; PB6:7 = I2C5 SCL/SDA */ - gpio_set_alternate_function(LM4_GPIO_A, 0xc0, 3); - gpio_set_alternate_function(LM4_GPIO_B, 0xcc, 3); - - /* Configure SDA as open-drain. SCL should not be open-drain, - * since it has an internal pull-up. */ - LM4_GPIO_ODR(LM4_GPIO_A) |= 0x80; - LM4_GPIO_ODR(LM4_GPIO_B) |= 0x88; -#else - /* PG6:7 = I2C5 SCL/SDA */ - gpio_set_alternate_function(LM4_GPIO_G, 0xc0, 3); - - /* Configure SDA as open-drain. SCL should not be open-drain, - * since it has an internal pull-up. */ - LM4_GPIO_ODR(LM4_GPIO_G) |= 0x80; -#endif -} - -static void i2c_init(void) -{ - volatile uint32_t scratch __attribute__((unused)); - uint32_t mask = 0; - int i; - - /* Enable I2C modules and delay a few clocks */ - for (i = 0; i < I2C_PORTS_USED; i++) - mask |= 1 << i2c_ports[i].port; - - LM4_SYSTEM_RCGCI2C |= mask; - scratch = LM4_SYSTEM_RCGCI2C; - - /* Configure GPIOs */ - configure_gpio(); - - /* No tasks are waiting on ports */ - for (i = 0; i < NUM_PORTS; i++) - task_waiting_on_port[i] = TASK_ID_INVALID; - - /* Initialize ports as master, with interrupts enabled */ - for (i = 0; i < I2C_PORTS_USED; i++) - LM4_I2C_MCR(i2c_ports[i].port) = 0x10; - - /* Set initial clock frequency */ - i2c_freq_changed(); - - /* Enable irqs */ - task_enable_irq(LM4_IRQ_I2C0); - task_enable_irq(LM4_IRQ_I2C1); - task_enable_irq(LM4_IRQ_I2C2); - task_enable_irq(LM4_IRQ_I2C3); - task_enable_irq(LM4_IRQ_I2C4); - task_enable_irq(LM4_IRQ_I2C5); -} -DECLARE_HOOK(HOOK_INIT, i2c_init, HOOK_PRIO_DEFAULT); diff --git a/chip/stm32/i2c.c b/chip/stm32/i2c.c index fe8655968c..4c83ad9678 100644 --- a/chip/stm32/i2c.c +++ b/chip/stm32/i2c.c @@ -57,7 +57,7 @@ #define I2C1 STM32_I2C1_PORT #define I2C2 STM32_I2C2_PORT -/* select the DMA channels matching the board configuration */ +/* Select the DMA channels matching the board configuration */ #define DMAC_SLAVE_TX ((I2C_PORT_SLAVE) ? DMAC_I2C2_TX : DMAC_I2C1_TX) #define DMAC_SLAVE_RX ((I2C_PORT_SLAVE) ? DMAC_I2C2_RX : DMAC_I2C1_RX) #define DMAC_HOST_TX ((I2C_PORT_HOST) ? DMAC_I2C2_TX : DMAC_I2C1_TX) @@ -68,8 +68,8 @@ enum { * A stop condition should take 2 clocks, but the process may need more * time to notice if it is preempted, so we poll repeatedly for 8 * clocks, before backing off and only check once every - * STOP_SENT_RETRY_US for up to TIMEOUT_STOP_SENT clocks before - * giving up. + * STOP_SENT_RETRY_US for up to TIMEOUT_STOP_SENT clocks before giving + * up. */ SLOW_STOP_SENT_US = I2C_PERIOD_US * 8, TIMEOUT_STOP_SENT_US = I2C_PERIOD_US * 200, @@ -93,7 +93,7 @@ static const struct dma_option dma_rx_option[NUM_PORTS] = { static uint16_t i2c_sr1[NUM_PORTS]; static struct mutex i2c_mutex; -/* buffer for host commands (including version, error code and checksum) */ +/* Buffer for host commands (including version, error code and checksum) */ static uint8_t host_buffer[EC_HOST_PARAM_SIZE + 4]; static struct host_cmd_handler_args host_cmd_args; @@ -136,7 +136,7 @@ void __board_i2c_release(int port) void board_i2c_release(int port) __attribute__((weak, alias("__board_i2c_release"))); -static int i2c_init_port(unsigned int port); +static void i2c_init_port(unsigned int port); static int i2c_write_raw_slave(int port, void *buf, int len) { @@ -452,7 +452,7 @@ static void unwedge_i2c_bus(int port) gpio_set_level(sda, 1); } -static int i2c_init_port(unsigned int port) +static void i2c_init_port(unsigned int port) { const int i2c_clock_bit[] = {21, 22}; @@ -490,29 +490,22 @@ static int i2c_init_port(unsigned int port) STM32_I2C_SR1(port) = 0; board_i2c_post_init(port); - - return EC_SUCCESS; } static void i2c_init(void) { - int rc = 0; - - /* FIXME: Add #defines to determine which channels to init */ - rc |= i2c_init_port(I2C1); - rc |= i2c_init_port(I2C2); - - /* enable event and error interrupts */ - if (!rc) { - task_enable_irq(STM32_IRQ_I2C1_EV); - task_enable_irq(STM32_IRQ_I2C1_ER); - task_enable_irq(STM32_IRQ_I2C2_EV); - task_enable_irq(STM32_IRQ_I2C2_ER); - } + /* TODO: Add #defines to determine which channels to init */ + i2c_init_port(I2C1); + i2c_init_port(I2C2); + + /* Enable event and error interrupts */ + task_enable_irq(STM32_IRQ_I2C1_EV); + task_enable_irq(STM32_IRQ_I2C1_ER); + task_enable_irq(STM32_IRQ_I2C2_EV); + task_enable_irq(STM32_IRQ_I2C2_ER); } DECLARE_HOOK(HOOK_INIT, i2c_init, HOOK_PRIO_DEFAULT); - /*****************************************************************************/ /* STM32 Host I2C */ @@ -532,7 +525,6 @@ DECLARE_HOOK(HOOK_INIT, i2c_init, HOOK_PRIO_DEFAULT); #define CR2_DMAEN (1 << 11) /* DMA enable */ #define CR2_LAST (1 << 12) /* Next EOT is last EOT */ - static inline void dump_i2c_reg(int port) { #ifdef CONFIG_DEBUG_I2C @@ -615,12 +607,14 @@ static int master_start(int port, int slave_addr) 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; @@ -670,7 +664,7 @@ static void handle_i2c_error(int port, int rv) timestamp_t t1, t2; uint32_t r; - /* we have not used the bus, just exit */ + /* We have not used the bus, just exit */ if (rv == EC_ERROR_BUSY) return; @@ -726,16 +720,17 @@ static void handle_i2c_error(int port, int rv) usleep(1000); r = STM32_I2C_SR2(port); } + cr_cleanup: - /** - * reset control register to the default state : + /* + * Reset control register to the default state : * I2C mode / Periphal enabled, ACK enabled */ STM32_I2C_CR1(port) = (1 << 10) | (1 << 0); } static int i2c_master_transmit(int port, int slave_addr, uint8_t *data, - int size, int stop) + int size, int stop) { int rv, rv_start; @@ -780,7 +775,7 @@ static int i2c_master_transmit(int port, int slave_addr, uint8_t *data, } static int i2c_master_receive(int port, int slave_addr, uint8_t *data, - int size) + int size) { int rv, rv_start; @@ -840,7 +835,7 @@ static int i2c_master_receive(int port, int slave_addr, uint8_t *data, * @return 0 if ok, else ER_ERROR... */ static int i2c_xfer(int port, int slave_addr, uint8_t *out, int out_bytes, - uint8_t *in, int in_bytes) + uint8_t *in, int in_bytes) { int rv; |