2 * Simulate an I2C eeprom
4 * Copyright (c) 2014 Google, Inc
6 * SPDX-License-Identifier: GPL-2.0+
18 #define debug_buffer print_buffer
20 #define debug_buffer(x, ...)
23 DECLARE_GLOBAL_DATA_PTR
;
25 struct sandbox_i2c_flash_plat_data
{
26 enum sandbox_i2c_eeprom_test_mode test_mode
;
28 int offset_len
; /* Length of an offset in bytes */
29 int size
; /* Size of data buffer */
32 struct sandbox_i2c_flash
{
36 void sandbox_i2c_eeprom_set_test_mode(struct udevice
*dev
,
37 enum sandbox_i2c_eeprom_test_mode mode
)
39 struct sandbox_i2c_flash_plat_data
*plat
= dev_get_platdata(dev
);
41 plat
->test_mode
= mode
;
44 void sandbox_i2c_eeprom_set_offset_len(struct udevice
*dev
, int offset_len
)
46 struct sandbox_i2c_flash_plat_data
*plat
= dev_get_platdata(dev
);
48 plat
->offset_len
= offset_len
;
51 static int sandbox_i2c_eeprom_xfer(struct udevice
*emul
, struct i2c_msg
*msg
,
54 struct sandbox_i2c_flash
*priv
= dev_get_priv(emul
);
57 debug("\n%s\n", __func__
);
58 debug_buffer(0, priv
->data
, 1, 16, 0);
59 for (; nmsgs
> 0; nmsgs
--, msg
++) {
60 struct sandbox_i2c_flash_plat_data
*plat
=
61 dev_get_platdata(emul
);
67 if (msg
->addr
+ msg
->len
> plat
->size
) {
68 debug("%s: Address %x, len %x is outside range 0..%x\n",
69 __func__
, msg
->addr
, msg
->len
, plat
->size
);
73 debug(" %s: msg->len=%d",
74 msg
->flags
& I2C_M_RD
? "read" : "write",
76 if (msg
->flags
& I2C_M_RD
) {
77 if (plat
->test_mode
== SIE_TEST_MODE_SINGLE_BYTE
)
79 debug(", offset %x, len %x: ", offset
, len
);
80 memcpy(msg
->buf
, priv
->data
+ offset
, len
);
81 memset(msg
->buf
+ len
, '\xff', msg
->len
- len
);
82 debug_buffer(0, msg
->buf
, 1, msg
->len
, 0);
83 } else if (len
>= plat
->offset_len
) {
87 for (i
= 0; i
< plat
->offset_len
; i
++, len
--)
88 offset
= (offset
<< 8) | *ptr
++;
89 debug(", set offset %x: ", offset
);
90 debug_buffer(0, msg
->buf
, 1, msg
->len
, 0);
91 if (plat
->test_mode
== SIE_TEST_MODE_SINGLE_BYTE
)
94 /* For testing, map offsets into our limited buffer */
95 for (i
= 24; i
> 0; i
-= 8) {
96 if (offset
> (1 << i
)) {
97 offset
= (offset
>> i
) |
98 (offset
& ((1 << i
) - 1));
102 memcpy(priv
->data
+ offset
, ptr
, len
);
105 debug_buffer(0, priv
->data
, 1, 16, 0);
110 struct dm_i2c_ops sandbox_i2c_emul_ops
= {
111 .xfer
= sandbox_i2c_eeprom_xfer
,
114 static int sandbox_i2c_eeprom_ofdata_to_platdata(struct udevice
*dev
)
116 struct sandbox_i2c_flash_plat_data
*plat
= dev_get_platdata(dev
);
118 plat
->size
= fdtdec_get_int(gd
->fdt_blob
, dev_of_offset(dev
),
120 plat
->filename
= fdt_getprop(gd
->fdt_blob
, dev_of_offset(dev
),
121 "sandbox,filename", NULL
);
122 if (!plat
->filename
) {
123 debug("%s: No filename for device '%s'\n", __func__
,
127 plat
->test_mode
= SIE_TEST_MODE_NONE
;
128 plat
->offset_len
= 1;
133 static int sandbox_i2c_eeprom_probe(struct udevice
*dev
)
135 struct sandbox_i2c_flash_plat_data
*plat
= dev_get_platdata(dev
);
136 struct sandbox_i2c_flash
*priv
= dev_get_priv(dev
);
138 priv
->data
= calloc(1, plat
->size
);
145 static int sandbox_i2c_eeprom_remove(struct udevice
*dev
)
147 struct sandbox_i2c_flash
*priv
= dev_get_priv(dev
);
154 static const struct udevice_id sandbox_i2c_ids
[] = {
155 { .compatible
= "sandbox,i2c-eeprom" },
159 U_BOOT_DRIVER(sandbox_i2c_emul
) = {
160 .name
= "sandbox_i2c_eeprom_emul",
161 .id
= UCLASS_I2C_EMUL
,
162 .of_match
= sandbox_i2c_ids
,
163 .ofdata_to_platdata
= sandbox_i2c_eeprom_ofdata_to_platdata
,
164 .probe
= sandbox_i2c_eeprom_probe
,
165 .remove
= sandbox_i2c_eeprom_remove
,
166 .priv_auto_alloc_size
= sizeof(struct sandbox_i2c_flash
),
167 .platdata_auto_alloc_size
= sizeof(struct sandbox_i2c_flash_plat_data
),
168 .ops
= &sandbox_i2c_emul_ops
,