From fa3b4a1f1f5c12df695ab5aa866746983fa3080e Mon Sep 17 00:00:00 2001 From: Christian Klarhorst Date: Wed, 2 Nov 2022 12:42:08 +0100 Subject: [PATCH] soc/software: Support non 8bit i2c memory addresses Add another parameter to i2c_read/write to specify the size (in bytes) of the addresses. --- litex/soc/software/bios/cmds/cmd_i2c.c | 35 ++++++++++++++++----- litex/soc/software/bios/cmds/cmd_litedram.c | 2 +- litex/soc/software/libbase/i2c.c | 32 +++++++++++++------ litex/soc/software/libbase/i2c.h | 4 +-- 4 files changed, 53 insertions(+), 20 deletions(-) diff --git a/litex/soc/software/bios/cmds/cmd_i2c.c b/litex/soc/software/bios/cmds/cmd_i2c.c index af3d180ba..df7b165ac 100644 --- a/litex/soc/software/bios/cmds/cmd_i2c.c +++ b/litex/soc/software/bios/cmds/cmd_i2c.c @@ -30,10 +30,17 @@ static void i2c_write_handler(int nb_params, char **params) { int i; char *c; + unsigned int addr; unsigned char write_params[32]; // also indirectly limited by CMD_LINE_BUFFER_SIZE - if (nb_params < 2) { - printf("i2c_write [, ...]"); + if (nb_params < 3) { + printf("i2c_write [, ...]"); + return; + } + + addr = strtoul(params[1], &c, 0); + if (*c != 0) { + printf("Incorrect value of parameter addr"); return; } @@ -50,7 +57,7 @@ static void i2c_write_handler(int nb_params, char **params) } } - if (!i2c_write(write_params[0], write_params[1], &write_params[2], nb_params - 2)) { + if (!i2c_write(write_params[0], addr, &write_params[3], nb_params - 3, write_params[2])) { printf("Error during I2C write"); return; } @@ -60,19 +67,21 @@ define_command(i2c_write, i2c_write_handler, "Write over I2C", I2C_CMDS); /** * Command "i2c_read" * - * Read I2C slave memory using 7-bit slave address and 8-bit memory address. + * Read I2C slave memory using 7-bit slave address and 8*-bit memory address. * */ static void i2c_read_handler(int nb_params, char **params) { char *c; int len; - unsigned char slave_addr, addr; + unsigned char slave_addr; + unsigned int addr; unsigned char buf[256]; bool send_stop = true; + unsigned int addr_size = 1; if (nb_params < 3) { - printf("i2c_read []"); + printf("i2c_read [] []"); return; } @@ -106,7 +115,19 @@ static void i2c_read_handler(int nb_params, char **params) } } - if (!i2c_read(slave_addr, addr, buf, len, send_stop)) { + if (nb_params > 4) { + addr_size = strtoul(params[4], &c, 0); + if (*c != 0) { + printf("Incorrect addr_size value"); + return; + } + if ((addr_size<1) || (addr_size>4)) { + printf("addr_size needs to be between 1 and 4"); + return; + } + } + + if (!i2c_read(slave_addr, addr, buf, len, send_stop, addr_size)) { printf("Error during I2C read"); return; } diff --git a/litex/soc/software/bios/cmds/cmd_litedram.c b/litex/soc/software/bios/cmds/cmd_litedram.c index 132015b17..1d9f104f8 100644 --- a/litex/soc/software/bios/cmds/cmd_litedram.c +++ b/litex/soc/software/bios/cmds/cmd_litedram.c @@ -388,7 +388,7 @@ static void sdram_spd_handler(int nb_params, char **params) } } - if (!i2c_read(SPD_RW_ADDR(spdaddr), 0, buf, len, send_stop)) { + if (!i2c_read(SPD_RW_ADDR(spdaddr), 0, buf, len, send_stop, 1)) { printf("Error when reading SPD EEPROM"); return; } diff --git a/litex/soc/software/libbase/i2c.c b/litex/soc/software/libbase/i2c.c index b4ad80444..56f39c232 100644 --- a/litex/soc/software/libbase/i2c.c +++ b/litex/soc/software/libbase/i2c.c @@ -188,9 +188,13 @@ void i2c_reset(void) * Some chips require that after transmiting the address, there will be no STOP in between: * START WR(slaveaddr) WR(addr) START WR(slaveaddr) RD(data) RD(data) ... STOP */ -bool i2c_read(unsigned char slave_addr, unsigned char addr, unsigned char *data, unsigned int len, bool send_stop) +bool i2c_read(unsigned char slave_addr, unsigned int addr, unsigned char *data, unsigned int len, bool send_stop, unsigned int addr_size) { - int i; + int i, j; + + if ((addr_size<1) || (addr_size>4)) { + return false; + } i2c_start(); @@ -198,9 +202,11 @@ bool i2c_read(unsigned char slave_addr, unsigned char addr, unsigned char *data, i2c_stop(); return false; } - if(!i2c_transmit_byte(addr)) { - i2c_stop(); - return false; + for (j=addr_size-1;j>=0;j--) { + if(!i2c_transmit_byte((unsigned char)(0xff & (addr >> (8*j))))) { + i2c_stop(); + return false; + } } if (send_stop) { @@ -227,9 +233,13 @@ bool i2c_read(unsigned char slave_addr, unsigned char addr, unsigned char *data, * First writes the memory starting address, then writes the data: * START WR(slaveaddr) WR(addr) WR(data) WR(data) ... STOP */ -bool i2c_write(unsigned char slave_addr, unsigned char addr, const unsigned char *data, unsigned int len) +bool i2c_write(unsigned char slave_addr, unsigned int addr, const unsigned char *data, unsigned int len, unsigned int addr_size) { - int i; + int i, j; + + if ((addr_size<1) || (addr_size>4)) { + return false; + } i2c_start(); @@ -237,9 +247,11 @@ bool i2c_write(unsigned char slave_addr, unsigned char addr, const unsigned char i2c_stop(); return false; } - if(!i2c_transmit_byte(addr)) { - i2c_stop(); - return false; + for (j=addr_size-1;j>=0;j--) { + if(!i2c_transmit_byte((unsigned char)(0xff & (addr >> (8*j))))) { + i2c_stop(); + return false; + } } for (i = 0; i < len; ++i) { if(!i2c_transmit_byte(data[i])) { diff --git a/litex/soc/software/libbase/i2c.h b/litex/soc/software/libbase/i2c.h index 2344e0d39..46f774c9d 100644 --- a/litex/soc/software/libbase/i2c.h +++ b/litex/soc/software/libbase/i2c.h @@ -33,8 +33,8 @@ struct i2c_dev { #define I2C_ADDR_RD(addr) (((addr) << 1) | 1u) void i2c_reset(void); -bool i2c_write(unsigned char slave_addr, unsigned char addr, const unsigned char *data, unsigned int len); -bool i2c_read(unsigned char slave_addr, unsigned char addr, unsigned char *data, unsigned int len, bool send_stop); +bool i2c_write(unsigned char slave_addr, unsigned int addr, const unsigned char *data, unsigned int len, unsigned int addr_size); +bool i2c_read(unsigned char slave_addr, unsigned int addr, unsigned char *data, unsigned int len, bool send_stop, unsigned int addr_size); bool i2c_poll(unsigned char slave_addr); int i2c_send_init_cmds(void); struct i2c_dev *get_i2c_devs(void);