summary refs log tree commit diff stats
path: root/hw/misc/i2c-echo.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2023-03-03 17:11:22 +0000
committerPeter Maydell <peter.maydell@linaro.org>2023-03-03 17:11:22 +0000
commitcad8db986560668afbaed972e162e3e7a2d3a34c (patch)
tree862e6366a2aa282d12a702467d5e64a7a37c8898 /hw/misc/i2c-echo.c
parentbfbcaae9636260d3b2d997cd958df983298d149d (diff)
parentb22a2d409b1acfdf0d63d1bb3595194ceb3d94da (diff)
downloadfocaccia-qemu-cad8db986560668afbaed972e162e3e7a2d3a34c.tar.gz
focaccia-qemu-cad8db986560668afbaed972e162e3e7a2d3a34c.zip
Merge tag 'pull-aspeed-20230302' of https://github.com/legoater/qemu into staging
aspeed queue:

* fix for the Aspeed I2C slave mode
* a new I2C echo device from Klaus and its associated test in avocado.
* initial SoC cleanups to allow the use of block devices instead of
  drives on the command line.
* new facebook machines and eeprom fixes for the Fuji
* readline fix

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmQAnrQACgkQUaNDx8/7
# 7KGIvQ//Te2eSxlZNxAXHb3HSVFRaBW+2EkJzNlalX75olFSzCLe8BnAHK5xPlYv
# JjU0aPjWaPohPLdbNbAsJY2B8AwMGbUTjSv+ORRWF6s97LTVD9WcAYHgOTCz6d2X
# ZrArJ5msEQAFEySOLmBqTcuyW3t4w8XeII+B09HZIS8Gn3F9kX5+4JCw9E4sX8fS
# n9ayclMmrXCPbkGA4bfwJp3KI1Tc/WXNRyG0AmPEmepid7ECr5tVvQoXRMF1Sy/D
# 10qbHEcmQXvZDy85M2ED1niOac4oU+EY8Wvjzkgc36uXcjqf0jIUfw56cwGSNVkW
# MhPXSMiH4tEjgxmtzld3LeA6TGfrFcCvRXYiCuYWHjBS3gptlqY6Q0580vxoQVXL
# lTYui57LB1YStNLcLG9toP0d4/fRfeqEx7ddCQKlopnW/K392eoJo0aYoVGVJhIC
# 3QhN525EFUwMm4FDpdSW29Gfbk/ytpf0u4hQ6JPeBl8psirRKqCGuwr5NOnPYTaN
# yErlsq2eL83t9kLo+2YIqgWic85wNP3kqAjIaE6lminqX7sWFH3V1g9HqUQZVG1g
# msatZMiCCvwSFuz3DPkSfnuhqwaHuhvCATZloCtguCmnbUK9qUVVzvodKw62sZrd
# GdS2XvRNyoOwezz0tDEvPipyZ7RpcaatryHNuzGwRsE5Lvr73dg=
# =ExnJ
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 02 Mar 2023 13:03:48 GMT
# gpg:                using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1
# gpg: Good signature from "Cédric Le Goater <clg@kaod.org>" [undefined]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: A0F6 6548 F048 95EB FE6B  0B60 51A3 43C7 CFFB ECA1

* tag 'pull-aspeed-20230302' of https://github.com/legoater/qemu:
  aspeed/smc: Replace SysBus IRQs with GPIO lines
  aspeed: Add a boot_rom overlap region in the SoC spi_boot container
  aspeed: Introduce a spi_boot region under the SoC
  aspeed/fuji : correct the eeprom size
  hw/at24c : modify at24c to support 1 byte address mode
  hw/arm/aspeed: Adding new machine Tiogapass in QEMU
  hw/arm/aspeed: Adding new machine Yosemitev2 in QEMU
  tests/avocado/machine_aspeed.py: Add an I2C slave test
  hw/misc: add a toy i2c echo device
  hw/i2c: only schedule pending master when bus is idle
  readline: fix hmp completion issue

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/misc/i2c-echo.c')
-rw-r--r--hw/misc/i2c-echo.c156
1 files changed, 156 insertions, 0 deletions
diff --git a/hw/misc/i2c-echo.c b/hw/misc/i2c-echo.c
new file mode 100644
index 0000000000..5705ab5d73
--- /dev/null
+++ b/hw/misc/i2c-echo.c
@@ -0,0 +1,156 @@
+#include "qemu/osdep.h"
+#include "qemu/timer.h"
+#include "qemu/main-loop.h"
+#include "block/aio.h"
+#include "hw/i2c/i2c.h"
+
+#define TYPE_I2C_ECHO "i2c-echo"
+OBJECT_DECLARE_SIMPLE_TYPE(I2CEchoState, I2C_ECHO)
+
+enum i2c_echo_state {
+    I2C_ECHO_STATE_IDLE,
+    I2C_ECHO_STATE_START_SEND,
+    I2C_ECHO_STATE_ACK,
+};
+
+typedef struct I2CEchoState {
+    I2CSlave parent_obj;
+
+    I2CBus *bus;
+
+    enum i2c_echo_state state;
+    QEMUBH *bh;
+
+    unsigned int pos;
+    uint8_t data[3];
+} I2CEchoState;
+
+static void i2c_echo_bh(void *opaque)
+{
+    I2CEchoState *state = opaque;
+
+    switch (state->state) {
+    case I2C_ECHO_STATE_IDLE:
+        return;
+
+    case I2C_ECHO_STATE_START_SEND:
+        if (i2c_start_send_async(state->bus, state->data[0])) {
+            goto release_bus;
+        }
+
+        state->pos++;
+        state->state = I2C_ECHO_STATE_ACK;
+        return;
+
+    case I2C_ECHO_STATE_ACK:
+        if (state->pos > 2) {
+            break;
+        }
+
+        if (i2c_send_async(state->bus, state->data[state->pos++])) {
+            break;
+        }
+
+        return;
+    }
+
+
+    i2c_end_transfer(state->bus);
+release_bus:
+    i2c_bus_release(state->bus);
+
+    state->state = I2C_ECHO_STATE_IDLE;
+}
+
+static int i2c_echo_event(I2CSlave *s, enum i2c_event event)
+{
+    I2CEchoState *state = I2C_ECHO(s);
+
+    switch (event) {
+    case I2C_START_RECV:
+        state->pos = 0;
+
+        break;
+
+    case I2C_START_SEND:
+        state->pos = 0;
+
+        break;
+
+    case I2C_FINISH:
+        state->pos = 0;
+        state->state = I2C_ECHO_STATE_START_SEND;
+        i2c_bus_master(state->bus, state->bh);
+
+        break;
+
+    case I2C_NACK:
+        break;
+
+    default:
+        return -1;
+    }
+
+    return 0;
+}
+
+static uint8_t i2c_echo_recv(I2CSlave *s)
+{
+    I2CEchoState *state = I2C_ECHO(s);
+
+    if (state->pos > 2) {
+        return 0xff;
+    }
+
+    return state->data[state->pos++];
+}
+
+static int i2c_echo_send(I2CSlave *s, uint8_t data)
+{
+    I2CEchoState *state = I2C_ECHO(s);
+
+    if (state->pos > 2) {
+        return -1;
+    }
+
+    state->data[state->pos++] = data;
+
+    return 0;
+}
+
+static void i2c_echo_realize(DeviceState *dev, Error **errp)
+{
+    I2CEchoState *state = I2C_ECHO(dev);
+    BusState *bus = qdev_get_parent_bus(dev);
+
+    state->bus = I2C_BUS(bus);
+    state->bh = qemu_bh_new(i2c_echo_bh, state);
+
+    return;
+}
+
+static void i2c_echo_class_init(ObjectClass *oc, void *data)
+{
+    I2CSlaveClass *sc = I2C_SLAVE_CLASS(oc);
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = i2c_echo_realize;
+
+    sc->event = i2c_echo_event;
+    sc->recv = i2c_echo_recv;
+    sc->send = i2c_echo_send;
+}
+
+static const TypeInfo i2c_echo = {
+    .name = TYPE_I2C_ECHO,
+    .parent = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(I2CEchoState),
+    .class_init = i2c_echo_class_init,
+};
+
+static void register_types(void)
+{
+    type_register_static(&i2c_echo);
+}
+
+type_init(register_types);