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