i2c: Add AT24Cxx EEPROM model
RFC PATCH 1/1 i2c: Add AT24Cxx EEPROM model
Hi
Below is a patch from Jan Kiszka
https://lists.gnu.org/archive/html/qemu-devel/2013-04/msg05714.html
but in one part and adapted to block layer changes. I would like to get this work mainlined and my question is whats missing to get this stuff mainlined? As far as i understand Jan is ok with this effort.
Best regards
Tim
Original patch descriptions:
Some devices react on multiple addresses. To emulate this, we could register them multiple times, but that is cumbersome. The AT24C16, e.g. listens on 8 different addresses.
Instead, introduce a device address mask that is applied on the transmitted address before matching it against the stored one. Moreover, the transmitted address is passed as additional parameter to the event callback of the device.
This implements I2C EEPROMs of the AT24Cxx series. Sizes from 1Kbit to 1024Kbit are supported. Each EEPROM is backed by a block device. Its size can be explicitly specified by selecting the exact device type (required for sizes < 512, the blockdev sector size) or implicitly by providing a block device image of the corresponding size. Device addresses are built from the device number property. Write protection can be configured by declaring the block device read-only.
---
hw/arm/pxa2xx.c | 3 +- hw/arm/tosa.c | 2 +- hw/arm/z2.c | 2 +- hw/audio/wm8750.c | 2 +- hw/display/ssd0303.c | 2 +- hw/gpio/max7310.c | 2 +- hw/i2c/core.c | 16 +- hw/i2c/smbus.c | 2 +- hw/input/lm832x.c | 2 +- hw/misc/tmp105.c | 2 +- hw/nvram/Makefile.objs | 1 + hw/nvram/at24.c | 392 +++++++++++++++++++++++++++++++++++++++++++++++++ hw/timer/ds1338.c | 2 +- hw/timer/twl92230.c | 2 +- include/hw/i2c/i2c.h | 4 +- 15 files changed, 420 insertions(+), 16 deletions(-) create mode 100644 hw/nvram/at24.c
hw/arm/pxa2xx.c +2 -1
@@ -1255,7 +1255,8 @@ static void pxa2xx_i2c_update(PXA2xxI2CState *s) }/* These are only stubs now. */ -static void pxa2xx_i2c_event (I2CSlave *i2c,enum i2c_event event) +static void pxa2xx_i2c_event (I2CSlave *i2c,enum i2c_event event, +uint8_t param) {PXA2xxI2CSlaveState *slave =PXA2XX_I2C_SLAVE (i2c);PXA2xxI2CState *s = slave->host;
hw/arm/tosa.c +1 -1
@@ -161,7 +161,7 @@ static int tosa_dac_send(I2CSlave *i2c, uint8_t data)return 0 ; } -static void tosa_dac_event (I2CSlave *i2c,enum i2c_event event) +static void tosa_dac_event (I2CSlave *i2c,enum i2c_event event,uint8_t param) {TosaDACState *s =TOSA_DAC (i2c);
hw/arm/z2.c +1 -1
@@ -221,7 +221,7 @@ static int aer915_send(I2CSlave *i2c, uint8_t data)return 0 ; } -static void aer915_event (I2CSlave *i2c,enum i2c_event event) +static void aer915_event (I2CSlave *i2c,enum i2c_event event,uint8_t param) {AER915State *s =AER915 (i2c);
hw/audio/wm8750.c +1 -1
@@ -302,7 +302,7 @@ static void wm8750_reset(I2CSlave *i2c) s->i2c_len =0 ; } -static void wm8750_event (I2CSlave *i2c,enum i2c_event event) +static void wm8750_event (I2CSlave *i2c,enum i2c_event event,uint8_t param) {WM8750State *s =WM8750 (i2c);
hw/display/ssd0303.c +1 -1
@@ -178,7 +178,7 @@ static int ssd0303_send(I2CSlave *i2c, uint8_t data)return 0 ; } -static void ssd0303_event (I2CSlave *i2c,enum i2c_event event) +static void ssd0303_event (I2CSlave *i2c,enum i2c_event event,uint8_t param) {ssd0303_state *s =SSD0303 (i2c);
hw/gpio/max7310.c +1 -1
@@ -128,7 +128,7 @@ static int max7310_tx(I2CSlave *i2c, uint8_t data)return 0 ; } -static void max7310_event (I2CSlave *i2c,enum i2c_event event) +static void max7310_event (I2CSlave *i2c,enum i2c_event event,uint8_t param) {MAX7310State *s =MAX7310 (i2c); s->len =0 ;
hw/i2c/core.c +12 -4
@@ -75,6 +75,13 @@ void i2c_set_slave_address(I2CSlave *dev, uint8_t address) dev->address = address; } +/* devices can appear multiple times on the I2C bus +multiple registration can be avoided using this mask */ +void i2c_set_slave_address_mask (I2CSlave *dev,uint8_t mask) +{ + dev->address_mask = mask; +} +/* Return nonzero if bus is busy. */ int i2c_bus_busy (I2CBus *bus) {
@@ -92,7 +99,7 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv) QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {DeviceState *qdev = kid->child;I2CSlave *candidate =I2C_SLAVE (qdev); -if (candidate->address == address) { +if (candidate->address == (address & candidate->address_mask)) { slave = candidate;break ; }
@@ -107,7 +114,7 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv)start condition. */ bus->current_dev = slave;if (sc->event) { - sc->event (slave, recv ?I2C_START_RECV :I2C_START_SEND ); + sc->event (slave, recv ?I2C_START_RECV :I2C_START_SEND , address); }return 0 ; }
@@ -123,7 +130,7 @@ void i2c_end_transfer(I2CBus *bus) sc =I2C_SLAVE_GET_CLASS (dev);if (sc->event) { - sc->event (dev,I2C_FINISH ); + sc->event (dev,I2C_FINISH ,0 ); } bus->current_dev =NULL ;
@@ -174,7 +181,7 @@ void i2c_nack(I2CBus *bus) sc =I2C_SLAVE_GET_CLASS (dev);if (sc->event) { - sc->event (dev,I2C_NACK ); + sc->event (dev,I2C_NACK ,0 ); } }
@@ -205,6 +212,7 @@ static int i2c_slave_qdev_init(DeviceState *dev)I2CSlave *s =I2C_SLAVE (dev);I2CSlaveClass *sc =I2C_SLAVE_GET_CLASS (s); + s->address_mask =0x7f ;return sc->init (s); }
hw/i2c/smbus.c +1 -1
@@ -66,7 +66,7 @@ static void smbus_do_write(SMBusDevice *dev) } } -static void smbus_i2c_event (I2CSlave *s,enum i2c_event event) +static void smbus_i2c_event (I2CSlave *s,enum i2c_event event,uint8_t param) {SMBusDevice *dev =SMBUS_DEVICE (s);
hw/input/lm832x.c +1 -1
@@ -382,7 +382,7 @@ static void lm_kbd_write(LM823KbdState *s, int reg, int byte, uint8_t value) } } -static void lm_i2c_event (I2CSlave *i2c,enum i2c_event event) +static void lm_i2c_event (I2CSlave *i2c,enum i2c_event event,uint8_t param) {LM823KbdState *s =LM8323 (i2c);
hw/misc/tmp105.c +1 -1
@@ -174,7 +174,7 @@ static int tmp105_tx(I2CSlave *i2c, uint8_t data)return 0 ; } -static void tmp105_event (I2CSlave *i2c,enum i2c_event event) +static void tmp105_event (I2CSlave *i2c,enum i2c_event event,uint8_t param) {TMP105State *s =TMP105 (i2c);
hw/nvram/Makefile.objs +1 -0
@@ -1,5 +1,6 @@ common-obj-$(CONFIG_DS1225Y) += ds1225y.o common-obj-y += eeprom93xx.o +common-obj-y += at24.o common-obj-y += fw_cfg.o common-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o obj-$(CONFIG_PSERIES) += spapr_nvram.o
hw/nvram/at24.c new file +392 -0
392 lines not on this page · raw message
hw/timer/ds1338.c +1 -1
@@ -91,7 +91,7 @@ static void inc_regptr(DS1338State *s) } } -static void ds1338_event (I2CSlave *i2c,enum i2c_event event) +static void ds1338_event (I2CSlave *i2c,enum i2c_event event,uint8_t param) {DS1338State *s =DS1338 (i2c);
hw/timer/twl92230.c +1 -1
@@ -711,7 +711,7 @@ static void menelaus_write(void *opaque, uint8_t addr, uint8_t value) } } -static void menelaus_event (I2CSlave *i2c,enum i2c_event event) +static void menelaus_event (I2CSlave *i2c,enum i2c_event event,uint8_t param) {MenelausState *s =TWL92230 (i2c);
include/hw/i2c/i2c.h +3 -1
@@ -39,7 +39,7 @@ typedef struct I2CSlaveClassint (*recv)(I2CSlave *s);/* Notify the slave of a bus state change. */ -void (*event)(I2CSlave *s,enum i2c_event event); +void (*event)(I2CSlave *s,enum i2c_event event,uint8_t param); } I2CSlaveClass;struct I2CSlave
@@ -48,10 +48,12 @@ struct I2CSlave/* Remaining fields for internal use by the I2C code. */ uint8_t address; +uint8_t address_mask; };I2CBus *i2c_init_bus (DeviceState *parent,const char *name);void i2c_set_slave_address (I2CSlave *dev,uint8_t address); +void i2c_set_slave_address_mask (I2CSlave *dev,uint8_t mask);int i2c_bus_busy (I2CBus *bus);int i2c_start_transfer (I2CBus *bus,uint8_t address,int recv);void i2c_end_transfer (I2CBus *bus);
Signature · 14 lines
1.9.1 Hottinger Baldwin Messtechnik GmbH, Im Tiefen See 45, 64293 Darmstadt, Germany | www.hbm.com Registered as GmbH (German limited liability corporation) in the commercial register at the local court of Darmstadt, HRB 1147 Company domiciled in Darmstadt | Managing Director: Andreas Huellhorst | Chairman of the board: Eoghan O'Lionaird Als Gesellschaft mit beschraenkter Haftung eingetragen im Handelsregister des Amtsgerichts Darmstadt unter HRB 1147 Sitz der Gesellschaft: Darmstadt | Geschaeftsfuehrung: Andreas Huellhorst | Aufsichtsratsvorsitzender: Eoghan O'Lionaird The information in this email is confidential. It is intended solely for the addressee. If you are not the intended recipient, please let me know and delete this email. Die in dieser E-Mail enthaltene Information ist vertraulich und lediglich fuer den Empfaenger bestimmt. Sollten Sie nicht der eigentliche Empfaenger sein, informieren Sie mich bitte kurz und loeschen diese E-Mail.
Hi,
Quoted 8 lines
Some devices react on multiple addresses. To emulate this, we could register them multiple times, but that is cumbersome. The AT24C16, e.g. listens on 8 different addresses.
Instead, introduce a device address mask that is applied on the transmitted address before matching it against the stored one. Moreover, the transmitted address is passed as additional parameter to the event callback of the device.
This interface change ...
Quoted 7 lines
This implements I2C EEPROMs of the AT24Cxx series. Sizes from 1Kbit to 1024Kbit are supported. Each EEPROM is backed by a block device. Its size can be explicitly specified by selecting the exact device type (required for sizes < 512, the blockdev sector size) or implicitly by providing a block device image of the corresponding size. Device addresses are built from the device number property. Write protection can be configured by declaring the block device read-only.
... and this new device should be two separate patches (but best sent as patch series to make clear why the interface change is needed).
cheers,
Gerd