summaryrefslogtreecommitdiff
path: root/chip/npcx/i2c.c
diff options
context:
space:
mode:
authorMulin Chao <mlchao@nuvoton.com>2015-08-27 11:10:57 +0800
committerchrome-bot <chrome-bot@chromium.org>2015-09-06 22:12:29 -0700
commite8bdf07a58850cfac026b4ad8409c229446a9243 (patch)
tree6ea66322a08b95dff576107c15b6df4b197e0ec3 /chip/npcx/i2c.c
parente5e8f84d412dc97d9e33b12fef61b6657627f772 (diff)
downloadchrome-ec-e8bdf07a58850cfac026b4ad8409c229446a9243.tar.gz
nuc: Fixed the bugs for flash and i2c drivers.
Since the length of flash-write function used by host command is not aligned to 256 bytes, we need to split it into several sequences to make sure it won't exceed page buffer size of flash. Add i2c stop condition checking to avoid unnecessary i2c unwedge operations. We found some battery will held scl for a while and master cann't issue stop condition immediately. Modified drivers: 1. flash.c: Add support for sequence programing. 2. i2c.c: Add i2c stop condition checking mechanism. 3. i2c.c: Fixed bug of i2c_is_raw_mode. (wrong bit offset) BUG=chrome-os-partner:34346 TEST=make buildall -j; test nuvoton IC specific drivers BRANCH=none Change-Id: I4f35a617466ba37bcc4e3aa5324c8950f824a4c2 Signed-off-by: Ian Chao <mlchao@nuvoton.com> Reviewed-on: https://chromium-review.googlesource.com/295662 Commit-Ready: Mulin Chao <mlchao@nuvoton.com> Tested-by: Mulin Chao <mlchao@nuvoton.com> Reviewed-by: Randall Spangler <rspangler@chromium.org> Reviewed-by: Shawn N <shawnn@chromium.org>
Diffstat (limited to 'chip/npcx/i2c.c')
-rw-r--r--chip/npcx/i2c.c60
1 files changed, 43 insertions, 17 deletions
diff --git a/chip/npcx/i2c.c b/chip/npcx/i2c.c
index 77788525e4..8b37e8428d 100644
--- a/chip/npcx/i2c.c
+++ b/chip/npcx/i2c.c
@@ -29,8 +29,11 @@
#define NPCX_I2C_PUBIT(controller, port) \
((controller*2) + port)
-/* Data abort timeout unit:ms*/
-#define I2C_ABORT_TIMEOUT 35
+/* Timeout for device should be available after reset (SMBus spec. unit:ms) */
+#define I2C_MAX_TIMEOUT 35
+/* Timeout for SCL held to low by slave device . (SMBus spec. unit:ms) */
+#define I2C_MIN_TIMEOUT 25
+
/* Marco functions of I2C */
#define I2C_START(ctrl) SET_BIT(NPCX_SMBCTL1(ctrl), NPCX_SMBCTL1_START)
#define I2C_STOP(ctrl) SET_BIT(NPCX_SMBCTL1(ctrl), NPCX_SMBCTL1_STOP)
@@ -118,35 +121,49 @@ int i2c_bus_busy(int controller)
return IS_BIT_SET(NPCX_SMBCST(controller), NPCX_SMBCST_BB) ? 1 : 0;
}
-int i2c_abort_data(int controller)
+static int i2c_wait_stop_completed(int controller, int timeout)
{
- uint16_t timeout = I2C_ABORT_TIMEOUT;
+ if (timeout <= 0)
+ return EC_ERROR_INVAL;
+
+ /* Wait till STOP condition is generated. ie. I2C bus is idle. */
+ while (timeout > 0) {
+ if (!IS_BIT_SET(NPCX_SMBCTL1(controller), NPCX_SMBCTL1_STOP))
+ break;
+ if (--timeout > 0)
+ msleep(1);
+ }
+
+ if (timeout)
+ return EC_SUCCESS;
+ else
+ return EC_ERROR_TIMEOUT;
+}
+int i2c_abort_data(int controller)
+{
/* Clear NEGACK, STASTR and BER bits */
SET_BIT(NPCX_SMBST(controller), NPCX_SMBST_BER);
SET_BIT(NPCX_SMBST(controller), NPCX_SMBST_STASTR);
SET_BIT(NPCX_SMBST(controller), NPCX_SMBST_NEGACK);
/* Wait till STOP condition is generated */
- while (--timeout) {
- if (!IS_BIT_SET(NPCX_SMBCTL1(controller), NPCX_SMBCTL1_STOP))
- break;
- msleep(1);
+ if (i2c_wait_stop_completed(controller, I2C_MAX_TIMEOUT)
+ != EC_SUCCESS) {
+ cprints(CC_I2C, "Abort i2c %02x fail!", controller);
+ /* Clear BB (BUS BUSY) bit */
+ SET_BIT(NPCX_SMBCST(controller), NPCX_SMBCST_BB);
+ return 0;
}
/* Clear BB (BUS BUSY) bit */
SET_BIT(NPCX_SMBCST(controller), NPCX_SMBCST_BB);
-
- if (timeout == 0) {
- cprints(CC_I2C, "Abort i2c %02x fail!", controller);
- return 0;
- } else
- return 1;
+ return 1;
}
void i2c_reset(int controller)
{
- uint16_t timeout = I2C_ABORT_TIMEOUT;
+ uint16_t timeout = I2C_MAX_TIMEOUT;
/* Disable the SMB module */
CLEAR_BIT(NPCX_SMBCTL2(controller), NPCX_SMBCTL2_ENABLE);
@@ -197,7 +214,8 @@ enum smb_error i2c_master_transaction(int controller)
/* Wait for transfer complete or timeout */
events = task_wait_event_mask(TASK_EVENT_I2C_IDLE,
p_status->timeout_us);
- /* Handle timeout */
+
+ /* Handle bus timeout */
if ((events & TASK_EVENT_I2C_IDLE) == 0) {
/* Recovery I2C controller */
i2c_recovery(controller);
@@ -212,6 +230,14 @@ enum smb_error i2c_master_transaction(int controller)
i2c_recovery(controller);
}
+ /* Wait till STOP condition is generated */
+ if (p_status->err_code == SMB_OK && i2c_wait_stop_completed(controller,
+ I2C_MIN_TIMEOUT) != EC_SUCCESS) {
+ cprints(CC_I2C, "STOP fail! scl %02x is held by slave device!",
+ controller);
+ p_status->err_code = SMB_TIMEOUT_ERROR;
+ }
+
return p_status->err_code;
}
@@ -510,7 +536,7 @@ int i2c_get_line_levels(int port)
*/
int i2c_is_raw_mode(int port)
{
- int bit = (port > NPCX_I2C_PORT0_1) ? port * 2 : port;
+ int bit = (port > NPCX_I2C_PORT0_1) ? ((port - 1) * 2) : port;
if (IS_BIT_SET(NPCX_DEVALT(2), bit))
return 0;