blob: 5ac652c29d719ab072a5c8ade192b49a327ae9ac [file] [log] [blame]
/*
* Copyright (c) 2023 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT invensense_icm42688
#include <zephyr/device.h>
#include <zephyr/drivers/emul.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/drivers/spi_emul.h>
#include <zephyr/logging/log.h>
#include <icm42688_reg.h>
LOG_MODULE_DECLARE(ICM42688, CONFIG_SENSOR_LOG_LEVEL);
#define NUM_REGS (UINT8_MAX >> 1)
struct icm42688_emul_data {
uint8_t reg[NUM_REGS];
};
struct icm42688_emul_cfg {
};
void icm42688_emul_set_reg(const struct emul *target, uint8_t reg_addr, const uint8_t *val,
size_t count)
{
struct icm42688_emul_data *data = target->data;
__ASSERT_NO_MSG(reg_addr + count < NUM_REGS);
memcpy(data->reg + reg_addr, val, count);
}
void icm42688_emul_get_reg(const struct emul *target, uint8_t reg_addr, uint8_t *val, size_t count)
{
struct icm42688_emul_data *data = target->data;
__ASSERT_NO_MSG(reg_addr + count < NUM_REGS);
memcpy(val, data->reg + reg_addr, count);
}
static void icm42688_emul_handle_write(const struct emul *target, uint8_t regn, uint8_t value)
{
struct icm42688_emul_data *data = target->data;
switch (regn) {
case REG_DEVICE_CONFIG:
if (FIELD_GET(BIT_SOFT_RESET, value) == 1) {
/* Perform a soft reset */
memset(data->reg, 0, NUM_REGS);
/* Initialized the who-am-i register */
data->reg[REG_WHO_AM_I] = WHO_AM_I_ICM42688;
/* Set the bit for the reset being done */
data->reg[REG_INT_STATUS] |= BIT_INT_STATUS_RESET_DONE;
}
break;
}
}
static int icm42688_emul_io_spi(const struct emul *target, const struct spi_config *config,
const struct spi_buf_set *tx_bufs,
const struct spi_buf_set *rx_bufs)
{
struct icm42688_emul_data *data = target->data;
const struct spi_buf *tx, *rx;
uint8_t regn;
bool is_read;
ARG_UNUSED(config);
__ASSERT_NO_MSG(tx_bufs != NULL);
tx = tx_bufs->buffers;
__ASSERT_NO_MSG(tx != NULL);
__ASSERT_NO_MSG(tx->len > 0);
regn = *(uint8_t *)tx->buf;
is_read = FIELD_GET(REG_SPI_READ_BIT, regn);
regn &= GENMASK(6, 0);
if (is_read) {
__ASSERT_NO_MSG(rx_bufs != NULL);
__ASSERT_NO_MSG(rx_bufs->count > 1);
rx = &rx_bufs->buffers[1];
__ASSERT_NO_MSG(rx->buf != NULL);
__ASSERT_NO_MSG(rx->len > 0);
for (uint16_t i = 0; i < rx->len; ++i) {
((uint8_t *)rx->buf)[i] = data->reg[regn + i];
}
} else {
/* Writing to regn */
uint8_t value;
__ASSERT_NO_MSG(tx_bufs->count > 1);
tx = &tx_bufs->buffers[1];
__ASSERT_NO_MSG(tx->len > 0);
value = ((uint8_t *)tx->buf)[0];
icm42688_emul_handle_write(target, regn, value);
}
return 0;
}
static int icm42688_emul_init(const struct emul *target, const struct device *parent)
{
struct icm42688_emul_data *data = target->data;
/* Initialized the who-am-i register */
data->reg[REG_WHO_AM_I] = WHO_AM_I_ICM42688;
return 0;
}
static const struct spi_emul_api icm42688_emul_spi_api = {
.io = icm42688_emul_io_spi,
};
#define ICM42688_EMUL_DEFINE(n, api) \
EMUL_DT_INST_DEFINE(n, icm42688_emul_init, &icm42688_emul_data_##n, \
&icm42688_emul_cfg_##n, &api, NULL)
#define ICM42688_EMUL_SPI(n) \
static struct icm42688_emul_data icm42688_emul_data_##n; \
static const struct icm42688_emul_cfg icm42688_emul_cfg_##n; \
ICM42688_EMUL_DEFINE(n, icm42688_emul_spi_api)
DT_INST_FOREACH_STATUS_OKAY(ICM42688_EMUL_SPI)