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