|
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 "hw.h" |
|
11 #include "i2c.h" |
|
12 |
|
13 struct i2c_bus |
|
14 { |
|
15 i2c_slave *current_dev; |
|
16 i2c_slave *dev; |
|
17 int saved_address; |
|
18 }; |
|
19 |
|
20 static void i2c_bus_save(QEMUFile *f, void *opaque) |
|
21 { |
|
22 i2c_bus *bus = (i2c_bus *)opaque; |
|
23 |
|
24 qemu_put_byte(f, bus->current_dev ? bus->current_dev->address : -1); |
|
25 } |
|
26 |
|
27 static int i2c_bus_load(QEMUFile *f, void *opaque, int version_id) |
|
28 { |
|
29 i2c_bus *bus = (i2c_bus *)opaque; |
|
30 |
|
31 if (version_id != 1) |
|
32 return -EINVAL; |
|
33 |
|
34 /* The bus is loaded before attached devices, so load and save the |
|
35 current device id. Devices will check themselves as loaded. */ |
|
36 bus->saved_address = (int8_t) qemu_get_byte(f); |
|
37 bus->current_dev = NULL; |
|
38 |
|
39 return 0; |
|
40 } |
|
41 |
|
42 /* Create a new I2C bus. */ |
|
43 i2c_bus *i2c_init_bus(void) |
|
44 { |
|
45 i2c_bus *bus; |
|
46 |
|
47 bus = (i2c_bus *)qemu_mallocz(sizeof(i2c_bus)); |
|
48 register_savevm("i2c_bus", -1, 1, i2c_bus_save, i2c_bus_load, bus); |
|
49 return bus; |
|
50 } |
|
51 |
|
52 /* Create a new slave device. */ |
|
53 i2c_slave *i2c_slave_init(i2c_bus *bus, int address, int size) |
|
54 { |
|
55 i2c_slave *dev; |
|
56 |
|
57 if (size < sizeof(i2c_slave)) |
|
58 hw_error("I2C struct too small"); |
|
59 |
|
60 dev = (i2c_slave *)qemu_mallocz(size); |
|
61 dev->address = address; |
|
62 dev->next = bus->dev; |
|
63 bus->dev = dev; |
|
64 dev->bus = bus; |
|
65 |
|
66 return dev; |
|
67 } |
|
68 |
|
69 void i2c_set_slave_address(i2c_slave *dev, int address) |
|
70 { |
|
71 dev->address = address; |
|
72 } |
|
73 |
|
74 /* Return nonzero if bus is busy. */ |
|
75 int i2c_bus_busy(i2c_bus *bus) |
|
76 { |
|
77 return bus->current_dev != NULL; |
|
78 } |
|
79 |
|
80 /* Returns non-zero if the address is not valid. */ |
|
81 /* TODO: Make this handle multiple masters. */ |
|
82 int i2c_start_transfer(i2c_bus *bus, int address, int recv) |
|
83 { |
|
84 i2c_slave *dev; |
|
85 |
|
86 for (dev = bus->dev; dev; dev = dev->next) { |
|
87 if (dev->address == address) |
|
88 break; |
|
89 } |
|
90 |
|
91 if (!dev) |
|
92 return 1; |
|
93 |
|
94 /* If the bus is already busy, assume this is a repeated |
|
95 start condition. */ |
|
96 bus->current_dev = dev; |
|
97 dev->event(dev, recv ? I2C_START_RECV : I2C_START_SEND); |
|
98 return 0; |
|
99 } |
|
100 |
|
101 void i2c_end_transfer(i2c_bus *bus) |
|
102 { |
|
103 i2c_slave *dev = bus->current_dev; |
|
104 |
|
105 if (!dev) |
|
106 return; |
|
107 |
|
108 dev->event(dev, I2C_FINISH); |
|
109 |
|
110 bus->current_dev = NULL; |
|
111 } |
|
112 |
|
113 int i2c_send(i2c_bus *bus, uint8_t data) |
|
114 { |
|
115 i2c_slave *dev = bus->current_dev; |
|
116 |
|
117 if (!dev) |
|
118 return -1; |
|
119 |
|
120 return dev->send(dev, data); |
|
121 } |
|
122 |
|
123 int i2c_recv(i2c_bus *bus) |
|
124 { |
|
125 i2c_slave *dev = bus->current_dev; |
|
126 |
|
127 if (!dev) |
|
128 return -1; |
|
129 |
|
130 return dev->recv(dev); |
|
131 } |
|
132 |
|
133 void i2c_nack(i2c_bus *bus) |
|
134 { |
|
135 i2c_slave *dev = bus->current_dev; |
|
136 |
|
137 if (!dev) |
|
138 return; |
|
139 |
|
140 dev->event(dev, I2C_NACK); |
|
141 } |
|
142 |
|
143 void i2c_slave_save(QEMUFile *f, i2c_slave *dev) |
|
144 { |
|
145 qemu_put_byte(f, dev->address); |
|
146 } |
|
147 |
|
148 void i2c_slave_load(QEMUFile *f, i2c_slave *dev) |
|
149 { |
|
150 dev->address = qemu_get_byte(f); |
|
151 if (dev->bus->saved_address == dev->address) |
|
152 dev->bus->current_dev = dev; |
|
153 } |