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