[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [RFC PATCH v1 1/4] SPI: initial support
From: |
Peter Crosthwaite |
Subject: |
Re: [Qemu-devel] [RFC PATCH v1 1/4] SPI: initial support |
Date: |
Tue, 3 Apr 2012 09:57:01 +1000 |
On Tue, Apr 3, 2012 at 3:39 AM, Peter Maydell <address@hidden> wrote:
> On 30 March 2012 07:37, Peter A. G. Crosthwaite
> <address@hidden> wrote:
>> defined spi bus and spi slave QOM interfaces. Inspired by and loosley based
>> on
>
> "Define"; "loosely".
>
ack
>> existing I2C framework.
>>
>> Signed-off-by: Peter A. G. Crosthwaite <address@hidden>
>> ---
>> Makefile.target | 1 +
>> hw/spi.c | 175
>> +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>> hw/spi.h | 86 +++++++++++++++++++++++++++
>> 3 files changed, 262 insertions(+), 0 deletions(-)
>> create mode 100644 hw/spi.c
>> create mode 100644 hw/spi.h
>>
>> diff --git a/Makefile.target b/Makefile.target
>> index 44b2e83..8fd3718 100644
>> --- a/Makefile.target
>> +++ b/Makefile.target
>> @@ -320,6 +320,7 @@ obj-mips-$(CONFIG_FULONG) += bonito.o vt82c686.o
>> mips_fulong2e.o
>> obj-microblaze-y = petalogix_s3adsp1800_mmu.o
>> obj-microblaze-y += petalogix_ml605_mmu.o
>> obj-microblaze-y += microblaze_boot.o
>> +obj-microblaze-y += spi.o
>
> This should be in common-obj-y with i2c.o, I think -- microblaze isn't
> the only target with SPI (eg hw/omap_spi.c).
>
ok
>> obj-microblaze-y += microblaze_pic_cpu.o
>> obj-microblaze-y += xilinx_intc.o
>> diff --git a/hw/spi.c b/hw/spi.c
>> new file mode 100644
>> index 0000000..3afef07
>> --- /dev/null
>> +++ b/hw/spi.c
>> @@ -0,0 +1,175 @@
>> +/*
>> + * QEMU SPI bus interface.
>> + *
>> + * Copyright (C) 2012 Peter A. G. Crosthwaite <address@hidden>
>> + * Copyright (C) 2012 PetaLogix
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * as published by the Free Software Foundation; either version
>> + * 2 of the License, or (at your option) any later version.
>> + *
>> + * You should have received a copy of the GNU General Public License along
>> + * with this program; if not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include "spi.h"
>> +
>> +static struct BusInfo spi_bus_info = {
>> + .name = "SPI",
>> + .size = sizeof(spi_bus)
>> +};
>> +
>> +static const VMStateDescription vmstate_spi_bus = {
>> + .name = "spi_bus",
>> + .version_id = 1,
>> + .minimum_version_id = 1,
>> + .minimum_version_id_old = 1,
>> + .fields = (VMStateField[]) {
>> + VMSTATE_UINT8(cur_slave, spi_bus),
>> + VMSTATE_END_OF_LIST()
>> + }
>> +};
>> +
>> +spi_bus *spi_init_bus(DeviceState *parent, int num_slaves, const char *name)
>> +{
>> + spi_bus *bus;
>> +
>> + bus = FROM_QBUS(spi_bus, qbus_create(&spi_bus_info, parent, name));
>> + if (num_slaves >= SPI_BUS_NO_CS) {
>> + hw_error("too many slaves on spi bus: %d\n", num_slaves);
>> + }
>> + bus->num_slaves = num_slaves;
>> + bus->slaves = g_malloc0(sizeof(*bus->slaves) * num_slaves);
>> + vmstate_register(NULL, -1, &vmstate_spi_bus, bus);
>> + return bus;
>> +}
>> +
>> +int spi_attach_slave(spi_bus *bus, SPISlave *slave, int cs)
>> +{
>> + if (bus->slaves[cs]) {
>> + return 1;
>> + }
>> + bus->slaves[cs] = slave;
>> + return 0;
>> +}
>> +
>> +int spi_set_cs(spi_bus *bus, int cs)
>> +{
>> + SPISlave *dev;
>> + SPISlaveClass *klass;
>> +
>> + if (bus->cur_slave == cs) {
>> + return 0;
>> + }
>> +
>> + if (bus->cur_slave != SPI_BUS_NO_CS) {
>> + dev = bus->slaves[bus->cur_slave];
>> + dev->cs = 0;
>> + klass = SPI_SLAVE_GET_CLASS(dev);
>> + klass->cs(dev, 0);
>> + }
>> +
>> + if (cs >= bus->num_slaves && cs != SPI_BUS_NO_CS) {
>> + hw_error("attempted to assert non existent spi CS line: %d\n", cs);
>> + }
>> +
>> + bus->cur_slave = (uint8_t)cs;
>> +
>> + if (cs != SPI_BUS_NO_CS) {
>> + dev = bus->slaves[cs];
>> + dev->cs = 1;
>> + klass = SPI_SLAVE_GET_CLASS(dev);
>> + klass->cs(dev, 1);
>> + }
>> + return 0;
>> +};
>> +
>> +int spi_get_cs(spi_bus *bus)
>> +{
>> + return bus->cur_slave;
>> +}
>> +
>> +SpiSlaveState spi_get_state(spi_bus *bus)
>> +{
>> + SPISlave *dev;
>> + SPISlaveClass *klass;
>> +
>> + if (bus->cur_slave == SPI_BUS_NO_CS) {
>> + return SPI_NO_CS;
>> + }
>> + dev = bus->slaves[bus->cur_slave];
>> + klass = SPI_SLAVE_GET_CLASS(dev);
>> +
>> + return klass->get_state(dev);
>> +}
>> +
>> +SpiSlaveState spi_send(spi_bus *bus, uint32_t data, int len)
>> +{
>> + SPISlave *dev;
>> + SPISlaveClass *klass;
>> +
>> + if (bus->cur_slave == SPI_BUS_NO_CS) {
>> + return SPI_NO_CS;
>> + }
>> + dev = bus->slaves[bus->cur_slave];
>> + klass = SPI_SLAVE_GET_CLASS(dev);
>> +
>> + return klass->send(dev, data, len);
>> +}
>> +
>> +SpiSlaveState spi_recv(spi_bus *bus, uint32_t *data)
>> +{
>> + SPISlave *dev;
>> + SPISlaveClass *klass;
>> +
>> + if (bus->cur_slave == SPI_BUS_NO_CS) {
>> + return SPI_NO_CS;
>> + }
>> + dev = bus->slaves[bus->cur_slave];
>> + klass = SPI_SLAVE_GET_CLASS(dev);
>> +
>> + return klass->recv(dev, data);
>> +}
>> +
>> +const VMStateDescription vmstate_spi_slave = {
>> + .name = "SPISlave",
>> + .version_id = 1,
>> + .minimum_version_id = 1,
>> + .minimum_version_id_old = 1,
>> + .fields = (VMStateField[]) {
>> + VMSTATE_UINT8(cs, SPISlave),
>> + VMSTATE_END_OF_LIST()
>> + }
>> +};
>> +
>> +static int spi_slave_qdev_init(DeviceState *dev)
>> +{
>> + SPISlave *s = SPI_SLAVE_FROM_QDEV(dev);
>> + SPISlaveClass *sc = SPI_SLAVE_GET_CLASS(s);
>> +
>> + return sc->init(s);
>> +}
>> +
>> +static void spi_slave_class_init(ObjectClass *klass, void *data)
>> +{
>> + DeviceClass *k = DEVICE_CLASS(klass);
>> + k->init = spi_slave_qdev_init;
>> + k->bus_info = &spi_bus_info;
>> +}
>> +
>> +static TypeInfo spi_slave_type_info = {
>> + .name = TYPE_SPI_SLAVE,
>> + .parent = TYPE_DEVICE,
>> + .instance_size = sizeof(SPISlave),
>> + .abstract = true,
>> + .class_size = sizeof(SPISlaveClass),
>> + .class_init = spi_slave_class_init,
>> +};
>> +
>> +static void spi_slave_register_types(void)
>> +{
>> + type_register_static(&spi_slave_type_info);
>> +}
>> +
>> +type_init(spi_slave_register_types)
>> diff --git a/hw/spi.h b/hw/spi.h
>> new file mode 100644
>> index 0000000..668e9b0
>> --- /dev/null
>> +++ b/hw/spi.h
>> @@ -0,0 +1,86 @@
>> +#ifndef QEMU_SPI_H
>> +#define QEMU_SPI_H
>> +
>> +#include "qdev.h"
>> +
>> +/* pass to spi_set_cs to deslect all devices on bus */
>
> "deselect"
>
>> +
>> +#define SPI_BUS_NO_CS 0xFF
>> +
>> +/* state of a SPI device,
>> + * SPI_NO_CS -> the CS pin in de-asserted -> device is tristated
>
> "is"
>
ack
>> + * SPI_IDLE -> CS is asserted and device ready to recv
>> + * SPI_DATA_PENDING -> CS is asserted and the device has pushed data to
>> master
>> + */
>> +
>> +typedef enum {
>> + SPI_NO_CS,
>> + SPI_IDLE,
>> + SPI_DATA_PENDING
>> +} SpiSlaveState;
>
> Why not SPISlaveState ?
>
ack
>> +
>> +typedef struct SPISlave {
>> + DeviceState qdev;
>> + uint8_t cs;
>> +} SPISlave;
>> +
>> +#define TYPE_SPI_SLAVE "spi-slave"
>> +#define SPI_SLAVE(obj) \
>> + OBJECT_CHECK(SPISlave, (obj), TYPE_SPI_SLAVE)
>> +#define SPI_SLAVE_CLASS(klass) \
>> + OBJECT_CLASS_CHECK(SPISlaveClass, (klass), TYPE_SPI_SLAVE)
>> +#define SPI_SLAVE_GET_CLASS(obj) \
>> + OBJECT_GET_CLASS(SPISlaveClass, (obj), TYPE_SPI_SLAVE)
>> +
>> +typedef struct SPISlaveClass {
>> + DeviceClass parent_class;
>> +
>> + /* Callbacks provided by the device. */
>> + int (*init)(SPISlave *s);
>> +
>> + /* change the cs pin state */
>> + void (*cs)(SPISlave *s, uint8_t select);
>> +
>> + /* Master to slave. */
>> + SpiSlaveState (*send)(SPISlave *s, uint32_t data, int len);
>> +
>> + /* Slave to master. */
>> + SpiSlaveState (*recv)(SPISlave *s, uint32_t *data);
>> +
>> + /* poll the spi device state */
>> + SpiSlaveState (*get_state)(SPISlave *s);
>> +} SPISlaveClass;
>> +
>> +#define SPI_SLAVE_FROM_QDEV(dev) DO_UPCAST(SPISlave, qdev, dev)
>> +#define FROM_SPI_SLAVE(type, dev) DO_UPCAST(type, spi, dev)
>> +
>> +extern const VMStateDescription vmstate_spi_slave;
>> +
>> +#define VMSTATE_SPI_SLAVE(_field, _state) { \
>> + .name = (stringify(_field)), \
>> + .size = sizeof(SPISlave), \
>> + .vmsd = &vmstate_spi_slave, \
>> + .flags = VMS_STRUCT, \
>> + .offset = vmstate_offset_value(_state, _field, SPISlave), \
>> +}
>> +
>> +typedef struct spi_bus {
>> + BusState qbus;
>> + SPISlave **slaves;
>> + uint8_t num_slaves;
>> + uint8_t cur_slave;
>> +} spi_bus;
>
> CODING_STYLE demands camelcase for type names, so SPIBus.
>
Ok, I have a related question tho, if camel casing with acronyms,
should a space perhaps be inserted after for readability? As in
SPI_Bus rather than SPIBus.
>> +
>> +/* create a new spi bus */
>> +spi_bus *spi_init_bus(DeviceState *parent, int num_slaves, const char
>> *name);
>> +int spi_attach_slave(spi_bus *bus, SPISlave *s, int cs);
>> +
>> +/* change the chip select. Return 1 on failure. */
>> +int spi_set_cs(spi_bus *bus, int cs);
>> +int spi_get_cs(spi_bus *bus);
>> +SpiSlaveState spi_get_state(spi_bus *bus);
>> +
>> +SpiSlaveState spi_send(spi_bus *bus, uint32_t data, int len);
>> +SpiSlaveState spi_recv(spi_bus *bus, uint32_t *data);
>
> I'm no SPI expert, but a bit of googling suggests that it's
> a synchronous duplex bus, so you always send a byte of data
> to the slave and get one back in return (even if for some slaves
> it might be random garbage). The current OMAP SPI devices in QEMU
> master have an API that reflects this: eg tsc210x_txrx() which
> takes an input value and returns an output value. This API
> seems to have separate send and recv methods -- can you explain
> how this works?
>
> (Incidentally if we're going to qdevify the SPI interface we
> should also convert the existing omap SPI devices...)
>
> thanks
> -- PMM
- Re: [Qemu-devel] [RFC PATCH v1 1/4] SPI: initial support, (continued)
- Re: [Qemu-devel] [RFC PATCH v1 1/4] SPI: initial support, Peter Crosthwaite, 2012/04/02
- Re: [Qemu-devel] [RFC PATCH v1 1/4] SPI: initial support, Peter Crosthwaite, 2012/04/02
- Re: [Qemu-devel] [RFC PATCH v1 1/4] SPI: initial support, Paul Brook, 2012/04/03
- Re: [Qemu-devel] [RFC PATCH v1 1/4] SPI: initial support, Peter Maydell, 2012/04/03
- Re: [Qemu-devel] [RFC PATCH v1 1/4] SPI: initial support, Paul Brook, 2012/04/03
- Re: [Qemu-devel] [RFC PATCH v1 1/4] SPI: initial support, Peter Crosthwaite, 2012/04/03
- Re: [Qemu-devel] [RFC PATCH v1 1/4] SPI: initial support, Paul Brook, 2012/04/04
- Re: [Qemu-devel] [RFC PATCH v1 1/4] SPI: initial support, Peter Crosthwaite, 2012/04/04
- Re: [Qemu-devel] [RFC PATCH v1 1/4] SPI: initial support, Peter Maydell, 2012/04/05
- Re: [Qemu-devel] [RFC PATCH v1 1/4] SPI: initial support, Peter Crosthwaite, 2012/04/06
- Re: [Qemu-devel] [RFC PATCH v1 1/4] SPI: initial support,
Peter Crosthwaite <=