summaryrefslogtreecommitdiff
path: root/driver/accelgyro_icm_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'driver/accelgyro_icm_common.c')
-rw-r--r--driver/accelgyro_icm_common.c287
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;
+}