aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve Markgraf <steve@steve-m.de>2018-06-17 03:09:43 +0200
committerSteve Markgraf <steve@steve-m.de>2018-06-17 03:09:43 +0200
commit0fb884942679d1246ae41d018764814401fd8c57 (patch)
treeabfbdafca949f2b0b3c06b21bb79f70fbcdb94b5
parent7ae9754ede8806df16977be28a4811fcf5eacdd0 (diff)
downloadosmo-fl2k-0fb884942679d1246ae41d018764814401fd8c57.tar.gz
osmo-fl2k-0fb884942679d1246ae41d018764814401fd8c57.tar.bz2
osmo-fl2k-0fb884942679d1246ae41d018764814401fd8c57.zip
lib: add I2C support
Note that the FL2000 only supports I2C transfers with a fixed length of 4 bytes. Signed-off-by: Steve Markgraf <steve@steve-m.de>
-rw-r--r--include/osmo-fl2k.h35
-rw-r--r--src/libosmo-fl2k.c101
2 files changed, 136 insertions, 0 deletions
diff --git a/include/osmo-fl2k.h b/include/osmo-fl2k.h
index 8d3cc3b..02ad4ad 100644
--- a/include/osmo-fl2k.h
+++ b/include/osmo-fl2k.h
@@ -37,6 +37,7 @@ enum fl2k_error {
FL2K_ERROR_NO_DEVICE = -2,
FL2K_ERROR_NOT_FOUND = -5,
FL2K_ERROR_BUSY = -6,
+ FL2K_ERROR_TIMEOUT = -7,
FL2K_ERROR_NO_MEM = -11,
};
@@ -121,6 +122,40 @@ FL2K_API int fl2k_start_tx(fl2k_dev_t *dev, fl2k_tx_cb_t cb,
*/
FL2K_API int fl2k_stop_tx(fl2k_dev_t *dev);
+/*!
+ * Read 4 bytes via the FL2K I2C bus
+ *
+ * \param dev the device handle given by fl2k_open()
+ * \param i2c_addr address of the I2C device
+ * \param reg_addr start address of the 4 bytes to be read
+ * \param data pointer to byte array of size 4
+ * \return 0 on success
+ * \note A read operation will look like this on the bus:
+ * START, I2C_ADDR(W), REG_ADDR, REP_START, I2C_ADDR(R), DATA[0], STOP
+ * START, I2C_ADDR(W), REG_ADDR+1, REP_START, I2C_ADDR(R), DATA[1], STOP
+ * START, I2C_ADDR(W), REG_ADDR+2, REP_START, I2C_ADDR(R), DATA[2], STOP
+ * START, I2C_ADDR(W), REG_ADDR+3, REP_START, I2C_ADDR(R), DATA[3], STOP
+ */
+FL2K_API int fl2k_i2c_read(fl2k_dev_t *dev, uint8_t i2c_addr,
+ uint8_t reg_addr, uint8_t *data);
+
+/*!
+ * Write 4 bytes via the FL2K I2C bus
+ *
+ * \param dev the device handle given by fl2k_open()
+ * \param i2c_addr address of the I2C device
+ * \param reg_addr start address of the 4 bytes to be written
+ * \param data pointer to byte array of size 4
+ * \return 0 on success
+ * \note A write operation will look like this on the bus:
+ * START, I2C_ADDR(W), REG_ADDR, DATA[0], STOP
+ * START, I2C_ADDR(W), REG_ADDR+1, DATA[1], STOP
+ * START, I2C_ADDR(W), REG_ADDR+2, DATA[2], STOP
+ * START, I2C_ADDR(W), REG_ADDR+3, DATA[3], STOP
+ */
+FL2K_API int fl2k_i2c_write(fl2k_dev_t *dev, uint8_t i2c_addr,
+ uint8_t reg_addr, uint8_t *data);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/libosmo-fl2k.c b/src/libosmo-fl2k.c
index 34b854e..1112539 100644
--- a/src/libosmo-fl2k.c
+++ b/src/libosmo-fl2k.c
@@ -985,3 +985,104 @@ int fl2k_stop_tx(fl2k_dev_t *dev)
return FL2K_ERROR_BUSY;
}
+
+int fl2k_i2c_read(fl2k_dev_t *dev, uint8_t i2c_addr, uint8_t reg_addr, uint8_t *data)
+{
+ int i, r, timeout = 1;
+ uint32_t reg;
+
+ if (!dev)
+ return FL2K_ERROR_INVALID_PARAM;
+
+ r = fl2k_read_reg(dev, 0x8020, &reg);
+ if (r < 0)
+ return r;
+
+ /* apply mask, clearing bit 30 disables periodic repetition of read */
+ reg &= 0x3ffc0000;
+
+ /* set I2C register and address, select I2C read (bit 7) */
+ reg |= (1 << 28) | (reg_addr << 8) | (1 << 7) | (i2c_addr & 0x7f);
+
+ r = fl2k_write_reg(dev, 0x8020, reg);
+ if (r < 0)
+ return r;
+
+ for (i = 0; i < 10; i++) {
+ sleep_ms(10);
+
+ r = fl2k_read_reg(dev, 0x8020, &reg);
+ if (r < 0)
+ return r;
+
+ /* check if operation completed */
+ if (reg & (1 << 31)) {
+ timeout = 0;
+ break;
+ }
+ }
+
+ if (timeout)
+ return FL2K_ERROR_TIMEOUT;
+
+ /* check if slave responded and all data was read */
+ if (reg & (0x0f << 24))
+ return FL2K_ERROR_NOT_FOUND;
+
+ /* read data from register 0x8024 */
+ return libusb_control_transfer(dev->devh, CTRL_IN, 0x40,
+ 0, 0x8024, data, 4, CTRL_TIMEOUT);
+}
+
+int fl2k_i2c_write(fl2k_dev_t *dev, uint8_t i2c_addr, uint8_t reg_addr, uint8_t *data)
+{
+ int i, r, timeout = 1;
+ uint32_t reg;
+
+ if (!dev)
+ return FL2K_ERROR_INVALID_PARAM;
+
+ /* write data to register 0x8028 */
+ r = libusb_control_transfer(dev->devh, CTRL_OUT, 0x41,
+ 0, 0x8028, data, 4, CTRL_TIMEOUT);
+
+ if (r < 0)
+ return r;
+
+ r = fl2k_read_reg(dev, 0x8020, &reg);
+ if (r < 0)
+ return r;
+
+ /* apply mask, clearing bit 30 disables periodic repetition of read */
+ reg &= 0x3ffc0000;
+
+ /* set I2C register and address */
+ reg |= (1 << 28) | (reg_addr << 8) | (i2c_addr & 0x7f);
+
+ r = fl2k_write_reg(dev, 0x8020, reg);
+ if (r < 0)
+ return r;
+
+ for (i = 0; i < 10; i++) {
+ sleep_ms(10);
+
+ r = fl2k_read_reg(dev, 0x8020, &reg);
+ if (r < 0)
+ return r;
+
+ /* check if operation completed */
+ if (reg & (1 << 31)) {
+ timeout = 0;
+ break;
+ }
+ }
+
+ if (timeout)
+ return FL2K_ERROR_TIMEOUT;
+
+ /* check if slave responded and all data was written */
+ if (reg & (0x0f << 24))
+ return FL2K_ERROR_NOT_FOUND;
+
+ return FL2K_SUCCESS;
+}