aboutsummaryrefslogtreecommitdiff
path: root/hw/ssi.c
diff options
context:
space:
mode:
authorPeter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>2012-07-24 12:23:22 +1000
committerPeter Crosthwaite <peter.crosthwaite@xilinx.com>2012-10-10 11:13:31 +1000
commit66530953319427d7c67a723076acd68075dc7db2 (patch)
tree6db9a1fea1d50f2d02a3ffeacb922332df9d208a /hw/ssi.c
parentb4a76e84f4997392c9d2eb6f4373dc376d2ffd82 (diff)
ssi: Implemented CS behaviour
Added default CS behaviour for SSI slaves. SSI devices can set a property to enable CS behaviour which will create a GPIO on the device which is the CS. Tristating of the bus on SSI transfers is implemented. Signed-off-by: Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com> Acked-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/ssi.c')
-rw-r--r--hw/ssi.c49
1 files changed, 48 insertions, 1 deletions
diff --git a/hw/ssi.c b/hw/ssi.c
index 35d0a04a08..2e4f2fecd1 100644
--- a/hw/ssi.c
+++ b/hw/ssi.c
@@ -27,19 +27,55 @@ static const TypeInfo ssi_bus_info = {
.instance_size = sizeof(SSIBus),
};
+static void ssi_cs_default(void *opaque, int n, int level)
+{
+ SSISlave *s = SSI_SLAVE(opaque);
+ bool cs = !!level;
+ assert(n == 0);
+ if (s->cs != cs) {
+ SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s);
+ if (ssc->set_cs) {
+ ssc->set_cs(s, cs);
+ }
+ }
+ s->cs = cs;
+}
+
+static uint32_t ssi_transfer_raw_default(SSISlave *dev, uint32_t val)
+{
+ SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(dev);
+
+ if ((dev->cs && ssc->cs_polarity == SSI_CS_HIGH) ||
+ (!dev->cs && ssc->cs_polarity == SSI_CS_LOW) ||
+ ssc->cs_polarity == SSI_CS_NONE) {
+ return ssc->transfer(dev, val);
+ }
+ return 0;
+}
+
static int ssi_slave_init(DeviceState *dev)
{
SSISlave *s = SSI_SLAVE(dev);
SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s);
+ if (ssc->transfer_raw == ssi_transfer_raw_default &&
+ ssc->cs_polarity != SSI_CS_NONE) {
+ qdev_init_gpio_in(&s->qdev, ssi_cs_default, 1);
+ }
+
return ssc->init(s);
}
static void ssi_slave_class_init(ObjectClass *klass, void *data)
{
+ SSISlaveClass *ssc = SSI_SLAVE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
+
dc->init = ssi_slave_init;
dc->bus_type = TYPE_SSI_BUS;
+ if (!ssc->transfer_raw) {
+ ssc->transfer_raw = ssi_transfer_raw_default;
+ }
}
static TypeInfo ssi_slave_info = {
@@ -74,12 +110,23 @@ uint32_t ssi_transfer(SSIBus *bus, uint32_t val)
QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
SSISlave *slave = SSI_SLAVE(kid->child);
ssc = SSI_SLAVE_GET_CLASS(slave);
- r |= ssc->transfer(slave, val);
+ r |= ssc->transfer_raw(slave, val);
}
return r;
}
+const VMStateDescription vmstate_ssi_slave = {
+ .name = "SSISlave",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(cs, SSISlave),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void ssi_slave_register_types(void)
{
type_register_static(&ssi_bus_info);