1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include "qemu/osdep.h"
22#include "hw/i2c/i2c.h"
23#include "hw/hw.h"
24#include "sysemu/blockdev.h"
25#include "hw/i2c/pca9548.h"
26#include "qemu/log.h"
27
28#ifndef PCA9548_DEBUG
29#define PCA9548_DEBUG 0
30#endif
31
32#define DB_PRINT(fmt, args...) do { \
33 if (PCA9548_DEBUG) { \
34 qemu_log("PCA9548: "fmt, ## args); \
35 } \
36} while (0);
37
38static void pca9548_reset(DeviceState *dev)
39{
40 PCA9548State *s = PCA9548(dev);
41 I2CSlave *i2cs = I2C_SLAVE(dev);
42
43
44
45
46 i2cs->address = 0;
47 i2cs->address_range = 0x80;
48
49 s->control_reg = 0;
50}
51
52static int pca9548_recv(I2CSlave *i2c)
53{
54 PCA9548State *s = PCA9548(i2c);
55 int i;
56 int ret = 0;
57
58 if (s->control_decoded) {
59 ret |= s->control_reg;
60 DB_PRINT("returning control register: %x\n", ret);
61 } else {
62 for (i = 0; i < NUM_BUSSES; ++i) {
63 if (s->control_reg & (1 << i)) {
64 ret |= i2c_recv(s->busses[i]);
65 DB_PRINT("recieving from active bus %d:%x\n", i, ret);
66 }
67 }
68 }
69
70 return ret;
71}
72
73static int pca9548_send(I2CSlave *i2c, uint8_t data)
74{
75 PCA9548State *s = PCA9548(i2c);
76 int i;
77 int ret = -1;
78
79 if (s->control_decoded) {
80 DB_PRINT("setting control register: %x\n", data);
81 s->control_reg = data;
82 ret = 0;
83 } else {
84 for (i = 0; i < NUM_BUSSES; ++i) {
85 if (s->control_reg & (1 << i)) {
86 DB_PRINT("sending to active bus %d:%x\n", i, data);
87 ret &= i2c_send(s->busses[i], data);
88 }
89 }
90 }
91
92 return ret;
93}
94
95static void pca9548_event(I2CSlave *i2c, enum i2c_event event)
96{
97 PCA9548State *s = PCA9548(i2c);
98 int i;
99
100 s->event = event;
101 for (i = 0; i < NUM_BUSSES; ++i) {
102 if (s->control_reg & (1 << i)) {
103 switch (event) {
104
105 case I2C_START_SEND:
106 case I2C_START_RECV:
107 break;
108
109 case I2C_FINISH:
110 if (!s->control_decoded) {
111 DB_PRINT("stopping active bus %d\n", i);
112 i2c_end_transfer(s->busses[i]);
113 }
114 break;
115 case I2C_NACK:
116 if (!s->control_decoded) {
117 DB_PRINT("nacking active bus %d\n", i);
118 i2c_nack(s->busses[i]);
119 }
120 break;
121 }
122 }
123 }
124}
125
126static int pca9548_decode_address(I2CSlave *i2c, uint8_t address)
127{
128 PCA9548State *s = PCA9548(i2c);
129 int i;
130 uint8_t channel_status = 0;
131
132 s->control_decoded = address ==
133 (PCA9548_CONTROL_ADDR | (s->chip_enable & 0x7));
134
135 if (s->control_decoded) {
136 return 0;
137 }
138
139 for (i = 0; i < NUM_BUSSES; ++i) {
140 if (s->control_reg & (1 << i)) {
141 DB_PRINT("starting active bus %d addr:%02x rnw:%d\n", i, address,
142 s->event == I2C_START_RECV);
143 channel_status |= (i2c_start_transfer(s->busses[i], address,
144 s->event == I2C_START_RECV)) << i;
145 }
146 }
147
148 if (s->control_reg == channel_status) {
149 return 1;
150 }
151
152 return 0;
153}
154
155static void pca9548_init(Object *obj)
156{
157 PCA9548State *s = PCA9548(obj);
158 int i;
159
160 for (i = 0; i < NUM_BUSSES; ++i) {
161 char bus_name[16];
162
163 snprintf(bus_name, sizeof(bus_name), "i2c@%d", i);
164 s->busses[i] = i2c_init_bus(DEVICE(s), bus_name);
165 }
166}
167
168static void pca9548_realize(DeviceState *dev, Error **errp)
169{
170
171}
172
173static const VMStateDescription vmstate_PCA9548 = {
174 .name = "pca9548",
175 .version_id = 1,
176 .fields = (VMStateField[]) {
177 VMSTATE_I2C_SLAVE(i2c, PCA9548State),
178 VMSTATE_UINT8(control_reg, PCA9548State),
179 VMSTATE_BOOL(control_decoded, PCA9548State),
180 VMSTATE_END_OF_LIST()
181 }
182};
183
184static Property pca9548_properties[] = {
185
186
187
188 DEFINE_PROP_UINT8("chip-enable", PCA9548State, chip_enable, 0),
189 DEFINE_PROP_END_OF_LIST(),
190};
191
192static void pca9548_class_init(ObjectClass *klass, void *data)
193{
194 DeviceClass *dc = DEVICE_CLASS(klass);
195 I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
196
197 k->event = pca9548_event;
198 k->recv = pca9548_recv;
199 k->send = pca9548_send;
200 k->decode_address = pca9548_decode_address;
201
202 dc->realize = pca9548_realize;
203 dc->reset = pca9548_reset;
204 dc->vmsd = &vmstate_PCA9548;
205 dc->props = pca9548_properties;
206}
207
208static TypeInfo pca9548_info = {
209 .name = TYPE_PCA9548,
210 .parent = TYPE_I2C_SLAVE,
211 .instance_size = sizeof(PCA9548State),
212 .instance_init = pca9548_init,
213 .class_init = pca9548_class_init,
214};
215
216static void pca9548_register_types(void)
217{
218 type_register_static(&pca9548_info);
219}
220
221type_init(pca9548_register_types)
222