summaryrefslogtreecommitdiff
path: root/driver/accel_kionix.c
diff options
context:
space:
mode:
Diffstat (limited to 'driver/accel_kionix.c')
-rw-r--r--driver/accel_kionix.c693
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)],
- &reg, 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, &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, &reg_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 */