Skip to content

Commit 6351512

Browse files
author
Luna Pes
committed
drivers: eeprom: fm25xxx: add support for infineon fm25xxx FRAM
This driver adds support for the Infineon FM25XXX series of chips. Has been tested on Infineon FM25CL64B-G. Signed-off-by: Luna Pes <[email protected]>
1 parent 1cb0b6a commit 6351512

File tree

5 files changed

+290
-0
lines changed

5 files changed

+290
-0
lines changed

drivers/eeprom/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,5 @@ zephyr_library_sources_ifdef(CONFIG_EEPROM_AT2X_EMUL eeprom_at2x_emul.c)
2626
zephyr_library_sources_ifdef(CONFIG_EEPROM_MB85RCXX eeprom_mb85rcxx.c)
2727

2828
zephyr_library_sources_ifdef(CONFIG_EEPROM_MB85RSXX eeprom_mb85rsxx.c)
29+
30+
zephyr_library_sources_ifdef(CONFIG_EEPROM_FM25XXX eeprom_fm25xxx.c)

drivers/eeprom/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ source "drivers/eeprom/Kconfig.tmp11x"
100100
source "drivers/eeprom/Kconfig.xec"
101101
source "drivers/eeprom/Kconfig.mb85rcxx"
102102
source "drivers/eeprom/Kconfig.mb85rsxx"
103+
source "drivers/eeprom/Kconfig.fm25xxx"
103104

104105
config EEPROM_SIMULATOR
105106
bool "Simulated EEPROM driver"

drivers/eeprom/Kconfig.fm25xxx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright (c) 2025 Luna Pes <[email protected]>
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config EEPROM_FM25XXX
5+
bool "Infineon FM25XXX SPI FRAM"
6+
default y
7+
depends on DT_HAS_INFINEON_FM25XXX_ENABLED
8+
select SPI
9+
help
10+
Enable Infineon FM25XXX SPI FRAM

drivers/eeprom/eeprom_fm25xxx.c

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
/*
2+
* Copyright (c) 2025 Luna Pes <[email protected]>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/* This file implements the Infineon AN304 SPI Guide for F-RAM */
8+
9+
#include "zephyr/devicetree.h"
10+
#include "zephyr/kernel.h"
11+
#include "zephyr/sys/byteorder.h"
12+
#include "zephyr/sys/util.h"
13+
#include <zephyr/device.h>
14+
#include <zephyr/drivers/eeprom.h>
15+
#include <zephyr/drivers/spi.h>
16+
#include <zephyr/logging/log.h>
17+
18+
#define DT_DRV_COMPAT infineon_fm25xxx
19+
20+
LOG_MODULE_REGISTER(fm25xxx, CONFIG_EEPROM_LOG_LEVEL);
21+
22+
/* Registers */
23+
#define FM25XXX_WREN 0x06
24+
#define FM25XXX_WRDI 0x04
25+
#define FM25XXX_RDSR 0x05
26+
#define FM25XXX_WRSR 0x01
27+
#define FM25XXX_READ 0x03
28+
#define FM25XXX_WRITE 0x02
29+
30+
struct fm25xxx_config {
31+
struct spi_dt_spec spi;
32+
size_t size;
33+
bool readonly;
34+
};
35+
36+
struct fm25xxx_data {
37+
struct k_mutex lock;
38+
};
39+
40+
static uint8_t eeprom_fm25xxx_size_to_addr_bytes(size_t size)
41+
{
42+
if (size <= 500) {
43+
return 1;
44+
} else if (size <= 64000) {
45+
return 2;
46+
} else {
47+
return 3;
48+
}
49+
}
50+
51+
static int eeprom_fm25xxx_set_enable_write(const struct device *dev, bool enable_writes)
52+
{
53+
const struct fm25xxx_config *config = dev->config;
54+
uint8_t op = enable_writes ? FM25XXX_WREN : FM25XXX_WRDI;
55+
56+
const struct spi_buf tx_bufs[] = {{
57+
.buf = &op,
58+
.len = sizeof(op),
59+
}};
60+
const struct spi_buf_set tx_buf_set = {
61+
.buffers = tx_bufs,
62+
.count = ARRAY_SIZE(tx_bufs),
63+
};
64+
65+
spi_write_dt(&config->spi, &tx_buf_set);
66+
67+
return 0;
68+
}
69+
70+
int eeprom_fm25xxx_read(const struct device *dev, off_t offset, void *data, size_t len)
71+
{
72+
int ret;
73+
const struct fm25xxx_config *config = dev->config;
74+
struct fm25xxx_data *dev_data = dev->data;
75+
76+
if (offset + len > config->size) {
77+
LOG_ERR("Can not read more data than the device size");
78+
return -EINVAL;
79+
}
80+
81+
if (len == 0) {
82+
return 0;
83+
}
84+
85+
uint8_t read_op[4] = {FM25XXX_READ};
86+
87+
size_t addr_bytes = eeprom_fm25xxx_size_to_addr_bytes(config->size);
88+
size_t op_len = 1 + addr_bytes;
89+
90+
switch (addr_bytes) {
91+
case 1:
92+
read_op[1] = offset & 0xff;
93+
break;
94+
case 2:
95+
sys_put_be16(offset, &read_op[1]);
96+
break;
97+
case 3:
98+
sys_put_be24(offset, &read_op[1]);
99+
break;
100+
default:
101+
LOG_ERR("Invalid number of address bytes %u", addr_bytes);
102+
return -EINVAL;
103+
}
104+
105+
LOG_HEXDUMP_WRN(read_op, 4, "Read op");
106+
107+
const struct spi_buf tx_bufs[] = {{
108+
.buf = &read_op,
109+
.len = op_len,
110+
}};
111+
const struct spi_buf_set tx_buf_set = {
112+
.buffers = tx_bufs,
113+
.count = ARRAY_SIZE(tx_bufs),
114+
};
115+
116+
const struct spi_buf rx_bufs[2] = {
117+
{
118+
.buf = NULL,
119+
.len = op_len,
120+
},
121+
{
122+
.buf = data,
123+
.len = len,
124+
},
125+
};
126+
const struct spi_buf_set rx_buf_set = {
127+
.buffers = rx_bufs,
128+
.count = ARRAY_SIZE(rx_bufs),
129+
};
130+
131+
ret = spi_transceive_dt(&config->spi, &tx_buf_set, &rx_buf_set);
132+
133+
if (ret != 0) {
134+
LOG_ERR("Failed to read from FRAM");
135+
return ret;
136+
}
137+
138+
return 0;
139+
}
140+
141+
int eeprom_fm25xxx_write(const struct device *dev, off_t offset, const void *data, size_t len)
142+
{
143+
int ret;
144+
const struct fm25xxx_config *config = dev->config;
145+
struct fm25xxx_data *dev_data = dev->data;
146+
147+
if (config->readonly) {
148+
LOG_ERR("Can not write to a readonly device");
149+
return -EACCES;
150+
}
151+
152+
if (offset + len > config->size) {
153+
LOG_ERR("Can not write more data than the device size");
154+
return -EINVAL;
155+
}
156+
157+
if (len == 0) {
158+
return 0;
159+
}
160+
161+
uint8_t write_op[4] = {FM25XXX_WRITE};
162+
163+
size_t addr_bytes = eeprom_fm25xxx_size_to_addr_bytes(config->size);
164+
size_t op_len = 1 + addr_bytes;
165+
166+
switch (addr_bytes) {
167+
case 1:
168+
write_op[1] = offset & 0xff;
169+
break;
170+
case 2:
171+
sys_put_be16(offset, &write_op[1]);
172+
break;
173+
case 3:
174+
sys_put_be24(offset, &write_op[1]);
175+
break;
176+
default:
177+
LOG_ERR("Invalid number of address bytes %u", addr_bytes);
178+
return -EINVAL;
179+
}
180+
181+
const struct spi_buf tx_bufs[] = {
182+
{
183+
.buf = &write_op,
184+
.len = op_len,
185+
},
186+
{
187+
.buf = (void *)data,
188+
.len = len,
189+
},
190+
};
191+
const struct spi_buf_set tx_buf_set = {
192+
.buffers = tx_bufs,
193+
.count = ARRAY_SIZE(tx_bufs),
194+
};
195+
196+
k_mutex_lock(&dev_data->lock, K_FOREVER);
197+
198+
ret = eeprom_fm25xxx_set_enable_write(dev, true);
199+
if (ret != 0) {
200+
k_mutex_unlock(&dev_data->lock);
201+
LOG_ERR("Could not enable writes");
202+
return ret;
203+
}
204+
205+
ret = spi_write_dt(&config->spi, &tx_buf_set);
206+
if (ret != 0) {
207+
k_mutex_unlock(&dev_data->lock);
208+
LOG_ERR("Failed to write to FRAM");
209+
return ret;
210+
}
211+
212+
ret = eeprom_fm25xxx_set_enable_write(dev, false);
213+
if (ret != 0) {
214+
k_mutex_unlock(&dev_data->lock);
215+
LOG_ERR("Could not disable writes");
216+
return ret;
217+
}
218+
219+
k_mutex_unlock(&dev_data->lock);
220+
221+
return 0;
222+
}
223+
224+
size_t eeprom_fm25xxx_get_size(const struct device *dev)
225+
{
226+
const struct fm25xxx_config *config = dev->config;
227+
228+
return config->size;
229+
}
230+
231+
static int eeprom_fm25xxx_init(const struct device *dev)
232+
{
233+
const struct fm25xxx_config *config = dev->config;
234+
struct fm25xxx_data *data = dev->data;
235+
236+
k_mutex_init(&data->lock);
237+
238+
if (!spi_is_ready_dt(&config->spi)) {
239+
LOG_ERR("SPI bus not ready");
240+
return -ENODEV;
241+
}
242+
243+
return 0;
244+
}
245+
246+
static DEVICE_API(eeprom, eeprom_fm25xxx_api) = {
247+
.read = &eeprom_fm25xxx_read,
248+
.write = &eeprom_fm25xxx_write,
249+
.size = &eeprom_fm25xxx_get_size,
250+
};
251+
252+
#define FM25XXX_INIT(inst) \
253+
static struct fm25xxx_data fm25xxx_data_##inst; \
254+
static const struct fm25xxx_config fm25xxx_config_##inst = { \
255+
.spi = SPI_DT_SPEC_INST_GET(inst, SPI_OP_MODE_MASTER | SPI_WORD_SET(8), 0), \
256+
.size = DT_INST_PROP(inst, size), \
257+
.readonly = DT_INST_PROP(inst, read_only), \
258+
}; \
259+
\
260+
DEVICE_DT_INST_DEFINE(inst, eeprom_fm25xxx_init, NULL, &fm25xxx_data_##inst, \
261+
&fm25xxx_config_##inst, POST_KERNEL, CONFIG_EEPROM_INIT_PRIORITY, \
262+
&eeprom_fm25xxx_api);
263+
264+
DT_INST_FOREACH_STATUS_OKAY(FM25XXX_INIT)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright (c) 2025 Luna Pes <[email protected]>
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: Infineon FM25XXX SPI FRAM
5+
6+
compatible: "infineon,fm25xxx"
7+
8+
include: ["eeprom-base.yaml", spi-device.yaml]
9+
10+
properties:
11+
size:
12+
required: true
13+
description: Total FRAM size in bytes.

0 commit comments

Comments
 (0)