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