}
-
/***************************************************************************** */
/* I2C access */
/***************************************************************************** */
-static int i2c_perform_data_transfer(struct i2c_bus* i2c)
+
+/* Translate I2C state to 0 on success or a glibc error code.
+ */
+static int i2c_state(struct i2c_bus* i2c)
{
int ret = 0;
- /* Start the process */
- i2c->state = I2C_BUSY;
- i2c->regs->ctrl_set = I2C_START_FLAG;
- /* Wait for process completion */
- do {} while (i2c->state == I2C_BUSY);
-
/* Handle returned state (errors or OK) */
switch (i2c->state) {
case I2C_OK:
case I2C_NO_DATA:
/* Return 0 : success */
break;
+ case I2C_BUSY:
+ ret = -EAGAIN;
+ break;
case I2C_NACK:
ret = -EREMOTEIO;
break;
return ret;
}
+
/* Release Bus
* Some devices do not release the Bus at the end of a transaction if they don't receive
* a start condition immediately followed by a stop condition.
/* Read
- * Performs a non-blocking read on the module's i2c bus.
+ * Performs a blocking read on the module's i2c bus.
* cmd_buf : buffer containing all control byte to be sent on the i2c bus
* cmd_size : size of the cmd_buf command buffer
* ctrl_buf : buffer containing action to be done after sending, like repeated START conditions
return -EINVAL;
if (i2c->state == I2C_BUSY) {
- return -EBUSY;
+ return -EAGAIN;
}
if (i2c->state != I2C_OK) {
/* What should we do ??? someone failed to reset status ? */
}
+ i2c->state = I2C_BUSY;
+
/* Set up i2c structure for read operation */
/* command (write) buffer */
i2c->out_buff = cmd_buf;
i2c->read_length = count;
i2c->read_index = 0;
- ret = i2c_perform_data_transfer(i2c);
+ /* Start the process */
+ i2c->regs->ctrl_set = I2C_START_FLAG;
+ /* Wait for process completion */
+ do {} while (i2c->state == I2C_BUSY);
+
+ ret = i2c_state(i2c);
if (ret == 0) {
return i2c->read_index;
}
return ret;
}
-/* Write
+/* Asynchronous Write
* Performs a non-blocking write on the module's i2c bus.
* buf : buffer containing all byte to be sent on the i2c bus,
* including conrtol bytes (address, offsets, ...)
* FIXME : note that STOP + START conditions are not allowed, the STOP would lead to sending
* the first bytes of buf, creating an infinite loop.
* RETURN VALUE
- * Upon successfull completion, returns the number of bytes written. On error, returns a negative
+ * Upon successfull transmition start, returns 0. On error, returns a negative
* integer equivalent to errors from glibc.
*/
-int i2c_write(uint8_t bus_num, const void *buf, size_t count, const void* ctrl_buf)
+int i2c_write_async(uint8_t bus_num, const void *buf, size_t count, const void* ctrl_buf)
{
struct i2c_bus* i2c = &(i2c_buses[0]);
- int ret = 0;
/* Checks */
if (i2c->regs != LPC_I2C0)
return -EINVAL;
if (i2c->state == I2C_BUSY) {
- return -EBUSY;
+ return -EAGAIN;
}
if (i2c->state != I2C_OK) {
/* What should we do ??? someone failed to reset status ? */
}
+ i2c->state = I2C_BUSY;
+
/* Clear read information to prevent entering master receiver states */
i2c->read_length = 0;
i2c->in_buff = NULL;
- i2c->state = I2C_BUSY;
/* Set up i2c_bus structure for write operation */
i2c->out_buff = buf;
i2c->write_length = count;
i2c->repeated_start_restart = ctrl_buf;
i2c->restart_after_data = 0;
- ret = i2c_perform_data_transfer(i2c);
+ /* Start the process */
+ i2c->regs->ctrl_set = I2C_START_FLAG;
+
+ return 0;
+}
+
+
+/* Write
+ * Performs a blocking write on the module's i2c bus.
+ * buf : buffer containing all byte to be sent on the i2c bus,
+ * including conrtol bytes (address, offsets, ...)
+ * count : the number of bytes to be sent, including address bytes and so on.
+ * ctrl_buf : buffer containing action to be done after sending, like repeated START conditions
+ * FIXME : note that STOP + START conditions are not allowed, the STOP would lead to sending
+ * the first bytes of buf, creating an infinite loop.
+ * RETURN VALUE
+ * Upon successfull completion, returns the number of bytes written. On error, returns a negative
+ * integer equivalent to errors from glibc.
+ */
+int i2c_write(uint8_t bus_num, const void *buf, size_t count, const void* ctrl_buf)
+{
+ struct i2c_bus* i2c = &(i2c_buses[0]);
+ int ret;
+
+ ret = i2c_write_async(bus_num, buf, count, ctrl_buf);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Wait for process completion */
+ do {} while (i2c->state == I2C_BUSY);
+
+ ret = i2c_state(i2c);
if (ret == 0) {
return i2c->write_length;
}
cmd_buf[ 4 + (2 * i) ] = data[i];
}
}
- ret = i2c_write(conf->bus_num, cmd_buf, (3 + (len * 2)), NULL);
+ do {
+ ret = i2c_write(conf->bus_num, cmd_buf, (3 + (len * 2)), NULL);
+ } while (ret == -EAGAIN);
if (ret != (3 + (len * 2))) {
conf->probe_ok = 0;
return ret;
*(start - 1) = SSD130x_DATA_ONLY;
/* Send data on I2C bus */
- ret = i2c_write(conf->bus_num, (start - 2), (2 + len), NULL);
+ do {
+ ret = i2c_write(conf->bus_num, (start - 2), (2 + len), NULL);
+ } while (ret == -EAGAIN);
/* Restore gddram data */
*(start - 2) = conf->gddram[0];
if (ret != 0) {
return ret;
}
- ret = ssd130x_send_data(conf, conf->gddram + 4, GDDRAM_SIZE);
- if (ret != GDDRAM_SIZE) {
- return ret;
- }
- return 0;
+
+ /* Setup I2C transfer */
+ *(conf->gddram + 2) = conf->address;
+ *(conf->gddram + 3) = SSD130x_DATA_ONLY;
+
+ /* Send data on I2C bus */
+ do {
+ ret = i2c_write_async(conf->bus_num, conf->gddram + 2, 2 + GDDRAM_SIZE, NULL);
+ } while (ret == -EAGAIN);
+
+ return ret;
}
/* Change a "tile" in the GDDRAM memory.
/* Modules I2C access */
/***************************************************************************** */
/* I2C Read
- * Performs a non-blocking read on the i2c bus.
+ * Performs a blocking read on the i2c bus.
* cmd_buf : buffer containing all control byte to be sent on the i2c bus
* cmd_size : size of the cmd_buf command buffer
* ctrl_buf : buffer containing action to be done after sending, like repeated START conditions
int i2c_read(uint8_t bus_num, const void *cmd_buf, size_t cmd_size, const void* ctrl_buf, void* inbuff, size_t count);
/* I2C Write
- * Performs a non-blocking write on the i2c bus.
+ * Performs a blocking write on the i2c bus.
* buf : buffer containing all byte to be sent on the i2c bus,
* including conrtol bytes (address, offsets, ...)
* count : the number of bytes to be sent, including address bytes and so on.
* Upon successfull completion, returns the number of bytes written. On error, returns a negative
* integer equivalent to errors from glibc.
* -EBADFD : Device not initialized
- * -EBUSY : Device or ressource Busy or Arbitration lost
+ * -EAGAIN : Device already in use
+ * -EBUSY : Arbitration lost
* -EAGAIN : Device already in use
* -EINVAL : Invalid argument (buf)
* -EREMOTEIO : Device did not acknowledge
*/
int i2c_write(uint8_t bus_num, const void *buf, size_t count, const void* ctrl_buf);
+/* I2C Asynchronous Write
+ * Performs a non-blocking write on the i2c bus.
+ * buf : buffer containing all byte to be sent on the i2c bus,
+ * including conrtol bytes (address, offsets, ...)
+ * count : the number of bytes to be sent, including address bytes and so on.
+ * ctrl_buf : buffer containing action to be done after sending, like repeated START conditions
+ * ctrl_buf has the same size as cmd_buf
+ * FIXME : note that STOP + START conditions are not allowed, the STOP would lead to sending
+ * the first bytes of buf, creating an infinite loop.
+ * RETURN VALUE
+ * Upon successfull transmition start, returns 0. On error, returns a negative
+ * integer equivalent to errors from glibc.
+ * -EBADFD : Device not initialized
+ * -EAGAIN : Device already in use
+ * -EINVAL : Invalid argument (buf)
+ */
+int i2c_write_async(uint8_t bus_num, const void *buf, size_t count, const void* ctrl_buf);
+
/* Release Bus
* Some devices do not release the Bus at the end of a transaction if they don't receive