summaryrefslogtreecommitdiff
path: root/chip
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2013-04-26 14:36:38 -0700
committerChromeBot <chrome-bot@google.com>2013-04-30 11:45:52 -0700
commit0a6b7620d6b4ba1a50500a75db3e76162eac5ce0 (patch)
tree8f55cf2a2ee6469981bd27924349bf80de0f295e /chip
parentc08e0ade765bf69fb9ab3f62305a84a4d3d34c1d (diff)
downloadchrome-ec-0a6b7620d6b4ba1a50500a75db3e76162eac5ce0.tar.gz
Move i2cread and i2cwrite functions to i2c_common
Also moves the handy i2cscan command to i2c_common. The platform-dependent interface is now i2c_xfer(). Still more to do in follow-up CLs; for example, i2c_read_string() has platform-dependent implementation, and the i2c/i2cread console commands aren't common yet. BUG=chrome-os-partner:18969 BRANCH=none TEST=i2cscan on link, spring Change-Id: Ia53d57beaa157bece293a4262257e20b4107589e Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/49492 Reviewed-by: Simon Glass <sjg@chromium.org> Commit-Queue: Daniel Erat <derat@chromium.org> Commit-Queue: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'chip')
-rw-r--r--chip/lm4/config.h5
-rw-r--r--chip/lm4/i2c.c179
-rw-r--r--chip/stm32/config.h5
-rw-r--r--chip/stm32/i2c.c124
4 files changed, 72 insertions, 241 deletions
diff --git a/chip/lm4/config.h b/chip/lm4/config.h
index 46a0b125cf..95727c0c84 100644
--- a/chip/lm4/config.h
+++ b/chip/lm4/config.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 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.
*/
@@ -21,6 +21,9 @@
/* Maximum number of deferrable functions */
#define DEFERRABLE_MAX_COUNT 8
+/* Number of I2C ports */
+#define I2C_PORT_COUNT 6
+
/****************************************************************************/
/* Memory mapping */
diff --git a/chip/lm4/i2c.c b/chip/lm4/i2c.c
index 4a47011c15..506538eebf 100644
--- a/chip/lm4/i2c.c
+++ b/chip/lm4/i2c.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 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.
*/
@@ -19,8 +19,6 @@
#define CPUTS(outstr) cputs(CC_I2C, outstr)
#define CPRINTF(format, args...) cprintf(CC_I2C, format, ## args)
-#define NUM_PORTS 6 /* Number of physical ports */
-
/* Flags for writes to MCS */
#define LM4_I2C_MCS_RUN (1 << 0)
#define LM4_I2C_MCS_START (1 << 1)
@@ -39,13 +37,7 @@
#define LM4_I2C_MCS_BUSBSY (1 << 6)
#define LM4_I2C_MCS_CLKTO (1 << 7)
-#define START 1
-#define STOP 1
-#define NO_START 0
-#define NO_STOP 0
-
-static task_id_t task_waiting_on_port[NUM_PORTS];
-static struct mutex port_mutex[NUM_PORTS];
+static task_id_t task_waiting_on_port[I2C_PORT_COUNT];
extern const struct i2c_port_t i2c_ports[I2C_PORTS_USED];
/**
@@ -98,24 +90,17 @@ static int wait_idle(int port)
return EC_SUCCESS;
}
-/**
- * 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_xfer(int port, int slave_addr, const uint8_t *out, int out_size,
- uint8_t *in, int in_size, int start, int stop)
+int i2c_get_line_levels(int port)
+{
+ /* Conveniently, MBMON bit (1 << 1) is SDA and (1 << 0) is SCL. */
+ return LM4_I2C_MBMON(port) & 0x03;
+}
+
+int i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_size,
+ uint8_t *in, int in_size, int flags)
{
int rv, i;
- int started = start ? 0 : 1;
+ int started = (flags & I2C_XFER_START) ? 0 : 1;
uint32_t reg_mcs;
if (out_size == 0 && in_size == 0)
@@ -165,7 +150,8 @@ static int i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_size,
* Send stop bit if the stop flag is on, and caller
* doesn't expect to receive data.
*/
- if (stop && in_size == 0 && i == (out_size - 1))
+ if ((flags & I2C_XFER_STOP) && in_size == 0 &&
+ i == (out_size - 1))
reg_mcs |= LM4_I2C_MCS_STOP;
LM4_I2C_MCS(port) = reg_mcs;
@@ -196,7 +182,7 @@ static int i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_size,
reg_mcs |= LM4_I2C_MCS_START;
}
/* ACK all bytes except the last one */
- if (stop && i == (in_size - 1))
+ if ((flags & I2C_XFER_STOP) && i == (in_size - 1))
reg_mcs |= LM4_I2C_MCS_STOP;
else
reg_mcs |= LM4_I2C_MCS_ACK;
@@ -217,89 +203,13 @@ static int i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_size,
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 */
- mutex_lock(port_mutex + port);
- rv = i2c_xfer(port, slave_addr, &reg, 1, buf, 2, START, STOP);
- mutex_unlock(port_mutex + port);
-
- if (rv)
- return rv;
-
- if (slave_addr & I2C_FLAG_BIG_ENDIAN)
- *data = ((int)buf[0] << 8) | buf[1];
- else
- *data = ((int)buf[1] << 8) | buf[0];
-
- return EC_SUCCESS;
-}
-
-int i2c_write16(int port, int slave_addr, int offset, int data)
-{
- int rv;
- uint8_t buf[3];
-
- buf[0] = offset & 0xff;
-
- if (slave_addr & I2C_FLAG_BIG_ENDIAN) {
- buf[1] = (data >> 8) & 0xff;
- buf[2] = data & 0xff;
- } else {
- buf[1] = data & 0xff;
- buf[2] = (data >> 8) & 0xff;
- }
-
- mutex_lock(port_mutex + port);
- 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;
- uint8_t reg, val;
-
- reg = offset;
-
- mutex_lock(port_mutex + port);
- rv = i2c_xfer(port, slave_addr, &reg, 1, &val, 1, START, STOP);
- mutex_unlock(port_mutex + port);
-
- if (!rv)
- *data = val;
-
- return rv;
-}
-
-int i2c_write8(int port, int slave_addr, int offset, int data)
-{
- int rv;
- uint8_t buf[2];
-
- buf[0] = offset;
- buf[1] = data;
-
- mutex_lock(port_mutex + port);
- 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 rv;
uint8_t reg, block_length;
- mutex_lock(port_mutex + port);
+ i2c_lock(port, 1);
reg = offset;
/*
@@ -307,7 +217,7 @@ int i2c_read_string(int port, int slave_addr, int offset, uint8_t *data,
* session open without a stop.
*/
rv = i2c_xfer(port, slave_addr, &reg, 1, &block_length, 1,
- START, NO_STOP);
+ I2C_XFER_START);
if (rv)
goto exit;
@@ -315,11 +225,11 @@ int i2c_read_string(int port, int slave_addr, int offset, uint8_t *data,
block_length = len - 1;
rv = i2c_xfer(port, slave_addr, 0, 0, data, block_length,
- NO_START, STOP);
+ I2C_XFER_STOP);
data[block_length] = 0;
exit:
- mutex_unlock(port_mutex + port);
+ i2c_lock(port, 0);
return rv;
}
@@ -398,7 +308,7 @@ static void i2c_init(void)
configure_gpio();
/* No tasks are waiting on ports */
- for (i = 0; i < NUM_PORTS; i++)
+ for (i = 0; i < I2C_PORT_COUNT; i++)
task_waiting_on_port[i] = TASK_ID_INVALID;
/* Initialize ports as master, with interrupts enabled */
@@ -452,39 +362,6 @@ DECLARE_IRQ(LM4_IRQ_I2C5, i2c5_interrupt, 2);
/*****************************************************************************/
/* Console commands */
-static void scan_bus(int port, const char *desc)
-{
- int rv;
- int a;
-
- ccprintf("Scanning %d %s", port, desc);
-
- /* Don't scan a busy port, since reads will just fail / time out */
- a = LM4_I2C_MBMON(port);
- if ((a & 0x03) != 0x03) {
- ccprintf(": port busy (SDA=%d, SCL=%d)\n",
- (LM4_I2C_MBMON(port) & 0x02) ? 1 : 0,
- (LM4_I2C_MBMON(port) & 0x01) ? 1 : 0);
- return;
- }
-
- mutex_lock(port_mutex + port);
-
- for (a = 0; a < 0x100; a += 2) {
- ccputs(".");
-
- /* Do a single read */
- LM4_I2C_MSA(port) = a | 0x01;
- LM4_I2C_MCS(port) = 0x07;
- rv = wait_idle(port);
- if (rv == EC_SUCCESS)
- ccprintf("\n 0x%02x", a);
- }
-
- mutex_unlock(port_mutex + port);
- ccputs("\n");
-}
-
static int command_i2cread(int argc, char **argv)
{
int port, addr, count = 1;
@@ -515,7 +392,7 @@ static int command_i2cread(int argc, char **argv)
}
ccprintf("Reading %d bytes from %d:0x%02x:", count, port, addr);
- mutex_lock(port_mutex + port);
+ i2c_lock(port, 1);
LM4_I2C_MSA(port) = addr | 0x01;
for (i = 0; i < count; i++) {
if (i == 0)
@@ -524,13 +401,13 @@ static int command_i2cread(int argc, char **argv)
LM4_I2C_MCS(port) = (i == count - 1 ? 0x05 : 0x09);
rv = wait_idle(port);
if (rv != EC_SUCCESS) {
- mutex_unlock(port_mutex + port);
+ i2c_lock(port, 0);
return rv;
}
d = LM4_I2C_MDR(port) & 0xff;
ccprintf(" 0x%02x", d);
}
- mutex_unlock(port_mutex + port);
+ i2c_lock(port, 0);
ccputs("\n");
return EC_SUCCESS;
}
@@ -539,15 +416,3 @@ DECLARE_CONSOLE_COMMAND(i2cread, command_i2cread,
"Read from I2C",
NULL);
-static int command_scan(int argc, char **argv)
-{
- int i;
-
- for (i = 0; i < I2C_PORTS_USED; i++)
- scan_bus(i2c_ports[i].port, i2c_ports[i].name);
- return EC_SUCCESS;
-}
-DECLARE_CONSOLE_COMMAND(i2cscan, command_scan,
- NULL,
- "Scan I2C ports for devices",
- NULL);
diff --git a/chip/stm32/config.h b/chip/stm32/config.h
index 989cafa087..ef97180ebd 100644
--- a/chip/stm32/config.h
+++ b/chip/stm32/config.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 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.
*/
@@ -34,6 +34,9 @@
/* Maximum number of deferrable functions */
#define DEFERRABLE_MAX_COUNT 8
+/* Number of I2C ports */
+#define I2C_PORT_COUNT 2
+
/* support programming on-chip flash */
#define CONFIG_FLASH
diff --git a/chip/stm32/i2c.c b/chip/stm32/i2c.c
index 2b968b0dd2..8680f59521 100644
--- a/chip/stm32/i2c.c
+++ b/chip/stm32/i2c.c
@@ -57,7 +57,6 @@
*/
#define I2C_BITBANG_DELAY_US 5
-#define NUM_PORTS 2
#define I2C1 STM32_I2C1_PORT
#define I2C2 STM32_I2C2_PORT
@@ -80,22 +79,21 @@ enum {
STOP_SENT_RETRY_US = 150,
};
-static const struct dma_option dma_tx_option[NUM_PORTS] = {
+static const struct dma_option dma_tx_option[I2C_PORT_COUNT] = {
{DMAC_I2C1_TX, (void *)&STM32_I2C_DR(I2C1),
DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD},
{DMAC_I2C2_TX, (void *)&STM32_I2C_DR(I2C2),
DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD},
};
-static const struct dma_option dma_rx_option[NUM_PORTS] = {
+static const struct dma_option dma_rx_option[I2C_PORT_COUNT] = {
{DMAC_I2C1_RX, (void *)&STM32_I2C_DR(I2C1),
DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD},
{DMAC_I2C2_RX, (void *)&STM32_I2C_DR(I2C2),
DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD},
};
-static uint16_t i2c_sr1[NUM_PORTS];
-static struct mutex i2c_mutex;
+static uint16_t i2c_sr1[I2C_PORT_COUNT];
/* Buffer for host commands (including version, error code and checksum) */
static uint8_t host_buffer[EC_HOST_PARAM_SIZE + 4];
@@ -710,7 +708,7 @@ cr_cleanup:
STM32_I2C_CR1(port) = (1 << 10) | (1 << 0);
}
-static int i2c_master_transmit(int port, int slave_addr, uint8_t *data,
+static int i2c_master_transmit(int port, int slave_addr, const uint8_t *data,
int size, int stop)
{
int rv, rv_start;
@@ -804,32 +802,18 @@ static int i2c_master_receive(int port, int slave_addr, uint8_t *data,
return wait_until_stop_sent(port);
}
-/**
- * Perform an I2C transaction, involve a write, and optional read.
- *
- * @param port I2C port to use (e.g. I2C_PORT_HOST)
- * @param slave_addr Slave address of chip to access on I2C bus
- * @param out Buffer containing bytes to output
- * @param out_bytes Number of bytes to send (must be >0)
- * @param in Buffer to place input bytes
- * @param in_bytes Number of bytse to receive
- * @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)
+int i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_bytes,
+ uint8_t *in, int in_bytes, int flags)
{
int rv;
- ASSERT(out && out_bytes);
- ASSERT(in || !in_bytes);
+ /* TODO: support start/stop flags */
- disable_sleep(SLEEP_MASK_I2C);
- mutex_lock(&i2c_mutex);
+ ASSERT(out || !out_bytes);
+ ASSERT(in || !in_bytes);
- if (i2c_claim(port)) {
- rv = EC_ERROR_BUSY;
- goto err_claim;
- }
+ if (i2c_claim(port))
+ return EC_ERROR_BUSY;
disable_i2c_interrupt(port);
@@ -843,58 +827,25 @@ static int i2c_xfer(int port, int slave_addr, uint8_t *out, int out_bytes,
i2c_release(port);
-err_claim:
- mutex_unlock(&i2c_mutex);
- enable_sleep(SLEEP_MASK_I2C);
-
- return rv;
-}
-
-int i2c_read16(int port, int slave_addr, int offset, int *data)
-{
- uint8_t reg, buf[2];
- int rv;
-
- reg = offset & 0xff;
- rv = i2c_xfer(port, slave_addr, &reg, 1, buf, 2);
-
- *data = (buf[1] << 8) | buf[0];
-
return rv;
}
-int i2c_write16(int port, int slave_addr, int offset, int data)
-{
- uint8_t buf[3];
-
- buf[0] = offset & 0xff;
- buf[1] = data & 0xff;
- buf[2] = (data >> 8) & 0xff;
-
- return i2c_xfer(port, slave_addr, buf, sizeof(buf), NULL, 0);
-}
-
-int i2c_read8(int port, int slave_addr, int offset, int *data)
+int i2c_get_line_levels(int port)
{
- uint8_t reg, buf[1];
- int rv;
-
- reg = offset & 0xff;
- rv = i2c_xfer(port, slave_addr, &reg, 1, buf, 1);
-
- *data = buf[0];
-
- return rv;
-}
+ enum gpio_signal sda, scl;
-int i2c_write8(int port, int slave_addr, int offset, int data)
-{
- uint8_t buf[2];
+ ASSERT(port == I2C1 || port == I2C2);
- buf[0] = offset & 0xff;
- buf[1] = data & 0xff;
+ if (port == I2C1) {
+ sda = GPIO_I2C1_SDA;
+ scl = GPIO_I2C1_SCL;
+ } else {
+ sda = GPIO_I2C2_SDA;
+ scl = GPIO_I2C2_SCL;
+ }
- return i2c_xfer(port, slave_addr, buf, sizeof(buf), NULL, 0);
+ return (gpio_get_level(sda) ? I2C_LINE_SDA_HIGH : 0) |
+ (gpio_get_level(scl) ? I2C_LINE_SCL_HIGH : 0);
}
int i2c_read_string(int port, int slave_addr, int offset, uint8_t *data,
@@ -902,23 +853,32 @@ int i2c_read_string(int port, int slave_addr, int offset, uint8_t *data,
{
int rv;
uint8_t reg, block_length;
+
+ /*
+ * TODO: when i2c_xfer() supports start/stop bits, won't need a temp
+ * buffer, and this code can merge with the LM4 implementation and
+ * move to i2c_common.c.
+ */
uint8_t buffer[SMBUS_MAX_BLOCK + 1];
if ((len <= 0) || (len > SMBUS_MAX_BLOCK))
return EC_ERROR_INVAL;
- reg = offset;
- rv = i2c_xfer(port, slave_addr, &reg, 1, buffer, SMBUS_MAX_BLOCK + 1);
- if (rv)
- return rv;
+ i2c_lock(port, 1);
- /* the length of the block is the first byte of the returned buffer */
- block_length = MIN(buffer[0], len - 1);
- buffer[block_length + 1] = 0;
-
- memcpy(data, buffer+1, block_length + 1);
+ reg = offset;
+ rv = i2c_xfer(port, slave_addr, &reg, 1, buffer, SMBUS_MAX_BLOCK + 1,
+ I2C_XFER_SINGLE);
+ if (rv == EC_SUCCESS) {
+ /* Block length is the first byte of the returned buffer */
+ block_length = MIN(buffer[0], len - 1);
+ buffer[block_length + 1] = 0;
+
+ memcpy(data, buffer+1, block_length + 1);
+ }
- return EC_SUCCESS;
+ i2c_lock(port, 0);
+ return rv;
}
/*****************************************************************************/