qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH v2] versatilepb: add i2c support


From: Oskar Andero
Subject: [Qemu-devel] [PATCH v2] versatilepb: add i2c support
Date: Tue, 3 Apr 2012 22:29:55 +0200

Signed-off-by: Oskar Andero <address@hidden>
---
 hw/versatilepb.c |   80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 80 insertions(+), 0 deletions(-)

diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 25afb1e..d4fe168 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -16,9 +16,18 @@
 #include "boards.h"
 #include "blockdev.h"
 #include "exec-memory.h"
+#include "bitbang_i2c.h"
 
 /* Primary interrupt controller.  */
 
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    bitbang_i2c_interface *bitbang;
+    int out;
+    int in;
+} VPBI2CState;
+
 typedef struct vpb_sic_state
 {
   SysBusDevice busdev;
@@ -153,6 +162,64 @@ static int vpb_sic_init(SysBusDevice *dev)
     return 0;
 }
 
+static uint64_t vpb_i2c_read(void *opaque, target_phys_addr_t offset,
+                             unsigned size)
+{
+    VPBI2CState *s = (VPBI2CState *)opaque;
+
+    if (offset == 0) {
+        return (s->out & 1) | (s->in << 1);
+    } else {
+        hw_error("%s: Bad offset 0x%x\n", __func__, (int)offset);
+        return -1;
+    }
+}
+
+static void vpb_i2c_write(void *opaque, target_phys_addr_t offset,
+                          uint64_t value, unsigned size)
+{
+    VPBI2CState *s = (VPBI2CState *)opaque;
+
+    switch (offset) {
+    case 0:
+        s->out |= value & 3;
+        break;
+    case 4:
+        s->out &= ~value;
+        break;
+    default:
+        hw_error("%s: Bad offset 0x%x\n", __func__, (int)offset);
+    }
+    bitbang_i2c_set(s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0);
+    s->in = bitbang_i2c_set(s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0);
+}
+
+static const MemoryRegionOps vpb_i2c_ops = {
+    .read = vpb_i2c_read,
+    .write = vpb_i2c_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int vpb_i2c_init(SysBusDevice *dev)
+{
+    VPBI2CState *s = FROM_SYSBUS(VPBI2CState, dev);
+    i2c_bus *bus;
+
+    bus = i2c_init_bus(&dev->qdev, "i2c");
+    s->bitbang = bitbang_i2c_init(bus);
+    memory_region_init_io(&s->iomem, &vpb_i2c_ops, s,
+                          "vpb-i2c", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    return 0;
+}
+
+static void vpb_i2c_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = vpb_i2c_init;
+}
+
 /* Board init.  */
 
 /* The AB and PB boards both use the same core, just with different
@@ -177,6 +244,7 @@ static void versatile_init(ram_addr_t ram_size,
     SysBusDevice *busdev;
     DeviceState *pl041;
     PCIBus *pci_bus;
+    i2c_bus *i2c;
     NICInfo *nd;
     int n;
     int done_smc = 0;
@@ -268,6 +336,10 @@ static void versatile_init(ram_addr_t ram_size,
     /* Add PL031 Real Time Clock. */
     sysbus_create_simple("pl031", 0x101e8000, pic[10]);
 
+    dev = sysbus_create_simple("vpb_i2c", 0x10002000, NULL);
+    i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
+    i2c_create_slave(i2c, "ds1338", 0x68);
+
     /* Add PL041 AACI Interface to the LM4549 codec */
     pl041 = qdev_create(NULL, "pl041");
     qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
@@ -380,9 +452,17 @@ static TypeInfo vpb_sic_info = {
     .class_init    = vpb_sic_class_init,
 };
 
+static const TypeInfo vpb_i2c_info = {
+    .name          = "vpb_i2c",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(VPBI2CState),
+    .class_init    = vpb_i2c_class_init,
+};
+
 static void versatilepb_register_types(void)
 {
     type_register_static(&vpb_sic_info);
+    type_register_static(&vpb_i2c_info);
 }
 
 type_init(versatilepb_register_types)
-- 
1.7.3.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]