1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
/* QEMU Synchronous Serial Interface support. */
/*
* In principle SSI is a point-point interface. As such the qemu
* implementation has a single peripheral on a "bus".
* However it is fairly common for boards to have multiple peripherals
* connected to a single master, and select devices with an external
* chip select. This is implemented in qemu by having an explicit mux device.
* It is assumed that master and peripheral are both using the same transfer
* width.
*/
#ifndef QEMU_SSI_H
#define QEMU_SSI_H
#include "hw/qdev-core.h"
#include "qom/object.h"
typedef enum SSICSMode SSICSMode;
#define TYPE_SSI_PERIPHERAL "ssi-peripheral"
OBJECT_DECLARE_TYPE(SSIPeripheral, SSIPeripheralClass,
SSI_PERIPHERAL)
#define SSI_GPIO_CS "ssi-gpio-cs"
enum SSICSMode {
SSI_CS_NONE = 0,
SSI_CS_LOW,
SSI_CS_HIGH,
};
/* Peripherals. */
struct SSIPeripheralClass {
DeviceClass parent_class;
void (*realize)(SSIPeripheral *dev, Error **errp);
/* if you have standard or no CS behaviour, just override transfer.
* This is called when the device cs is active (true by default).
* See ssi_transfer().
*/
uint32_t (*transfer)(SSIPeripheral *dev, uint32_t val);
/* called when the CS line changes. Optional, devices only need to implement
* this if they have side effects associated with the cs line (beyond
* tristating the txrx lines).
*/
int (*set_cs)(SSIPeripheral *dev, bool select);
/* define whether or not CS exists and is active low/high */
SSICSMode cs_polarity;
/* if you have non-standard CS behaviour override this to take control
* of the CS behaviour at the device level. transfer, set_cs, and
* cs_polarity are unused if this is overwritten. Transfer_raw will
* always be called for the device for every txrx access to the parent bus
* See ssi_transfer().
*/
uint32_t (*transfer_raw)(SSIPeripheral *dev, uint32_t val);
};
struct SSIPeripheral {
DeviceState parent_obj;
/* cache the class */
SSIPeripheralClass *spc;
/* Chip select state */
bool cs;
/* Chip select index */
uint8_t cs_index;
};
extern const VMStateDescription vmstate_ssi_peripheral;
#define VMSTATE_SSI_PERIPHERAL(_field, _state) { \
.name = (stringify(_field)), \
.size = sizeof(SSIPeripheral), \
.vmsd = &vmstate_ssi_peripheral, \
.flags = VMS_STRUCT, \
.offset = vmstate_offset_value(_state, _field, SSIPeripheral), \
}
DeviceState *ssi_create_peripheral(SSIBus *bus, const char *name);
/**
* ssi_realize_and_unref: realize and unref an SSI peripheral
* @dev: SSI peripheral to realize
* @bus: SSI bus to put it on
* @errp: error pointer
*
* Call 'realize' on @dev, put it on the specified @bus, and drop the
* reference to it. Errors are reported via @errp and by returning
* false.
*
* This function is useful if you have created @dev via qdev_new()
* (which takes a reference to the device it returns to you), so that
* you can set properties on it before realizing it. If you don't need
* to set properties then ssi_create_peripheral() is probably better (as it
* does the create, init and realize in one step).
*
* If you are embedding the SSI peripheral into another QOM device and
* initialized it via some variant on object_initialize_child() then
* do not use this function, because that family of functions arrange
* for the only reference to the child device to be held by the parent
* via the child<> property, and so the reference-count-drop done here
* would be incorrect. (Instead you would want ssi_realize(), which
* doesn't currently exist but would be trivial to create if we had
* any code that wanted it.)
*/
bool ssi_realize_and_unref(DeviceState *dev, SSIBus *bus, Error **errp);
/* Master interface. */
SSIBus *ssi_create_bus(DeviceState *parent, const char *name);
/**
* Transfer a word on a SSI bus
* @bus: SSI bus
* @val: word to transmit
*
* At the same time, read a word and write the @val one on the SSI bus.
*
* SSI words might vary between 8 and 32 bits. The same number of bits
* written is received.
*
* Return: word value received
*/
uint32_t ssi_transfer(SSIBus *bus, uint32_t val);
DeviceState *ssi_get_cs(SSIBus *bus, uint8_t cs_index);
#endif
|