Revision 54e17933 hw/omap_i2c.c
b/hw/omap_i2c.c | ||
---|---|---|
19 | 19 |
#include "hw.h" |
20 | 20 |
#include "i2c.h" |
21 | 21 |
#include "omap.h" |
22 |
#include "sysbus.h" |
|
22 | 23 |
|
23 |
struct omap_i2c_s { |
|
24 |
|
|
25 |
typedef struct OMAPI2CState { |
|
26 |
SysBusDevice busdev; |
|
24 | 27 |
MemoryRegion iomem; |
25 | 28 |
qemu_irq irq; |
26 | 29 |
qemu_irq drq[2]; |
27 | 30 |
i2c_bus *bus; |
28 | 31 |
|
29 | 32 |
uint8_t revision; |
33 |
void *iclk; |
|
34 |
void *fclk; |
|
35 |
|
|
30 | 36 |
uint8_t mask; |
31 | 37 |
uint16_t stat; |
32 | 38 |
uint16_t dma; |
... | ... | |
40 | 46 |
uint8_t divider; |
41 | 47 |
uint8_t times[2]; |
42 | 48 |
uint16_t test; |
43 |
}; |
|
49 |
} OMAPI2CState;
|
|
44 | 50 |
|
45 | 51 |
#define OMAP2_INTR_REV 0x34 |
46 | 52 |
#define OMAP2_GC_REV 0x34 |
47 | 53 |
|
48 |
static void omap_i2c_interrupts_update(struct omap_i2c_s *s)
|
|
54 |
static void omap_i2c_interrupts_update(OMAPI2CState *s)
|
|
49 | 55 |
{ |
50 | 56 |
qemu_set_irq(s->irq, s->stat & s->mask); |
51 | 57 |
if ((s->dma >> 15) & 1) /* RDMA_EN */ |
... | ... | |
54 | 60 |
qemu_set_irq(s->drq[1], (s->stat >> 4) & 1); /* XRDY */ |
55 | 61 |
} |
56 | 62 |
|
57 |
static void omap_i2c_fifo_run(struct omap_i2c_s *s)
|
|
63 |
static void omap_i2c_fifo_run(OMAPI2CState *s)
|
|
58 | 64 |
{ |
59 | 65 |
int ack = 1; |
60 | 66 |
|
... | ... | |
122 | 128 |
s->control &= ~(1 << 1); /* STP */ |
123 | 129 |
} |
124 | 130 |
|
125 |
void omap_i2c_reset(struct omap_i2c_s *s)
|
|
131 |
static void omap_i2c_reset(DeviceState *dev)
|
|
126 | 132 |
{ |
133 |
OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState, |
|
134 |
sysbus_from_qdev(dev)); |
|
127 | 135 |
s->mask = 0; |
128 | 136 |
s->stat = 0; |
129 | 137 |
s->dma = 0; |
... | ... | |
143 | 151 |
|
144 | 152 |
static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr) |
145 | 153 |
{ |
146 |
struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
|
|
154 |
OMAPI2CState *s = opaque;
|
|
147 | 155 |
int offset = addr & OMAP_MPUI_REG_MASK; |
148 | 156 |
uint16_t ret; |
149 | 157 |
|
... | ... | |
243 | 251 |
static void omap_i2c_write(void *opaque, target_phys_addr_t addr, |
244 | 252 |
uint32_t value) |
245 | 253 |
{ |
246 |
struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
|
|
254 |
OMAPI2CState *s = opaque;
|
|
247 | 255 |
int offset = addr & OMAP_MPUI_REG_MASK; |
248 | 256 |
int nack; |
249 | 257 |
|
... | ... | |
309 | 317 |
} |
310 | 318 |
|
311 | 319 |
if (value & 2) |
312 |
omap_i2c_reset(s);
|
|
320 |
omap_i2c_reset(&s->busdev.qdev);
|
|
313 | 321 |
break; |
314 | 322 |
|
315 | 323 |
case 0x24: /* I2C_CON */ |
316 | 324 |
s->control = value & 0xcf87; |
317 | 325 |
if (~value & (1 << 15)) { /* I2C_EN */ |
318 | 326 |
if (s->revision < OMAP2_INTR_REV) |
319 |
omap_i2c_reset(s);
|
|
327 |
omap_i2c_reset(&s->busdev.qdev);
|
|
320 | 328 |
break; |
321 | 329 |
} |
322 | 330 |
if ((value & (1 << 15)) && !(value & (1 << 10))) { /* MST */ |
... | ... | |
385 | 393 |
static void omap_i2c_writeb(void *opaque, target_phys_addr_t addr, |
386 | 394 |
uint32_t value) |
387 | 395 |
{ |
388 |
struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
|
|
396 |
OMAPI2CState *s = opaque;
|
|
389 | 397 |
int offset = addr & OMAP_MPUI_REG_MASK; |
390 | 398 |
|
391 | 399 |
switch (offset) { |
... | ... | |
426 | 434 |
.endianness = DEVICE_NATIVE_ENDIAN, |
427 | 435 |
}; |
428 | 436 |
|
429 |
struct omap_i2c_s *omap_i2c_init(MemoryRegion *sysmem, |
|
430 |
target_phys_addr_t base, |
|
431 |
qemu_irq irq, |
|
432 |
qemu_irq *dma, |
|
433 |
omap_clk clk) |
|
437 |
static int omap_i2c_init(SysBusDevice *dev) |
|
434 | 438 |
{ |
435 |
struct omap_i2c_s *s = (struct omap_i2c_s *) |
|
436 |
g_malloc0(sizeof(struct omap_i2c_s)); |
|
437 |
|
|
438 |
/* TODO: set a value greater or equal to real hardware */ |
|
439 |
s->revision = 0x11; |
|
440 |
s->irq = irq; |
|
441 |
s->drq[0] = dma[0]; |
|
442 |
s->drq[1] = dma[1]; |
|
443 |
s->bus = i2c_init_bus(NULL, "i2c"); |
|
444 |
omap_i2c_reset(s); |
|
439 |
OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState, dev); |
|
445 | 440 |
|
446 |
memory_region_init_io(&s->iomem, &omap_i2c_ops, s, "omap.i2c", 0x800); |
|
447 |
memory_region_add_subregion(sysmem, base, &s->iomem); |
|
448 |
|
|
449 |
return s; |
|
441 |
if (!s->fclk) { |
|
442 |
hw_error("omap_i2c: fclk not connected\n"); |
|
443 |
} |
|
444 |
if (s->revision >= OMAP2_INTR_REV && !s->iclk) { |
|
445 |
/* Note that OMAP1 doesn't have a separate interface clock */ |
|
446 |
hw_error("omap_i2c: iclk not connected\n"); |
|
447 |
} |
|
448 |
sysbus_init_irq(dev, &s->irq); |
|
449 |
sysbus_init_irq(dev, &s->drq[0]); |
|
450 |
sysbus_init_irq(dev, &s->drq[1]); |
|
451 |
memory_region_init_io(&s->iomem, &omap_i2c_ops, s, "omap.i2c", |
|
452 |
(s->revision < OMAP2_INTR_REV) ? 0x800 : 0x1000); |
|
453 |
sysbus_init_mmio(dev, &s->iomem); |
|
454 |
s->bus = i2c_init_bus(&dev->qdev, NULL); |
|
455 |
return 0; |
|
450 | 456 |
} |
451 | 457 |
|
452 |
struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta, |
|
453 |
qemu_irq irq, qemu_irq *dma, omap_clk fclk, omap_clk iclk) |
|
454 |
{ |
|
455 |
struct omap_i2c_s *s = (struct omap_i2c_s *) |
|
456 |
g_malloc0(sizeof(struct omap_i2c_s)); |
|
458 |
static Property omap_i2c_properties[] = { |
|
459 |
DEFINE_PROP_UINT8("revision", OMAPI2CState, revision, 0), |
|
460 |
DEFINE_PROP_PTR("iclk", OMAPI2CState, iclk), |
|
461 |
DEFINE_PROP_PTR("fclk", OMAPI2CState, fclk), |
|
462 |
DEFINE_PROP_END_OF_LIST(), |
|
463 |
}; |
|
457 | 464 |
|
458 |
s->revision = 0x34; |
|
459 |
s->irq = irq; |
|
460 |
s->drq[0] = dma[0]; |
|
461 |
s->drq[1] = dma[1]; |
|
462 |
s->bus = i2c_init_bus(NULL, "i2c"); |
|
463 |
omap_i2c_reset(s); |
|
465 |
static void omap_i2c_class_init(ObjectClass *klass, void *data) |
|
466 |
{ |
|
467 |
DeviceClass *dc = DEVICE_CLASS(klass); |
|
468 |
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); |
|
469 |
k->init = omap_i2c_init; |
|
470 |
dc->props = omap_i2c_properties; |
|
471 |
dc->reset = omap_i2c_reset; |
|
472 |
} |
|
464 | 473 |
|
465 |
memory_region_init_io(&s->iomem, &omap_i2c_ops, s, "omap2.i2c", |
|
466 |
omap_l4_region_size(ta, 0)); |
|
467 |
omap_l4_attach(ta, 0, &s->iomem); |
|
474 |
static TypeInfo omap_i2c_info = { |
|
475 |
.name = "omap_i2c", |
|
476 |
.parent = TYPE_SYS_BUS_DEVICE, |
|
477 |
.instance_size = sizeof(OMAPI2CState), |
|
478 |
.class_init = omap_i2c_class_init, |
|
479 |
}; |
|
468 | 480 |
|
469 |
return s; |
|
481 |
static void omap_i2c_register_types(void) |
|
482 |
{ |
|
483 |
type_register_static(&omap_i2c_info); |
|
470 | 484 |
} |
471 | 485 |
|
472 |
i2c_bus *omap_i2c_bus(struct omap_i2c_s *s)
|
|
486 |
i2c_bus *omap_i2c_bus(DeviceState *omap_i2c)
|
|
473 | 487 |
{ |
488 |
OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState, sysbus_from_qdev(omap_i2c)); |
|
474 | 489 |
return s->bus; |
475 | 490 |
} |
491 |
|
|
492 |
type_init(omap_i2c_register_types) |
Also available in: Unified diff