Skip to content

Commit 3950927

Browse files
committed
nvmem: Introduce EEPROM NVMEM support
wip Signed-off-by: Pieter De Gendt <[email protected]>
1 parent 675f93a commit 3950927

File tree

8 files changed

+423
-1
lines changed

8 files changed

+423
-1
lines changed

dts/bindings/mtd/eeprom-base.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33

44
# Common fields for EEPROM devices
55

6-
include: base.yaml
6+
include:
7+
- base.yaml
8+
- nvmem-provider.yaml
79

810
properties:
911
size:
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
description: |
4+
Non-Volatile Memory (NVMEM) provider.
5+
6+
NVMEM provider refers to an entity that implements methods to
7+
initialize, read and write the non-volatile memory.
8+
9+
properties:
10+
"#address-cells":
11+
type: int
12+
description: |
13+
Number of cells required to represent a child node's
14+
reg property address.
15+
16+
"#size-cells":
17+
type: int
18+
description: |
19+
Number of cells required to represent a child node's size.
20+
21+
child-binding:
22+
description: |
23+
Each child node of the NVMEM provider node represents
24+
an individual NVMEM cell. These should usually
25+
look like this:
26+
27+
cell_nodelabel: cell@START_OFFSET {
28+
reg = <0xSTART_OFFSET 0xSIZE>;
29+
};
30+
31+
properties:
32+
reg:
33+
type: array
34+
required: true
35+
description: |
36+
This should be in the format <OFFSET SIZE>, where OFFSET
37+
is the offset of the NVMEM cell relative to the base
38+
address of the parent memory, and SIZE is the size of
39+
the cell in bytes.
40+
41+
read-only:
42+
type: boolean
43+
description: Set this property if the cell is read-only.
44+
45+
bits:
46+
type: array
47+
description: |
48+
Is pair of bit location and number of bits, which specifies
49+
offset in bit and number of bits within the address range
50+
specified by reg property. Offset takes values from 0-7.

include/zephyr/nvmem.h

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
/*
2+
* Copyright (c) 2025 Basalte bv
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
/**
7+
* @file
8+
* @brief Main header file for NVMEM API.
9+
* @ingroup nvmem_interface
10+
*/
11+
12+
#ifndef ZEPHYR_INCLUDE_NVMEM_H_
13+
#define ZEPHYR_INCLUDE_NVMEM_H_
14+
15+
/**
16+
* @brief Interfaces for NVMEM cells.
17+
* @defgroup nvmem_interface NVMEM
18+
* @since 4.3
19+
* @version 0.1.0
20+
* @ingroup io_interfaces
21+
* @{
22+
*/
23+
24+
#include <sys/types.h>
25+
#include <zephyr/device.h>
26+
#include <zephyr/devicetree.h>
27+
#include <zephyr/devicetree/nvmem.h>
28+
29+
#ifdef __cplusplus
30+
extern "C" {
31+
#endif
32+
33+
/**
34+
* @name NVMEM cell flags
35+
* @anchor NVMEM_CELL_FLAGS
36+
* @{
37+
*/
38+
39+
#define NVMEM_CELL_READ_ONLY BIT(0)
40+
41+
/**
42+
* @brief Provides a type to hold NVMEM cell flags.
43+
*
44+
* @see @ref NVMEM_CELL_FLAGS.
45+
*/
46+
47+
typedef uint8_t nvmem_cell_flags_t;
48+
49+
/** @} */
50+
51+
/**
52+
* @brief Non-Volatile Memory cell representation.
53+
*/
54+
struct nvmem_cell {
55+
/** NVMEM parent controller device instance. */
56+
const struct device *dev;
57+
/** Offset of the NVMEM cell relative to the parent controller's base address */
58+
off_t offset;
59+
/** Size of the NVMEM cell */
60+
size_t size;
61+
/** Bit-flags for the NVMEM cell */
62+
nvmem_cell_flags_t flags;
63+
};
64+
65+
/**
66+
* @brief Static initializer for a struct nvmem_cell.
67+
*
68+
* This returns a static initializer for a struct nvmem_cell given a devicetree
69+
* node identifier and a name.
70+
*
71+
* Example devicetree fragment:
72+
*
73+
* @code{.dts}
74+
* mac_eeprom: mac_eeprom@2 {
75+
* #address-cells = <1>;
76+
* #size-cells = <1>;
77+
* mac_address: mac_address@fa {
78+
* reg = <0xfa 0x06>;
79+
* };
80+
* };
81+
*
82+
* eth: ethernet {
83+
* nvmem-cells = <&mac_address>;
84+
* nvmem-cell-names = "mac-address";
85+
* };
86+
* @endcode
87+
*
88+
* Example usage:
89+
*
90+
* @code{.c}
91+
* const struct nvmem_cell cell =;
92+
* NVMEM_CELL_GET_BY_NAME(DT_NODELABEL(eth), mac_address);
93+
*
94+
* // Initializes 'cell' to:
95+
* // {
96+
* // .dev = DEVICE_DT_GET(DT_NODELABEL(mac_eeprom)),
97+
* // .offset = 0xfa,
98+
* // .size = 6,
99+
* // }
100+
* @endcode
101+
*
102+
* @param node_id Devicetree node identifier.
103+
* @param name Lowercase-and-underscores name of an nvmem-cells element as defined by
104+
* the node's nvmem-cell-names property.
105+
*
106+
* @return Static initializer for a struct nvmem_cell for the property.
107+
*
108+
* @see NVMEM_CELL_INST_GET_BY_NAME
109+
*/
110+
#define NVMEM_CELL_GET_BY_NAME(node_id, name) \
111+
{ \
112+
.dev = DT_MTD_FROM_NVMEM_CELL(DT_NVMEM_CELL_BY_NAME(node_id, name)), \
113+
.offset = DT_REG_ADDR(DT_NVMEM_CELL_BY_NAME(nod_ide, name)), \
114+
.size = DT_REG_SIZE(DT_NVMEM_CELL_BY_NAME(node_id, name)), \
115+
.flags = COND_CODE_1(DT_PROP(DT_NVMEM_CELL_BY_NAME(node_id, name),read_only), \
116+
(NVMEM_CELL_READ_ONLY), (0)), \
117+
}
118+
119+
/**
120+
* @brief Static initializer for a struct nvmem_cell from a DT_DRV_COMPAT
121+
* instance.
122+
*
123+
* @param inst DT_DRV_COMPAT instance number
124+
* @param name Lowercase-and-underscores name of an nvmem-cells element as defined by
125+
* the node's nvmem-cell-names property.
126+
*
127+
* @return Static initializer for a struct nvmem_cell for the property.
128+
*
129+
* @see NVMEM_CELL_GET_BY_NAME
130+
*/
131+
#define NVMEM_CELL_INST_GET_BY_NAME(inst, name) NVMEM_CELL_GET_BY_NAME(DT_DRV_INST(inst), name)
132+
133+
/**
134+
* @brief Like NVMEM_CELL_GET_BY_NAME(), with a fallback to a default value.
135+
*
136+
* If the devicetree node identifier 'node_id' refers to a node with a property
137+
* 'nvmem-cells', this expands to <tt>NVMEM_CELL_GET_BY_NAME(node_id, name)</tt>. The
138+
* @p default_value parameter is not expanded in this case. Otherwise, this
139+
* expands to @p default_value.
140+
*
141+
* @param node_id Devicetree node identifier.
142+
* @param name Lowercase-and-underscores name of an nvmem-cells element as defined by
143+
* the node's nvmem-cell-names property.
144+
* @param default_value Fallback value to expand to.
145+
*
146+
* @return Static initializer for a struct nvmem_cell for the property,
147+
* or @p default_value if the node or property do not exist.
148+
*
149+
* @see NVMEM_CELL_INST_GET_BY_NAME_OR
150+
*/
151+
#define NVMEM_CELL_GET_BY_NAME_OR(node_id, name, default_value) \
152+
COND_CODE_1(DT_NODE_HAS_PROP(node_id, pwms), \
153+
(NVMEM_CELL_GET_BY_NAME(node_id, name)), \
154+
(default_value))
155+
156+
/**
157+
* @brief Like NVMEM_CELL_INST_GET_BY_NAME(), with a fallback to a default
158+
* value.
159+
*
160+
* @param inst DT_DRV_COMPAT instance number
161+
* @param name Lowercase-and-underscores name of an nvmem-cells element as defined by
162+
* the node's nvmem-cell-names property.
163+
* @param default_value Fallback value to expand to.
164+
*
165+
* @return Static initializer for a struct nvmem_cell for the property,
166+
* or @p default_value if the node or property do not exist.
167+
*
168+
* @see NVMEM_CELL_GET_BY_NAME_OR
169+
*/
170+
#define NVMEM_CELL_INST_GET_BY_NAME_OR(inst, name, default_value) \
171+
NVMEM_CELL_GET_BY_NAME_OR(DT_DRV_INST(inst), name, default_value)
172+
173+
/**
174+
* @brief Static initializer for a struct nvmem_cell.
175+
*
176+
* This returns a static initializer for a struct nvmem_cell given a devicetree
177+
* node identifier and an index.
178+
*
179+
* Example devicetree fragment:
180+
*
181+
* @code{.dts}
182+
* mac_eeprom: mac_eeprom@2 {
183+
* #address-cells = <1>;
184+
* #size-cells = <1>;
185+
* mac_address: mac_address@fa {
186+
* reg = <0xfa 0x06>;
187+
* };
188+
* };
189+
*
190+
* eth: ethernet {
191+
* nvmem-cells = <&mac_address>;
192+
* nvmem-cell-names = "mac-address";
193+
* };
194+
* @endcode
195+
*
196+
* Example usage:
197+
*
198+
* @code{.c}
199+
* const struct nvmem_cell cell =;
200+
* NVMEM_CELL_GET_BY_IDX(DT_NODELABEL(eth), 0);
201+
*
202+
* // Initializes 'cell' to:
203+
* // {
204+
* // .dev = DEVICE_DT_GET(DT_NODELABEL(mac_eeprom)),
205+
* // .offset = 0xfa,
206+
* // .size = 6,
207+
* // }
208+
* @endcode
209+
*
210+
* @param node_id Devicetree node identifier.
211+
* @param idx Logical index into 'nvmem-cells' property.
212+
*
213+
* @return Static initializer for a struct nvmem_cell for the property.
214+
*
215+
* @see NVMEM_CELL_INST_GET_BY_IDX
216+
*/
217+
#define NVMEM_CELL_GET_BY_IDX(node_id, idx) \
218+
{ \
219+
.dev = DT_MTD_FROM_NVMEM_CELL(DT_NVMEM_CELL_BY_IDX(node_id, idx)), \
220+
.offset = DT_REG_ADDR(DT_NVMEM_CELL_BY_IDX(node_id, idx)), \
221+
.size = DT_REG_SIZE(DT_NVMEM_CELL_BY_IDX(node_id, idx)), \
222+
.flags = COND_CODE_1(DT_PROP(DT_NVMEM_CELL_BY_IDX(node_id, idx),read_only), \
223+
(NVMEM_CELL_READ_ONLY), (0)), \
224+
}
225+
226+
/**
227+
* @brief Static initializer for a struct nvmem_cell from a DT_DRV_COMPAT
228+
* instance.
229+
*
230+
* @param inst DT_DRV_COMPAT instance number
231+
* @param idx Logical index into 'nvmem-cells' property.
232+
*
233+
* @return Static initializer for a struct nvmem_cell for the property.
234+
*
235+
* @see NVMEM_CELL_GET_BY_IDX
236+
*/
237+
#define NVMEM_CELL_INST_GET_BY_IDX(inst, idx) NVMEM_CELL_GET_BY_IDX(DT_DRV_INST(inst), idx)
238+
239+
/**
240+
* @brief Like NVMEM_CELL_GET_BY_IDX(), with a fallback to a default value.
241+
*
242+
* If the devicetree node identifier 'node_id' refers to a node with a property
243+
* 'nvmem-cells', this expands to <tt>NVMEM_CELL_GET_BY_IDX(node_id, idx)</tt>. The
244+
* @p default_value parameter is not expanded in this case. Otherwise, this
245+
* expands to @p default_value.
246+
*
247+
* @param node_id Devicetree node identifier.
248+
* @param idx Logical index into 'nvmem-cells' property.
249+
* @param default_value Fallback value to expand to.
250+
*
251+
* @return Static initializer for a struct nvmem_cell for the property,
252+
* or @p default_value if the node or property do not exist.
253+
*
254+
* @see NVMEM_CELL_INST_GET_BY_IDX_OR
255+
*/
256+
#define NVMEM_CELL_GET_BY_IDX_OR(node_id, idx, default_value) \
257+
COND_CODE_1(DT_NODE_HAS_PROP(node_id, nvmem_cells), \
258+
(NVMEM_CELL_GET_BY_IDX(node_id, idx)), \
259+
(default_value))
260+
261+
/**
262+
* @brief Like NVMEM_CELL_INST_GET_BY_IDX(), with a fallback to a default
263+
* value.
264+
*
265+
* @param inst DT_DRV_COMPAT instance number
266+
* @param idx Logical index into 'nvmem-cells' property.
267+
* @param default_value Fallback value to expand to.
268+
*
269+
* @return Static initializer for a struct nvmem_cell for the property,
270+
* or @p default_value if the node or property do not exist.
271+
*
272+
* @see NVMEM_CELL_GET_BY_IDX_OR
273+
*/
274+
#define NVMEM_CELL_INST_GET_BY_IDX_OR(inst, idx, default_value) \
275+
NVMEM_CELL_GET_BY_IDX_OR(DT_DRV_INST(inst), idx, default_value)
276+
277+
/**
278+
* @brief Read data from NVMEM cell.
279+
*
280+
* @param cell The NVMEM cell.
281+
* @param data Buffer to store read data.
282+
* @param len Number of bytes to read.
283+
*
284+
* @return 0 on success, negative errno code on failure.
285+
*/
286+
int nvmem_cell_read(const struct nvmem_cell *cell, void *data, size_t len);
287+
288+
/**
289+
* @brief Write data to NVMEM cell.
290+
*
291+
* @param cell The NVMEM cell.
292+
* @param data Buffer with data to write.
293+
* @param len Number of bytes to write.
294+
*
295+
* @return 0 on success, negative errno code on failure.
296+
*/
297+
int nvmem_cell_write(const struct nvmem_cell *cell, const void *data, size_t len);
298+
299+
#ifdef __cplusplus
300+
}
301+
#endif
302+
303+
/**
304+
* @}
305+
*/
306+
307+
#endif /* ZEPHYR_INCLUDE_NVMEM_H_ */

subsys/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ add_subdirectory_ifdef(CONFIG_JWT jwt)
5353
add_subdirectory_ifdef(CONFIG_LLEXT llext)
5454
add_subdirectory_ifdef(CONFIG_MODEM_MODULES modem)
5555
add_subdirectory_ifdef(CONFIG_NETWORKING net)
56+
add_subdirectory_ifdef(CONFIG_NVMEM nvmem)
5657
add_subdirectory_ifdef(CONFIG_PROFILING profiling)
5758
add_subdirectory_ifdef(CONFIG_RETENTION retention)
5859
add_subdirectory_ifdef(CONFIG_SECURE_STORAGE secure_storage)

subsys/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ source "subsys/mgmt/Kconfig"
3535
source "subsys/modbus/Kconfig"
3636
source "subsys/modem/Kconfig"
3737
source "subsys/net/Kconfig"
38+
source "subsys/nvmem/Kconfig"
3839
source "subsys/pm/Kconfig"
3940
source "subsys/pmci/Kconfig"
4041
source "subsys/portability/Kconfig"

subsys/nvmem/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
zephyr_library()
4+
5+
zephyr_library_sources(nvmem.c)

0 commit comments

Comments
 (0)