190d37239SPaul Brook /* QEMU Synchronous Serial Interface support. */ 290d37239SPaul Brook 390d37239SPaul Brook /* In principle SSI is a point-point interface. As such the qemu 490d37239SPaul Brook implementation has a single slave device on a "bus". 590d37239SPaul Brook However it is fairly common for boards to have multiple slaves 690d37239SPaul Brook connected to a single master, and select devices with an external 790d37239SPaul Brook chip select. This is implemented in qemu by having an explicit mux device. 890d37239SPaul Brook It is assumed that master and slave are both using the same transfer width. 990d37239SPaul Brook */ 1090d37239SPaul Brook 1190d37239SPaul Brook #ifndef QEMU_SSI_H 1290d37239SPaul Brook #define QEMU_SSI_H 1390d37239SPaul Brook 14a27bd6c7SMarkus Armbruster #include "hw/qdev-core.h" 15db1015e9SEduardo Habkost #include "qom/object.h" 1690d37239SPaul Brook 178fd06719SAlistair Francis typedef enum SSICSMode SSICSMode; 1890d37239SPaul Brook 19cd6c4cf2SAnthony Liguori #define TYPE_SSI_SLAVE "ssi-slave" 20c821774aSEduardo Habkost OBJECT_DECLARE_TYPE(SSISlave, SSISlaveClass, 21*30b5707cSEduardo Habkost SSI_SLAVE) 22cd6c4cf2SAnthony Liguori 23de77914eSPeter Crosthwaite #define SSI_GPIO_CS "ssi-gpio-cs" 24de77914eSPeter Crosthwaite 258fd06719SAlistair Francis enum SSICSMode { 2666530953SPeter A. G. Crosthwaite SSI_CS_NONE = 0, 2766530953SPeter A. G. Crosthwaite SSI_CS_LOW, 2866530953SPeter A. G. Crosthwaite SSI_CS_HIGH, 298fd06719SAlistair Francis }; 3066530953SPeter A. G. Crosthwaite 3190d37239SPaul Brook /* Slave devices. */ 328fd06719SAlistair Francis struct SSISlaveClass { 33cd6c4cf2SAnthony Liguori DeviceClass parent_class; 34cd6c4cf2SAnthony Liguori 357673bb4cSCédric Le Goater void (*realize)(SSISlave *dev, Error **errp); 3666530953SPeter A. G. Crosthwaite 3766530953SPeter A. G. Crosthwaite /* if you have standard or no CS behaviour, just override transfer. 3866530953SPeter A. G. Crosthwaite * This is called when the device cs is active (true by default). 3966530953SPeter A. G. Crosthwaite */ 4090d37239SPaul Brook uint32_t (*transfer)(SSISlave *dev, uint32_t val); 4166530953SPeter A. G. Crosthwaite /* called when the CS line changes. Optional, devices only need to implement 4266530953SPeter A. G. Crosthwaite * this if they have side effects associated with the cs line (beyond 4366530953SPeter A. G. Crosthwaite * tristating the txrx lines). 4466530953SPeter A. G. Crosthwaite */ 4566530953SPeter A. G. Crosthwaite int (*set_cs)(SSISlave *dev, bool select); 4666530953SPeter A. G. Crosthwaite /* define whether or not CS exists and is active low/high */ 4766530953SPeter A. G. Crosthwaite SSICSMode cs_polarity; 4866530953SPeter A. G. Crosthwaite 4966530953SPeter A. G. Crosthwaite /* if you have non-standard CS behaviour override this to take control 5066530953SPeter A. G. Crosthwaite * of the CS behaviour at the device level. transfer, set_cs, and 5166530953SPeter A. G. Crosthwaite * cs_polarity are unused if this is overwritten. Transfer_raw will 5266530953SPeter A. G. Crosthwaite * always be called for the device for every txrx access to the parent bus 5366530953SPeter A. G. Crosthwaite */ 5466530953SPeter A. G. Crosthwaite uint32_t (*transfer_raw)(SSISlave *dev, uint32_t val); 558fd06719SAlistair Francis }; 5690d37239SPaul Brook 5790d37239SPaul Brook struct SSISlave { 581f760d5fSPeter Crosthwaite DeviceState parent_obj; 5966530953SPeter A. G. Crosthwaite 6066530953SPeter A. G. Crosthwaite /* Chip select state */ 6166530953SPeter A. G. Crosthwaite bool cs; 6290d37239SPaul Brook }; 6390d37239SPaul Brook 6466530953SPeter A. G. Crosthwaite extern const VMStateDescription vmstate_ssi_slave; 6566530953SPeter A. G. Crosthwaite 6666530953SPeter A. G. Crosthwaite #define VMSTATE_SSI_SLAVE(_field, _state) { \ 6766530953SPeter A. G. Crosthwaite .name = (stringify(_field)), \ 6866530953SPeter A. G. Crosthwaite .size = sizeof(SSISlave), \ 6966530953SPeter A. G. Crosthwaite .vmsd = &vmstate_ssi_slave, \ 7066530953SPeter A. G. Crosthwaite .flags = VMS_STRUCT, \ 7166530953SPeter A. G. Crosthwaite .offset = vmstate_offset_value(_state, _field, SSISlave), \ 7266530953SPeter A. G. Crosthwaite } 7366530953SPeter A. G. Crosthwaite 7490d37239SPaul Brook DeviceState *ssi_create_slave(SSIBus *bus, const char *name); 75581e109dSPeter Maydell /** 76581e109dSPeter Maydell * ssi_realize_and_unref: realize and unref an SSI slave device 77581e109dSPeter Maydell * @dev: SSI slave device to realize 78581e109dSPeter Maydell * @bus: SSI bus to put it on 79581e109dSPeter Maydell * @errp: error pointer 80581e109dSPeter Maydell * 81581e109dSPeter Maydell * Call 'realize' on @dev, put it on the specified @bus, and drop the 82581e109dSPeter Maydell * reference to it. Errors are reported via @errp and by returning 83581e109dSPeter Maydell * false. 84581e109dSPeter Maydell * 85581e109dSPeter Maydell * This function is useful if you have created @dev via qdev_new() 86581e109dSPeter Maydell * (which takes a reference to the device it returns to you), so that 87581e109dSPeter Maydell * you can set properties on it before realizing it. If you don't need 88581e109dSPeter Maydell * to set properties then ssi_create_slave() is probably better (as it 89581e109dSPeter Maydell * does the create, init and realize in one step). 90581e109dSPeter Maydell * 91581e109dSPeter Maydell * If you are embedding the SSI slave into another QOM device and 92581e109dSPeter Maydell * initialized it via some variant on object_initialize_child() then 93581e109dSPeter Maydell * do not use this function, because that family of functions arrange 94581e109dSPeter Maydell * for the only reference to the child device to be held by the parent 95581e109dSPeter Maydell * via the child<> property, and so the reference-count-drop done here 96581e109dSPeter Maydell * would be incorrect. (Instead you would want ssi_realize(), which 97581e109dSPeter Maydell * doesn't currently exist but would be trivial to create if we had 98581e109dSPeter Maydell * any code that wanted it.) 99581e109dSPeter Maydell */ 100581e109dSPeter Maydell bool ssi_realize_and_unref(DeviceState *dev, SSIBus *bus, Error **errp); 10190d37239SPaul Brook 10290d37239SPaul Brook /* Master interface. */ 10302e2da45SPaul Brook SSIBus *ssi_create_bus(DeviceState *parent, const char *name); 10490d37239SPaul Brook 10590d37239SPaul Brook uint32_t ssi_transfer(SSIBus *bus, uint32_t val); 10690d37239SPaul Brook 10790d37239SPaul Brook #endif 108