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