From: Nathael Pajani Date: Tue, 13 Sep 2016 16:23:54 +0000 (+0200) Subject: I2C driver fixes Move the release_bus part to a specific function as it blocks some... X-Git-Url: http://git.techno-innov.fr/?a=commitdiff_plain;h=ff026cf9c0f7614675acbc51519134c4a5f3b5d1;p=soft%2Flpc82x%2Fcore I2C driver fixes Move the release_bus part to a specific function as it blocks some devices and most will work without it. --- diff --git a/drivers/i2c.c b/drivers/i2c.c index 726bc3f..56d9e80 100644 --- a/drivers/i2c.c +++ b/drivers/i2c.c @@ -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 diff --git a/include/drivers/i2c.h b/include/drivers/i2c.h index b67c96d..3eb4e3e 100644 --- a/include/drivers/i2c.h +++ b/include/drivers/i2c.h @@ -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);