To enable testing of I2C, add a simple I2C EEPROM simulator for sandbox. It supports reading and writing from a small data store. Signed-off-by: Simon Glass <sjg@chromium.org> Acked-by: Heiko Schocher <hs@denx.de> Reviewed-by: Masahiro Yamada <yamada.m@jp.panasonic.com>master
parent
d19de0d314
commit
6ec1b75358
@ -0,0 +1,26 @@ |
||||
/*
|
||||
* Test-related constants for sandbox |
||||
* |
||||
* Copyright (c) 2014 Google, Inc |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef __ASM_TEST_H |
||||
#define __ASM_TEST_H |
||||
|
||||
/* The sandbox driver always permits an I2C device with this address */ |
||||
#define SANDBOX_I2C_TEST_ADDR 0x59 |
||||
|
||||
enum sandbox_i2c_eeprom_test_mode { |
||||
SIE_TEST_MODE_NONE, |
||||
/* Permits read/write of only one byte per I2C transaction */ |
||||
SIE_TEST_MODE_SINGLE_BYTE, |
||||
}; |
||||
|
||||
void sandbox_i2c_eeprom_set_test_mode(struct udevice *dev, |
||||
enum sandbox_i2c_eeprom_test_mode mode); |
||||
|
||||
void sandbox_i2c_eeprom_set_offset_len(struct udevice *dev, int offset_len); |
||||
|
||||
#endif |
@ -0,0 +1,168 @@ |
||||
/*
|
||||
* Simulate an I2C eeprom |
||||
* |
||||
* Copyright (c) 2014 Google, Inc |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <dm.h> |
||||
#include <fdtdec.h> |
||||
#include <i2c.h> |
||||
#include <malloc.h> |
||||
#include <asm/test.h> |
||||
|
||||
#ifdef DEBUG |
||||
#define debug_buffer print_buffer |
||||
#else |
||||
#define debug_buffer(x, ...) |
||||
#endif |
||||
|
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
|
||||
struct sandbox_i2c_flash_plat_data { |
||||
enum sandbox_i2c_eeprom_test_mode test_mode; |
||||
const char *filename; |
||||
int offset_len; /* Length of an offset in bytes */ |
||||
int size; /* Size of data buffer */ |
||||
}; |
||||
|
||||
struct sandbox_i2c_flash { |
||||
uint8_t *data; |
||||
}; |
||||
|
||||
void sandbox_i2c_eeprom_set_test_mode(struct udevice *dev, |
||||
enum sandbox_i2c_eeprom_test_mode mode) |
||||
{ |
||||
struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev); |
||||
|
||||
plat->test_mode = mode; |
||||
} |
||||
|
||||
void sandbox_i2c_eeprom_set_offset_len(struct udevice *dev, int offset_len) |
||||
{ |
||||
struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev); |
||||
|
||||
plat->offset_len = offset_len; |
||||
} |
||||
|
||||
static int sandbox_i2c_eeprom_xfer(struct udevice *emul, struct i2c_msg *msg, |
||||
int nmsgs) |
||||
{ |
||||
struct sandbox_i2c_flash *priv = dev_get_priv(emul); |
||||
uint offset = 0; |
||||
|
||||
debug("\n%s\n", __func__); |
||||
debug_buffer(0, priv->data, 1, 16, 0); |
||||
for (; nmsgs > 0; nmsgs--, msg++) { |
||||
struct sandbox_i2c_flash_plat_data *plat = |
||||
dev_get_platdata(emul); |
||||
int len; |
||||
u8 *ptr; |
||||
|
||||
if (!plat->size) |
||||
return -ENODEV; |
||||
if (msg->addr + msg->len > plat->size) { |
||||
debug("%s: Address %x, len %x is outside range 0..%x\n", |
||||
__func__, msg->addr, msg->len, plat->size); |
||||
return -EINVAL; |
||||
} |
||||
len = msg->len; |
||||
debug(" %s: msg->len=%d", |
||||
msg->flags & I2C_M_RD ? "read" : "write", |
||||
msg->len); |
||||
if (msg->flags & I2C_M_RD) { |
||||
if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE) |
||||
len = 1; |
||||
debug(", offset %x, len %x: ", offset, len); |
||||
memcpy(msg->buf, priv->data + offset, len); |
||||
memset(msg->buf + len, '\xff', msg->len - len); |
||||
debug_buffer(0, msg->buf, 1, msg->len, 0); |
||||
} else if (len >= plat->offset_len) { |
||||
int i; |
||||
|
||||
ptr = msg->buf; |
||||
for (i = 0; i < plat->offset_len; i++, len--) |
||||
offset = (offset << 8) | *ptr++; |
||||
debug(", set offset %x: ", offset); |
||||
debug_buffer(0, msg->buf, 1, msg->len, 0); |
||||
if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE) |
||||
len = min(len, 1); |
||||
|
||||
/* For testing, map offsets into our limited buffer */ |
||||
for (i = 24; i > 0; i -= 8) { |
||||
if (offset > (1 << i)) { |
||||
offset = (offset >> i) | |
||||
(offset & ((1 << i) - 1)); |
||||
offset += i; |
||||
} |
||||
} |
||||
memcpy(priv->data + offset, ptr, len); |
||||
} |
||||
} |
||||
debug_buffer(0, priv->data, 1, 16, 0); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
struct dm_i2c_ops sandbox_i2c_emul_ops = { |
||||
.xfer = sandbox_i2c_eeprom_xfer, |
||||
}; |
||||
|
||||
static int sandbox_i2c_eeprom_ofdata_to_platdata(struct udevice *dev) |
||||
{ |
||||
struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev); |
||||
|
||||
plat->size = fdtdec_get_int(gd->fdt_blob, dev->of_offset, |
||||
"sandbox,size", 32); |
||||
plat->filename = fdt_getprop(gd->fdt_blob, dev->of_offset, |
||||
"sandbox,filename", NULL); |
||||
if (!plat->filename) { |
||||
debug("%s: No filename for device '%s'\n", __func__, |
||||
dev->name); |
||||
return -EINVAL; |
||||
} |
||||
plat->test_mode = SIE_TEST_MODE_NONE; |
||||
plat->offset_len = 1; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int sandbox_i2c_eeprom_probe(struct udevice *dev) |
||||
{ |
||||
struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev); |
||||
struct sandbox_i2c_flash *priv = dev_get_priv(dev); |
||||
|
||||
priv->data = calloc(1, plat->size); |
||||
if (!priv->data) |
||||
return -ENOMEM; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int sandbox_i2c_eeprom_remove(struct udevice *dev) |
||||
{ |
||||
struct sandbox_i2c_flash *priv = dev_get_priv(dev); |
||||
|
||||
free(priv->data); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static const struct udevice_id sandbox_i2c_ids[] = { |
||||
{ .compatible = "sandbox,i2c-eeprom" }, |
||||
{ } |
||||
}; |
||||
|
||||
U_BOOT_DRIVER(sandbox_i2c_emul) = { |
||||
.name = "sandbox_i2c_eeprom_emul", |
||||
.id = UCLASS_I2C_EMUL, |
||||
.of_match = sandbox_i2c_ids, |
||||
.ofdata_to_platdata = sandbox_i2c_eeprom_ofdata_to_platdata, |
||||
.probe = sandbox_i2c_eeprom_probe, |
||||
.remove = sandbox_i2c_eeprom_remove, |
||||
.priv_auto_alloc_size = sizeof(struct sandbox_i2c_flash), |
||||
.platdata_auto_alloc_size = sizeof(struct sandbox_i2c_flash_plat_data), |
||||
.ops = &sandbox_i2c_emul_ops, |
||||
}; |
Loading…
Reference in new issue