add read/write combinations
Change-Id: Idf9b05b985cdfd9281e6d8daf67f81171cda02f0
diff --git a/system/dev/soc/aml-a113/a113-bus.c b/system/dev/soc/aml-a113/a113-bus.c
index 9da0b73..45b1f7a 100644
--- a/system/dev/soc/aml-a113/a113-bus.c
+++ b/system/dev/soc/aml-a113/a113-bus.c
@@ -67,17 +67,24 @@
.release = a113_bus_release,
};
+static void i2chandler(aml_i2c_txn_t *txn) {
+ uint64_t *temp = (uint64_t*)txn->rx_buff;
+ printf("handler got back %016lx\n",*temp);
+ *temp = 0;
+}
+
+static uint8_t txbuff[8];
+static uint8_t rxbuff[8];
+
static int i2c_test_thread(void *arg) {
aml_i2c_connection_t *conn = arg;
- uint8_t buff[8] = {0,1,2,3,4,5,6,7};
+
printf("test thread\n");
while(1) {
+ txbuff[0] = 0x00;
printf("writing async\n");
- aml_i2c_wr_async(conn,buff,8,NULL);
- completion_signal(&conn->dev->txn_active);
+ aml_i2c_wr_rd_async(conn,txbuff,1,rxbuff,8,&i2chandler);
sleep(1);
- for(int i=0; i<8; i++)
- buff[i]++;
}
return 0;
}
@@ -146,7 +153,7 @@
aml_i2c_connection_t *conn3;
- aml_i2c_connect(&conn1,i2cb_dev,0x10,7);
+ aml_i2c_connect(&conn1,i2cb_dev,0x18,7);
aml_i2c_connect(&conn2,i2cb_dev,0x18,7);
aml_i2c_connect(&conn3,i2cb_dev,0x10,7);
diff --git a/system/dev/soc/aml-a113/aml-i2c.c b/system/dev/soc/aml-a113/aml-i2c.c
index b55c1a6..ea83965 100644
--- a/system/dev/soc/aml-a113/aml-i2c.c
+++ b/system/dev/soc/aml-a113/aml-i2c.c
@@ -41,6 +41,17 @@
return 0;
}
+zx_status_t aml_i2c_set_slave_addr(aml_i2c_dev_t *dev, uint16_t addr) {
+
+ addr &= 0x7f;
+ uint32_t reg = dev->virt_regs->slave_addr;
+ reg = reg & 0xff;
+ reg = reg | ((addr << 1) & 0xff);
+ dev->virt_regs->slave_addr = reg;
+
+ return ZX_OK;
+}
+
static int aml_i2c_thread(void *arg) {
aml_i2c_dev_t *dev = arg;
@@ -51,14 +62,25 @@
mtx_lock(&dev->mutex);
txn = list_remove_tail_type(&dev->txn_list,aml_i2c_txn_t,node);
mtx_unlock(&dev->mutex);
- uint64_t* temp = (uint64_t*)txn->tx_buff;
-
- aml_i2c_write(dev,txn->tx_buff,txn->tx_len);
- printf("Worker Got %016lx\n",*temp);
+ aml_i2c_set_slave_addr(dev, txn->conn->slave_addr);
+ if (txn->tx_len > 0) {
+ aml_i2c_write(dev,txn->tx_buff,txn->tx_len);
+ for (int i=0; i<8; i++) txn->tx_buff[i] = 7;//debug junk
+ if ((txn->cb) && (txn->rx_len == 0)) {
+ txn->cb(txn);
+ }
+ }
+ if (txn->rx_len > 0) {
+ aml_i2c_read(dev,txn->rx_buff,txn->rx_len);
+ if (txn->cb) {
+ txn->cb(txn);
+ }
+ }
txn->tx_len=0;
mtx_lock(&dev->mutex);
list_add_head(&dev->free_txn_list,&txn->node);
mtx_unlock(&dev->mutex);
+
}
printf("List empty...waiting\n");
completion_wait(&dev->txn_active, ZX_TIME_INFINITE);
@@ -95,42 +117,81 @@
return ZX_OK;
}
-zx_status_t aml_i2c_wr_async(aml_i2c_connection_t *conn, uint8_t *buff, uint32_t len, void* cb) {
+static aml_i2c_txn_t *aml_i2c_get_txn(aml_i2c_connection_t *conn) {
- ZX_DEBUG_ASSERT(conn);
- ZX_DEBUG_ASSERT(len <= 8);
-
+ //printf("getting lock\n");
+ mtx_lock(&conn->dev->mutex);
+ //printf("got lock\n");
aml_i2c_txn_t *txn;
- aml_i2c_dev_t *dev = conn->dev;
- ZX_DEBUG_ASSERT(dev);
-
- mtx_lock(&dev->mutex);
-
- txn = list_remove_head_type(&dev->free_txn_list, aml_i2c_txn_t, node);
+ txn = list_remove_head_type(&conn->dev->free_txn_list, aml_i2c_txn_t, node);
if (!txn) {
- printf("new txn\n");
+ //printf("new txn\n");
txn = calloc(1, sizeof(aml_i2c_txn_t));
if (!txn) {
- mtx_unlock(&dev->mutex);
- return ZX_ERR_NO_MEMORY;
+ mtx_unlock(&conn->dev->mutex);
+ return NULL;
}
- } else {
- printf("recycled txn\n");
}
+ mtx_unlock(&conn->dev->mutex);
+ return txn;
+}
- for (uint32_t i = 0; i < len; i++)
- txn->tx_buff[i] = buff[i];
- txn->tx_len = len;
- txn->rx_len = 0;
+static inline void aml_i2c_queue_txn(aml_i2c_connection_t *conn, aml_i2c_txn_t *txn){
+ mtx_lock(&conn->dev->mutex);
+ list_add_head(&conn->dev->txn_list, &txn->node);
+ mtx_unlock(&conn->dev->mutex);
+}
+
+static inline zx_status_t aml_i2c_queue_async(aml_i2c_connection_t *conn,
+ uint8_t *txbuff, uint32_t txlen,
+ uint8_t *rxbuff, uint32_t rxlen,
+ void* cb) {
+ ZX_DEBUG_ASSERT(conn);
+ ZX_DEBUG_ASSERT(txlen <= 8);
+ ZX_DEBUG_ASSERT(rxlen <= 8);
+
+ aml_i2c_txn_t *txn;
+
+ txn = aml_i2c_get_txn(conn);
+ if (!txn) return ZX_ERR_NO_MEMORY;
+
+ txn->tx_buff = txbuff;
+ txn->tx_len = txlen;
+ txn->rx_len = rxlen;
+ txn->rx_buff = rxbuff;
txn->cb = cb;
txn->conn = conn;
-//need mutex
- list_add_head(&dev->txn_list, &txn->node);
- mtx_unlock(&dev->mutex);
+
+ aml_i2c_queue_txn(conn,txn);
+ completion_signal(&conn->dev->txn_active);
return ZX_OK;
}
+zx_status_t aml_i2c_rd_async(aml_i2c_connection_t *conn, uint8_t *buff, uint32_t len, void* cb) {
+
+ ZX_DEBUG_ASSERT(buff);
+ return aml_i2c_queue_async(conn, NULL, 0, buff, len, cb);
+}
+
+zx_status_t aml_i2c_wr_async(aml_i2c_connection_t *conn, uint8_t *buff, uint32_t len, void* cb) {
+
+ ZX_DEBUG_ASSERT(buff);
+ return aml_i2c_queue_async(conn, buff, len, NULL, 0, cb);
+}
+
+zx_status_t aml_i2c_wr_rd_async(aml_i2c_connection_t *conn, uint8_t *txbuff, uint32_t txlen,
+ uint8_t *rxbuff, uint32_t rxlen,
+ void* cb) {
+
+ ZX_DEBUG_ASSERT(txbuff);
+ ZX_DEBUG_ASSERT(rxbuff);
+ return aml_i2c_queue_async(conn, txbuff, txlen, rxbuff, rxlen, cb);
+}
+
+
+
+
zx_status_t aml_i2c_write(aml_i2c_dev_t *dev, uint8_t *buff, uint32_t len) {
ZX_DEBUG_ASSERT(len<=8); //temporary hack, only transactions that can fit in hw buffer
@@ -203,16 +264,7 @@
return ZX_OK;
}
-zx_status_t aml_i2c_set_slave_addr(aml_i2c_dev_t *dev, uint16_t addr) {
- addr &= 0x7f;
- uint32_t reg = dev->virt_regs->slave_addr;
- reg = reg & 0xff;
- reg = reg | ((addr << 1) & 0xff);
- dev->virt_regs->slave_addr = reg;
-
- return ZX_OK;
-}
zx_status_t aml_i2c_connect(aml_i2c_connection_t **connection,
aml_i2c_dev_t *dev,
diff --git a/system/dev/soc/aml-a113/aml-i2c.h b/system/dev/soc/aml-a113/aml-i2c.h
index a5f565c..179540f 100644
--- a/system/dev/soc/aml-a113/aml-i2c.h
+++ b/system/dev/soc/aml-a113/aml-i2c.h
@@ -57,14 +57,16 @@
is the ability to do a write,read sequence without having another
transaction on the bus in between the write/read.
*/
-typedef struct {
+typedef struct aml_i2c_txn aml_i2c_txn_t;
+
+typedef struct aml_i2c_txn {
list_node_t node;
- uint8_t tx_buff[8];
+ uint8_t *tx_buff;
uint32_t tx_len;
- uint8_t rx_buff[8];
+ uint8_t *rx_buff;
uint32_t rx_len;
aml_i2c_connection_t *conn;
- void *cb;
+ void (*cb)(aml_i2c_txn_t *txn);
} aml_i2c_txn_t;
struct aml_i2c_dev {
@@ -96,4 +98,7 @@
uint32_t num_addr_bits);
zx_status_t aml_i2c_wr_async(aml_i2c_connection_t *conn, uint8_t *buff, uint32_t len, void* cb);
-zx_status_t aml_i2c_rd_async(aml_i2c_connection_t *conn, uint8_t *buff, uint32_t len, void* cb);
\ No newline at end of file
+zx_status_t aml_i2c_rd_async(aml_i2c_connection_t *conn, uint8_t *buff, uint32_t len, void* cb);
+zx_status_t aml_i2c_wr_rd_async(aml_i2c_connection_t *conn, uint8_t *txbuff, uint32_t txlen,
+ uint8_t *rxbuff, uint32_t rxlen,
+ void* cb);
\ No newline at end of file