summaryrefslogtreecommitdiffstats
path: root/include/hw/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'include/hw/i2c')
-rw-r--r--include/hw/i2c/aspeed_i2c.h11
-rw-r--r--include/hw/i2c/i2c.h30
2 files changed, 41 insertions, 0 deletions
diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index 1398befc10..300a89b343 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -174,6 +174,8 @@ REG32(I2CM_DMA_LEN, 0x1c)
FIELD(I2CM_DMA_LEN, TX_BUF_LEN_W1T, 15, 1)
FIELD(I2CM_DMA_LEN, TX_BUF_LEN, 0, 11)
REG32(I2CS_INTR_CTRL, 0x20)
+ FIELD(I2CS_INTR_CTRL, PKT_CMD_FAIL, 17, 1)
+ FIELD(I2CS_INTR_CTRL, PKT_CMD_DONE, 16, 1)
REG32(I2CS_INTR_STS, 0x24)
/* 31:29 shared with I2CD_INTR_STS[31:29] */
FIELD(I2CS_INTR_STS, SLAVE_PARKING_STS, 24, 2)
@@ -184,6 +186,7 @@ REG32(I2CS_INTR_STS, 0x24)
FIELD(I2CS_INTR_STS, PKT_CMD_FAIL, 17, 1)
FIELD(I2CS_INTR_STS, PKT_CMD_DONE, 16, 1)
/* 14:0 shared with I2CD_INTR_STS[14:0] */
+ FIELD(I2CS_INTR_STS, SLAVE_ADDR_RX_MATCH, 7, 1)
REG32(I2CS_CMD, 0x28)
FIELD(I2CS_CMD, W1_CTRL, 31, 1)
FIELD(I2CS_CMD, PKT_MODE_ACTIVE_ADDR, 17, 2)
@@ -223,6 +226,9 @@ struct AspeedI2CBus {
struct AspeedI2CState *controller;
+ /* slave mode */
+ I2CSlave *slave;
+
MemoryRegion mr;
I2CBus *bus;
@@ -249,6 +255,11 @@ struct AspeedI2CState {
AddressSpace dram_as;
};
+#define TYPE_ASPEED_I2C_BUS_SLAVE "aspeed.i2c.slave"
+OBJECT_DECLARE_SIMPLE_TYPE(AspeedI2CBusSlave, ASPEED_I2C_BUS_SLAVE)
+struct AspeedI2CBusSlave {
+ I2CSlave i2c;
+};
struct AspeedI2CClass {
SysBusDeviceClass parent_class;
diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h
index 5ca3b708c0..9b9581d230 100644
--- a/include/hw/i2c/i2c.h
+++ b/include/hw/i2c/i2c.h
@@ -12,6 +12,7 @@
enum i2c_event {
I2C_START_RECV,
I2C_START_SEND,
+ I2C_START_SEND_ASYNC,
I2C_FINISH,
I2C_NACK /* Masker NACKed a receive byte. */
};
@@ -28,6 +29,9 @@ struct I2CSlaveClass {
/* Master to slave. Returns non-zero for a NAK, 0 for success. */
int (*send)(I2CSlave *s, uint8_t data);
+ /* Master to slave (asynchronous). Receiving slave must call i2c_ack(). */
+ void (*send_async)(I2CSlave *s, uint8_t data);
+
/*
* Slave to master. This cannot fail, the device should always
* return something here.
@@ -69,13 +73,25 @@ struct I2CNode {
QLIST_ENTRY(I2CNode) next;
};
+typedef struct I2CPendingMaster I2CPendingMaster;
+
+struct I2CPendingMaster {
+ QEMUBH *bh;
+ QSIMPLEQ_ENTRY(I2CPendingMaster) entry;
+};
+
typedef QLIST_HEAD(I2CNodeList, I2CNode) I2CNodeList;
+typedef QSIMPLEQ_HEAD(I2CPendingMasters, I2CPendingMaster) I2CPendingMasters;
struct I2CBus {
BusState qbus;
I2CNodeList current_devs;
+ I2CPendingMasters pending_masters;
uint8_t saved_address;
bool broadcast;
+
+ /* Set from slave currently mastering the bus. */
+ QEMUBH *bh;
};
I2CBus *i2c_init_bus(DeviceState *parent, const char *name);
@@ -115,9 +131,23 @@ int i2c_start_recv(I2CBus *bus, uint8_t address);
*/
int i2c_start_send(I2CBus *bus, uint8_t address);
+/**
+ * i2c_start_send_async: start an asynchronous 'send' transfer on an I2C bus.
+ *
+ * @bus: #I2CBus to be used
+ * @address: address of the slave
+ *
+ * Return: 0 on success, -1 on error
+ */
+int i2c_start_send_async(I2CBus *bus, uint8_t address);
+
void i2c_end_transfer(I2CBus *bus);
void i2c_nack(I2CBus *bus);
+void i2c_ack(I2CBus *bus);
+void i2c_bus_master(I2CBus *bus, QEMUBH *bh);
+void i2c_bus_release(I2CBus *bus);
int i2c_send(I2CBus *bus, uint8_t data);
+int i2c_send_async(I2CBus *bus, uint8_t data);
uint8_t i2c_recv(I2CBus *bus);
bool i2c_scan_bus(I2CBus *bus, uint8_t address, bool broadcast,
I2CNodeList *current_devs);