2 * QEMU Synchronous Serial Interface support
4 * Copyright (c) 2009 CodeSourcery.
5 * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com)
6 * Copyright (c) 2012 PetaLogix Pty Ltd.
7 * Written by Paul Brook
9 * This code is licensed under the GNU GPL v2.
11 * Contributions after 2012-01-13 are licensed under the terms of the
12 * GNU GPL, version 2 or (at your option) any later version.
15 #include "qemu/osdep.h"
16 #include "hw/qdev-properties.h"
17 #include "hw/ssi/ssi.h"
18 #include "migration/vmstate.h"
19 #include "qemu/module.h"
20 #include "qapi/error.h"
21 #include "qom/object.h"
27 #define TYPE_SSI_BUS "SSI"
28 OBJECT_DECLARE_SIMPLE_TYPE(SSIBus
, SSI_BUS
)
30 DeviceState
*ssi_get_cs(SSIBus
*bus
, uint8_t cs_index
)
32 BusState
*b
= BUS(bus
);
35 QTAILQ_FOREACH(kid
, &b
->children
, sibling
) {
36 SSIPeripheral
*kid_ssi
= SSI_PERIPHERAL(kid
->child
);
37 if (kid_ssi
->cs_index
== cs_index
) {
45 static bool ssi_bus_check_address(BusState
*b
, DeviceState
*dev
, Error
**errp
)
47 SSIPeripheral
*s
= SSI_PERIPHERAL(dev
);
49 if (ssi_get_cs(SSI_BUS(b
), s
->cs_index
)) {
50 error_setg(errp
, "CS index '0x%x' in use by a %s device", s
->cs_index
,
51 object_get_typename(OBJECT(dev
)));
58 static void ssi_bus_class_init(ObjectClass
*klass
, void *data
)
60 BusClass
*k
= BUS_CLASS(klass
);
62 k
->check_address
= ssi_bus_check_address
;
65 static const TypeInfo ssi_bus_info
= {
68 .instance_size
= sizeof(SSIBus
),
69 .class_init
= ssi_bus_class_init
,
72 static void ssi_cs_default(void *opaque
, int n
, int level
)
74 SSIPeripheral
*s
= SSI_PERIPHERAL(opaque
);
79 s
->spc
->set_cs(s
, cs
);
85 static uint32_t ssi_transfer_raw_default(SSIPeripheral
*dev
, uint32_t val
)
87 SSIPeripheralClass
*ssc
= dev
->spc
;
89 if ((dev
->cs
&& ssc
->cs_polarity
== SSI_CS_HIGH
) ||
90 (!dev
->cs
&& ssc
->cs_polarity
== SSI_CS_LOW
) ||
91 ssc
->cs_polarity
== SSI_CS_NONE
) {
92 return ssc
->transfer(dev
, val
);
97 static void ssi_peripheral_realize(DeviceState
*dev
, Error
**errp
)
99 SSIPeripheral
*s
= SSI_PERIPHERAL(dev
);
100 SSIPeripheralClass
*ssc
= SSI_PERIPHERAL_GET_CLASS(s
);
102 if (ssc
->transfer_raw
== ssi_transfer_raw_default
&&
103 ssc
->cs_polarity
!= SSI_CS_NONE
) {
104 qdev_init_gpio_in_named(dev
, ssi_cs_default
, SSI_GPIO_CS
, 1);
108 ssc
->realize(s
, errp
);
111 static Property ssi_peripheral_properties
[] = {
112 DEFINE_PROP_UINT8("cs", SSIPeripheral
, cs_index
, 0),
113 DEFINE_PROP_END_OF_LIST(),
116 static void ssi_peripheral_class_init(ObjectClass
*klass
, void *data
)
118 SSIPeripheralClass
*ssc
= SSI_PERIPHERAL_CLASS(klass
);
119 DeviceClass
*dc
= DEVICE_CLASS(klass
);
121 dc
->realize
= ssi_peripheral_realize
;
122 dc
->bus_type
= TYPE_SSI_BUS
;
123 if (!ssc
->transfer_raw
) {
124 ssc
->transfer_raw
= ssi_transfer_raw_default
;
126 device_class_set_props(dc
, ssi_peripheral_properties
);
129 static const TypeInfo ssi_peripheral_info
= {
130 .name
= TYPE_SSI_PERIPHERAL
,
131 .parent
= TYPE_DEVICE
,
132 .class_init
= ssi_peripheral_class_init
,
133 .class_size
= sizeof(SSIPeripheralClass
),
137 bool ssi_realize_and_unref(DeviceState
*dev
, SSIBus
*bus
, Error
**errp
)
139 return qdev_realize_and_unref(dev
, &bus
->parent_obj
, errp
);
142 DeviceState
*ssi_create_peripheral(SSIBus
*bus
, const char *name
)
144 DeviceState
*dev
= qdev_new(name
);
146 ssi_realize_and_unref(dev
, bus
, &error_fatal
);
150 SSIBus
*ssi_create_bus(DeviceState
*parent
, const char *name
)
153 bus
= qbus_new(TYPE_SSI_BUS
, parent
, name
);
157 uint32_t ssi_transfer(SSIBus
*bus
, uint32_t val
)
159 BusState
*b
= BUS(bus
);
163 QTAILQ_FOREACH(kid
, &b
->children
, sibling
) {
164 SSIPeripheral
*p
= SSI_PERIPHERAL(kid
->child
);
165 r
|= p
->spc
->transfer_raw(p
, val
);
171 const VMStateDescription vmstate_ssi_peripheral
= {
174 .minimum_version_id
= 1,
175 .fields
= (const VMStateField
[]) {
176 VMSTATE_BOOL(cs
, SSIPeripheral
),
177 VMSTATE_END_OF_LIST()
181 static void ssi_peripheral_register_types(void)
183 type_register_static(&ssi_bus_info
);
184 type_register_static(&ssi_peripheral_info
);
187 type_init(ssi_peripheral_register_types
)