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