diff options
author | Yidi Lin <yidi.lin@mediatek.com> | 2017-06-14 10:54:28 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-03-19 17:04:54 -0700 |
commit | 7640df67aaf2fa8d135ee04f9a63090816adaf17 (patch) | |
tree | 4345e611c05a459b022becdc81dc38a229c5f6af /driver/accel_kionix.c | |
parent | 1c03af23e1f8a62b6815fd520de5ace9e365b12f (diff) | |
download | chrome-ec-7640df67aaf2fa8d135ee04f9a63090816adaf17.tar.gz |
driver: kionix: Add software reset flow for KX022
Kionix suggests that it is recommended to issue the Software Reset
command after the device was powered. This is effective against
dynamic or non-linear behavior of a power supply or unexpected
noise above normal on the power rail during a power up.
BRANCH=eve
BUG=b:62607555
TEST=kx022:
1. press power button 10 second to power off.
2. power on the DUT
3. refresh + power button to cold reboot the DUT
4. Check the g-sensor by 'ectool motionsense'
kxcj9:
eve: sensor kxcj9 found.
Signed-off-by: Yidi Lin <yidi.lin@mediatek.com>
Reviewed-on: https://chromium-review.googlesource.com/536723
Reviewed-by: Gwendal Grignou <gwendal@chromium.org>
(cherry picked from commit 5a52614b8c87ab1de84c461b7bbd0b4a14dc7fdb)
Conflict in init routine in accel_kionix.c.
By moving WHOAMI after reset, we expect the test to work the first
time.)
Change-Id: I362f2af59253519aa35b72cfb6b666c49e425777
Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/753969
Diffstat (limited to 'driver/accel_kionix.c')
-rw-r--r-- | driver/accel_kionix.c | 141 |
1 files changed, 92 insertions, 49 deletions
diff --git a/driver/accel_kionix.c b/driver/accel_kionix.c index b3a1cde3ab..150a050226 100644 --- a/driver/accel_kionix.c +++ b/driver/accel_kionix.c @@ -513,68 +513,107 @@ static int init(const struct motion_sensor_t *s) int ret, val, reg, reset_field; uint8_t timeout; - /* The chip can take up to 10ms to boot */ mutex_lock(s->mutex); - reg = KIONIX_WHO_AM_I(V(s)); - timeout = 0; - do { - msleep(1); - /* Read WHO_AM_I to be sure the device has booted */ - ret = raw_read8(s->port, s->addr, reg, &val); - if (ret == EC_SUCCESS) - break; - - /* Check for timeout. */ - if (timeout++ > 20) { - ret = EC_ERROR_TIMEOUT; - break; + if (V(s)) { + /* The chip can take up to 10ms to boot */ + reg = KIONIX_WHO_AM_I(V(s)); + timeout = 0; + do { + msleep(1); + /* Read WHO_AM_I to be sure the device has booted */ + ret = raw_read8(s->port, s->addr, reg, &val); + if (ret == EC_SUCCESS) + break; + + /* Check for timeout. */ + if (timeout++ > 20) { + ret = EC_ERROR_TIMEOUT; + break; + } + } while (1); + } else { + /* Write 0x00 to the internal register for KX022 */ + reg = KX022_INTERNAL; + ret = raw_write8(s->port, s->addr, reg, 0x0); + if (ret != EC_SUCCESS) { + /* + * For I2C communication, if ACK was not received + * from the first address, resend the command using + * the second address. + */ + if (!KIONIX_IS_SPI(s->addr)) { + ret = raw_write8(s->port, s->addr & ~4, reg, + 0x0); + } } - } while (1); - if (ret != EC_SUCCESS) { - mutex_unlock(s->mutex); - return ret; } + if (ret != EC_SUCCESS) + goto reset_failed; + + /* Issue a software reset. */ reg = KIONIX_CTRL2_REG(V(s)); reset_field = KIONIX_RESET_FIELD(V(s)); - /* Issue a software reset. */ + if (V(s)) { + /* Place the sensor in standby mode to make changes. */ + ret = disable_sensor(s, &val); + if (ret != EC_SUCCESS) + goto reset_failed; + ret = raw_read8(s->port, s->addr, reg, &val); + if (ret != EC_SUCCESS) + goto reset_failed; - /* Place the sensor in standby mode to make changes. */ - ret = disable_sensor(s, &val); - if (ret != EC_SUCCESS) { - mutex_unlock(s->mutex); - return ret; - } - ret = raw_read8(s->port, s->addr, reg, &val); - if (ret != EC_SUCCESS) { - mutex_unlock(s->mutex); - return ret; - } - val |= reset_field; - ret = raw_write8(s->port, s->addr, reg, val); - if (ret != EC_SUCCESS) { - mutex_unlock(s->mutex); - return ret; + val |= reset_field; + } else { + /* Write 0 to CTRL2 for KX022 */ + ret = raw_write8(s->port, s->addr, reg, 0x0); + if (ret != EC_SUCCESS) + goto reset_failed; + + val = reset_field; } - /* The SRST will be cleared when reset is complete. */ - timeout = 0; - do { - msleep(1); + ret = raw_write8(s->port, s->addr, reg, val); + if (ret != EC_SUCCESS) + goto reset_failed; + + if (V(s)) { + /* The SRST will be cleared when reset is complete. */ + timeout = 0; + do { + msleep(1); + + ret = raw_read8(s->port, s->addr, reg, &val); + /* Reset complete. */ + if ((ret == EC_SUCCESS) && !(val & reset_field)) + break; + /* Check for timeout. */ + if (timeout++ > 20) { + ret = EC_ERROR_TIMEOUT; + goto reset_failed; + } + } while (1); + } else { + /* Wait 2 milliseconds for completion of the software reset. */ + msleep(2); + reg = KX022_COTR; ret = raw_read8(s->port, s->addr, reg, &val); - /* Reset complete. */ - if ((ret == EC_SUCCESS) && !(val & reset_field)) - break; - - /* Check for timeout. */ - if (timeout++ > 20) { - ret = EC_ERROR_TIMEOUT; - mutex_unlock(s->mutex); - return ret; + if (val != KX022_COTR_VAL_DEFAULT) { + CPRINTF("[%s: the software reset failed]\n", s->name); + ret = EC_ERROR_HW_INTERNAL; + goto reset_failed; } - } while (1); + } + + reg = KIONIX_WHO_AM_I(V(s)); + ret = raw_read8(s->port, s->addr, reg, &val); + if (ret != EC_SUCCESS || val != KIONIX_WHO_AM_I_VAL(V(s))) { + ret = EC_ERROR_HW_INTERNAL; + goto reset_failed; + } + mutex_unlock(s->mutex); /* Initialize with the desired parameters. */ @@ -586,6 +625,10 @@ static int init(const struct motion_sensor_t *s) return ret; return sensor_init_done(s); + +reset_failed: + mutex_unlock(s->mutex); + return ret; } const struct accelgyro_drv kionix_accel_drv = { |