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>
This commit is contained in:
Steve Markgraf 2018-06-17 03:09:43 +02:00
parent 7ae9754ede
commit 0fb8849426
2 changed files with 136 additions and 0 deletions

View File

@ -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

View File

@ -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;
}