zephyr/drivers/eeprom/eeprom_at2x_emul.c
Michał Barnaś 4aac1756a9 i2c: use device instead of name for i2c dump messages
This commit changes the parameter of i2c_dump_msgs function from
string name to pointer to the device structure.
It allows for comparison of device pointers and allow to use
the printed device name in i2c shell commands.

Signed-off-by: Michał Barnaś <mb@semihalf.com>
2023-09-06 17:54:53 +02:00

168 lines
4.7 KiB
C

/*
* Copyright 2020 Google LLC
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT atmel_at24
#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(atmel_at24);
#include <zephyr/device.h>
#include <zephyr/drivers/emul.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/i2c_emul.h>
/** Run-time data used by the emulator */
struct at24_emul_data {
/** I2C emulator detail */
struct i2c_emul emul;
/** AT24 device being emulated */
const struct device *i2c;
/** Current register to read (address) */
uint32_t cur_reg;
};
/** Static configuration for the emulator */
struct at24_emul_cfg {
/** EEPROM data contents */
uint8_t *buf;
/** Size of EEPROM in bytes */
uint32_t size;
/** Address of EEPROM on i2c bus */
uint16_t addr;
/** Address width for EEPROM in bits (only 8 is supported at present) */
uint8_t addr_width;
};
/**
* Emulator an I2C transfer to an AT24 chip
*
* This handles simple reads and writes
*
* @param emul I2C emulation information
* @param msgs List of messages to process. For 'read' messages, this function
* updates the 'buf' member with the data that was read
* @param num_msgs Number of messages to process
* @param addr Address of the I2C target device. This is assumed to be correct,
* due to the
* @retval 0 If successful
* @retval -EIO General input / output error
*/
static int at24_emul_transfer(const struct emul *target, struct i2c_msg *msgs,
int num_msgs, int addr)
{
struct at24_emul_data *data;
const struct at24_emul_cfg *cfg;
unsigned int len;
bool too_fast;
uint32_t i2c_cfg;
data = target->data;
cfg = target->cfg;
if (cfg->addr != addr) {
LOG_ERR("Address mismatch, expected %02x, got %02x", cfg->addr,
addr);
return -EIO;
}
if (i2c_get_config(data->i2c, &i2c_cfg)) {
LOG_ERR("i2c_get_config failed");
return -EIO;
}
/* For testing purposes, fail if the bus speed is above standard */
too_fast = (I2C_SPEED_GET(i2c_cfg) > I2C_SPEED_STANDARD);
if (too_fast) {
LOG_ERR("Speed too high");
return -EIO;
}
i2c_dump_msgs_rw(target->dev, msgs, num_msgs, addr, false);
switch (num_msgs) {
case 1:
if (msgs->flags & I2C_MSG_READ) {
/* handle read */
break;
}
data->cur_reg = msgs->buf[0];
len = MIN(msgs->len - 1, cfg->size - data->cur_reg);
memcpy(&cfg->buf[data->cur_reg], &msgs->buf[1], len);
return 0;
case 2:
if (msgs->flags & I2C_MSG_READ) {
LOG_ERR("Unexpected read");
return -EIO;
}
data->cur_reg = msgs->buf[0];
/* Now process the 'read' part of the message */
msgs++;
if (!(msgs->flags & I2C_MSG_READ)) {
LOG_ERR("Unexpected write");
return -EIO;
}
break;
default:
LOG_ERR("Invalid number of messages");
return -EIO;
}
/* Read data from the EEPROM into the buffer */
len = MIN(msgs->len, cfg->size - data->cur_reg);
memcpy(msgs->buf, &cfg->buf[data->cur_reg], len);
data->cur_reg += len;
return 0;
}
/* Device instantiation */
static struct i2c_emul_api bus_api = {
.transfer = at24_emul_transfer,
};
/**
* Set up a new AT24 emulator
*
* This should be called for each AT24 device that needs to be emulated. It
* registers it with the I2C emulation controller.
*
* @param target Emulation information
* @param parent Device to emulate (must use AT24 driver)
* @return 0 indicating success (always)
*/
static int emul_atmel_at24_init(const struct emul *target, const struct device *parent)
{
const struct at24_emul_cfg *cfg = target->cfg;
struct at24_emul_data *data = target->data;
data->emul.api = &bus_api;
data->emul.addr = cfg->addr;
data->emul.target = target;
data->i2c = parent;
data->cur_reg = 0;
/* Start with an erased EEPROM, assuming all 0xff */
memset(cfg->buf, 0xff, cfg->size);
return 0;
}
#define EEPROM_AT24_EMUL(n) \
static uint8_t at24_emul_buf_##n[DT_INST_PROP(n, size)]; \
static struct at24_emul_data at24_emul_data_##n; \
static const struct at24_emul_cfg at24_emul_cfg_##n = { \
.buf = at24_emul_buf_##n, \
.size = DT_INST_PROP(n, size), \
.addr = DT_INST_REG_ADDR(n), \
.addr_width = 8, \
}; \
EMUL_DT_INST_DEFINE(n, emul_atmel_at24_init, &at24_emul_data_##n, &at24_emul_cfg_##n, \
&bus_api, NULL)
DT_INST_FOREACH_STATUS_OKAY(EEPROM_AT24_EMUL)