Add a simple SPI peripheral that echoes back received data. Useful for testing SPI controllers.
Signed-off-by: Octavian Purdila <ta...@google.com> --- include/hw/misc/spi_tester.h | 32 +++++++++++++++++ hw/misc/spi_tester.c | 67 ++++++++++++++++++++++++++++++++++++ hw/misc/Kconfig | 5 +++ hw/misc/meson.build | 1 + 4 files changed, 105 insertions(+) create mode 100644 include/hw/misc/spi_tester.h create mode 100644 hw/misc/spi_tester.c diff --git a/include/hw/misc/spi_tester.h b/include/hw/misc/spi_tester.h new file mode 100644 index 0000000000..8935f3f1af --- /dev/null +++ b/include/hw/misc/spi_tester.h @@ -0,0 +1,32 @@ +/* + * Simple SPI peripheral device used for SPI controller testing. + * + * Copyright (c) 2024 Google LLC. + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_SPI_TESTER_H +#define HW_SPI_TESTER_H + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/bswap.h" +#include "hw/irq.h" +#include "hw/ssi/ssi.h" +#include "qemu/timer.h" +#include "hw/qdev-properties.h" + +#define TYPE_SPI_TESTER "spi-tester" +#define SPI_TESTER(obj) OBJECT_CHECK(SpiTesterState, (obj), TYPE_SPI_TESTER) + +typedef struct { + SSIPeripheral ssidev; + bool cs; +} SpiTesterState; + +#endif /* HW_SPI_TESTER_H */ diff --git a/hw/misc/spi_tester.c b/hw/misc/spi_tester.c new file mode 100644 index 0000000000..2793ce52dc --- /dev/null +++ b/hw/misc/spi_tester.c @@ -0,0 +1,67 @@ +/* + * Simple SPI peripheral echo device used for SPI controller testing. + * + * Copyright (c) 2024 Google LLC. + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "migration/vmstate.h" +#include "hw/misc/spi_tester.h" + +static uint32_t spi_tester_transfer(SSIPeripheral *dev, uint32_t value) +{ + SpiTesterState *s = SPI_TESTER(dev); + + if (s->cs) { + return 0; + } + + return value; +} + +static int spi_tester_set_cs(SSIPeripheral *dev, bool select) +{ + SpiTesterState *s = SPI_TESTER(dev); + + s->cs = select; + + return 0; +} + +static const VMStateDescription vmstate_spi_tester = { + .name = "spi-tester", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_SSI_PERIPHERAL(ssidev, SpiTesterState), + VMSTATE_BOOL(cs, SpiTesterState), + VMSTATE_END_OF_LIST() + } +}; + +static void spi_tester_class_init(ObjectClass *klass, void *data) +{ + SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_spi_tester; + k->transfer = spi_tester_transfer; + k->set_cs = spi_tester_set_cs; + k->cs_polarity = SSI_CS_LOW; +} + +static const TypeInfo spi_tester_types[] = { + { + .name = TYPE_SPI_TESTER, + .parent = TYPE_SSI_PERIPHERAL, + .instance_size = sizeof(SpiTesterState), + .class_init = spi_tester_class_init, + }, +}; + +DEFINE_TYPES(spi_tester_types); diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 3e93c12c8e..484ee3149f 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -218,6 +218,11 @@ config I2C_TESTER default y if TEST_DEVICES depends on I2C +config SPI_TESTER + bool + default y if TEST_DEVICES + depends on SSI + config FLEXCOMM bool select I2C diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 4f22231fa3..413171f379 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -159,6 +159,7 @@ system_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa_ec.c')) system_ss.add(when: 'CONFIG_LASI', if_true: files('lasi.c')) system_ss.add(when: 'CONFIG_I2C_TESTER', if_true: files('i2c_tester.c')) +system_ss.add(when: 'CONFIG_SPI_TESTER', if_true: files('spi_tester.c')) system_ss.add(when: 'CONFIG_FLEXCOMM', if_true: files('flexcomm.c')) system_ss.add(when: 'CONFIG_RT500_CLKCTL', if_true: files('rt500_clkctl0.c', 'rt500_clkctl1.c')) -- 2.46.0.662.g92d0881bb0-goog