I2C driver fixes
authorNathael Pajani <nathael.pajani@ed3l.fr>
Tue, 13 Sep 2016 16:23:54 +0000 (18:23 +0200)
committerNathael Pajani <nathael.pajani@ed3l.fr>
Tue, 13 Sep 2016 16:23:54 +0000 (18:23 +0200)
Move the release_bus part to a specific function as it blocks some devices
and most will work without it.

drivers/i2c.c
include/drivers/i2c.h

index 726bc3f..56d9e80 100644 (file)
@@ -44,7 +44,6 @@
  *
  * clock : current i2c clock.
  * state : global state of the i2c engine.
- * master_status : status returned by i2c block as found in "status" register.
  *
  * ctrl_buf : This buffer, if used, must have the SAME size as out_buff.
  *           Then, instead of simply moving to the next byte, the corresponding condition
@@ -58,8 +57,6 @@ struct i2c_bus {
        uint32_t power_bit;
        volatile uint32_t clock;
        volatile uint32_t state;
-       volatile uint32_t master_status;
-       volatile uint32_t slave_status;
 
        volatile const char* out_buff;
        volatile const char* ctrl_buf;
@@ -112,20 +109,14 @@ static struct i2c_bus i2c_buses[NB_I2C_BUSSES] = {
 
 /* I2C Interrupt handler */
 /* Actual version will stop on NACKs */
-/* See LPC1764 user's manual UM10360 on page 457 (19.9.5) for details on I2C State machine */
 void I2C_Handler(uint32_t bus_num)
 {
-       uint8_t status = 0;
        uint8_t condition = I2C_CONT;
        struct i2c_bus* i2c = &(i2c_buses[bus_num]);
 
-       /* This handler deals with master read and master write only */
-       i2c->master_status = i2c->regs->status; /* Store current status */
-       i2c->slave_status = i2c->regs->status;
-       status = (i2c->regs->status & 0xFF);
-
        /* I2C State Machine ! */
-       switch (status) {
+       /* This handler deals with master read and master write only */
+       switch (i2c->regs->status & 0xFF) {
 
        /* Errors */
                case 0x00: /* Should never happen */
@@ -158,8 +149,10 @@ void I2C_Handler(uint32_t bus_num)
                        break;
 
        /* NACKs */
-               case 0x07:  /* NACK on Address */
-               case 0x09:  /* NACK on Data byte */
+               case 0x06:  /* NACK on Address */
+               case 0x07:
+               case 0x08:  /* NACK on Data byte */
+               case 0x09:
                        /* Send a STOP condition will end transactions and let the driver retry later. */
                        i2c->regs->master_ctrl = I2C_MASTER_STOP;
                        i2c->state = I2C_NACK;
@@ -305,8 +298,26 @@ static int i2c_perform_data_transfer(struct i2c_bus* i2c)
                        break;
        }
 
+       /* Done with the Bus, Disable the interrupts */
+       i2c->regs->int_en_clr = (I2C_ST_MASTER_PENDING | I2C_ST_MASTER_ARB_LOSS | I2C_ST_MASTER_STERR);
+       i2c->state = I2C_OK;
+
+       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.
+ */
+void i2c_release_bus(uint8_t bus_num)
+{
+       struct i2c_bus* i2c = NULL;
+       if (bus_num >= NB_I2C_BUSSES) {
+               return;
+       }
+       i2c = &(i2c_buses[bus_num]);
        /* Force device to release the bus :
-        *    send a START followed by a STOP (initiate transmission with nul write_length) */
+        *  send a START followed by a STOP (initiate transmission with nul write_length) */
        i2c->state = I2C_BUSY;
        i2c->write_length = 0;
        i2c->regs->master_data = 0;
@@ -314,11 +325,9 @@ static int i2c_perform_data_transfer(struct i2c_bus* i2c)
        i2c->regs->int_en_set = I2C_ST_MASTER_PENDING;
        do {} while (i2c->state == I2C_BUSY); /* FIXME : OS should schedule here */
        i2c->state = I2C_OK;
-       
+
        /* Done with the Bus, Disable the interrupts */ 
        i2c->regs->int_en_clr = (I2C_ST_MASTER_PENDING | I2C_ST_MASTER_ARB_LOSS | I2C_ST_MASTER_STERR);
-
-       return ret;
 }
 
 /* Read
index b67c96d..3eb4e3e 100644 (file)
@@ -101,6 +101,7 @@ enum i2c_state_machine_states {
 /***************************************************************************** */
 /*                Modules I2C access                                           */
 /***************************************************************************** */
+
 /* I2C Read
  * Performs a non-blocking read on the i2c bus.
  *   cmd_buf : buffer containing all control byte to be sent on the i2c bus
@@ -143,6 +144,12 @@ int i2c_read(uint8_t bus_num, const void *cmd_buf, size_t cmd_size, const void*
 int i2c_write(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
+ *   a start condition immediately followed by a stop condition.
+ */
+void i2c_release_bus(uint8_t bus_num);
+
 
 int i2c_set_timeout(uint8_t bus_num, uint16_t timeout);