Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 67 additions & 10 deletions drivers/eeprom/eeprom_at2x.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ static int eeprom_at2x_read(const struct device *dev, off_t offset, void *buf,
{
const struct eeprom_at2x_config *config = dev->config;
struct eeprom_at2x_data *data = dev->data;
int err;
uint8_t *pbuf = buf;
int ret;

if (!len) {
return 0;
Expand All @@ -104,14 +105,21 @@ static int eeprom_at2x_read(const struct device *dev, off_t offset, void *buf,
}

k_mutex_lock(&data->lock, K_FOREVER);
err = config->read_fn(dev, offset, buf, len);
k_mutex_unlock(&data->lock);
while (len) {
ret = config->read_fn(dev, offset, pbuf, len);
if (ret < 0) {
LOG_ERR("failed to read EEPROM (err %d)", ret);
k_mutex_unlock(&data->lock);
return ret;
}

if (err) {
LOG_ERR("failed to read EEPROM (err %d)", err);
return err;
pbuf += ret;
offset += ret;
len -= ret;
}

k_mutex_unlock(&data->lock);

return 0;
}

Expand Down Expand Up @@ -201,29 +209,66 @@ static size_t eeprom_at2x_size(const struct device *dev)
}

#ifdef CONFIG_EEPROM_AT24

/**
* @brief translate an offset to a device address / offset pair
*
* It allows to address several devices as a continuous memory region
* but also to address higher part of eeprom for chips
* with more than 2^(addr_width) adressable word.
*/
static uint16_t eeprom_at24_translate_offset(const struct device *dev,
off_t *offset)
{
const struct eeprom_at2x_config *config = dev->config;

const uint16_t addr_incr = *offset >> config->addr_width;
*offset &= BIT_MASK(config->addr_width);

return config->bus_addr + addr_incr;
}

static size_t eeprom_at24_adjust_read_count(const struct device *dev,
off_t offset, size_t len)
{
const struct eeprom_at2x_config *config = dev->config;
const size_t remainder = BIT(config->addr_width) - offset;

if (len > remainder) {
len = remainder;
}

return len;
}

static int eeprom_at24_read(const struct device *dev, off_t offset, void *buf,
size_t len)
{
const struct eeprom_at2x_config *config = dev->config;
struct eeprom_at2x_data *data = dev->data;
int64_t timeout;
uint8_t addr[2];
uint16_t bus_addr;
int err;

bus_addr = eeprom_at24_translate_offset(dev, &offset);

if (config->addr_width == 16) {
sys_put_be16(offset, addr);
} else {
addr[0] = offset & BIT_MASK(8);
}

len = eeprom_at24_adjust_read_count(dev, offset, len);

/*
* A write cycle may be in progress so reads must be attempted
* until the current write cycle should be completed.
*/
timeout = k_uptime_get() + config->timeout;
while (1) {
int64_t now = k_uptime_get();
err = i2c_write_read(data->bus_dev, config->bus_addr,
err = i2c_write_read(data->bus_dev, bus_addr,
addr, config->addr_width / 8,
buf, len);
if (!err || now > timeout) {
Expand All @@ -232,7 +277,11 @@ static int eeprom_at24_read(const struct device *dev, off_t offset, void *buf,
k_sleep(K_MSEC(1));
}

return err;
if (err < 0) {
return err;
}

return len;
}

static int eeprom_at24_write(const struct device *dev, off_t offset,
Expand All @@ -243,9 +292,12 @@ static int eeprom_at24_write(const struct device *dev, off_t offset,
int count = eeprom_at2x_limit_write_count(dev, offset, len);
uint8_t block[config->addr_width / 8 + count];
int64_t timeout;
uint16_t bus_addr;
int i = 0;
int err;

bus_addr = eeprom_at24_translate_offset(dev, &offset);

/*
* Not all I2C EEPROMs support repeated start so the the
* address (offset) and data (buf) must be provided in one
Expand All @@ -266,7 +318,7 @@ static int eeprom_at24_write(const struct device *dev, off_t offset,
while (1) {
int64_t now = k_uptime_get();
err = i2c_write(data->bus_dev, block, sizeof(block),
config->bus_addr);
bus_addr);
if (!err || now > timeout) {
break;
}
Expand Down Expand Up @@ -404,7 +456,12 @@ static int eeprom_at25_read(const struct device *dev, off_t offset, void *buf,
return err;
}

return spi_transceive(data->bus_dev, &data->spi_cfg, &tx, &rx);
err = spi_transceive(data->bus_dev, &data->spi_cfg, &tx, &rx);
if (err < 0) {
return err;
}

return len;
}

static int eeprom_at25_wren(const struct device *dev)
Expand Down