blob: a3a09f4c03e9a23190ef60a20aedaa75cad720b6 [file] [log] [blame]
/*
* Copyright 2023, Alvaro Garcia <maxpowel@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*
* Emulator for max17048 fuel gauge
*/
#define DT_DRV_COMPAT maxim_max17048
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(maxim_max17048);
#include <zephyr/device.h>
#include <zephyr/drivers/emul.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/i2c_emul.h>
#include <zephyr/sys/byteorder.h>
#include "max17048.h"
static int crate_value = 0x4000;
void emul_max17048_set_crate_status(int value)
{
crate_value = value;
}
/** Static configuration for the emulator */
struct max17048_emul_cfg {
/** I2C address of emulator */
uint16_t addr;
};
static int emul_max17048_reg_write(const struct emul *target, int reg, int val)
{
return -EIO;
}
static int emul_max17048_reg_read(const struct emul *target, int reg, int *val)
{
switch (reg) {
case REGISTER_VERSION:
*val = 0x1000;
break;
case REGISTER_CRATE:
*val = crate_value;
break;
case REGISTER_SOC:
*val = 0x3525;
break;
case REGISTER_VCELL:
*val = 0x4387;
break;
default:
LOG_ERR("Unknown register 0x%x read", reg);
return -EIO;
}
LOG_INF("read 0x%x = 0x%x", reg, *val);
return 0;
}
static int max17048_emul_transfer_i2c(const struct emul *target, struct i2c_msg *msgs,
int num_msgs, int addr)
{
/* Largely copied from emul_bmi160.c */
unsigned int val;
int reg;
int rc;
__ASSERT_NO_MSG(msgs && num_msgs);
i2c_dump_msgs_rw(target->dev, msgs, num_msgs, addr, false);
switch (num_msgs) {
case 2:
if (msgs->flags & I2C_MSG_READ) {
LOG_ERR("Unexpected read");
return -EIO;
}
if (msgs->len != 1) {
LOG_ERR("Unexpected msg0 length %d", msgs->len);
return -EIO;
}
reg = msgs->buf[0];
/* Now process the 'read' part of the message */
msgs++;
if (msgs->flags & I2C_MSG_READ) {
switch (msgs->len - 1) {
case 1:
rc = emul_max17048_reg_read(target, reg, &val);
if (rc) {
/* Return before writing bad value to message buffer */
return rc;
}
/* SBS uses SMBus, which sends data in little-endian format. */
sys_put_le16(val, msgs->buf);
break;
default:
LOG_ERR("Unexpected msg1 length %d", msgs->len);
return -EIO;
}
} else {
/* We write a word (2 bytes by the SBS spec) */
if (msgs->len != 2) {
LOG_ERR("Unexpected msg1 length %d", msgs->len);
}
uint16_t value = sys_get_le16(msgs->buf);
rc = emul_max17048_reg_write(target, reg, value);
}
break;
default:
LOG_ERR("Invalid number of messages: %d", num_msgs);
return -EIO;
}
return rc;
}
static const struct i2c_emul_api max17048_emul_api_i2c = {
.transfer = max17048_emul_transfer_i2c,
};
/**
* Set up a new emulator (I2C)
*
* @param emul Emulation information
* @param parent Device to emulate
* @return 0 indicating success (always)
*/
static int emul_max17048_init(const struct emul *target, const struct device *parent)
{
ARG_UNUSED(target);
ARG_UNUSED(parent);
return 0;
}
/*
* Main instantiation macro.
*/
#define MAX17048_EMUL(n) \
static const struct max17048_emul_cfg max17048_emul_cfg_##n = { \
.addr = DT_INST_REG_ADDR(n), \
}; \
EMUL_DT_INST_DEFINE(n, emul_max17048_init, NULL, \
&max17048_emul_cfg_##n, &max17048_emul_api_i2c, NULL)
DT_INST_FOREACH_STATUS_OKAY(MAX17048_EMUL)