@@ -578,7 +578,7 @@ endif
obj-arm-y = integratorcp.o versatilepb.o smc91c111.o arm_pic.o arm_timer.o
obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
-obj-arm-y += versatile_pci.o
+obj-arm-y += versatile_pci.o versatile_i2c.o
obj-arm-y += realview_gic.o realview.o arm_sysctl.o mpcore.o
obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
obj-arm-y += pl061.o
new file mode 100644
@@ -0,0 +1,119 @@
+/*
+ * Versatile i2c interface
+ *
+ * Copyright (c) 2009 BenoƮt Canet <benoit.canet@gmail.com>
+ *
+ * This code is licenced under the GNU GPL v2.
+ */
+#include "hw.h"
+#include "sysbus.h"
+
+#define I2C_CONTROL 0x0
+#define I2C_CONTROLS 0x0
+#define I2C_CONTROLC 0x4
+
+#define DATA 1<<1
+#define CLOCK 1
+
+typedef struct versatile_i2c_state {
+ SysBusDevice busdev;
+ int last_clock;
+ int last_data;
+ int read_data; /* data from decoder */
+ qemu_irq out[2]; /* 0 = data, 1 = clock */
+} versatile_i2c_state;
+
+static void versatile_i2c_gpio_set(void *opaque, int irq, int level)
+{
+ versatile_i2c_state *s = (versatile_i2c_state *) opaque;
+
+ if (irq == 0)
+ s->read_data = level;
+}
+
+static uint32_t versatile_i2c_read(void *opaque, target_phys_addr_t offset)
+{
+ versatile_i2c_state *s = (versatile_i2c_state *) opaque;
+
+ switch (offset) {
+ case I2C_CONTROL:
+ return (s->read_data << 1) | s->last_clock;
+ default:
+ hw_error("versatile_i2c_read: Bad offset %x\n", (int)offset);
+ return 0;
+ }
+}
+
+static void versatile_i2c_write(void *opaque, target_phys_addr_t offset,
+ uint32_t value)
+{
+ versatile_i2c_state *s = (versatile_i2c_state *) opaque;
+ int data = s->last_data;
+ int clock = s->last_clock;
+
+ switch (offset) {
+ case I2C_CONTROLS:
+ if (value & DATA)
+ data = 1;
+ if (value & CLOCK)
+ clock = 1;
+ break;
+ case I2C_CONTROLC:
+ if (value & DATA)
+ data = 0;
+ if (value & CLOCK)
+ clock = 0;
+ break;
+ default:
+ hw_error("versatile_i2c_write: Bad offset %x\n", (int)offset);
+ }
+
+ s->last_clock = clock;
+ s->last_data = data;
+
+ qemu_set_irq(s->out[0], data);
+ qemu_set_irq(s->out[1], clock);
+}
+
+static CPUReadMemoryFunc *versatile_i2c_readfn[] = {
+ versatile_i2c_read,
+ versatile_i2c_read,
+ versatile_i2c_read
+};
+
+static CPUWriteMemoryFunc *versatile_i2c_writefn[] = {
+ versatile_i2c_write,
+ versatile_i2c_write,
+ versatile_i2c_write
+};
+
+static void versatile_i2c_reset(versatile_i2c_state *s)
+{
+ s->last_clock = 1;
+ s->last_data = 1;
+ qemu_set_irq(s->out[0], s->last_data);
+ qemu_set_irq(s->out[1], s->last_clock);
+}
+
+static void versatile_i2c_init(SysBusDevice *dev)
+{
+ versatile_i2c_state *s = FROM_SYSBUS(versatile_i2c_state, dev);
+ int iomemtype;
+
+ versatile_i2c_reset(s);
+
+ iomemtype = cpu_register_io_memory(versatile_i2c_readfn,
+ versatile_i2c_writefn, s);
+ sysbus_init_mmio(dev, 0x1000, iomemtype);
+
+ qdev_init_gpio_in(&dev->qdev, versatile_i2c_gpio_set, 1);
+ qdev_init_gpio_out(&dev->qdev, s->out, 2);
+}
+
+static void versatile_i2c_register_devices(void)
+{
+ sysbus_register_dev("versatile,i2c", sizeof(versatile_i2c_state),
+ versatile_i2c_init);
+}
+
+device_init(versatile_i2c_register_devices)
Signed-off-by: Benoit Canet <benoit.canet@gmail.com> --- Makefile.target | 2 +- hw/versatile_i2c.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 1 deletions(-) create mode 100644 hw/versatile_i2c.c