Line data Source code
1 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 : * @brief Non-Volatile Memory cell representation.
35 : */
36 1 : struct nvmem_cell {
37 : /** NVMEM parent controller device instance. */
38 1 : const struct device *dev;
39 : /** Offset of the NVMEM cell relative to the parent controller's base address */
40 1 : off_t offset;
41 : /** Size of the NVMEM cell */
42 1 : size_t size;
43 : /** Indicator if the NVMEM cell is read-write or read-only */
44 1 : bool read_only;
45 : };
46 :
47 : /**
48 : * @brief Static initializer for a struct nvmem_cell.
49 : *
50 : * This returns a static initializer for a struct nvmem_cell given a devicetree
51 : * node identifier.
52 : *
53 : * @note This is a helper macro for other NVMEM_CELL_GET macros to initialize the
54 : * nvmem_cell struct.
55 : *
56 : * Example devicetree fragment:
57 : *
58 : * @code{.dts}
59 : * mac_eeprom: mac_eeprom@2 {
60 : * nvmem-layout {
61 : * compatible = "fixed-layout";
62 : * #address-cells = <1>;
63 : * #size-cells = <1>;
64 : *
65 : * mac_address: mac_address@fa {
66 : * reg = <0xfa 0x06>;
67 : * #nvmem-cell-cells = <0>;
68 : * };
69 : * };
70 : * };
71 : * @endcode
72 : *
73 : * Example usage:
74 : *
75 : * @code{.c}
76 : * const struct nvmem_cell cell = NVMEM_CELL_INIT(DT_NODELABEL(mac_address));
77 : *
78 : * // Initializes 'cell' to:
79 : * // {
80 : * // .dev = DEVICE_DT_GET(DT_NODELABEL(mac_eeprom)),
81 : * // .offset = 0xfa,
82 : * // .size = 6,
83 : * // .read_only = false,
84 : * // }
85 : * @endcode
86 : *
87 : * @param node_id Devicetree node identifier.
88 : *
89 : * @return Static initializer for a struct nvmem_cell
90 : */
91 1 : #define NVMEM_CELL_INIT(node_id) \
92 : { \
93 : .dev = DEVICE_DT_GET(DT_MTD_FROM_NVMEM_CELL(node_id)), \
94 : .offset = DT_REG_ADDR(node_id), \
95 : .size = DT_REG_SIZE(node_id), \
96 : .read_only = DT_PROP(node_id, read_only), \
97 : }
98 :
99 : /**
100 : * @brief Static initializer for a struct nvmem_cell.
101 : *
102 : * This returns a static initializer for a struct nvmem_cell given a devicetree
103 : * node identifier and a name.
104 : *
105 : * Example devicetree fragment:
106 : *
107 : * @code{.dts}
108 : * mac_eeprom: mac_eeprom@2 {
109 : * nvmem-layout {
110 : * compatible = "fixed-layout";
111 : * #address-cells = <1>;
112 : * #size-cells = <1>;
113 : *
114 : * mac_address: mac_address@fa {
115 : * reg = <0xfa 0x06>;
116 : * #nvmem-cell-cells = <0>;
117 : * };
118 : * };
119 : * };
120 : *
121 : * eth: ethernet {
122 : * nvmem-cells = <&mac_address>;
123 : * nvmem-cell-names = "mac-address";
124 : * };
125 : * @endcode
126 : *
127 : * Example usage:
128 : *
129 : * @code{.c}
130 : * const struct nvmem_cell cell =
131 : * NVMEM_CELL_GET_BY_NAME(DT_NODELABEL(eth), mac_address);
132 : *
133 : * // Initializes 'cell' to:
134 : * // {
135 : * // .dev = DEVICE_DT_GET(DT_NODELABEL(mac_eeprom)),
136 : * // .offset = 0xfa,
137 : * // .size = 6,
138 : * // .read_only = false,
139 : * // }
140 : * @endcode
141 : *
142 : * @param node_id Devicetree node identifier.
143 : * @param name Lowercase-and-underscores name of an nvmem-cells element as defined by
144 : * the node's nvmem-cell-names property.
145 : *
146 : * @return Static initializer for a struct nvmem_cell for the property.
147 : *
148 : * @see NVMEM_CELL_INST_GET_BY_NAME
149 : */
150 1 : #define NVMEM_CELL_GET_BY_NAME(node_id, name) NVMEM_CELL_INIT(DT_NVMEM_CELL_BY_NAME(node_id, name))
151 :
152 : /**
153 : * @brief Static initializer for a struct nvmem_cell from a DT_DRV_COMPAT
154 : * instance.
155 : *
156 : * @param inst DT_DRV_COMPAT instance number
157 : * @param name Lowercase-and-underscores name of an nvmem-cells element as defined by
158 : * the node's nvmem-cell-names property.
159 : *
160 : * @return Static initializer for a struct nvmem_cell for the property.
161 : *
162 : * @see NVMEM_CELL_GET_BY_NAME
163 : */
164 1 : #define NVMEM_CELL_INST_GET_BY_NAME(inst, name) NVMEM_CELL_GET_BY_NAME(DT_DRV_INST(inst), name)
165 :
166 : /**
167 : * @brief Like NVMEM_CELL_GET_BY_NAME(), with a fallback to a default value.
168 : *
169 : * If the devicetree node identifier 'node_id' refers to a node with a property
170 : * 'nvmem-cells', this expands to <tt>NVMEM_CELL_GET_BY_NAME(node_id, name)</tt>. The
171 : * @p default_value parameter is not expanded in this case. Otherwise, this
172 : * expands to @p default_value.
173 : *
174 : * @param node_id Devicetree node identifier.
175 : * @param name Lowercase-and-underscores name of an nvmem-cells element as defined by
176 : * the node's nvmem-cell-names property.
177 : * @param default_value Fallback value to expand to.
178 : *
179 : * @return Static initializer for a struct nvmem_cell for the property,
180 : * or @p default_value if the node or property do not exist.
181 : *
182 : * @see NVMEM_CELL_INST_GET_BY_NAME_OR
183 : */
184 1 : #define NVMEM_CELL_GET_BY_NAME_OR(node_id, name, default_value) \
185 : COND_CODE_1(DT_NODE_HAS_PROP(node_id, nvmem_cells), \
186 : (NVMEM_CELL_GET_BY_NAME(node_id, name)), \
187 : (default_value))
188 :
189 : /**
190 : * @brief Like NVMEM_CELL_INST_GET_BY_NAME(), with a fallback to a default
191 : * value.
192 : *
193 : * @param inst DT_DRV_COMPAT instance number
194 : * @param name Lowercase-and-underscores name of an nvmem-cells element as defined by
195 : * the node's nvmem-cell-names property.
196 : * @param default_value Fallback value to expand to.
197 : *
198 : * @return Static initializer for a struct nvmem_cell for the property,
199 : * or @p default_value if the node or property do not exist.
200 : *
201 : * @see NVMEM_CELL_GET_BY_NAME_OR
202 : */
203 1 : #define NVMEM_CELL_INST_GET_BY_NAME_OR(inst, name, default_value) \
204 : NVMEM_CELL_GET_BY_NAME_OR(DT_DRV_INST(inst), name, default_value)
205 :
206 : /**
207 : * @brief Static initializer for a struct nvmem_cell.
208 : *
209 : * This returns a static initializer for a struct nvmem_cell given a devicetree
210 : * node identifier and an index.
211 : *
212 : * Example devicetree fragment:
213 : *
214 : * @code{.dts}
215 : * mac_eeprom: mac_eeprom@2 {
216 : * nvmem-layout {
217 : * compatible = "fixed-layout";
218 : * #address-cells = <1>;
219 : * #size-cells = <1>;
220 : *
221 : * mac_address: mac_address@fa {
222 : * reg = <0xfa 0x06>;
223 : * #nvmem-cell-cells = <0>;
224 : * };
225 : * };
226 : * };
227 : *
228 : * eth: ethernet {
229 : * nvmem-cells = <&mac_address>;
230 : * nvmem-cell-names = "mac-address";
231 : * };
232 : * @endcode
233 : *
234 : * Example usage:
235 : *
236 : * @code{.c}
237 : * const struct nvmem_cell cell =
238 : * NVMEM_CELL_GET_BY_IDX(DT_NODELABEL(eth), 0);
239 : *
240 : * // Initializes 'cell' to:
241 : * // {
242 : * // .dev = DEVICE_DT_GET(DT_NODELABEL(mac_eeprom)),
243 : * // .offset = 0xfa,
244 : * // .size = 6,
245 : * // .read_only = false,
246 : * // }
247 : * @endcode
248 : *
249 : * @param node_id Devicetree node identifier.
250 : * @param idx Logical index into 'nvmem-cells' property.
251 : *
252 : * @return Static initializer for a struct nvmem_cell for the property.
253 : *
254 : * @see NVMEM_CELL_INST_GET_BY_IDX
255 : */
256 1 : #define NVMEM_CELL_GET_BY_IDX(node_id, idx) NVMEM_CELL_INIT(DT_NVMEM_CELL_BY_IDX(node_id, idx))
257 :
258 : /**
259 : * @brief Static initializer for a struct nvmem_cell from a DT_DRV_COMPAT
260 : * instance.
261 : *
262 : * @param inst DT_DRV_COMPAT instance number
263 : * @param idx Logical index into 'nvmem-cells' property.
264 : *
265 : * @return Static initializer for a struct nvmem_cell for the property.
266 : *
267 : * @see NVMEM_CELL_GET_BY_IDX
268 : */
269 1 : #define NVMEM_CELL_INST_GET_BY_IDX(inst, idx) NVMEM_CELL_GET_BY_IDX(DT_DRV_INST(inst), idx)
270 :
271 : /**
272 : * @brief Like NVMEM_CELL_GET_BY_IDX(), with a fallback to a default value.
273 : *
274 : * If the devicetree node identifier 'node_id' refers to a node with a property
275 : * 'nvmem-cells', this expands to <tt>NVMEM_CELL_GET_BY_IDX(node_id, idx)</tt>. The
276 : * @p default_value parameter is not expanded in this case. Otherwise, this
277 : * expands to @p default_value.
278 : *
279 : * @param node_id Devicetree node identifier.
280 : * @param idx Logical index into 'nvmem-cells' property.
281 : * @param default_value Fallback value to expand to.
282 : *
283 : * @return Static initializer for a struct nvmem_cell for the property,
284 : * or @p default_value if the node or property do not exist.
285 : *
286 : * @see NVMEM_CELL_INST_GET_BY_IDX_OR
287 : */
288 1 : #define NVMEM_CELL_GET_BY_IDX_OR(node_id, idx, default_value) \
289 : COND_CODE_1(DT_NODE_HAS_PROP(node_id, nvmem_cells), \
290 : (NVMEM_CELL_GET_BY_IDX(node_id, idx)), \
291 : (default_value))
292 :
293 : /**
294 : * @brief Like NVMEM_CELL_INST_GET_BY_IDX(), with a fallback to a default
295 : * value.
296 : *
297 : * @param inst DT_DRV_COMPAT instance number
298 : * @param idx Logical index into 'nvmem-cells' property.
299 : * @param default_value Fallback value to expand to.
300 : *
301 : * @return Static initializer for a struct nvmem_cell for the property,
302 : * or @p default_value if the node or property do not exist.
303 : *
304 : * @see NVMEM_CELL_GET_BY_IDX_OR
305 : */
306 1 : #define NVMEM_CELL_INST_GET_BY_IDX_OR(inst, idx, default_value) \
307 : NVMEM_CELL_GET_BY_IDX_OR(DT_DRV_INST(inst), idx, default_value)
308 :
309 : /**
310 : * @brief Read data from an NVMEM cell.
311 : *
312 : * @param cell The NVMEM cell.
313 : * @param data Buffer to store read data.
314 : * @param off The offset to start reading from.
315 : * @param len Number of bytes to read.
316 : *
317 : * @kconfig_dep{CONFIG_NVMEM}
318 : *
319 : * @return 0 on success, negative errno code on failure.
320 : */
321 1 : int nvmem_cell_read(const struct nvmem_cell *cell, void *data, off_t off, size_t len);
322 :
323 : /**
324 : * @brief Write data to an NVMEM cell.
325 : *
326 : * @param cell The NVMEM cell.
327 : * @param data Buffer with data to write.
328 : * @param off The offset to start writing to.
329 : * @param len Number of bytes to write.
330 : *
331 : * @kconfig_dep{CONFIG_NVMEM}
332 : *
333 : * @return 0 on success, negative errno code on failure.
334 : */
335 1 : int nvmem_cell_write(const struct nvmem_cell *cell, const void *data, off_t off, size_t len);
336 :
337 : /**
338 : * @brief Validate that the NVMEM cell is ready.
339 : *
340 : * @param cell The NVMEM cell.
341 : *
342 : * @return true if the NVMEM cell is ready for use and false otherwise.
343 : */
344 1 : static inline bool nvmem_cell_is_ready(const struct nvmem_cell *cell)
345 : {
346 : return cell != NULL && device_is_ready(cell->dev);
347 : }
348 :
349 : #ifdef __cplusplus
350 : }
351 : #endif
352 :
353 : /**
354 : * @}
355 : */
356 :
357 : #endif /* ZEPHYR_INCLUDE_NVMEM_H_ */
|