1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Public API for retained memory drivers
10  */
11 
12 #ifndef ZEPHYR_INCLUDE_DRIVERS_RETAINED_MEM_
13 #define ZEPHYR_INCLUDE_DRIVERS_RETAINED_MEM_
14 
15 #include <stdint.h>
16 #include <stddef.h>
17 #include <sys/types.h>
18 #include <zephyr/kernel.h>
19 #include <zephyr/device.h>
20 #include <zephyr/types.h>
21 #include <zephyr/sys/math_extras.h>
22 
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26 
27 BUILD_ASSERT(!(sizeof(off_t) > sizeof(size_t)),
28 	     "Size of off_t must be equal or less than size of size_t");
29 
30 /**
31  * @brief Retained memory driver interface
32  * @defgroup retained_mem_interface Retained memory driver interface
33  * @since 3.4
34  * @version 0.8.0
35  * @ingroup io_interfaces
36  * @{
37  */
38 
39 /**
40  * @typedef	retained_mem_size_api
41  * @brief	Callback API to get size of retained memory area.
42  * See retained_mem_size() for argument description.
43  */
44 typedef ssize_t (*retained_mem_size_api)(const struct device *dev);
45 
46 /**
47  * @typedef	retained_mem_read_api
48  * @brief	Callback API to read from retained memory area.
49  * See retained_mem_read() for argument description.
50  */
51 typedef int (*retained_mem_read_api)(const struct device *dev, off_t offset, uint8_t *buffer,
52 				     size_t size);
53 
54 /**
55  * @typedef	retained_mem_write_api
56  * @brief	Callback API to write to retained memory area.
57  * See retained_mem_write() for argument description.
58  */
59 typedef int (*retained_mem_write_api)(const struct device *dev, off_t offset,
60 				      const uint8_t *buffer, size_t size);
61 
62 /**
63  * @typedef	retained_mem_clear_api
64  * @brief	Callback API to clear retained memory area (reset all data to 0x00).
65  * See retained_mem_clear() for argument description.
66  */
67 typedef int (*retained_mem_clear_api)(const struct device *dev);
68 
69 /**
70  * @brief Retained memory driver API
71  * API which can be used by a device to store data in a retained memory area. Retained memory is
72  * memory that is retained while the device is powered but is lost when power to the device is
73  * lost (note that low power modes in some devices may clear the data also). This may be in a
74  * non-initialised RAM region, or in specific registers, but is not reset when a different
75  * application begins execution or the device is rebooted (without power loss). It must support
76  * byte-level reading and writing without a need to erase data before writing.
77  *
78  * Note that drivers must implement all functions, none of the functions are optional.
79  */
80 __subsystem struct retained_mem_driver_api {
81 	retained_mem_size_api size;
82 	retained_mem_read_api read;
83 	retained_mem_write_api write;
84 	retained_mem_clear_api clear;
85 };
86 
87 /**
88  * @brief		Returns the size of the retained memory area.
89  *
90  * @param dev		Retained memory device to use.
91  *
92  * @retval		Positive value indicating size in bytes on success, else negative errno
93  *			code.
94  */
95 __syscall ssize_t retained_mem_size(const struct device *dev);
96 
z_impl_retained_mem_size(const struct device * dev)97 static inline ssize_t z_impl_retained_mem_size(const struct device *dev)
98 {
99 	struct retained_mem_driver_api *api = (struct retained_mem_driver_api *)dev->api;
100 
101 	return api->size(dev);
102 }
103 
104 /**
105  * @brief		Reads data from the Retained memory area.
106  *
107  * @param dev		Retained memory device to use.
108  * @param offset	Offset to read data from.
109  * @param buffer	Buffer to store read data in.
110  * @param size		Size of data to read.
111  *
112  * @retval		0 on success else negative errno code.
113  */
114 __syscall int retained_mem_read(const struct device *dev, off_t offset, uint8_t *buffer,
115 				size_t size);
116 
z_impl_retained_mem_read(const struct device * dev,off_t offset,uint8_t * buffer,size_t size)117 static inline int z_impl_retained_mem_read(const struct device *dev, off_t offset,
118 					   uint8_t *buffer, size_t size)
119 {
120 	struct retained_mem_driver_api *api = (struct retained_mem_driver_api *)dev->api;
121 	size_t area_size;
122 
123 	/* Validate user-supplied parameters */
124 	if (size == 0) {
125 		return 0;
126 	}
127 
128 	area_size = api->size(dev);
129 
130 	if (offset < 0 || size > area_size || (area_size - size) < (size_t)offset) {
131 		return -EINVAL;
132 	}
133 
134 	return api->read(dev, offset, buffer, size);
135 }
136 
137 /**
138  * @brief		Writes data to the Retained memory area - underlying data does not need to
139  *			be cleared prior to writing.
140  *
141  * @param dev		Retained memory device to use.
142  * @param offset	Offset to write data to.
143  * @param buffer	Data to write.
144  * @param size		Size of data to be written.
145  *
146  * @retval		0 on success else negative errno code.
147  */
148 __syscall int retained_mem_write(const struct device *dev, off_t offset, const uint8_t *buffer,
149 				 size_t size);
150 
z_impl_retained_mem_write(const struct device * dev,off_t offset,const uint8_t * buffer,size_t size)151 static inline int z_impl_retained_mem_write(const struct device *dev, off_t offset,
152 					    const uint8_t *buffer, size_t size)
153 {
154 	struct retained_mem_driver_api *api = (struct retained_mem_driver_api *)dev->api;
155 	size_t area_size;
156 
157 	/* Validate user-supplied parameters */
158 	if (size == 0) {
159 		return 0;
160 	}
161 
162 	area_size = api->size(dev);
163 
164 	if (offset < 0 || size > area_size || (area_size - size) < (size_t)offset) {
165 		return -EINVAL;
166 	}
167 
168 	return api->write(dev, offset, buffer, size);
169 }
170 
171 /**
172  * @brief		Clears data in the retained memory area by setting it to 0x00.
173  *
174  * @param dev		Retained memory device to use.
175  *
176  * @retval		0 on success else negative errno code.
177  */
178 __syscall int retained_mem_clear(const struct device *dev);
179 
z_impl_retained_mem_clear(const struct device * dev)180 static inline int z_impl_retained_mem_clear(const struct device *dev)
181 {
182 	struct retained_mem_driver_api *api = (struct retained_mem_driver_api *)dev->api;
183 
184 	return api->clear(dev);
185 }
186 
187 /**
188  * @}
189  */
190 
191 #ifdef __cplusplus
192 }
193 #endif
194 
195 #include <zephyr/syscalls/retained_mem.h>
196 
197 #endif /* ZEPHYR_INCLUDE_DRIVERS_RETAINED_MEM_ */
198