diff options
Diffstat (limited to 'driver/accelgyro_icm_common.c')
-rw-r--r-- | driver/accelgyro_icm_common.c | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/driver/accelgyro_icm_common.c b/driver/accelgyro_icm_common.c new file mode 100644 index 0000000000..f4ec5a4a7e --- /dev/null +++ b/driver/accelgyro_icm_common.c @@ -0,0 +1,287 @@ +/* Copyright 2020 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. + */ + +/** + * ICM accelerometer and gyroscope module for Chrome EC + * 3D digital accelerometer & 3D digital gyroscope + */ + +#include "accelgyro.h" +#include "console.h" +#include "i2c.h" +#include "spi.h" +#include "driver/accelgyro_icm_common.h" +#include "driver/accelgyro_icm426xx.h" + +#define CPUTS(outstr) cputs(CC_ACCEL, outstr) +#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args) +#define CPRINTS(format, args...) cprints(CC_ACCEL, format, ## args) + +#ifdef CONFIG_SPI_ACCEL_PORT +static int icm_spi_raw_read(const int addr, const uint8_t reg, + uint8_t *data, const int len) +{ + uint8_t cmd = 0x80 | reg; + + return spi_transaction(&spi_devices[addr], &cmd, 1, data, len); +} + +static int icm_spi_raw_write(const int addr, const uint8_t reg, + const uint8_t *data, const int len) +{ + uint8_t cmd[3]; + int i; + + if (len > 2) + return EC_ERROR_UNIMPLEMENTED; + + cmd[0] = reg; + for (i = 0; i < len; ++i) + cmd[i + 1] = data[i]; + + return spi_transaction(&spi_devices[addr], cmd, len + 1, NULL, 0); +} +#endif + +static int icm_bank_sel(const struct motion_sensor_t *s, const int reg) +{ + struct icm_drv_data_t *st = ICM_GET_DATA(s); + uint8_t bank = ICM426XX_REG_GET_BANK(reg); + int ret; + + if (bank == st->bank) + return EC_SUCCESS; + + ret = EC_ERROR_UNIMPLEMENTED; +#ifdef I2C_PORT_ACCEL + ret = i2c_write8(s->port, s->addr, + ICM426XX_REG_BANK_SEL, bank); +#endif + + if (ret == EC_SUCCESS) + st->bank = bank; + + return ret; +} + +/** + * Read 8 bits register + */ +int icm_read8(const struct motion_sensor_t *s, const int reg, int *data_ptr) +{ + const uint8_t addr = ICM426XX_REG_GET_ADDR(reg); + int ret; + + ret = icm_bank_sel(s, reg); + if (ret != EC_SUCCESS) + return ret; + + ret = EC_ERROR_UNIMPLEMENTED; +#ifdef I2C_PORT_ACCEL + ret = i2c_read8(s->port, s->addr, addr, data_ptr); +#endif + + return ret; +} + +/** + * Write 8 bits register + */ +int icm_write8(const struct motion_sensor_t *s, const int reg, int data) +{ + const uint8_t addr = ICM426XX_REG_GET_ADDR(reg); + int ret; + + ret = icm_bank_sel(s, reg); + if (ret != EC_SUCCESS) + return ret; + + ret = EC_ERROR_UNIMPLEMENTED; +#ifdef I2C_PORT_ACCEL + ret = i2c_write8(s->port, s->addr, addr, data); +#endif + + return ret; +} + +/** + * Read 16 bits register + */ +int icm_read16(const struct motion_sensor_t *s, const int reg, int *data_ptr) +{ + const uint8_t addr = ICM426XX_REG_GET_ADDR(reg); + int ret; + + ret = icm_bank_sel(s, reg); + if (ret != EC_SUCCESS) + return ret; + + ret = EC_ERROR_UNIMPLEMENTED; +#ifdef I2C_PORT_ACCEL + ret = i2c_read16(s->port, s->addr, + addr, data_ptr); +#endif + + return ret; +} + +/** + * Write 16 bits register + */ +int icm_write16(const struct motion_sensor_t *s, const int reg, int data) +{ + const uint8_t addr = ICM426XX_REG_GET_ADDR(reg); + int ret; + + ret = icm_bank_sel(s, reg); + if (ret != EC_SUCCESS) + return ret; + + ret = EC_ERROR_UNIMPLEMENTED; +#ifdef I2C_PORT_ACCEL + ret = i2c_write16(s->port, s->addr, addr, data); +#endif + + return ret; +} + +/** + * Read n bytes + */ +int icm_read_n(const struct motion_sensor_t *s, const int reg, + uint8_t *data_ptr, const int len) +{ + const uint8_t addr = ICM426XX_REG_GET_ADDR(reg); + int ret; + + ret = icm_bank_sel(s, reg); + if (ret != EC_SUCCESS) + return ret; + + ret = EC_ERROR_UNIMPLEMENTED; +#ifdef I2C_PORT_ACCEL + ret = i2c_read_block(s->port, s->addr, addr, + data_ptr, len); +#endif + + return ret; +} + +int icm_field_update8(const struct motion_sensor_t *s, const int reg, + const uint8_t field_mask, const uint8_t set_value) +{ + const uint8_t addr = ICM426XX_REG_GET_ADDR(reg); + int ret; + + ret = icm_bank_sel(s, reg); + if (ret != EC_SUCCESS) + return ret; + + ret = EC_ERROR_UNIMPLEMENTED; +#ifdef I2C_PORT_ACCEL + ret = i2c_field_update8(s->port, s->addr, addr, + field_mask, set_value); +#endif + + return ret; +} + +int icm_get_resolution(const struct motion_sensor_t *s) +{ + return ICM_RESOLUTION; +} + +int icm_get_range(const struct motion_sensor_t *s) +{ + struct accelgyro_saved_data_t *data = ICM_GET_SAVED_DATA(s); + + return data->range; +} + +int icm_get_data_rate(const struct motion_sensor_t *s) +{ + struct accelgyro_saved_data_t *data = ICM_GET_SAVED_DATA(s); + + return data->odr; +} + +/* FIFO header: 1 byte */ +#define ICM_FIFO_HEADER_MSG BIT(7) +#define ICM_FIFO_HEADER_ACCEL BIT(6) +#define ICM_FIFO_HEADER_GYRO BIT(5) +#define ICM_FIFO_HEADER_TMST_FSYNC GENMASK(3, 2) +#define ICM_FIFO_HEADER_ODR_ACCEL BIT(1) +#define ICM_FIFO_HEADER_ODR_GYRO BIT(0) + +/* FIFO data packet */ +struct icm_fifo_sensor_data { + int16_t x; + int16_t y; + int16_t z; +} __packed; + +struct icm_fifo_1sensor_packet { + uint8_t header; + struct icm_fifo_sensor_data data; + int8_t temp; +} __packed; +#define ICM_FIFO_1SENSOR_PACKET_SIZE 8 + +struct icm_fifo_2sensors_packet { + uint8_t header; + struct icm_fifo_sensor_data accel; + struct icm_fifo_sensor_data gyro; + int8_t temp; + uint16_t timestamp; +} __packed; +#define ICM_FIFO_2SENSORS_PACKET_SIZE 16 + +ssize_t icm_fifo_decode_packet(const void *packet, const uint8_t **accel, + const uint8_t **gyro) +{ + const struct icm_fifo_1sensor_packet *pack1 = packet; + const struct icm_fifo_2sensors_packet *pack2 = packet; + uint8_t header = *((const uint8_t *)packet); + + /* FIFO empty */ + if (header & ICM_FIFO_HEADER_MSG) { + if (accel != NULL) + *accel = NULL; + if (gyro != NULL) + *gyro = NULL; + return 0; + } + + /* accel + gyro */ + if ((header & ICM_FIFO_HEADER_ACCEL) && + (header & ICM_FIFO_HEADER_GYRO)) { + if (accel != NULL) + *accel = (uint8_t *)&pack2->accel; + if (gyro != NULL) + *gyro = (uint8_t *)&pack2->gyro; + return ICM_FIFO_2SENSORS_PACKET_SIZE; + } + + /* accel only */ + if (header & ICM_FIFO_HEADER_ACCEL) { + if (accel != NULL) + *accel = (uint8_t *)&pack1->data; + if (gyro != NULL) + *gyro = NULL; + return ICM_FIFO_1SENSOR_PACKET_SIZE; + } + + /* gyro only */ + if (header & ICM_FIFO_HEADER_GYRO) { + if (accel != NULL) + *accel = NULL; + if (gyro != NULL) + *gyro = (uint8_t *)&pack1->data; + return ICM_FIFO_1SENSOR_PACKET_SIZE; + } + + /* invalid packet if here */ + return -EC_ERROR_INVAL; +} |