2 * Simulate an I2C eeprom
4 * Copyright (c) 2014 Google, Inc
6 * SPDX-License-Identifier: GPL-2.0+
17 #define debug_buffer print_buffer
19 #define debug_buffer(x, ...)
22 DECLARE_GLOBAL_DATA_PTR
;
24 struct sandbox_i2c_flash_plat_data
{
25 enum sandbox_i2c_eeprom_test_mode test_mode
;
27 int offset_len
; /* Length of an offset in bytes */
28 int size
; /* Size of data buffer */
31 struct sandbox_i2c_flash
{
35 void sandbox_i2c_eeprom_set_test_mode(struct udevice
*dev
,
36 enum sandbox_i2c_eeprom_test_mode mode
)
38 struct sandbox_i2c_flash_plat_data
*plat
= dev_get_platdata(dev
);
40 plat
->test_mode
= mode
;
43 void sandbox_i2c_eeprom_set_offset_len(struct udevice
*dev
, int offset_len
)
45 struct sandbox_i2c_flash_plat_data
*plat
= dev_get_platdata(dev
);
47 plat
->offset_len
= offset_len
;
50 static int sandbox_i2c_eeprom_xfer(struct udevice
*emul
, struct i2c_msg
*msg
,
53 struct sandbox_i2c_flash
*priv
= dev_get_priv(emul
);
56 debug("\n%s\n", __func__
);
57 debug_buffer(0, priv
->data
, 1, 16, 0);
58 for (; nmsgs
> 0; nmsgs
--, msg
++) {
59 struct sandbox_i2c_flash_plat_data
*plat
=
60 dev_get_platdata(emul
);
66 if (msg
->addr
+ msg
->len
> plat
->size
) {
67 debug("%s: Address %x, len %x is outside range 0..%x\n",
68 __func__
, msg
->addr
, msg
->len
, plat
->size
);
72 debug(" %s: msg->len=%d",
73 msg
->flags
& I2C_M_RD
? "read" : "write",
75 if (msg
->flags
& I2C_M_RD
) {
76 if (plat
->test_mode
== SIE_TEST_MODE_SINGLE_BYTE
)
78 debug(", offset %x, len %x: ", offset
, len
);
79 memcpy(msg
->buf
, priv
->data
+ offset
, len
);
80 memset(msg
->buf
+ len
, '\xff', msg
->len
- len
);
81 debug_buffer(0, msg
->buf
, 1, msg
->len
, 0);
82 } else if (len
>= plat
->offset_len
) {
86 for (i
= 0; i
< plat
->offset_len
; i
++, len
--)
87 offset
= (offset
<< 8) | *ptr
++;
88 debug(", set offset %x: ", offset
);
89 debug_buffer(0, msg
->buf
, 1, msg
->len
, 0);
90 if (plat
->test_mode
== SIE_TEST_MODE_SINGLE_BYTE
)
93 /* For testing, map offsets into our limited buffer */
94 for (i
= 24; i
> 0; i
-= 8) {
95 if (offset
> (1 << i
)) {
96 offset
= (offset
>> i
) |
97 (offset
& ((1 << i
) - 1));
101 memcpy(priv
->data
+ offset
, ptr
, len
);
104 debug_buffer(0, priv
->data
, 1, 16, 0);
109 struct dm_i2c_ops sandbox_i2c_emul_ops
= {
110 .xfer
= sandbox_i2c_eeprom_xfer
,
113 static int sandbox_i2c_eeprom_ofdata_to_platdata(struct udevice
*dev
)
115 struct sandbox_i2c_flash_plat_data
*plat
= dev_get_platdata(dev
);
117 plat
->size
= dev_read_u32_default(dev
, "sandbox,size", 32);
118 plat
->filename
= dev_read_string(dev
, "sandbox,filename");
119 if (!plat
->filename
) {
120 debug("%s: No filename for device '%s'\n", __func__
,
124 plat
->test_mode
= SIE_TEST_MODE_NONE
;
125 plat
->offset_len
= 1;
130 static int sandbox_i2c_eeprom_probe(struct udevice
*dev
)
132 struct sandbox_i2c_flash_plat_data
*plat
= dev_get_platdata(dev
);
133 struct sandbox_i2c_flash
*priv
= dev_get_priv(dev
);
135 priv
->data
= calloc(1, plat
->size
);
142 static int sandbox_i2c_eeprom_remove(struct udevice
*dev
)
144 struct sandbox_i2c_flash
*priv
= dev_get_priv(dev
);
151 static const struct udevice_id sandbox_i2c_ids
[] = {
152 { .compatible
= "sandbox,i2c-eeprom" },
156 U_BOOT_DRIVER(sandbox_i2c_emul
) = {
157 .name
= "sandbox_i2c_eeprom_emul",
158 .id
= UCLASS_I2C_EMUL
,
159 .of_match
= sandbox_i2c_ids
,
160 .ofdata_to_platdata
= sandbox_i2c_eeprom_ofdata_to_platdata
,
161 .probe
= sandbox_i2c_eeprom_probe
,
162 .remove
= sandbox_i2c_eeprom_remove
,
163 .priv_auto_alloc_size
= sizeof(struct sandbox_i2c_flash
),
164 .platdata_auto_alloc_size
= sizeof(struct sandbox_i2c_flash_plat_data
),
165 .ops
= &sandbox_i2c_emul_ops
,