xref: /openbmc/qemu/hw/misc/i2c-echo.c (revision ad66b5cb)
1 #include "qemu/osdep.h"
2 #include "qemu/timer.h"
3 #include "qemu/main-loop.h"
4 #include "block/aio.h"
5 #include "hw/i2c/i2c.h"
6 
7 #define TYPE_I2C_ECHO "i2c-echo"
8 OBJECT_DECLARE_SIMPLE_TYPE(I2CEchoState, I2C_ECHO)
9 
10 enum i2c_echo_state {
11     I2C_ECHO_STATE_IDLE,
12     I2C_ECHO_STATE_START_SEND,
13     I2C_ECHO_STATE_ACK,
14 };
15 
16 typedef struct I2CEchoState {
17     I2CSlave parent_obj;
18 
19     I2CBus *bus;
20 
21     enum i2c_echo_state state;
22     QEMUBH *bh;
23 
24     unsigned int pos;
25     uint8_t data[3];
26 } I2CEchoState;
27 
28 static void i2c_echo_bh(void *opaque)
29 {
30     I2CEchoState *state = opaque;
31 
32     switch (state->state) {
33     case I2C_ECHO_STATE_IDLE:
34         return;
35 
36     case I2C_ECHO_STATE_START_SEND:
37         if (i2c_start_send_async(state->bus, state->data[0])) {
38             goto release_bus;
39         }
40 
41         state->pos++;
42         state->state = I2C_ECHO_STATE_ACK;
43         return;
44 
45     case I2C_ECHO_STATE_ACK:
46         if (state->pos > 2) {
47             break;
48         }
49 
50         if (i2c_send_async(state->bus, state->data[state->pos++])) {
51             break;
52         }
53 
54         return;
55     }
56 
57 
58     i2c_end_transfer(state->bus);
59 release_bus:
60     i2c_bus_release(state->bus);
61 
62     state->state = I2C_ECHO_STATE_IDLE;
63 }
64 
65 static int i2c_echo_event(I2CSlave *s, enum i2c_event event)
66 {
67     I2CEchoState *state = I2C_ECHO(s);
68 
69     switch (event) {
70     case I2C_START_RECV:
71         state->pos = 0;
72 
73         break;
74 
75     case I2C_START_SEND:
76         state->pos = 0;
77 
78         break;
79 
80     case I2C_FINISH:
81         state->pos = 0;
82         state->state = I2C_ECHO_STATE_START_SEND;
83         i2c_bus_master(state->bus, state->bh);
84 
85         break;
86 
87     case I2C_NACK:
88         break;
89 
90     default:
91         return -1;
92     }
93 
94     return 0;
95 }
96 
97 static uint8_t i2c_echo_recv(I2CSlave *s)
98 {
99     I2CEchoState *state = I2C_ECHO(s);
100 
101     if (state->pos > 2) {
102         return 0xff;
103     }
104 
105     return state->data[state->pos++];
106 }
107 
108 static int i2c_echo_send(I2CSlave *s, uint8_t data)
109 {
110     I2CEchoState *state = I2C_ECHO(s);
111 
112     if (state->pos > 2) {
113         return -1;
114     }
115 
116     state->data[state->pos++] = data;
117 
118     return 0;
119 }
120 
121 static void i2c_echo_realize(DeviceState *dev, Error **errp)
122 {
123     I2CEchoState *state = I2C_ECHO(dev);
124     BusState *bus = qdev_get_parent_bus(dev);
125 
126     state->bus = I2C_BUS(bus);
127     state->bh = qemu_bh_new(i2c_echo_bh, state);
128 
129     return;
130 }
131 
132 static void i2c_echo_class_init(ObjectClass *oc, void *data)
133 {
134     I2CSlaveClass *sc = I2C_SLAVE_CLASS(oc);
135     DeviceClass *dc = DEVICE_CLASS(oc);
136 
137     dc->realize = i2c_echo_realize;
138 
139     sc->event = i2c_echo_event;
140     sc->recv = i2c_echo_recv;
141     sc->send = i2c_echo_send;
142 }
143 
144 static const TypeInfo i2c_echo = {
145     .name = TYPE_I2C_ECHO,
146     .parent = TYPE_I2C_SLAVE,
147     .instance_size = sizeof(I2CEchoState),
148     .class_init = i2c_echo_class_init,
149 };
150 
151 static void register_types(void)
152 {
153     type_register_static(&i2c_echo);
154 }
155 
156 type_init(register_types);
157