* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
+#include "qemu/osdep.h"
#include "hw/hw.h"
#include "bitbang_i2c.h"
#include "hw/sysbus.h"
} bitbang_i2c_state;
struct bitbang_i2c_interface {
- i2c_bus *bus;
+ I2CBus *bus;
bitbang_i2c_state state;
int last_data;
int last_clock;
return bitbang_i2c_ret(i2c, 1);
case WAITING_FOR_ACK:
+ {
+ int ret;
+
if (i2c->current_addr < 0) {
i2c->current_addr = i2c->buffer;
DPRINTF("Address 0x%02x\n", i2c->current_addr);
- i2c_start_transfer(i2c->bus, i2c->current_addr >> 1,
- i2c->current_addr & 1);
+ ret = i2c_start_transfer(i2c->bus, i2c->current_addr >> 1,
+ i2c->current_addr & 1);
} else {
DPRINTF("Sent 0x%02x\n", i2c->buffer);
- i2c_send(i2c->bus, i2c->buffer);
+ ret = i2c_send(i2c->bus, i2c->buffer);
+ }
+ if (ret) {
+ /* NACK (either addressing a nonexistent device, or the
+ * device we were sending to decided to NACK us).
+ */
+ DPRINTF("Got NACK\n");
+ bitbang_i2c_enter_stop(i2c);
+ return bitbang_i2c_ret(i2c, 1);
}
if (i2c->current_addr & 1) {
i2c->state = RECEIVING_BIT7;
i2c->state = SENDING_BIT7;
}
return bitbang_i2c_ret(i2c, 0);
-
+ }
case RECEIVING_BIT7:
i2c->buffer = i2c_recv(i2c->bus);
DPRINTF("RX byte 0x%02x\n", i2c->buffer);
abort();
}
-bitbang_i2c_interface *bitbang_i2c_init(i2c_bus *bus)
+bitbang_i2c_interface *bitbang_i2c_init(I2CBus *bus)
{
bitbang_i2c_interface *s;
}
/* GPIO interface. */
-typedef struct {
- SysBusDevice busdev;
+
+#define TYPE_GPIO_I2C "gpio_i2c"
+#define GPIO_I2C(obj) OBJECT_CHECK(GPIOI2CState, (obj), TYPE_GPIO_I2C)
+
+typedef struct GPIOI2CState {
+ SysBusDevice parent_obj;
+
MemoryRegion dummy_iomem;
bitbang_i2c_interface *bitbang;
int last_level;
}
}
-static int gpio_i2c_init(SysBusDevice *dev)
+static void gpio_i2c_init(Object *obj)
{
- GPIOI2CState *s = FROM_SYSBUS(GPIOI2CState, dev);
- i2c_bus *bus;
+ DeviceState *dev = DEVICE(obj);
+ GPIOI2CState *s = GPIO_I2C(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ I2CBus *bus;
- memory_region_init(&s->dummy_iomem, OBJECT(s), "gpio_i2c", 0);
- sysbus_init_mmio(dev, &s->dummy_iomem);
+ memory_region_init(&s->dummy_iomem, obj, "gpio_i2c", 0);
+ sysbus_init_mmio(sbd, &s->dummy_iomem);
- bus = i2c_init_bus(&dev->qdev, "i2c");
+ bus = i2c_init_bus(dev, "i2c");
s->bitbang = bitbang_i2c_init(bus);
- qdev_init_gpio_in(&dev->qdev, bitbang_i2c_gpio_set, 2);
- qdev_init_gpio_out(&dev->qdev, &s->out, 1);
-
- return 0;
+ qdev_init_gpio_in(dev, bitbang_i2c_gpio_set, 2);
+ qdev_init_gpio_out(dev, &s->out, 1);
}
static void gpio_i2c_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = gpio_i2c_init;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->desc = "Virtual GPIO to I2C bridge";
}
static const TypeInfo gpio_i2c_info = {
- .name = "gpio_i2c",
+ .name = TYPE_GPIO_I2C,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(GPIOI2CState),
+ .instance_init = gpio_i2c_init,
.class_init = gpio_i2c_class_init,
};