Statistics
| Branch: | Revision:

root / hw / ssi.c @ 9a6ee9fd

History | View | Annotate | Download (4.1 kB)

1
/*
2
 * QEMU Synchronous Serial Interface support
3
 *
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
8
 *
9
 * This code is licensed under the GNU GPL v2.
10
 *
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.
13
 */
14

    
15
#include "ssi.h"
16

    
17
struct SSIBus {
18
    BusState qbus;
19
};
20

    
21
#define TYPE_SSI_BUS "SSI"
22
#define SSI_BUS(obj) OBJECT_CHECK(SSIBus, (obj), TYPE_SSI_BUS)
23

    
24
static const TypeInfo ssi_bus_info = {
25
    .name = TYPE_SSI_BUS,
26
    .parent = TYPE_BUS,
27
    .instance_size = sizeof(SSIBus),
28
};
29

    
30
static void ssi_cs_default(void *opaque, int n, int level)
31
{
32
    SSISlave *s = SSI_SLAVE(opaque);
33
    bool cs = !!level;
34
    assert(n == 0);
35
    if (s->cs != cs) {
36
        SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s);
37
        if (ssc->set_cs) {
38
            ssc->set_cs(s, cs);
39
        }
40
    }
41
    s->cs = cs;
42
}
43

    
44
static uint32_t ssi_transfer_raw_default(SSISlave *dev, uint32_t val)
45
{
46
    SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(dev);
47

    
48
    if ((dev->cs && ssc->cs_polarity == SSI_CS_HIGH) ||
49
            (!dev->cs && ssc->cs_polarity == SSI_CS_LOW) ||
50
            ssc->cs_polarity == SSI_CS_NONE) {
51
        return ssc->transfer(dev, val);
52
    }
53
    return 0;
54
}
55

    
56
static int ssi_slave_init(DeviceState *dev)
57
{
58
    SSISlave *s = SSI_SLAVE(dev);
59
    SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s);
60

    
61
    if (ssc->transfer_raw == ssi_transfer_raw_default &&
62
            ssc->cs_polarity != SSI_CS_NONE) {
63
        qdev_init_gpio_in(&s->qdev, ssi_cs_default, 1);
64
    }
65

    
66
    return ssc->init(s);
67
}
68

    
69
static void ssi_slave_class_init(ObjectClass *klass, void *data)
70
{
71
    SSISlaveClass *ssc = SSI_SLAVE_CLASS(klass);
72
    DeviceClass *dc = DEVICE_CLASS(klass);
73

    
74
    dc->init = ssi_slave_init;
75
    dc->bus_type = TYPE_SSI_BUS;
76
    if (!ssc->transfer_raw) {
77
        ssc->transfer_raw = ssi_transfer_raw_default;
78
    }
79
}
80

    
81
static const TypeInfo ssi_slave_info = {
82
    .name = TYPE_SSI_SLAVE,
83
    .parent = TYPE_DEVICE,
84
    .class_init = ssi_slave_class_init,
85
    .class_size = sizeof(SSISlaveClass),
86
    .abstract = true,
87
};
88

    
89
DeviceState *ssi_create_slave_no_init(SSIBus *bus, const char *name)
90
{
91
    return qdev_create(&bus->qbus, name);
92
}
93

    
94
DeviceState *ssi_create_slave(SSIBus *bus, const char *name)
95
{
96
    DeviceState *dev = ssi_create_slave_no_init(bus, name);
97

    
98
    qdev_init_nofail(dev);
99
    return dev;
100
}
101

    
102
SSIBus *ssi_create_bus(DeviceState *parent, const char *name)
103
{
104
    BusState *bus;
105
    bus = qbus_create(TYPE_SSI_BUS, parent, name);
106
    return FROM_QBUS(SSIBus, bus);
107
}
108

    
109
uint32_t ssi_transfer(SSIBus *bus, uint32_t val)
110
{
111
    BusChild *kid;
112
    SSISlaveClass *ssc;
113
    uint32_t r = 0;
114

    
115
    QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
116
        SSISlave *slave = SSI_SLAVE(kid->child);
117
        ssc = SSI_SLAVE_GET_CLASS(slave);
118
        r |= ssc->transfer_raw(slave, val);
119
    }
120

    
121
    return r;
122
}
123

    
124
const VMStateDescription vmstate_ssi_slave = {
125
    .name = "SSISlave",
126
    .version_id = 1,
127
    .minimum_version_id = 1,
128
    .minimum_version_id_old = 1,
129
    .fields      = (VMStateField[]) {
130
        VMSTATE_BOOL(cs, SSISlave),
131
        VMSTATE_END_OF_LIST()
132
    }
133
};
134

    
135
static void ssi_slave_register_types(void)
136
{
137
    type_register_static(&ssi_bus_info);
138
    type_register_static(&ssi_slave_info);
139
}
140

    
141
type_init(ssi_slave_register_types)
142

    
143
typedef struct SSIAutoConnectArg {
144
    qemu_irq **cs_linep;
145
    SSIBus *bus;
146
} SSIAutoConnectArg;
147

    
148
static int ssi_auto_connect_slave(Object *child, void *opaque)
149
{
150
    SSIAutoConnectArg *arg = opaque;
151
    SSISlave *dev = (SSISlave *)object_dynamic_cast(child, TYPE_SSI_SLAVE);
152
    qemu_irq cs_line;
153

    
154
    if (!dev) {
155
        return 0;
156
    }
157

    
158
    cs_line = qdev_get_gpio_in(DEVICE(dev), 0);
159
    qdev_set_parent_bus(DEVICE(dev), &arg->bus->qbus);
160
    **arg->cs_linep = cs_line;
161
    (*arg->cs_linep)++;
162
    return 0;
163
}
164

    
165
void ssi_auto_connect_slaves(DeviceState *parent, qemu_irq *cs_line,
166
                             SSIBus *bus)
167
{
168
    SSIAutoConnectArg arg = {
169
        .cs_linep = &cs_line,
170
        .bus = bus
171
    };
172

    
173
    object_child_foreach(OBJECT(parent), ssi_auto_connect_slave, &arg);
174
}