diff options
Diffstat (limited to 'chip/nrf51/i2c.c')
-rw-r--r-- | chip/nrf51/i2c.c | 304 |
1 files changed, 0 insertions, 304 deletions
diff --git a/chip/nrf51/i2c.c b/chip/nrf51/i2c.c deleted file mode 100644 index ff23152c89..0000000000 --- a/chip/nrf51/i2c.c +++ /dev/null @@ -1,304 +0,0 @@ -/* Copyright 2014 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 "clock.h" -#include "common.h" -#include "console.h" -#include "gpio.h" -#include "hooks.h" -#include "i2c.h" -#include "ppi.h" -#include "registers.h" -#include "task.h" -#include "timer.h" -#include "util.h" - -/* Console output macros */ -#define CPUTS(outstr) cputs(CC_I2C, outstr) -#define CPRINTF(format, args...) cprintf(CC_I2C, format, ## args) -#define CPRINTS(format, args...) cprints(CC_I2C, format, ## args) - -#define I2C_TIMEOUT 20000 - -/* Keep track of the PPI channel used for each port */ -static int i2c_ppi_chan[] = {-1, -1}; - -static void i2c_init_port(unsigned int port); - -/* board-specific setup for post-I2C module init */ -void __board_i2c_post_init(int port) -{ -} - -void board_i2c_post_init(int port) - __attribute__((weak, alias("__board_i2c_post_init"))); - -static void i2c_init_port(unsigned int port) -{ - NRF51_TWI_RXDRDY(port) = 0; - NRF51_TWI_TXDSENT(port) = 0; - - NRF51_TWI_PSELSCL(port) = NRF51_TWI_SCL_PIN(port); - NRF51_TWI_PSELSDA(port) = NRF51_TWI_SDA_PIN(port); - NRF51_TWI_FREQUENCY(port) = NRF51_TWI_FREQ(port); - - NRF51_PPI_CHENCLR = 1 << i2c_ppi_chan[port]; - - NRF51_PPI_EEP(i2c_ppi_chan[port]) = (uint32_t)&NRF51_TWI_BB(port); - NRF51_PPI_TEP(i2c_ppi_chan[port]) = - (uint32_t)&NRF51_TWI_SUSPEND(port); - - /* Master enable */ - NRF51_TWI_ENABLE(port) = NRF51_TWI_ENABLE_VAL; - - if (!(i2c_raw_get_scl(port) && (i2c_raw_get_sda(port)))) - CPRINTF("port %d could be wedged\n", port); -} - -void i2c_init(void) -{ - int i, rv; - - gpio_config_module(MODULE_I2C, 1); - - for (i = 0; i < i2c_ports_used; i++) { - if (i2c_ppi_chan[i] == -1) { - rv = ppi_request_channel(&i2c_ppi_chan[i]); - ASSERT(rv == EC_SUCCESS); - - i2c_init_port(i); - } - } -} - -static void dump_i2c_reg(int port) -{ -#ifdef CONFIG_I2C_DEBUG - CPRINTF("port : %01d\n", port); - CPRINTF("Regs :\n"); - CPRINTF(" 1: INTEN : %08x\n", NRF51_TWI_INTEN(port)); - CPRINTF(" 2: ERRORSRC : %08x\n", NRF51_TWI_ERRORSRC(port)); - CPRINTF(" 3: ENABLE : %08x\n", NRF51_TWI_ENABLE(port)); - CPRINTF(" 4: PSELSCL : %08x\n", NRF51_TWI_PSELSCL(port)); - CPRINTF(" 5: PSELSDA : %08x\n", NRF51_TWI_PSELSDA(port)); - CPRINTF(" 6: RXD : %08x\n", NRF51_TWI_RXD(port)); - CPRINTF(" 7: TXD : %08x\n", NRF51_TWI_TXD(port)); - CPRINTF(" 8: FREQUENCY : %08x\n", NRF51_TWI_FREQUENCY(port)); - CPRINTF(" 9: ADDRESS : %08x\n", NRF51_TWI_ADDRESS(port)); - CPRINTF("Events :\n"); - CPRINTF(" STOPPED : %08x\n", NRF51_TWI_STOPPED(port)); - CPRINTF(" RXDRDY : %08x\n", NRF51_TWI_RXDRDY(port)); - CPRINTF(" TXDSENT : %08x\n", NRF51_TWI_TXDSENT(port)); - CPRINTF(" ERROR : %08x\n", NRF51_TWI_ERROR(port)); - CPRINTF(" BB : %08x\n", NRF51_TWI_BB(port)); -#endif /* CONFIG_I2C_DEBUG */ -} - -static void i2c_recover(int port) -{ - /* - * Recovery of the TWI peripheral: - * To recover a TWI peripheral that has been locked up you must use - * the following code. - * After the recover function it is important to reconfigure all - * relevant TWI registers explicitly to ensure that it operates - * correctly. - * TWI0: - * NRF_TWI0->ENABLE = - * TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos; - * *(uint32_t *)(NRF_TWI0_BASE + 0xFFC) = 0; - * nrf_delay_us(5); - * *(uint32_t *)(NRF_TWI0_BASE + 0xFFC) = 1; - * NRF_TWI0->ENABLE = - * TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos; - */ - NRF51_TWI_ENABLE(port) = NRF51_TWI_DISABLE_VAL; - NRF51_TWI_POWER(port) = 0; - udelay(5); - NRF51_TWI_POWER(port) = 1; - - i2c_init_port(port); -} - -static void handle_i2c_error(int port, int rv) -{ - if (rv == EC_SUCCESS) - return; - -#ifdef CONFIG_I2C_DEBUG - if (rv != EC_ERROR_TIMEOUT) - CPRINTF("handle_i2c_error %d\n", rv); - else - CPRINTF("handle_i2c_error: Timeout\n"); - - dump_i2c_reg(port); -#endif - - /* This may be a little too heavy handed. */ - i2c_recover(port); -} - -static int i2c_master_write(const int port, const uint16_t slave_addr_flags, - const uint8_t *data, int size, int stop) -{ - int bytes_sent; - int timeout = I2C_TIMEOUT; - - NRF51_TWI_ADDRESS(port) = I2C_STRIP_FLAGS(slave_addr_flags); - - /* Clear the sent bit */ - NRF51_TWI_TXDSENT(port) = 0; - - for (bytes_sent = 0; bytes_sent < size; bytes_sent++) { - /*Send a byte */ - NRF51_TWI_TXD(port) = data[bytes_sent]; - - /* Only send a start for the first byte */ - if (bytes_sent == 0) - NRF51_TWI_STARTTX(port) = 1; - - /* Wait for ACK/NACK */ - timeout = I2C_TIMEOUT; - while (timeout > 0 && NRF51_TWI_TXDSENT(port) == 0 && - NRF51_TWI_ERROR(port) == 0) - timeout--; - - if (timeout == 0) - return EC_ERROR_TIMEOUT; - - if (NRF51_TWI_ERROR(port)) - return EC_ERROR_UNKNOWN; - - /* Clear the sent bit */ - NRF51_TWI_TXDSENT(port) = 0; - } - - if (stop) { - NRF51_TWI_STOPPED(port) = 0; - NRF51_TWI_STOP(port) = 1; - timeout = 10; - while (NRF51_TWI_STOPPED(port) == 0 && timeout > 0) - timeout--; - } - - return EC_SUCCESS; -} - -static int i2c_master_read(const int port, const uint16_t slave_addr_flags, - uint8_t *data, int size) -{ - int curr_byte; - int timeout = I2C_TIMEOUT; - - NRF51_TWI_ADDRESS(port) = I2C_STRIP_FLAGS(slave_addr_flags); - - if (size == 1) /* Last byte: stop after this one. */ - NRF51_PPI_TEP(i2c_ppi_chan[port]) = - (uint32_t)&NRF51_TWI_STOP(port); - else - NRF51_PPI_TEP(i2c_ppi_chan[port]) = - (uint32_t)&NRF51_TWI_SUSPEND(port); - NRF51_PPI_CHENSET = 1 << i2c_ppi_chan[port]; - - NRF51_TWI_RXDRDY(port) = 0; - NRF51_TWI_STARTRX(port) = 1; - - for (curr_byte = 0; curr_byte < size; curr_byte++) { - - /* Wait for data */ - while (timeout > 0 && NRF51_TWI_RXDRDY(port) == 0 && - NRF51_TWI_ERROR(port) == 0) - timeout--; - - if (timeout == 0) - return EC_ERROR_TIMEOUT; - - if (NRF51_TWI_ERROR(port)) - return EC_ERROR_UNKNOWN; - - data[curr_byte] = NRF51_TWI_RXD(port); - NRF51_TWI_RXDRDY(port) = 0; - - /* Second to the last byte: stop next time. */ - if (curr_byte == size-2) - NRF51_PPI_TEP(i2c_ppi_chan[port]) = - (uint32_t)&NRF51_TWI_STOP(port); - - /* - * According to nRF51822-PAN v2.4 (Product Anomaly Notice), - * the I2C locks up when RESUME is triggered too soon. - * "the firmware should ensure that the time between receiving - * the RXDRDY event and trigging the RESUME task is at least - * two times the TWI clock period (i.e. 20 μs at 100 kbps). - * Provided the TWI slave doesn’t do clock stretching during - * the ACK bit, this will be enough to avoid the RESUME task - * hit the end of the ACK bit. If this fails, a recovery of - * the peripheral will be necessary, see i2c_recover. - */ - udelay(20); - NRF51_TWI_RESUME(port) = 1; - } - - timeout = I2C_TIMEOUT; - while (NRF51_TWI_STOPPED(port) == 0 && timeout > 0) - timeout--; - - NRF51_TWI_STOP(port) = 0; - - NRF51_PPI_CHENCLR = 1 << i2c_ppi_chan[port]; - - return EC_SUCCESS; -} - -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 rv = EC_SUCCESS; - - ASSERT(out || !out_bytes); - ASSERT(in || !in_bytes); - - if (out_bytes) - rv = i2c_master_write(port, slave_addr_flags, - out, out_bytes, - in_bytes ? 0 : 1); - if (rv == EC_SUCCESS && in_bytes) - rv = i2c_master_read(port, slave_addr_flags, - in, in_bytes); - - handle_i2c_error(port, rv); - - 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 SDA 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); -} - |