diff options
author | Randall Spangler <rspangler@chromium.org> | 2013-03-19 13:40:59 -0700 |
---|---|---|
committer | ChromeBot <chrome-bot@google.com> | 2013-03-20 15:23:29 -0700 |
commit | 34e17d4c05ccc4ad48b0a717aebcf278c97f1a79 (patch) | |
tree | 6afb325abc859c8e99ea9b5d7ced633557a0bde4 | |
parent | 19920f1f74f07e00160f4bb817d756f2af024744 (diff) | |
download | chrome-ec-34e17d4c05ccc4ad48b0a717aebcf278c97f1a79.tar.gz |
Move I2C arbitration to its own file
It's only board-specific in that we've only needed it on snow so far.
But by that logic, x86_power would be board specific because we've
only needed it on link.
No functionality change, just moving code between files and renaming
the interface to indicate it's not board-specific.
BUG=chrome-os-partner:18343
BRANCH=none
TEST=build daisy,snow,spring
Change-Id: I35debdaa71829d55a2fbc5d3c62b2aaf6e467633
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/45879
-rw-r--r-- | board/snow/board.c | 96 | ||||
-rw-r--r-- | board/snow/board.h | 2 | ||||
-rw-r--r-- | chip/stm32/i2c.c | 27 | ||||
-rw-r--r-- | common/build.mk | 1 | ||||
-rw-r--r-- | common/i2c_arbitration.c | 104 | ||||
-rw-r--r-- | include/i2c.h | 30 | ||||
-rw-r--r-- | include/i2c_arbitration.h | 44 |
7 files changed, 157 insertions, 147 deletions
diff --git a/board/snow/board.c b/board/snow/board.c index 3964f15f3a..2f5900340b 100644 --- a/board/snow/board.c +++ b/board/snow/board.c @@ -229,34 +229,6 @@ void board_power_led_config(enum powerled_config config) } } -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 = 100 * 1000, -}; - -/* - * This reflects the desired value of GPIO_EC_CLAIM to ensure that the - * GPIO is driven correctly when re-enabled before AP power on. - */ -static char i2c_claimed_by_ec; - -static void board_pre_init_hook(void) -{ -#ifdef CONFIG_ARBITRATE_I2C - gpio_set_flags(GPIO_AP_CLAIM, GPIO_PULL_UP); - gpio_set_level(GPIO_EC_CLAIM, i2c_claimed_by_ec ? 0 : 1); - gpio_set_flags(GPIO_EC_CLAIM, GPIO_OUTPUT); - usleep(BUS_SLEW_DELAY_US); -#endif -} -DECLARE_HOOK(HOOK_CHIPSET_PRE_INIT, board_pre_init_hook, HOOK_PRIO_DEFAULT); - static void board_startup_hook(void) { gpio_set_flags(GPIO_SUSPEND_L, INT_BOTH_PULL_UP); @@ -267,77 +239,9 @@ static void board_shutdown_hook(void) { /* Disable pull-up on SUSPEND_L during shutdown to prevent leakage */ gpio_set_flags(GPIO_SUSPEND_L, INT_BOTH_FLOATING); - -#ifdef CONFIG_ARBITRATE_I2C - gpio_set_flags(GPIO_AP_CLAIM, GPIO_INPUT); - gpio_set_flags(GPIO_EC_CLAIM, GPIO_INPUT); -#endif } DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, board_shutdown_hook, HOOK_PRIO_DEFAULT); -#ifdef CONFIG_ARBITRATE_I2C - -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_ANY_OFF)) { - i2c_claimed_by_ec = 1; - 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 */ - i2c_claimed_by_ec = 1; - 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); - - gpio_set_level(GPIO_EC_CLAIM, 1); - usleep(BUS_SLEW_DELAY_US); - i2c_claimed_by_ec = 0; - - panic_puts("Unable to access I2C bus (arbitration timeout)\n"); - 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); - usleep(BUS_SLEW_DELAY_US); - i2c_claimed_by_ec = 0; - } -} -#endif /* CONFIG_ARBITRATE_I2C */ - /* * Force the pmic to reset completely. This forces an entire system reset, * and therefore should never return diff --git a/board/snow/board.h b/board/snow/board.h index 89e77e4f0c..5f2bb4c5c9 100644 --- a/board/snow/board.h +++ b/board/snow/board.h @@ -24,6 +24,7 @@ #define CONFIG_CONFIGURE_BOARD_LATE #define CONFIG_HOST_COMMAND_STATUS #define CONFIG_I2C +#define CONFIG_I2C_ARBITRATION #undef CONFIG_TASK_PROFILING #define CONFIG_WATCHDOG_HELP @@ -50,7 +51,6 @@ #define I2C_PORT_BATTERY I2C_PORT_HOST #define I2C_PORT_CHARGER I2C_PORT_HOST #define I2C_PORT_SLAVE 1 -#define CONFIG_ARBITRATE_I2C I2C_PORT_HOST #define GPIO_AP_CLAIM GPIO_SPI1_NSS /* AP claims bus */ #define GPIO_EC_CLAIM GPIO_SPI1_MISO /* EC claims bus */ diff --git a/chip/stm32/i2c.c b/chip/stm32/i2c.c index e2f1a9fbd8..a682883c89 100644 --- a/chip/stm32/i2c.c +++ b/chip/stm32/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. */ @@ -12,6 +12,7 @@ #include "hooks.h" #include "host_command.h" #include "i2c.h" +#include "i2c_arbitration.h" #include "registers.h" #include "task.h" #include "timer.h" @@ -123,22 +124,6 @@ static inline void disable_ack(int port) STM32_I2C_CR1(port) &= ~(1 << 10); } -int __board_i2c_claim(int port) -{ - return 0; -} - -int board_i2c_claim(int port) - __attribute__((weak, alias("__board_i2c_claim"))); - - -void __board_i2c_release(int port) -{ -} - -void board_i2c_release(int port) - __attribute__((weak, alias("__board_i2c_release"))); - static void i2c_init_port(unsigned int port); static int i2c_write_raw_slave(int port, void *buf, int len) @@ -464,9 +449,9 @@ static void i2c_init_port(unsigned int port) if (!(STM32_RCC_APB1ENR & (1 << i2c_clock_bit[port]))) { /* Only unwedge the bus if the clock is off */ - if (board_i2c_claim(port) == EC_SUCCESS) { + if (i2c_claim(port) == EC_SUCCESS) { unwedge_i2c_bus(port); - board_i2c_release(port); + i2c_release(port); } /* enable I2C2 clock */ @@ -848,7 +833,7 @@ static int i2c_xfer(int port, int slave_addr, uint8_t *out, int out_bytes, disable_sleep(SLEEP_MASK_I2C); mutex_lock(&i2c_mutex); - if (board_i2c_claim(port)) { + if (i2c_claim(port)) { rv = EC_ERROR_BUSY; goto err_claim; } @@ -863,7 +848,7 @@ static int i2c_xfer(int port, int slave_addr, uint8_t *out, int out_bytes, enable_i2c_interrupt(port); - board_i2c_release(port); + i2c_release(port); err_claim: mutex_unlock(&i2c_mutex); diff --git a/common/build.mk b/common/build.mk index 7fb75d3a39..a490cf9479 100644 --- a/common/build.mk +++ b/common/build.mk @@ -19,6 +19,7 @@ common-$(CONFIG_EOPTION)+=eoption.o common-$(CONFIG_EXTPOWER_GPIO)+=extpower_gpio.o common-$(CONFIG_FLASH)+=flash_common.o fmap.o common-$(CONFIG_I2C)+=i2c_commands.o +common-$(CONFIG_I2C_ARBITRATION)+=i2c_arbitration.o common-$(CONFIG_IR357x)+=ir357x.o common-$(CONFIG_KEYBOARD_TEST)+=keyboard_test.o common-$(CONFIG_LP5562)+=lp5562.o diff --git a/common/i2c_arbitration.c b/common/i2c_arbitration.c new file mode 100644 index 0000000000..70b4b81dcd --- /dev/null +++ b/common/i2c_arbitration.c @@ -0,0 +1,104 @@ +/* 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. + */ +/* I2C arbitration using a pair of GPIO lines */ + +#include "chipset.h" +#include "common.h" +#include "gpio.h" +#include "hooks.h" +#include "i2c.h" +#include "timer.h" +#include "util.h" + +/* Time between requesting bus and deciding that we have it */ +#define BUS_SLEW_DELAY_US 10 + +/* Time between retrying to see if the AP has released the bus */ +#define BUS_WAIT_RETRY_US 3000 + +/* Time to wait until the bus becomes free */ +#define BUS_WAIT_FREE_US (100 * 1000) + +/* + * This reflects the desired value of GPIO_EC_CLAIM to ensure that the + * GPIO is driven correctly when re-enabled before AP power on. + */ +static char i2c_claimed_by_ec; + +int 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_ANY_OFF)) { + i2c_claimed_by_ec = 1; + 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 */ + i2c_claimed_by_ec = 1; + 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); + + gpio_set_level(GPIO_EC_CLAIM, 1); + usleep(BUS_SLEW_DELAY_US); + i2c_claimed_by_ec = 0; + + panic_puts("Unable to access I2C bus (arbitration timeout)\n"); + return EC_ERROR_BUSY; +} + +void i2c_release(int port) +{ + if (port == I2C_PORT_HOST) { + /* Release our claim */ + gpio_set_level(GPIO_EC_CLAIM, 1); + usleep(BUS_SLEW_DELAY_US); + i2c_claimed_by_ec = 0; + } +} + +static void i2c_pre_init_hook(void) +{ + gpio_set_flags(GPIO_AP_CLAIM, GPIO_PULL_UP); + gpio_set_level(GPIO_EC_CLAIM, i2c_claimed_by_ec ? 0 : 1); + gpio_set_flags(GPIO_EC_CLAIM, GPIO_OUTPUT); + usleep(BUS_SLEW_DELAY_US); +} +DECLARE_HOOK(HOOK_CHIPSET_PRE_INIT, i2c_pre_init_hook, HOOK_PRIO_DEFAULT); + +static void i2c_shutdown_hook(void) +{ + gpio_set_flags(GPIO_AP_CLAIM, GPIO_INPUT); + gpio_set_flags(GPIO_EC_CLAIM, GPIO_INPUT); +} +DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, i2c_shutdown_hook, HOOK_PRIO_DEFAULT); diff --git a/include/i2c.h b/include/i2c.h index dbf933e102..d14008a2d0 100644 --- a/include/i2c.h +++ b/include/i2c.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. */ @@ -48,32 +48,4 @@ int i2c_write8(int port, int slave_addr, int offset, int data); int i2c_read_string(int port, int slave_addr, int offset, uint8_t *data, int len); -/** - * Claim an I2C port for use in master mode - * - * If this function succeed, then you must later call board_i2c_release() - * to release the claim. - * - * This function may optionally be implemented by a board file. If provided - * then it should check the port number and arbitrate as needed. - * - * This function will not be called to claim an already-claimed port. - * - * @param port Port to claim (0 for first, 1 for second, etc.) - * @return 0 if claimed successfully, -1 if it is in use - */ -int board_i2c_claim(int port); - -/** - * Release an I2C port (after previously being claimed) - * - * This function may optionally be implemented by a board file. If provided - * then it should check the port number and arbitrate as needed. - * - * This function will not be called to release an already-released port. - * - * @param port Port to claim (0 for first, 1 for second, etc.) - */ -void board_i2c_release(int port); - #endif /* __CROS_EC_I2C_H */ diff --git a/include/i2c_arbitration.h b/include/i2c_arbitration.h new file mode 100644 index 0000000000..cf4d39d247 --- /dev/null +++ b/include/i2c_arbitration.h @@ -0,0 +1,44 @@ +/* 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. + */ + +/* I2C arbitration for Chrome EC */ + +#ifndef __CROS_EC_I2C_ARBITRATION_H +#define __CROS_EC_I2C_ARBITRATION_H + +#include "common.h" + +#ifdef CONFIG_I2C_ARBITRATION + +/** + * Claim an I2C port for use in master mode. + * + * If this function succeeds, you must later call i2c_release() to release the + * claim. + * + * This function must not be called to claim an already-claimed port. + * + * @param port Port to claim (0 for first, 1 for second, etc.) + * @return 0 if claimed successfully, -1 if it is in use + */ +int i2c_claim(int port); + +/** + * Release an I2C port (after previously being claimed) + * + * This function must not be called to release an already-released port. + * + * @param port Port to claim (0 for first, 1 for second, etc.) + */ +void i2c_release(int port); + +#else + +static inline int i2c_claim(int port) { return EC_SUCCESS; } +static inline void i2c_release(int port) {} + +#endif + +#endif /* __CROS_EC_I2C_ARBITRATION_H */ |