2 * *AT24C* series I2C EEPROM
4 * Copyright (c) 2015 Michael Davidsaver
6 * This work is licensed under the terms of the GNU GPL, version 2. See
7 * the LICENSE file in the top-level directory.
12 #include "qemu/osdep.h"
13 #include "qapi/error.h"
15 #include "hw/i2c/i2c.h"
16 #include "sysemu/block-backend.h"
18 /* #define DEBUG_AT24C */
21 #define DPRINTK(FMT, ...) printf(TYPE_AT24C_EE " : " FMT, ## __VA_ARGS__)
23 #define DPRINTK(FMT, ...) do {} while (0)
26 #define ERR(FMT, ...) fprintf(stderr, TYPE_AT24C_EE " : " FMT, \
29 #define TYPE_AT24C_EE "at24c-eeprom"
30 #define AT24C_EE(obj) OBJECT_CHECK(EEPROMState, (obj), TYPE_AT24C_EE)
32 typedef struct EEPROMState
{
37 /* total size in bytes */
40 /* cells changed since last START? */
42 /* during WRITE, # of address bytes transfered */
51 int at24c_eeprom_event(I2CSlave
*s
, enum i2c_event event
)
53 EEPROMState
*ee
= container_of(s
, EEPROMState
, parent_obj
);
61 if (ee
->blk
&& ee
->changed
) {
62 int len
= blk_pwrite(ee
->blk
, 0, ee
->mem
, ee
->rsize
, 0);
63 if (len
!= ee
->rsize
) {
65 " : failed to write backing file\n");
67 DPRINTK("Wrote to backing file\n");
78 int at24c_eeprom_recv(I2CSlave
*s
)
80 EEPROMState
*ee
= AT24C_EE(s
);
83 ret
= ee
->mem
[ee
->cur
];
85 ee
->cur
= (ee
->cur
+ 1u) % ee
->rsize
;
86 DPRINTK("Recv %02x %c\n", ret
, ret
);
92 int at24c_eeprom_send(I2CSlave
*s
, uint8_t data
)
94 EEPROMState
*ee
= AT24C_EE(s
);
96 if (ee
->haveaddr
< 2) {
100 if (ee
->haveaddr
== 2) {
101 ee
->cur
%= ee
->rsize
;
102 DPRINTK("Set pointer %04x\n", ee
->cur
);
107 DPRINTK("Send %02x\n", data
);
108 ee
->mem
[ee
->cur
] = data
;
111 DPRINTK("Send error %02x read-only\n", data
);
113 ee
->cur
= (ee
->cur
+ 1u) % ee
->rsize
;
121 int at24c_eeprom_init(I2CSlave
*i2c
)
123 EEPROMState
*ee
= AT24C_EE(i2c
);
125 ee
->mem
= g_malloc0(ee
->rsize
);
128 int64_t len
= blk_getlength(ee
->blk
);
130 if (len
!= ee
->rsize
) {
131 ERR(TYPE_AT24C_EE
" : Backing file size %lu != %u\n",
132 (unsigned long)len
, (unsigned)ee
->rsize
);
136 if (blk_set_perm(ee
->blk
, BLK_PERM_CONSISTENT_READ
| BLK_PERM_WRITE
,
137 BLK_PERM_ALL
, &error_fatal
) < 0)
140 " : Backing file incorrect permission\n");
148 void at24c_eeprom_reset(DeviceState
*state
)
150 EEPROMState
*ee
= AT24C_EE(state
);
156 memset(ee
->mem
, 0, ee
->rsize
);
159 int len
= blk_pread(ee
->blk
, 0, ee
->mem
, ee
->rsize
);
161 if (len
!= ee
->rsize
) {
163 " : Failed initial sync with backing file\n");
165 DPRINTK("Reset read backing file\n");
169 static Property at24c_eeprom_props
[] = {
170 DEFINE_PROP_UINT32("rom-size", EEPROMState
, rsize
, 0),
171 DEFINE_PROP_BOOL("writable", EEPROMState
, writable
, true),
172 DEFINE_PROP_DRIVE("drive", EEPROMState
, blk
),
173 DEFINE_PROP_END_OF_LIST()
177 void at24c_eeprom_class_init(ObjectClass
*klass
, void *data
)
179 DeviceClass
*dc
= DEVICE_CLASS(klass
);
180 I2CSlaveClass
*k
= I2C_SLAVE_CLASS(klass
);
182 k
->init
= &at24c_eeprom_init
;
183 k
->event
= &at24c_eeprom_event
;
184 k
->recv
= &at24c_eeprom_recv
;
185 k
->send
= &at24c_eeprom_send
;
187 dc
->props
= at24c_eeprom_props
;
188 dc
->reset
= at24c_eeprom_reset
;
192 const TypeInfo at24c_eeprom_type
= {
193 .name
= TYPE_AT24C_EE
,
194 .parent
= TYPE_I2C_SLAVE
,
195 .instance_size
= sizeof(EEPROMState
),
196 .class_size
= sizeof(I2CSlaveClass
),
197 .class_init
= at24c_eeprom_class_init
,
200 static void at24c_eeprom_register(void)
202 type_register_static(&at24c_eeprom_type
);
205 type_init(at24c_eeprom_register
)