1 // SPDX-License-Identifier: GPL-2.0+
3 * Simulate an I2C eeprom
5 * Copyright (c) 2014 Google, Inc
16 #define debug_buffer print_buffer
18 #define debug_buffer(x, ...)
21 struct sandbox_i2c_flash_plat_data
{
22 enum sandbox_i2c_eeprom_test_mode test_mode
;
24 int offset_len
; /* Length of an offset in bytes */
25 int size
; /* Size of data buffer */
28 struct sandbox_i2c_flash
{
32 void sandbox_i2c_eeprom_set_test_mode(struct udevice
*dev
,
33 enum sandbox_i2c_eeprom_test_mode mode
)
35 struct sandbox_i2c_flash_plat_data
*plat
= dev_get_platdata(dev
);
37 plat
->test_mode
= mode
;
40 void sandbox_i2c_eeprom_set_offset_len(struct udevice
*dev
, int offset_len
)
42 struct sandbox_i2c_flash_plat_data
*plat
= dev_get_platdata(dev
);
44 plat
->offset_len
= offset_len
;
47 static int sandbox_i2c_eeprom_xfer(struct udevice
*emul
, struct i2c_msg
*msg
,
50 struct sandbox_i2c_flash
*priv
= dev_get_priv(emul
);
53 debug("\n%s\n", __func__
);
54 debug_buffer(0, priv
->data
, 1, 16, 0);
55 for (; nmsgs
> 0; nmsgs
--, msg
++) {
56 struct sandbox_i2c_flash_plat_data
*plat
=
57 dev_get_platdata(emul
);
63 if (msg
->addr
+ msg
->len
> plat
->size
) {
64 debug("%s: Address %x, len %x is outside range 0..%x\n",
65 __func__
, msg
->addr
, msg
->len
, plat
->size
);
69 debug(" %s: msg->len=%d",
70 msg
->flags
& I2C_M_RD
? "read" : "write",
72 if (msg
->flags
& I2C_M_RD
) {
73 if (plat
->test_mode
== SIE_TEST_MODE_SINGLE_BYTE
)
75 debug(", offset %x, len %x: ", offset
, len
);
76 memcpy(msg
->buf
, priv
->data
+ offset
, len
);
77 memset(msg
->buf
+ len
, '\xff', msg
->len
- len
);
78 debug_buffer(0, msg
->buf
, 1, msg
->len
, 0);
79 } else if (len
>= plat
->offset_len
) {
83 for (i
= 0; i
< plat
->offset_len
; i
++, len
--)
84 offset
= (offset
<< 8) | *ptr
++;
85 debug(", set offset %x: ", offset
);
86 debug_buffer(0, msg
->buf
, 1, msg
->len
, 0);
87 if (plat
->test_mode
== SIE_TEST_MODE_SINGLE_BYTE
)
90 /* For testing, map offsets into our limited buffer */
91 for (i
= 24; i
> 0; i
-= 8) {
92 if (offset
> (1 << i
)) {
93 offset
= (offset
>> i
) |
94 (offset
& ((1 << i
) - 1));
98 memcpy(priv
->data
+ offset
, ptr
, len
);
101 debug_buffer(0, priv
->data
, 1, 16, 0);
106 struct dm_i2c_ops sandbox_i2c_emul_ops
= {
107 .xfer
= sandbox_i2c_eeprom_xfer
,
110 static int sandbox_i2c_eeprom_ofdata_to_platdata(struct udevice
*dev
)
112 struct sandbox_i2c_flash_plat_data
*plat
= dev_get_platdata(dev
);
114 plat
->size
= dev_read_u32_default(dev
, "sandbox,size", 32);
115 plat
->filename
= dev_read_string(dev
, "sandbox,filename");
116 if (!plat
->filename
) {
117 debug("%s: No filename for device '%s'\n", __func__
,
121 plat
->test_mode
= SIE_TEST_MODE_NONE
;
122 plat
->offset_len
= 1;
127 static int sandbox_i2c_eeprom_probe(struct udevice
*dev
)
129 struct sandbox_i2c_flash_plat_data
*plat
= dev_get_platdata(dev
);
130 struct sandbox_i2c_flash
*priv
= dev_get_priv(dev
);
132 priv
->data
= calloc(1, plat
->size
);
139 static int sandbox_i2c_eeprom_remove(struct udevice
*dev
)
141 struct sandbox_i2c_flash
*priv
= dev_get_priv(dev
);
148 static const struct udevice_id sandbox_i2c_ids
[] = {
149 { .compatible
= "sandbox,i2c-eeprom" },
153 U_BOOT_DRIVER(sandbox_i2c_emul
) = {
154 .name
= "sandbox_i2c_eeprom_emul",
155 .id
= UCLASS_I2C_EMUL
,
156 .of_match
= sandbox_i2c_ids
,
157 .ofdata_to_platdata
= sandbox_i2c_eeprom_ofdata_to_platdata
,
158 .probe
= sandbox_i2c_eeprom_probe
,
159 .remove
= sandbox_i2c_eeprom_remove
,
160 .priv_auto_alloc_size
= sizeof(struct sandbox_i2c_flash
),
161 .platdata_auto_alloc_size
= sizeof(struct sandbox_i2c_flash_plat_data
),
162 .ops
= &sandbox_i2c_emul_ops
,