]> git.proxmox.com Git - qemu.git/blob - hw/i2c.c
Initial OMAP I^2C controller implementation (communication not tested).
[qemu.git] / hw / i2c.c
1 /*
2 * QEMU I2C bus interface.
3 *
4 * Copyright (c) 2007 CodeSourcery.
5 * Written by Paul Brook
6 *
7 * This code is licenced under the LGPL.
8 */
9
10 #include "vl.h"
11
12 struct i2c_bus
13 {
14 i2c_slave *current_dev;
15 i2c_slave *dev;
16 };
17
18 /* Create a new I2C bus. */
19 i2c_bus *i2c_init_bus(void)
20 {
21 i2c_bus *bus;
22
23 bus = (i2c_bus *)qemu_mallocz(sizeof(i2c_bus));
24 return bus;
25 }
26
27 /* Create a new slave device. */
28 i2c_slave *i2c_slave_init(i2c_bus *bus, int address, int size)
29 {
30 i2c_slave *dev;
31
32 if (size < sizeof(i2c_slave))
33 cpu_abort(cpu_single_env, "I2C struct too small");
34
35 dev = (i2c_slave *)qemu_mallocz(size);
36 dev->address = address;
37 dev->next = bus->dev;
38 bus->dev = dev;
39
40 return dev;
41 }
42
43 void i2c_set_slave_address(i2c_slave *dev, int address)
44 {
45 dev->address = address;
46 }
47
48 /* Return nonzero if bus is busy. */
49 int i2c_bus_busy(i2c_bus *bus)
50 {
51 return bus->current_dev != NULL;
52 }
53
54 /* Returns non-zero if the address is not valid. */
55 /* TODO: Make this handle multiple masters. */
56 int i2c_start_transfer(i2c_bus *bus, int address, int recv)
57 {
58 i2c_slave *dev;
59
60 for (dev = bus->dev; dev; dev = dev->next) {
61 if (dev->address == address)
62 break;
63 }
64
65 if (!dev)
66 return 1;
67
68 /* If the bus is already busy, assume this is a repeated
69 start condition. */
70 bus->current_dev = dev;
71 dev->event(dev, recv ? I2C_START_RECV : I2C_START_SEND);
72 return 0;
73 }
74
75 void i2c_end_transfer(i2c_bus *bus)
76 {
77 i2c_slave *dev = bus->current_dev;
78
79 if (!dev)
80 return;
81
82 dev->event(dev, I2C_FINISH);
83
84 bus->current_dev = NULL;
85 }
86
87 int i2c_send(i2c_bus *bus, uint8_t data)
88 {
89 i2c_slave *dev = bus->current_dev;
90
91 if (!dev)
92 return -1;
93
94 return dev->send(dev, data);
95 }
96
97 int i2c_recv(i2c_bus *bus)
98 {
99 i2c_slave *dev = bus->current_dev;
100
101 if (!dev)
102 return -1;
103
104 return dev->recv(dev);
105 }
106
107 void i2c_nack(i2c_bus *bus)
108 {
109 i2c_slave *dev = bus->current_dev;
110
111 if (!dev)
112 return;
113
114 dev->event(dev, I2C_NACK);
115 }
116
117 void i2c_bus_save(QEMUFile *f, i2c_bus *bus)
118 {
119 qemu_put_byte(f, bus->current_dev ? bus->current_dev->address : 0x00);
120 }
121
122 void i2c_bus_load(QEMUFile *f, i2c_bus *bus)
123 {
124 i2c_slave *dev;
125 uint8_t address = qemu_get_byte(f);
126
127 if (address) {
128 for (dev = bus->dev; dev; dev = dev->next)
129 if (dev->address == address) {
130 bus->current_dev = dev;
131 return;
132 }
133
134 fprintf(stderr, "%s: I2C slave with address %02x disappeared\n",
135 __FUNCTION__, address);
136 }
137 }
138
139 void i2c_slave_save(QEMUFile *f, i2c_slave *dev)
140 {
141 qemu_put_byte(f, dev->address);
142 }
143
144 void i2c_slave_load(QEMUFile *f, i2c_slave *dev)
145 {
146 dev->address = qemu_get_byte(f);
147 }