Commit 4495ed7d authored by Adam Wujek's avatar Adam Wujek

[BUG: #249] userspace/libwr: implement soft reset of i2c bus

The I2C transfer can be interrupted by a restart of a switch. An I2C slave
is not aware about an ARM restart so it expect the continuation of the
transfer.
Signed-off-by: 's avatarAdam Wujek <dev_public@wujek.eu>
parent 225a0169
......@@ -2,6 +2,7 @@
* i2c_bitbang.c
*/
#include <stdlib.h>
#include <string.h>
#include <libwr/util.h>
......@@ -14,6 +15,7 @@ static int32_t i2c_bitbang_transfer(struct i2c_bus *bus, uint32_t address,
uint32_t to_write, uint32_t to_read,
uint8_t * data);
static int32_t i2c_bitbang_scan(struct i2c_bus *bus, uint32_t address);
void i2c_slave_soft_reset(struct i2c_bus *i2c_bus, int i);
int i2c_bitbang_init_bus(struct i2c_bus *bus)
{
......@@ -36,6 +38,9 @@ int i2c_bitbang_init_bus(struct i2c_bus *bus)
bus->transfer = i2c_bitbang_transfer;
bus->scan = i2c_bitbang_scan;
/* Perform a soft reset of a bus */
i2c_slave_soft_reset(bus, -1);
return 0;
}
......@@ -70,6 +75,35 @@ static void mi2c_stop(struct i2c_bitbang *bus)
mi2c_pin_out(bus->sda, 1);
}
void i2c_slave_soft_reset(struct i2c_bus *i2c_bus, int port)
{
int i = 0;
struct i2c_bitbang *bb_bus;
bb_bus = (struct i2c_bitbang *)i2c_bus->type_specific;
shw_pio_setdir(bb_bus->sda, PIO_IN); //let SDA float so we can read it
shw_udelay(I2C_DELAY); // wait for the SDA to become stable
if (shw_pio_get(bb_bus->sda)) {
uint8_t tmp;
/* read from address 0 on this bus, just in case the bus before
* reset was in the middle of transfer of an address */
i2c_bitbang_transfer(i2c_bus, 0x0, 0, 1, &tmp);
/* bus in correct state, nothing to do */
return;
}
while(!shw_pio_get(bb_bus->sda) && i < 30) {
mi2c_pin_out(bb_bus->scl, 1);
mi2c_pin_out(bb_bus->scl, 0);
mi2c_pin_out(bb_bus->scl, 1);
i++;
}
mi2c_stop(bb_bus);
}
static int mi2c_write_byte(struct i2c_bitbang *bus, uint8_t data)
{
int ack = 0;
......
......@@ -17,5 +17,6 @@ struct i2c_bitbang {
};
int i2c_bitbang_init_bus(struct i2c_bus *bus);
void i2c_slave_soft_reset(struct i2c_bus *i2c_bus, int port);
#endif //I2C_CPU_BB_H
......@@ -198,6 +198,8 @@ struct i2c_bus i2c_buses[] = {
int shw_sfp_buses_init(void)
{
int i;
uint8_t byte1, byte2;
struct i2c_bus* mux_bus;
pr_info("Initializing SFP I2C busses...\n");
for (i = 0; i < ARRAY_SIZE(i2c_buses); i++) {
......@@ -208,6 +210,15 @@ int shw_sfp_buses_init(void)
}
// printf("init: success: %s\n", i2c_buses[i].name);
}
mux_bus = &i2c_buses[WR_MUX_BUS];
for (i = WR_SFP2_BUS; i <= WR_SFP17_BUS; i++) {
/* Set the mask in the PCA9548 */
byte1 = (1 << bus_masks[i]) & 0xff;
byte2 = ((1 << bus_masks[i]) >> 8) & 0xff;
i2c_transfer(mux_bus, 0x70, 1, 0, &byte1);
i2c_transfer(mux_bus, 0x71, 1, 0, &byte2);
i2c_slave_soft_reset(mux_bus, i + 1);
}
return 0;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment