diff options
Diffstat (limited to 'driver/accel_kionix.c')
-rw-r--r-- | driver/accel_kionix.c | 693 |
1 files changed, 0 insertions, 693 deletions
diff --git a/driver/accel_kionix.c b/driver/accel_kionix.c deleted file mode 100644 index 69f0ca9073..0000000000 --- a/driver/accel_kionix.c +++ /dev/null @@ -1,693 +0,0 @@ -/* Copyright 2015 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. - */ - -/* - * Kionix Accelerometer driver for Chrome EC - * - * Supported: KX022, KXCJ9 - */ - -#include "accelgyro.h" -#include "common.h" -#include "console.h" -#include "accel_kionix.h" -#include "accel_kx022.h" -#include "accel_kxcj9.h" -#include "i2c.h" -#include "math_util.h" -#include "motion_orientation.h" -#include "spi.h" -#include "task.h" -#include "util.h" - -#define CPUTS(outstr) cputs(CC_ACCEL, outstr) -#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args) - -/* Number of times to attempt to enable sensor before giving up. */ -#define SENSOR_ENABLE_ATTEMPTS 3 - -#if !defined(CONFIG_ACCEL_KXCJ9) && !defined(CONFIG_ACCEL_KX022) -#error "Must use either KXCJ9 or KX022" -#endif - -#if defined(CONFIG_ACCEL_KXCJ9) && !defined(CONFIG_ACCEL_KX022) -#define V(s_) 1 -#elif defined(CONFIG_ACCEL_KX022) && !defined(CONFIG_ACCEL_KXCJ9) -#define V(s_) 0 -#else -#define V(s_) ((s_)->chip == MOTIONSENSE_CHIP_KXCJ9) -#endif -/* Index for which table to use. */ -#if !defined(CONFIG_ACCEL_KXCJ9) || !defined(CONFIG_ACCEL_KX022) -#define T(s_) 0 -#else -#define T(s_) V(s_) -#endif /* !defined(CONFIG_ACCEL_KXCJ9) || !defined(CONFIG_ACCEL_KX022) */ - -STATIC_IF(CONFIG_KX022_ORIENTATION_SENSOR) int check_orientation_locked( - const struct motion_sensor_t *s); - -/* List of range values in +/-G's and their associated register values. */ -static const struct accel_param_pair ranges[][3] = { -#ifdef CONFIG_ACCEL_KX022 - { {2, KX022_GSEL_2G}, - {4, KX022_GSEL_4G}, - {8, KX022_GSEL_8G} }, -#endif /* defined(CONFIG_ACCEL_KX022) */ -#ifdef CONFIG_ACCEL_KXCJ9 - { {2, KXCJ9_GSEL_2G}, - {4, KXCJ9_GSEL_4G}, - {8, KXCJ9_GSEL_8G_14BIT} }, -#endif /* defined(CONFIG_ACCEL_KXCJ9) */ -}; - -/* List of resolution values in bits and their associated register values. */ -static const struct accel_param_pair resolutions[][2] = { -#ifdef CONFIG_ACCEL_KX022 - { {8, KX022_RES_8BIT}, - {16, KX022_RES_16BIT} }, -#endif /* defined(CONFIG_ACCEL_KX022) */ -#ifdef CONFIG_ACCEL_KXCJ9 - { {8, KXCJ9_RES_8BIT}, - {12, KXCJ9_RES_12BIT} }, -#endif /* defined(CONFIG_ACCEL_KXCJ9) */ -}; - -/* List of ODR values in mHz and their associated register values. */ -static const struct accel_param_pair datarates[][13] = { -#ifdef CONFIG_ACCEL_KX022 - /* One duplicate because table sizes must match. */ - { {781, KX022_OSA_0_781HZ}, - {781, KX022_OSA_0_781HZ}, - {1563, KX022_OSA_1_563HZ}, - {3125, KX022_OSA_3_125HZ}, - {6250, KX022_OSA_6_250HZ}, - {12500, KX022_OSA_12_50HZ}, - {25000, KX022_OSA_25_00HZ}, - {50000, KX022_OSA_50_00HZ}, - {100000, KX022_OSA_100_0HZ}, - {200000, KX022_OSA_200_0HZ}, - {400000, KX022_OSA_400_0HZ}, - {800000, KX022_OSA_800_0HZ}, - {1600000, KX022_OSA_1600HZ} }, -#endif /* defined(CONFIG_ACCEL_KX022) */ -#ifdef CONFIG_ACCEL_KXCJ9 - { {0, KXCJ9_OSA_0_000HZ}, - {781, KXCJ9_OSA_0_781HZ}, - {1563, KXCJ9_OSA_1_563HZ}, - {3125, KXCJ9_OSA_3_125HZ}, - {6250, KXCJ9_OSA_6_250HZ}, - {12500, KXCJ9_OSA_12_50HZ}, - {25000, KXCJ9_OSA_25_00HZ}, - {50000, KXCJ9_OSA_50_00HZ}, - {100000, KXCJ9_OSA_100_0HZ}, - {200000, KXCJ9_OSA_200_0HZ}, - {400000, KXCJ9_OSA_400_0HZ}, - {800000, KXCJ9_OSA_800_0HZ}, - {1600000, KXCJ9_OSA_1600_HZ} }, -#endif /* defined(CONFIG_ACCEL_KXCJ9) */ -}; - -/** - * Find index into a accel_param_pair that matches the given engineering value - * passed in. The round_up flag is used to specify whether to round up or down. - * Note, this function always returns a valid index. If the request is - * outside the range of values, it returns the closest valid index. - */ -static int find_param_index(const int eng_val, const int round_up, - const struct accel_param_pair *pairs, - const int size) -{ - int i; - - /* Linear search for index to match. */ - for (i = 0; i < size - 1; i++) { - if (eng_val <= pairs[i].val) - return i; - - if (eng_val < pairs[i+1].val) { - if (round_up) - return i + 1; - else - return i; - } - } - - return i; -} - -/** - * Read register from accelerometer. - */ -static int raw_read8(const int port, - const uint16_t i2c_spi_addr_flags, - const int reg, int *data_ptr) -{ - int rv = EC_ERROR_INVAL; - - if (ACCEL_ADDR_IS_SPI(i2c_spi_addr_flags)) { -#ifdef CONFIG_SPI_ACCEL_PORT - uint8_t val; - uint8_t cmd = 0x80 | reg; - - rv = spi_transaction( - &spi_devices[ACCEL_GET_SPI_ADDR(i2c_spi_addr_flags)], - &cmd, 1, &val, 1); - if (rv == EC_SUCCESS) - *data_ptr = val; - -#endif - } else { - rv = i2c_read8(port, i2c_spi_addr_flags, - reg, data_ptr); - } - return rv; -} - -/** - * Write register from accelerometer. - */ -static int raw_write8(const int port, - const uint16_t i2c_spi_addr_flags, - const int reg, int data) -{ - int rv = EC_ERROR_INVAL; - - if (ACCEL_ADDR_IS_SPI(i2c_spi_addr_flags)) { -#ifdef CONFIG_SPI_ACCEL_PORT - uint8_t cmd[2] = { reg, data }; - - rv = spi_transaction( - &spi_devices[ACCEL_GET_SPI_ADDR(i2c_spi_addr_flags)], - cmd, 2, NULL, 0); -#endif - } else { - rv = i2c_write8(port, i2c_spi_addr_flags, - reg, data); - } - return rv; -} - -static int raw_read_multi(const int port, - const uint16_t i2c_spi_addr_flags, - uint8_t reg, uint8_t *rxdata, int rxlen) -{ - int rv = EC_ERROR_INVAL; - - if (ACCEL_ADDR_IS_SPI(i2c_spi_addr_flags)) { -#ifdef CONFIG_SPI_ACCEL_PORT - reg |= 0x80; - rv = spi_transaction( - &spi_devices[ACCEL_GET_SPI_ADDR(i2c_spi_addr_flags)], - ®, 1, rxdata, rxlen); -#endif - } else { - rv = i2c_read_block(port, i2c_spi_addr_flags, - reg, rxdata, rxlen); - } - return rv; -} - -/** - * Disable sensor by taking it out of operating mode. When disabled, the - * acceleration data does not change. - * - * Note: This is intended to be called in a pair with enable_sensor(). - * - * @param s Pointer to motion sensor data - * @param reg_val Pointer to location to store control register after disabling - * - * @return EC_SUCCESS if successful, EC_ERROR_* otherwise - */ -static int disable_sensor(const struct motion_sensor_t *s, int *reg_val) -{ - int i, ret, reg, pc1_field; - - reg = KIONIX_CTRL1_REG(V(s)); - pc1_field = KIONIX_PC1_FIELD(V(s)); - - /* - * Read the current state of the control register - * so that we can restore it later. - */ - for (i = 0; i < SENSOR_ENABLE_ATTEMPTS; i++) { - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - reg, reg_val); - if (ret != EC_SUCCESS) - continue; - - *reg_val &= ~pc1_field; - - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - reg, *reg_val); - if (ret == EC_SUCCESS) - return EC_SUCCESS; - } - return ret; -} - -/** - * Enable sensor by placing it in operating mode. - * - * Note: This is intended to be called in a pair with disable_sensor(). - * - * @param s Pointer to motion sensor data - * @param reg_val Value of the control register to write to sensor - * - * @return EC_SUCCESS if successful, EC_ERROR_* otherwise - */ -static int enable_sensor(const struct motion_sensor_t *s, int reg_val) -{ - int i, ret, reg, pc1_field; - - reg = KIONIX_CTRL1_REG(V(s)); - pc1_field = KIONIX_PC1_FIELD(V(s)); - - for (i = 0; i < SENSOR_ENABLE_ATTEMPTS; i++) { - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - reg, ®_val); - if (ret != EC_SUCCESS) - continue; - - /* Enable tilt orientation mode if lid sensor */ - if (IS_ENABLED(CONFIG_KX022_ORIENTATION_SENSOR) && - (s->location == MOTIONSENSE_LOC_LID) && - (V(s) == 0)) - reg_val |= KX022_CNTL1_TPE; - - /* Enable accelerometer based on reg_val value. */ - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - reg, reg_val | pc1_field); - - /* On first success, we are done. */ - if (ret == EC_SUCCESS) - break; - } - return ret; -} - -/** - * Set a register value. - * - * @param s Pointer to motion sensor data - * @param reg Register to write to - * @param reg_val Value of the control register to write to sensor - * @param field Bitfield to modify. - * - * @return EC_SUCCESS if successful, EC_ERROR_* otherwise - */ -static int set_value(const struct motion_sensor_t *s, int reg, int val, - int field) -{ - int ret, reg_val_new, reg_val; - - /* Disable the sensor to allow for changing of critical parameters. */ - mutex_lock(s->mutex); - ret = disable_sensor(s, ®_val); - if (ret != EC_SUCCESS) { - mutex_unlock(s->mutex); - return ret; - } - - /* Determine new value of control reg and attempt to write it. */ - reg_val_new = (reg_val & ~field) | val; - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - reg, reg_val_new); - - /* If successfully written, then save the range. */ - if (ret == EC_SUCCESS) - /* Re-enable the sensor. */ - ret = enable_sensor(s, reg_val_new); - - mutex_unlock(s->mutex); - return ret; -} - -static int set_range(struct motion_sensor_t *s, int range, int rnd) -{ - int ret, index, reg, range_field, range_val; - - /* Find index for interface pair matching the specified range. */ - index = find_param_index(range, rnd, ranges[T(s)], - ARRAY_SIZE(ranges[T(s)])); - range_field = KIONIX_RANGE_FIELD(V(s)); - reg = KIONIX_CTRL1_REG(V(s)); - range_val = ranges[T(s)][index].reg; - - ret = set_value(s, reg, range_val, range_field); - if (ret == EC_SUCCESS) - s->current_range = ranges[T(s)][index].val; - return ret; -} - -static int set_resolution(const struct motion_sensor_t *s, int res, int rnd) -{ - int ret, index, reg, res_field, res_val; - struct kionix_accel_data *data = s->drv_data; - - /* Find index for interface pair matching the specified resolution. */ - index = find_param_index(res, rnd, resolutions[T(s)], - ARRAY_SIZE(resolutions[T(s)])); - res_val = resolutions[T(s)][index].reg; - res_field = KIONIX_RES_FIELD(V(s)); - reg = KIONIX_CTRL1_REG(V(s)); - - ret = set_value(s, reg, res_val, res_field); - if (ret == EC_SUCCESS) - data->sensor_resolution = resolutions[T(s)][index].val; - return ret; -} - -static int get_resolution(const struct motion_sensor_t *s) -{ - struct kionix_accel_data *data = s->drv_data; - - return data->sensor_resolution; -} - -static int set_data_rate(const struct motion_sensor_t *s, int rate, int rnd) -{ - int ret, index, reg, odr_field, odr_val; - struct kionix_accel_data *data = s->drv_data; - - /* Find index for interface pair matching the specified rate. */ - index = find_param_index(rate, rnd, datarates[T(s)], - ARRAY_SIZE(datarates[T(s)])); - odr_val = datarates[T(s)][index].reg; - reg = KIONIX_ODR_REG(V(s)); - odr_field = KIONIX_ODR_FIELD(V(s)); - - ret = set_value(s, reg, odr_val, odr_field); - if (ret == EC_SUCCESS) - data->base.odr = datarates[T(s)][index].val; - return ret; -} - -static int get_data_rate(const struct motion_sensor_t *s) -{ - struct kionix_accel_data *data = s->drv_data; - - return data->base.odr; -} - -static int set_offset(const struct motion_sensor_t *s, const int16_t *offset, - int16_t temp) -{ - /* temperature is ignored */ - struct kionix_accel_data *data = s->drv_data; - data->offset[X] = offset[X]; - data->offset[Y] = offset[Y]; - data->offset[Z] = offset[Z]; - return EC_SUCCESS; -} - -static int get_offset(const struct motion_sensor_t *s, int16_t *offset, - int16_t *temp) -{ - struct kionix_accel_data *data = s->drv_data; - offset[X] = data->offset[X]; - offset[Y] = data->offset[Y]; - offset[Z] = data->offset[Z]; - *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; - return EC_SUCCESS; -} - -static __maybe_unused enum motionsensor_orientation kx022_convert_orientation( - const struct motion_sensor_t *s, - int orientation) -{ - enum motionsensor_orientation res = MOTIONSENSE_ORIENTATION_UNKNOWN; - - switch (orientation) { - case KX022_ORIENT_PORTRAIT: - res = MOTIONSENSE_ORIENTATION_PORTRAIT; - break; - case KX022_ORIENT_INVERT_PORTRAIT: - res = MOTIONSENSE_ORIENTATION_UPSIDE_DOWN_PORTRAIT; - break; - case KX022_ORIENT_LANDSCAPE: - res = MOTIONSENSE_ORIENTATION_LANDSCAPE; - break; - case KX022_ORIENT_INVERT_LANDSCAPE: - res = MOTIONSENSE_ORIENTATION_UPSIDE_DOWN_LANDSCAPE; - break; - default: - break; - } - res = motion_orientation_remap(s, res); - return res; -} - -#ifdef CONFIG_KX022_ORIENTATION_SENSOR -static int check_orientation_locked(const struct motion_sensor_t *s) -{ - struct kionix_accel_data *data = s->drv_data; - int orientation, raw_orientation; - int ret; - - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - KX022_TSCP, &raw_orientation); - if (ret != EC_SUCCESS) - return ret; - - /* mask off up and down events, we don't care about those */ - raw_orientation &= KX022_ORIENT_MASK; - if (raw_orientation && (raw_orientation != data->raw_orientation)) { - data->raw_orientation = raw_orientation; - orientation = kx022_convert_orientation(s, raw_orientation); - *motion_orientation_ptr(s) = orientation; - } - return ret; -} - -bool motion_orientation_changed(const struct motion_sensor_t *s) -{ - return ((struct kionix_accel_data *)s->drv_data)->orientation != - ((struct kionix_accel_data *)s->drv_data)->last_orientation; -} - -enum motionsensor_orientation *motion_orientation_ptr( - const struct motion_sensor_t *s) -{ - return &((struct kionix_accel_data *)s->drv_data)->orientation; -} - -void motion_orientation_update(const struct motion_sensor_t *s) -{ - ((struct kionix_accel_data *)s->drv_data)->last_orientation = - ((struct kionix_accel_data *)s->drv_data)->orientation; -} - -#endif - -static int read(const struct motion_sensor_t *s, intv3_t v) -{ - uint8_t acc[6]; - uint8_t reg; - int ret, i, resolution; - struct kionix_accel_data *data = s->drv_data; - - /* Read 6 bytes starting at XOUT_L. */ - reg = KIONIX_XOUT_L(V(s)); - mutex_lock(s->mutex); - ret = raw_read_multi(s->port, s->i2c_spi_addr_flags, reg, acc, 6); - if (IS_ENABLED(CONFIG_KX022_ORIENTATION_SENSOR) && - (s->location == MOTIONSENSE_LOC_LID) && - (V(s) == 0) && - (ret == EC_SUCCESS)) - ret = check_orientation_locked(s); - mutex_unlock(s->mutex); - - if (ret != EC_SUCCESS) - return ret; - - /* - * Convert acceleration to a signed 16-bit number. Note, based on - * the order of the registers: - * - * acc[0] = XOUT_L - * acc[1] = XOUT_H - * acc[2] = YOUT_L - * acc[3] = YOUT_H - * acc[4] = ZOUT_L - * acc[5] = ZOUT_H - * - * Add calibration offset before returning the data. - */ - resolution = get_resolution(s); - for (i = X; i <= Z; i++) { - if (V(s)) { - v[i] = (((int8_t)acc[i * 2 + 1]) << 4) | - (acc[i * 2] >> 4); - v[i] <<= 16 - resolution; - } else { - if (resolution == 8) - acc[i * 2] = 0; - v[i] = (((int8_t)acc[i * 2 + 1]) << 8) | acc[i * 2]; - } - } - rotate(v, *s->rot_standard_ref, v); - - /* apply offset in the device coordinates */ - for (i = X; i <= Z; i++) - v[i] += (data->offset[i] << 5) / s->current_range; - - return EC_SUCCESS; -} - -static int init(struct motion_sensor_t *s) -{ - int ret, val, reg, reset_field; - uint8_t timeout; - - mutex_lock(s->mutex); - 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->i2c_spi_addr_flags, - 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->i2c_spi_addr_flags, - 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 (!ACCEL_ADDR_IS_SPI(s->i2c_spi_addr_flags)) { - const uint16_t i2c_alt_addr_flags = - I2C_STRIP_FLAGS( - s->i2c_spi_addr_flags) - & ~2; - ret = raw_write8(s->port, - i2c_alt_addr_flags, - reg, 0x0); - } - } - } - - if (ret != EC_SUCCESS) - goto reset_failed; - - /* Issue a software reset. */ - reg = KIONIX_CTRL2_REG(V(s)); - reset_field = KIONIX_RESET_FIELD(V(s)); - - 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->i2c_spi_addr_flags, reg, &val); - if (ret != EC_SUCCESS) - goto reset_failed; - - val |= reset_field; - } else { - /* Write 0 to CTRL2 for KX022 */ - ret = raw_write8(s->port, s->i2c_spi_addr_flags, reg, 0x0); - if (ret != EC_SUCCESS) - goto reset_failed; - - val = reset_field; - } - - ret = raw_write8(s->port, s->i2c_spi_addr_flags, 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->i2c_spi_addr_flags, - 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->i2c_spi_addr_flags, reg, &val); - if (val != KX022_COTR_VAL_DEFAULT) { - CPRINTF("[%s: the software reset failed]\n", s->name); - ret = EC_ERROR_HW_INTERNAL; - goto reset_failed; - } - } - - reg = KIONIX_WHO_AM_I(V(s)); - ret = raw_read8(s->port, s->i2c_spi_addr_flags, 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. */ - if (V(s)) - ret = set_resolution(s, 12, 1); - else - ret = set_resolution(s, 16, 1); - if (ret != EC_SUCCESS) - return ret; - - return sensor_init_done(s); - -reset_failed: - mutex_unlock(s->mutex); - return ret; -} - -const struct accelgyro_drv kionix_accel_drv = { - .init = init, - .read = read, - .set_range = set_range, - .set_resolution = set_resolution, - .get_resolution = get_resolution, - .set_data_rate = set_data_rate, - .get_data_rate = get_data_rate, - .set_offset = set_offset, - .get_offset = get_offset, -}; - -#ifdef CONFIG_CMD_I2C_STRESS_TEST_ACCEL -struct i2c_stress_test_dev kionix_i2c_stress_test_dev = { - .reg_info = { - .read_reg = KIONIX_WHO_AM_I(V(s)), - .read_val = KIONIX_WHO_AM_I_VAL(V(s)), - .write_reg = KIONIX_ODR_REG(V(s)), - }, - .i2c_read = &raw_read8, - .i2c_write = &raw_write8, -}; -#endif /* CONFIG_CMD_I2C_STRESS_TEST_ACCEL */ |