bbram: mcp7940c: Add emulator
Add an emulator for the mcp7940c BBRAM that supports reading and writing. Signed-off-by: Yuval Peress <peress@google.com>
This commit is contained in:
parent
59675bf682
commit
69dfb2fee3
|
@ -12,5 +12,6 @@ zephyr_library_sources_ifdef(CONFIG_BBRAM_IT8XXX2_EMUL bbram_it8xxx2_emul.c)
|
|||
zephyr_library_include_directories_ifdef(CONFIG_BBRAM_IT8XXX2 .)
|
||||
zephyr_library_sources_ifdef(CONFIG_BBRAM_EMUL bbram_emul.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_BBRAM_MICROCHIP_MCP7940N bbram_microchip_mcp7940n.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_BBRAM_MICROCHIP_MCP7940N_EMUL bbram_microchip_mcp7940n_emul.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_BBRAM_XEC bbram_xec.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_BBRAM_STM32 bbram_stm32.c)
|
||||
|
|
|
@ -8,3 +8,12 @@ config BBRAM_MICROCHIP_MCP7940N
|
|||
select I2C
|
||||
help
|
||||
Enable driver for Microchip MCP7940N SRAM based battery-backed RAM.
|
||||
|
||||
config BBRAM_MICROCHIP_MCP7940N_EMUL
|
||||
bool "Emulator for the Microchip MCP7940N SRAM BBRAM driver"
|
||||
default y
|
||||
depends on BBRAM_MICROCHIP_MCP7940N
|
||||
depends on EMUL
|
||||
help
|
||||
Enable the emulator for the Microchip MCP7940N SRAM based
|
||||
battery-backed RAM.
|
||||
|
|
|
@ -153,7 +153,7 @@ static int microchip_mcp7940n_bbram_read(const struct device *dev, size_t offset
|
|||
size_t i = 0;
|
||||
int32_t rc = 0;
|
||||
|
||||
if ((offset + size) > MICROCHIP_MCP7940N_SRAM_SIZE) {
|
||||
if (size == 0 || (offset + size) > MICROCHIP_MCP7940N_SRAM_SIZE) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -186,7 +186,7 @@ static int microchip_mcp7940n_bbram_write(const struct device *dev, size_t offse
|
|||
size_t i = 0;
|
||||
int32_t rc = 0;
|
||||
|
||||
if ((offset + size) > MICROCHIP_MCP7940N_SRAM_SIZE) {
|
||||
if (size == 0 || (offset + size) > MICROCHIP_MCP7940N_SRAM_SIZE) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
150
drivers/bbram/bbram_microchip_mcp7940n_emul.c
Normal file
150
drivers/bbram/bbram_microchip_mcp7940n_emul.c
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT microchip_mcp7940n
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/emul.h>
|
||||
#include <zephyr/drivers/emul_bbram.h>
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/drivers/i2c_emul.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_DECLARE(bbram_microchip_mcp7940n, CONFIG_BBRAM_LOG_LEVEL);
|
||||
|
||||
#define MICROCHIP_MCP7940N_SRAM_OFFSET 0x20
|
||||
#define MICROCHIP_MCP7940N_SRAM_SIZE 64
|
||||
#define MICROCHIP_MCP7940N_RTCWKDAY_REGISTER_ADDRESS 0x03
|
||||
#define MICROCHIP_MCP7940N_RTCWKDAY_VBATEN_BIT BIT(3)
|
||||
#define MICROCHIP_MCP7940N_RTCWKDAY_PWRFAIL_BIT BIT(4)
|
||||
|
||||
struct mcp7940n_emul_cfg {
|
||||
};
|
||||
|
||||
struct mcp7940n_emul_data {
|
||||
uint8_t rtcwkday;
|
||||
uint8_t data[MICROCHIP_MCP7940N_SRAM_SIZE];
|
||||
};
|
||||
|
||||
static int mcp7940n_emul_init(const struct emul *target, const struct device *parent)
|
||||
{
|
||||
ARG_UNUSED(target);
|
||||
ARG_UNUSED(parent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mcp7940n_emul_transfer_i2c(const struct emul *target, struct i2c_msg *msgs, int num_msgs,
|
||||
int addr)
|
||||
{
|
||||
struct mcp7940n_emul_data *data = target->data;
|
||||
|
||||
i2c_dump_msgs_rw(target->dev, msgs, num_msgs, addr, false);
|
||||
|
||||
if (num_msgs < 1) {
|
||||
LOG_ERR("Invalid number of messages: %d", num_msgs);
|
||||
return -EIO;
|
||||
}
|
||||
if (FIELD_GET(I2C_MSG_READ, msgs->flags)) {
|
||||
LOG_ERR("Unexpected read");
|
||||
return -EIO;
|
||||
}
|
||||
if (msgs->len < 1) {
|
||||
LOG_ERR("Unexpected msg0 length %d", msgs->len);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
uint8_t regn = msgs->buf[0];
|
||||
bool is_read = FIELD_GET(I2C_MSG_READ, msgs->flags) == 1;
|
||||
bool is_stop = FIELD_GET(I2C_MSG_STOP, msgs->flags) == 1;
|
||||
|
||||
if (!is_stop && !is_read) {
|
||||
/* First message was a write with the register number, check next message */
|
||||
msgs++;
|
||||
is_read = FIELD_GET(I2C_MSG_READ, msgs->flags) == 1;
|
||||
is_stop = FIELD_GET(I2C_MSG_STOP, msgs->flags) == 1;
|
||||
}
|
||||
|
||||
if (is_read) {
|
||||
/* Read data */
|
||||
if (regn == MICROCHIP_MCP7940N_RTCWKDAY_REGISTER_ADDRESS) {
|
||||
msgs->buf[0] = data->rtcwkday;
|
||||
return 0;
|
||||
}
|
||||
if (regn >= MICROCHIP_MCP7940N_SRAM_OFFSET &&
|
||||
regn + msgs->len <=
|
||||
MICROCHIP_MCP7940N_SRAM_OFFSET + MICROCHIP_MCP7940N_SRAM_SIZE) {
|
||||
for (int i = 0; i < msgs->len; ++i) {
|
||||
msgs->buf[i] =
|
||||
data->data[regn + i - MICROCHIP_MCP7940N_SRAM_OFFSET];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/* Write data */
|
||||
if (regn == MICROCHIP_MCP7940N_RTCWKDAY_REGISTER_ADDRESS) {
|
||||
data->rtcwkday = msgs->buf[1];
|
||||
return 0;
|
||||
}
|
||||
if (regn >= MICROCHIP_MCP7940N_SRAM_OFFSET &&
|
||||
regn + msgs->len - 1 <=
|
||||
MICROCHIP_MCP7940N_SRAM_OFFSET + MICROCHIP_MCP7940N_SRAM_SIZE) {
|
||||
for (int i = 0; i < msgs->len; ++i) {
|
||||
data->data[regn + i - MICROCHIP_MCP7940N_SRAM_OFFSET] =
|
||||
msgs->buf[1 + i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static const struct i2c_emul_api mcp7940n_emul_api_i2c = {
|
||||
.transfer = mcp7940n_emul_transfer_i2c,
|
||||
};
|
||||
|
||||
static int mcp7940n_emul_backend_set_data(const struct emul *target, size_t offset, size_t count,
|
||||
const uint8_t *buffer)
|
||||
{
|
||||
struct mcp7940n_emul_data *data = target->data;
|
||||
|
||||
if (offset + count > MICROCHIP_MCP7940N_SRAM_SIZE) {
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
data->data[offset + i] = buffer[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mcp7940n_emul_backend_get_data(const struct emul *target, size_t offset, size_t count,
|
||||
uint8_t *buffer)
|
||||
{
|
||||
struct mcp7940n_emul_data *data = target->data;
|
||||
|
||||
if (offset + count > MICROCHIP_MCP7940N_SRAM_SIZE) {
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
buffer[i] = data->data[offset + i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct emul_bbram_backend_api mcp7940n_emul_backend_api = {
|
||||
.set_data = mcp7940n_emul_backend_set_data,
|
||||
.get_data = mcp7940n_emul_backend_get_data,
|
||||
};
|
||||
|
||||
#define MCP7940N_EMUL(inst) \
|
||||
static const struct mcp7940n_emul_cfg mcp7940n_emul_cfg_##inst; \
|
||||
static struct mcp7940n_emul_data mcp7940n_emul_data_##inst; \
|
||||
EMUL_DT_INST_DEFINE(inst, mcp7940n_emul_init, &mcp7940n_emul_data_##inst, \
|
||||
&mcp7940n_emul_cfg_##inst, &mcp7940n_emul_api_i2c, \
|
||||
&mcp7940n_emul_backend_api)
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(MCP7940N_EMUL)
|
Loading…
Reference in a new issue