summaryrefslogtreecommitdiff
path: root/common/i2c.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/i2c.c')
-rw-r--r--common/i2c.c26
1 files changed, 18 insertions, 8 deletions
diff --git a/common/i2c.c b/common/i2c.c
index 6e8bf10c4e..c06df9d784 100644
--- a/common/i2c.c
+++ b/common/i2c.c
@@ -33,6 +33,7 @@
#endif
static struct mutex port_mutex[I2C_CONTROLLER_COUNT];
+static uint32_t i2c_port_active_count;
int i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_size,
uint8_t *in, int in_size, int flags)
@@ -57,18 +58,27 @@ void i2c_lock(int port, int lock)
ASSERT(port != -1);
#endif
if (lock) {
- /*
- * Don't allow deep sleep when I2C port is locked
- * TODO(crbug.com/537759): Fix sleep mask for multi-port lock.
- */
+ mutex_lock(port_mutex + port);
+
+ /* Disable interrupt during changing counter for preemption. */
+ interrupt_disable();
+
+ i2c_port_active_count++;
+ /* Ec cannot enter sleep if there's any i2c port active. */
disable_sleep(SLEEP_MASK_I2C_MASTER);
- mutex_lock(port_mutex + port);
+ interrupt_enable();
} else {
- mutex_unlock(port_mutex + port);
+ interrupt_disable();
+
+ i2c_port_active_count--;
+ /* Once there is no i2c port active, enable sleep bit of i2c. */
+ if (!i2c_port_active_count)
+ enable_sleep(SLEEP_MASK_I2C_MASTER);
- /* Allow deep sleep again after I2C port is unlocked */
- enable_sleep(SLEEP_MASK_I2C_MASTER);
+ interrupt_enable();
+
+ mutex_unlock(port_mutex + port);
}
}