summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2012-06-26 14:21:28 -0700
committerGerrit <chrome-bot@google.com>2012-07-02 22:35:50 -0700
commit34bba875778918f1b4e45c5f3ced982adbca5b9e (patch)
tree80edcadbe2645275ca72fc05c3925b1294a434bb
parent95f11b09ebcddacd121b976f9c38c4694e648223 (diff)
downloadchrome-ec-34bba875778918f1b4e45c5f3ced982adbca5b9e.tar.gz
snow: Implement I2C arbitration
Use two suitable GPIOs to implement a simple arbitration scheme. Each side owns one of the GPIOs, which are normally pulled high. When one side wants to use I2C as a master, it pulls its GPIO low, waits for a short period to make sure that the other side is not also pulling its GPIO low, and then goes ahead with the transaction. When the transaction is over, the GPIO is released, thus freeing the I2C bus up for use by the other end. For simplicity the terminolgy used here is EC for us, and AP for the other end. BUG=chrome-os-partner:10888 TEST=manual: build for all boards boot on snow (cannot test i2c as it is broken) Change-Id: I97d9fbd5aba8248c8c1240baaec17db22860665c Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/26142
-rw-r--r--board/snow/board.c71
-rw-r--r--chip/stm32/i2c.c8
2 files changed, 71 insertions, 8 deletions
diff --git a/board/snow/board.c b/board/snow/board.c
index 4c9e30bd4b..4231ee4b2a 100644
--- a/board/snow/board.c
+++ b/board/snow/board.c
@@ -5,12 +5,15 @@
/* Snow board-specific configuration */
#include "board.h"
+#include "chipset.h"
#include "common.h"
+#include "console.h"
#include "dma.h"
#include "gpio.h"
#include "i2c.h"
#include "registers.h"
#include "spi.h"
+#include "timer.h"
#include "util.h"
#define GPIO_KB_INPUT (GPIO_INPUT | GPIO_PULL_UP | GPIO_INT_BOTH)
@@ -170,3 +173,71 @@ void board_interrupt_host(int active)
/* interrupt host by using active low EC_INT signal */
gpio_set_level(GPIO_EC_INT, !active);
}
+
+enum {
+ /* Time between requesting bus and deciding that we have it */
+ BUS_SLEW_DELAY_US = 10,
+
+ /* Time between retrying to see if the AP has released the bus */
+ BUS_WAIT_RETRY_US = 3000,
+
+ /* Time to wait until the bus becomes free */
+ BUS_WAIT_FREE_US = 50 * 1000,
+};
+
+#ifdef CONFIG_ARBITRATE_I2C
+#define GPIO_AP_CLAIM GPIO_SPI1_NSS
+#define GPIO_EC_CLAIM GPIO_SPI1_MISO
+
+int board_i2c_claim(int port)
+{
+ timestamp_t start;
+
+ if (port != I2C_PORT_HOST)
+ return EC_SUCCESS;
+
+ /* If AP is off, we have the bus */
+ if (!chipset_in_state(CHIPSET_STATE_ON)) {
+ gpio_set_level(GPIO_EC_CLAIM, 0);
+ return EC_SUCCESS;
+ }
+
+ /* Start a round of trying to claim the bus */
+ start = get_time();
+ do {
+ timestamp_t start_retry;
+ int waiting = 0;
+
+ /* Indicate that we want to claim the bus */
+ gpio_set_level(GPIO_EC_CLAIM, 0);
+ usleep(BUS_SLEW_DELAY_US);
+
+ /* Wait for the AP to release it */
+ start_retry = get_time();
+ while (time_since32(start_retry) < BUS_WAIT_RETRY_US) {
+ if (gpio_get_level(GPIO_AP_CLAIM)) {
+ /* We got it, so return */
+ return EC_SUCCESS;
+ }
+
+ if (!waiting)
+ waiting = 1;
+ }
+
+ /* It didn't release, so give up, wait, and try again */
+ gpio_set_level(GPIO_EC_CLAIM, 1);
+
+ usleep(BUS_WAIT_RETRY_US);
+ } while (time_since32(start) < BUS_WAIT_FREE_US);
+
+ return EC_ERROR_BUSY;
+}
+
+void board_i2c_release(int port)
+{
+ if (port == I2C_PORT_HOST) {
+ /* Release our claim */
+ gpio_set_level(GPIO_EC_CLAIM, 1);
+ }
+}
+#endif
diff --git a/chip/stm32/i2c.c b/chip/stm32/i2c.c
index e4840e786e..ec3be2ace7 100644
--- a/chip/stm32/i2c.c
+++ b/chip/stm32/i2c.c
@@ -424,10 +424,6 @@ static int i2c_master_transmit(int port, int slave_addr, uint8_t *data,
{
int rv, i;
- /* if the AP is ON, don't play with the connection */
- if ((port == I2C_PORT_SLAVE) && chipset_in_state(CHIPSET_STATE_ON))
- return EC_ERROR_BUSY;
-
disable_ack(port);
rv = master_start(port, slave_addr);
if (rv)
@@ -471,10 +467,6 @@ static int i2c_master_receive(int port, int slave_addr, uint8_t *data,
*/
int rv, i;
- /* if the AP is ON, don't play with the connection */
- if ((port == I2C_PORT_SLAVE) && chipset_in_state(CHIPSET_STATE_ON))
- return EC_ERROR_BUSY;
-
if (data == NULL || size < 1)
return EC_ERROR_INVAL;