| 
									
										
										
										
											2007-09-16 21:08:06 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  |  * QEMU I2C bus interface. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (c) 2007 CodeSourcery. | 
					
						
							|  |  |  |  * Written by Paul Brook | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2011-06-26 12:21:35 +10:00
										 |  |  |  * This code is licensed under the LGPL. | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-26 18:17:30 +00:00
										 |  |  | #include "qemu/osdep.h"
 | 
					
						
							| 
									
										
										
										
											2013-02-05 17:06:20 +01:00
										 |  |  | #include "hw/i2c/i2c.h"
 | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  | typedef struct I2CNode I2CNode; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct I2CNode { | 
					
						
							|  |  |  |     I2CSlave *elt; | 
					
						
							|  |  |  |     QLIST_ENTRY(I2CNode) next; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-27 14:39:58 +02:00
										 |  |  | #define I2C_BROADCAST 0x00
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-03 00:18:51 +02:00
										 |  |  | struct I2CBus | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-05-23 00:05:19 +01:00
										 |  |  |     BusState qbus; | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |     QLIST_HEAD(, I2CNode) current_devs; | 
					
						
							| 
									
										
										
										
											2009-09-29 22:48:26 +02:00
										 |  |  |     uint8_t saved_address; | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |     bool broadcast; | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-28 18:01:36 +02:00
										 |  |  | static Property i2c_props[] = { | 
					
						
							|  |  |  |     DEFINE_PROP_UINT8("address", struct I2CSlave, address, 0), | 
					
						
							|  |  |  |     DEFINE_PROP_END_OF_LIST(), | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-02 09:00:20 +02:00
										 |  |  | #define TYPE_I2C_BUS "i2c-bus"
 | 
					
						
							| 
									
										
										
										
											2013-08-03 00:18:51 +02:00
										 |  |  | #define I2C_BUS(obj) OBJECT_CHECK(I2CBus, (obj), TYPE_I2C_BUS)
 | 
					
						
							| 
									
										
										
										
											2012-05-02 09:00:20 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | static const TypeInfo i2c_bus_info = { | 
					
						
							|  |  |  |     .name = TYPE_I2C_BUS, | 
					
						
							|  |  |  |     .parent = TYPE_BUS, | 
					
						
							| 
									
										
										
										
											2013-08-03 00:18:51 +02:00
										 |  |  |     .instance_size = sizeof(I2CBus), | 
					
						
							| 
									
										
										
										
											2009-06-30 14:12:08 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-29 22:48:27 +02:00
										 |  |  | static void i2c_bus_pre_save(void *opaque) | 
					
						
							| 
									
										
										
										
											2008-07-01 23:16:53 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-08-03 00:18:51 +02:00
										 |  |  |     I2CBus *bus = opaque; | 
					
						
							| 
									
										
										
										
											2008-07-01 23:16:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |     bus->saved_address = -1; | 
					
						
							|  |  |  |     if (!QLIST_EMPTY(&bus->current_devs)) { | 
					
						
							|  |  |  |         if (!bus->broadcast) { | 
					
						
							|  |  |  |             bus->saved_address = QLIST_FIRST(&bus->current_devs)->elt->address; | 
					
						
							| 
									
										
										
										
											2016-07-27 14:39:58 +02:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             bus->saved_address = I2C_BROADCAST; | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-07-01 23:16:53 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-29 22:48:27 +02:00
										 |  |  | static const VMStateDescription vmstate_i2c_bus = { | 
					
						
							|  |  |  |     .name = "i2c_bus", | 
					
						
							|  |  |  |     .version_id = 1, | 
					
						
							|  |  |  |     .minimum_version_id = 1, | 
					
						
							|  |  |  |     .pre_save = i2c_bus_pre_save, | 
					
						
							| 
									
										
										
										
											2014-04-16 16:01:33 +02:00
										 |  |  |     .fields = (VMStateField[]) { | 
					
						
							| 
									
										
										
										
											2013-08-03 00:18:51 +02:00
										 |  |  |         VMSTATE_UINT8(saved_address, I2CBus), | 
					
						
							| 
									
										
										
										
											2009-09-29 22:48:27 +02:00
										 |  |  |         VMSTATE_END_OF_LIST() | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | /* Create a new I2C bus.  */ | 
					
						
							| 
									
										
										
										
											2013-08-03 00:18:51 +02:00
										 |  |  | I2CBus *i2c_init_bus(DeviceState *parent, const char *name) | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-08-03 00:18:51 +02:00
										 |  |  |     I2CBus *bus; | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-07 14:45:17 +02:00
										 |  |  |     bus = I2C_BUS(qbus_create(TYPE_I2C_BUS, parent, name)); | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |     QLIST_INIT(&bus->current_devs); | 
					
						
							| 
									
										
										
										
											2010-06-25 11:09:07 -06:00
										 |  |  |     vmstate_register(NULL, -1, &vmstate_i2c_bus, bus); | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  |     return bus; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-04 20:28:27 -06:00
										 |  |  | void i2c_set_slave_address(I2CSlave *dev, uint8_t address) | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     dev->address = address; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Return nonzero if bus is busy.  */ | 
					
						
							| 
									
										
										
										
											2013-08-03 00:18:51 +02:00
										 |  |  | int i2c_bus_busy(I2CBus *bus) | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |     return !QLIST_EMPTY(&bus->current_devs); | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-24 10:42:33 -05:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Returns non-zero if the address is not valid.  If this is called | 
					
						
							|  |  |  |  * again without an intervening i2c_end_transfer(), like in the SMBus | 
					
						
							|  |  |  |  * case where the operation is switched from write to read, this | 
					
						
							|  |  |  |  * function will not rescan the bus and thus cannot fail. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | /* TODO: Make this handle multiple masters.  */ | 
					
						
							| 
									
										
										
										
											2013-08-03 00:18:51 +02:00
										 |  |  | int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv) | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-12-23 15:34:39 -06:00
										 |  |  |     BusChild *kid; | 
					
						
							| 
									
										
										
										
											2011-12-04 20:39:20 -06:00
										 |  |  |     I2CSlaveClass *sc; | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |     I2CNode *node; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-27 14:39:58 +02:00
										 |  |  |     if (address == I2C_BROADCAST) { | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |         /*
 | 
					
						
							|  |  |  |          * This is a broadcast, the current_devs will be all the devices of the | 
					
						
							|  |  |  |          * bus. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         bus->broadcast = true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-24 16:26:55 +01:00
										 |  |  |     /*
 | 
					
						
							|  |  |  |      * If there are already devices in the list, that means we are in | 
					
						
							|  |  |  |      * the middle of a transaction and we shouldn't rescan the bus. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * This happens with any SMBus transaction, even on a pure I2C | 
					
						
							|  |  |  |      * device.  The interface does a transaction start without | 
					
						
							|  |  |  |      * terminating the previous transaction. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     if (QLIST_EMPTY(&bus->current_devs)) { | 
					
						
							|  |  |  |         QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { | 
					
						
							|  |  |  |             DeviceState *qdev = kid->child; | 
					
						
							|  |  |  |             I2CSlave *candidate = I2C_SLAVE(qdev); | 
					
						
							|  |  |  |             if ((candidate->address == address) || (bus->broadcast)) { | 
					
						
							|  |  |  |                 node = g_malloc(sizeof(struct I2CNode)); | 
					
						
							|  |  |  |                 node->elt = candidate; | 
					
						
							|  |  |  |                 QLIST_INSERT_HEAD(&bus->current_devs, node, next); | 
					
						
							|  |  |  |                 if (!bus->broadcast) { | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2009-06-08 09:27:19 +03:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |     if (QLIST_EMPTY(&bus->current_devs)) { | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  |         return 1; | 
					
						
							| 
									
										
										
										
											2011-12-04 20:39:20 -06:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |     QLIST_FOREACH(node, &bus->current_devs, next) { | 
					
						
							|  |  |  |         sc = I2C_SLAVE_GET_CLASS(node->elt); | 
					
						
							|  |  |  |         /* If the bus is already busy, assume this is a repeated
 | 
					
						
							|  |  |  |            start condition.  */ | 
					
						
							|  |  |  |         if (sc->event) { | 
					
						
							|  |  |  |             sc->event(node->elt, recv ? I2C_START_RECV : I2C_START_SEND); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-12-04 20:39:20 -06:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-03 00:18:51 +02:00
										 |  |  | void i2c_end_transfer(I2CBus *bus) | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-12-04 20:39:20 -06:00
										 |  |  |     I2CSlaveClass *sc; | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |     I2CNode *node, *next; | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |     QLIST_FOREACH_SAFE(node, &bus->current_devs, next, next) { | 
					
						
							|  |  |  |         sc = I2C_SLAVE_GET_CLASS(node->elt); | 
					
						
							|  |  |  |         if (sc->event) { | 
					
						
							|  |  |  |             sc->event(node->elt, I2C_FINISH); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         QLIST_REMOVE(node, next); | 
					
						
							|  |  |  |         g_free(node); | 
					
						
							| 
									
										
										
										
											2011-12-04 20:39:20 -06:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |     bus->broadcast = false; | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  | int i2c_send_recv(I2CBus *bus, uint8_t *data, bool send) | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-12-04 20:39:20 -06:00
										 |  |  |     I2CSlaveClass *sc; | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |     I2CNode *node; | 
					
						
							|  |  |  |     int ret = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |     if (send) { | 
					
						
							|  |  |  |         QLIST_FOREACH(node, &bus->current_devs, next) { | 
					
						
							|  |  |  |             sc = I2C_SLAVE_GET_CLASS(node->elt); | 
					
						
							|  |  |  |             if (sc->send) { | 
					
						
							|  |  |  |                 ret = ret || sc->send(node->elt, *data); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 ret = -1; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return ret ? -1 : 0; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         if ((QLIST_EMPTY(&bus->current_devs)) || (bus->broadcast)) { | 
					
						
							|  |  |  |             return -1; | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         sc = I2C_SLAVE_GET_CLASS(QLIST_FIRST(&bus->current_devs)->elt); | 
					
						
							|  |  |  |         if (sc->recv) { | 
					
						
							|  |  |  |             ret = sc->recv(QLIST_FIRST(&bus->current_devs)->elt); | 
					
						
							|  |  |  |             if (ret < 0) { | 
					
						
							|  |  |  |                 return ret; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 *data = ret; | 
					
						
							|  |  |  |                 return 0; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return -1; | 
					
						
							| 
									
										
										
										
											2011-12-04 20:39:20 -06:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  | int i2c_send(I2CBus *bus, uint8_t data) | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |     return i2c_send_recv(bus, &data, true); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  | int i2c_recv(I2CBus *bus) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint8_t data; | 
					
						
							|  |  |  |     int ret = i2c_send_recv(bus, &data, false); | 
					
						
							| 
									
										
										
										
											2011-12-04 20:39:20 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |     return ret < 0 ? ret : data; | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-03 00:18:51 +02:00
										 |  |  | void i2c_nack(I2CBus *bus) | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-12-04 20:39:20 -06:00
										 |  |  |     I2CSlaveClass *sc; | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |     I2CNode *node; | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |     if (QLIST_EMPTY(&bus->current_devs)) { | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2011-12-04 20:39:20 -06:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |     QLIST_FOREACH(node, &bus->current_devs, next) { | 
					
						
							|  |  |  |         sc = I2C_SLAVE_GET_CLASS(node->elt); | 
					
						
							|  |  |  |         if (sc->event) { | 
					
						
							|  |  |  |             sc->event(node->elt, I2C_NACK); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-12-04 20:39:20 -06:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2007-05-23 00:03:59 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-29 22:48:28 +02:00
										 |  |  | static int i2c_slave_post_load(void *opaque, int version_id) | 
					
						
							| 
									
										
										
										
											2007-05-24 18:50:09 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-12-04 20:28:27 -06:00
										 |  |  |     I2CSlave *dev = opaque; | 
					
						
							| 
									
										
										
										
											2013-08-03 00:18:51 +02:00
										 |  |  |     I2CBus *bus; | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |     I2CNode *node; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-07 14:45:17 +02:00
										 |  |  |     bus = I2C_BUS(qdev_get_parent_bus(DEVICE(dev))); | 
					
						
							| 
									
										
										
										
											2016-07-27 14:39:58 +02:00
										 |  |  |     if ((bus->saved_address == dev->address) || | 
					
						
							|  |  |  |         (bus->saved_address == I2C_BROADCAST)) { | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:14 +01:00
										 |  |  |         node = g_malloc(sizeof(struct I2CNode)); | 
					
						
							|  |  |  |         node->elt = dev; | 
					
						
							|  |  |  |         QLIST_INSERT_HEAD(&bus->current_devs, node, next); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:08 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-09-29 22:48:28 +02:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-29 22:48:30 +02:00
										 |  |  | const VMStateDescription vmstate_i2c_slave = { | 
					
						
							| 
									
										
										
										
											2011-12-04 20:28:27 -06:00
										 |  |  |     .name = "I2CSlave", | 
					
						
							| 
									
										
										
										
											2009-09-29 22:48:28 +02:00
										 |  |  |     .version_id = 1, | 
					
						
							|  |  |  |     .minimum_version_id = 1, | 
					
						
							|  |  |  |     .post_load = i2c_slave_post_load, | 
					
						
							| 
									
										
										
										
											2014-04-16 16:01:33 +02:00
										 |  |  |     .fields = (VMStateField[]) { | 
					
						
							| 
									
										
										
										
											2011-12-04 20:28:27 -06:00
										 |  |  |         VMSTATE_UINT8(address, I2CSlave), | 
					
						
							| 
									
										
										
										
											2009-09-29 22:48:28 +02:00
										 |  |  |         VMSTATE_END_OF_LIST() | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-09 15:02:56 -06:00
										 |  |  | static int i2c_slave_qdev_init(DeviceState *dev) | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:08 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-01-25 09:12:54 +01:00
										 |  |  |     I2CSlave *s = I2C_SLAVE(dev); | 
					
						
							| 
									
										
										
										
											2011-12-04 20:39:20 -06:00
										 |  |  |     I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(s); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-04 20:39:20 -06:00
										 |  |  |     return sc->init(s); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-03 00:18:51 +02:00
										 |  |  | DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr) | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:08 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     DeviceState *dev; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-23 00:05:19 +01:00
										 |  |  |     dev = qdev_create(&bus->qbus, name); | 
					
						
							| 
									
										
										
										
											2009-09-29 22:48:26 +02:00
										 |  |  |     qdev_prop_set_uint8(dev, "address", addr); | 
					
						
							| 
									
										
										
										
											2009-10-07 01:15:58 +02:00
										 |  |  |     qdev_init_nofail(dev); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:08 +01:00
										 |  |  |     return dev; | 
					
						
							| 
									
										
										
										
											2007-05-24 18:50:09 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2011-12-04 20:39:20 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  | static void i2c_slave_class_init(ObjectClass *klass, void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     DeviceClass *k = DEVICE_CLASS(klass); | 
					
						
							|  |  |  |     k->init = i2c_slave_qdev_init; | 
					
						
							| 
									
										
										
										
											2013-07-29 17:17:45 +03:00
										 |  |  |     set_bit(DEVICE_CATEGORY_MISC, k->categories); | 
					
						
							| 
									
										
										
										
											2012-05-02 09:00:20 +02:00
										 |  |  |     k->bus_type = TYPE_I2C_BUS; | 
					
						
							| 
									
										
										
										
											2012-03-28 18:12:47 +02:00
										 |  |  |     k->props = i2c_props; | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-10 16:19:07 +01:00
										 |  |  | static const TypeInfo i2c_slave_type_info = { | 
					
						
							| 
									
										
										
										
											2011-12-04 20:39:20 -06:00
										 |  |  |     .name = TYPE_I2C_SLAVE, | 
					
						
							|  |  |  |     .parent = TYPE_DEVICE, | 
					
						
							|  |  |  |     .instance_size = sizeof(I2CSlave), | 
					
						
							|  |  |  |     .abstract = true, | 
					
						
							|  |  |  |     .class_size = sizeof(I2CSlaveClass), | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     .class_init = i2c_slave_class_init, | 
					
						
							| 
									
										
										
										
											2011-12-04 20:39:20 -06:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-09 15:20:55 +01:00
										 |  |  | static void i2c_slave_register_types(void) | 
					
						
							| 
									
										
										
										
											2011-12-04 20:39:20 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-05-02 09:00:20 +02:00
										 |  |  |     type_register_static(&i2c_bus_info); | 
					
						
							| 
									
										
										
										
											2011-12-04 20:39:20 -06:00
										 |  |  |     type_register_static(&i2c_slave_type_info); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-09 15:20:55 +01:00
										 |  |  | type_init(i2c_slave_register_types) |