drivers: mb85rc: support use of multiple modules as a single one
Allow use of multiple mb85rc frams at contiguous i2c addresses as a single big fram module. Tested on mb85rc1mt used as two 32K modules, where the first one was at mb85rc1mt's first i2c address and the second one at mb85rc1mt's second i2c address. Signed-off-by: Jakub Michalski <jmichalski@internships.antmicro.com> Signed-off-by: Mateusz Sierszulski <msierszulski@antmicro.com>
This commit is contained in:
parent
a5c0a9656d
commit
f54a7b1602
|
@ -20,6 +20,7 @@ struct mb85rcxx_config {
|
|||
struct i2c_dt_spec i2c;
|
||||
struct gpio_dt_spec wp_gpio;
|
||||
size_t size;
|
||||
size_t pagesize;
|
||||
uint8_t addr_width;
|
||||
bool readonly;
|
||||
};
|
||||
|
@ -43,16 +44,31 @@ static uint16_t mb85rcxx_translate_address(const struct device *dev, off_t offse
|
|||
{
|
||||
const struct mb85rcxx_config *cfg = dev->config;
|
||||
|
||||
off_t page_offset = offset % cfg->pagesize;
|
||||
|
||||
if (cfg->addr_width > 8) {
|
||||
sys_put_be16(offset, addr);
|
||||
sys_put_be16(page_offset, addr);
|
||||
addr[0] &= BIT_MASK(cfg->addr_width - 8);
|
||||
} else {
|
||||
addr[0] = offset & BIT_MASK(cfg->addr_width);
|
||||
addr[0] = page_offset & BIT_MASK(cfg->addr_width);
|
||||
}
|
||||
|
||||
return cfg->i2c.addr + (offset >> cfg->addr_width);
|
||||
}
|
||||
|
||||
static size_t mb85rcxx_remaining_len_in_page(const struct device *dev, off_t offset, size_t len)
|
||||
{
|
||||
const struct mb85rcxx_config *cfg = dev->config;
|
||||
off_t page_offset = offset % cfg->pagesize;
|
||||
size_t rem = cfg->pagesize - page_offset;
|
||||
|
||||
if (rem > len) {
|
||||
rem = len;
|
||||
}
|
||||
|
||||
return rem;
|
||||
}
|
||||
|
||||
static int mb85rcxx_init(const struct device *dev)
|
||||
{
|
||||
const struct mb85rcxx_config *cfg = dev->config;
|
||||
|
@ -87,6 +103,7 @@ static int mb85rcxx_read(const struct device *dev, off_t offset, void *buf, size
|
|||
struct mb85rcxx_data *data = dev->data;
|
||||
uint8_t addr[2];
|
||||
uint16_t i2c_addr;
|
||||
size_t len_in_page;
|
||||
int ret;
|
||||
|
||||
if (offset + len > cfg->size) {
|
||||
|
@ -94,16 +111,27 @@ static int mb85rcxx_read(const struct device *dev, off_t offset, void *buf, size
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
i2c_addr = mb85rcxx_translate_address(dev, offset, addr);
|
||||
|
||||
k_mutex_lock(&data->lock, K_FOREVER);
|
||||
ret = i2c_write_read(cfg->i2c.bus, i2c_addr, addr, DIV_ROUND_UP(cfg->addr_width, 8), buf,
|
||||
len);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("failed to read FRAM (err %d)", ret);
|
||||
|
||||
while (len) {
|
||||
i2c_addr = mb85rcxx_translate_address(dev, offset, addr);
|
||||
len_in_page = mb85rcxx_remaining_len_in_page(dev, offset, len);
|
||||
|
||||
ret = i2c_write_read(cfg->i2c.bus, i2c_addr, addr, DIV_ROUND_UP(cfg->addr_width, 8),
|
||||
buf, len_in_page);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("failed to read FRAM (err %d)", ret);
|
||||
k_mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
len -= len_in_page;
|
||||
*(char *)&buf += len_in_page;
|
||||
offset += len_in_page;
|
||||
}
|
||||
|
||||
k_mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mb85rcxx_i2c_write(const struct device *dev, uint16_t i2c_addr, uint8_t *addr,
|
||||
|
@ -129,6 +157,7 @@ static int mb85rcxx_write(const struct device *dev, off_t offset, const void *bu
|
|||
struct mb85rcxx_data *data = dev->data;
|
||||
uint8_t addr[2];
|
||||
uint16_t i2c_addr;
|
||||
size_t len_in_page;
|
||||
int ret;
|
||||
|
||||
if (cfg->readonly) {
|
||||
|
@ -147,10 +176,24 @@ static int mb85rcxx_write(const struct device *dev, off_t offset, const void *bu
|
|||
return ret;
|
||||
}
|
||||
|
||||
i2c_addr = mb85rcxx_translate_address(dev, offset, addr);
|
||||
|
||||
k_mutex_lock(&data->lock, K_FOREVER);
|
||||
ret = mb85rcxx_i2c_write(dev, i2c_addr, addr, buf, len);
|
||||
|
||||
while (len) {
|
||||
i2c_addr = mb85rcxx_translate_address(dev, offset, addr);
|
||||
len_in_page = mb85rcxx_remaining_len_in_page(dev, offset, len);
|
||||
|
||||
ret = mb85rcxx_i2c_write(dev, i2c_addr, addr, buf, len);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("failed to write to FRAM (err %d)", ret);
|
||||
k_mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
len -= len_in_page;
|
||||
*(char *)&buf += len_in_page;
|
||||
offset += len_in_page;
|
||||
}
|
||||
|
||||
k_mutex_unlock(&data->lock);
|
||||
mb85rcxx_write_protect_set(dev, 1);
|
||||
return ret;
|
||||
|
@ -177,6 +220,9 @@ static const struct eeprom_driver_api mb85rcxx_driver_api = {
|
|||
IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, wp_gpios), \
|
||||
(.wp_gpio = GPIO_DT_SPEC_INST_GET(inst, wp_gpios),)) \
|
||||
.size = DT_INST_PROP(inst, size), \
|
||||
.pagesize = \
|
||||
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, pagesize), \
|
||||
(DT_INST_PROP(inst, pagesize)), (DT_INST_PROP(inst, size))), \
|
||||
.addr_width = DT_INST_PROP(inst, address_width), \
|
||||
.readonly = DT_INST_PROP(inst, read_only)}; \
|
||||
\
|
||||
|
|
|
@ -12,6 +12,12 @@ properties:
|
|||
required: true
|
||||
description: Total FRAM size in bytes.
|
||||
|
||||
pagesize:
|
||||
type: int
|
||||
description: |
|
||||
Size of the single FRAM module in bytes.
|
||||
If not provided it is assumed to be the same as total size.
|
||||
|
||||
address-width:
|
||||
type: int
|
||||
required: true
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
compatible = "fujitsu,mb85rcxx";
|
||||
reg = <0x1>;
|
||||
size = <131072>;
|
||||
pagesize = <131072>;
|
||||
address-width = <16>;
|
||||
wp-gpios = <&test_gpio 0 0>;
|
||||
/* read-only; */
|
||||
|
|
Loading…
Reference in a new issue