1 /*
2  * Copyright (c) 2023, Nordic Semiconductor ASA
3  * Copyright (c) 2023, Bjarki Arge Andreasen
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #define DT_DRV_COMPAT zephyr_retained_reg
9 
10 #include <string.h>
11 #include <zephyr/device.h>
12 #include <zephyr/devicetree.h>
13 #include <zephyr/drivers/retained_mem.h>
14 #include <zephyr/kernel.h>
15 #include <zephyr/sys/util.h>
16 #include <zephyr/logging/log.h>
17 
18 LOG_MODULE_REGISTER(retained_mem_zephyr_reg, CONFIG_RETAINED_MEM_LOG_LEVEL);
19 
20 struct zephyr_retained_mem_reg_data {
21 #ifdef CONFIG_RETAINED_MEM_MUTEXES
22 	struct k_mutex lock;
23 #endif
24 };
25 
26 struct zephyr_retained_mem_reg_config {
27 	uint8_t *address;
28 	size_t size;
29 };
30 
zephyr_retained_mem_reg_lock_take(const struct device * dev)31 static inline void zephyr_retained_mem_reg_lock_take(const struct device *dev)
32 {
33 #ifdef CONFIG_RETAINED_MEM_MUTEXES
34 	struct zephyr_retained_mem_reg_data *data = dev->data;
35 
36 	k_mutex_lock(&data->lock, K_FOREVER);
37 #else
38 	ARG_UNUSED(dev);
39 #endif
40 }
41 
zephyr_retained_mem_reg_lock_release(const struct device * dev)42 static inline void zephyr_retained_mem_reg_lock_release(const struct device *dev)
43 {
44 #ifdef CONFIG_RETAINED_MEM_MUTEXES
45 	struct zephyr_retained_mem_reg_data *data = dev->data;
46 
47 	k_mutex_unlock(&data->lock);
48 #else
49 	ARG_UNUSED(dev);
50 #endif
51 }
52 
zephyr_retained_mem_reg_init(const struct device * dev)53 static int zephyr_retained_mem_reg_init(const struct device *dev)
54 {
55 #ifdef CONFIG_RETAINED_MEM_MUTEXES
56 	struct zephyr_retained_mem_reg_data *data = dev->data;
57 
58 	k_mutex_init(&data->lock);
59 #endif
60 
61 	return 0;
62 }
63 
zephyr_retained_mem_reg_size(const struct device * dev)64 static ssize_t zephyr_retained_mem_reg_size(const struct device *dev)
65 {
66 	const struct zephyr_retained_mem_reg_config *config = dev->config;
67 
68 	return (ssize_t)config->size;
69 }
70 
zephyr_retained_mem_reg_read(const struct device * dev,off_t offset,uint8_t * buffer,size_t size)71 static int zephyr_retained_mem_reg_read(const struct device *dev, off_t offset, uint8_t *buffer,
72 					size_t size)
73 {
74 	const struct zephyr_retained_mem_reg_config *config = dev->config;
75 
76 	zephyr_retained_mem_reg_lock_take(dev);
77 
78 	memcpy(buffer, (config->address + offset), size);
79 
80 	zephyr_retained_mem_reg_lock_release(dev);
81 
82 	return 0;
83 }
84 
zephyr_retained_mem_reg_write(const struct device * dev,off_t offset,const uint8_t * buffer,size_t size)85 static int zephyr_retained_mem_reg_write(const struct device *dev, off_t offset,
86 					 const uint8_t *buffer, size_t size)
87 {
88 	const struct zephyr_retained_mem_reg_config *config = dev->config;
89 
90 	zephyr_retained_mem_reg_lock_take(dev);
91 
92 	memcpy((config->address + offset), buffer, size);
93 
94 	zephyr_retained_mem_reg_lock_release(dev);
95 
96 	return 0;
97 }
98 
zephyr_retained_mem_reg_clear(const struct device * dev)99 static int zephyr_retained_mem_reg_clear(const struct device *dev)
100 {
101 	const struct zephyr_retained_mem_reg_config *config = dev->config;
102 
103 	zephyr_retained_mem_reg_lock_take(dev);
104 
105 	memset(config->address, 0, config->size);
106 
107 	zephyr_retained_mem_reg_lock_release(dev);
108 
109 	return 0;
110 }
111 
112 static DEVICE_API(retained_mem, zephyr_retained_mem_reg_api) = {
113 	.size = zephyr_retained_mem_reg_size,
114 	.read = zephyr_retained_mem_reg_read,
115 	.write = zephyr_retained_mem_reg_write,
116 	.clear = zephyr_retained_mem_reg_clear,
117 };
118 
119 #define ZEPHYR_RETAINED_MEM_REG_DEVICE(inst)							\
120 	static struct zephyr_retained_mem_reg_data zephyr_retained_mem_reg_data_##inst;		\
121 	static const struct zephyr_retained_mem_reg_config					\
122 			zephyr_retained_mem_reg_config_##inst = {				\
123 		.address = (uint8_t *)DT_INST_REG_ADDR(inst),					\
124 		.size = DT_INST_REG_SIZE(inst),							\
125 	};											\
126 	DEVICE_DT_INST_DEFINE(inst,								\
127 			      &zephyr_retained_mem_reg_init,					\
128 			      NULL,								\
129 			      &zephyr_retained_mem_reg_data_##inst,				\
130 			      &zephyr_retained_mem_reg_config_##inst,				\
131 			      POST_KERNEL,							\
132 			      CONFIG_RETAINED_MEM_INIT_PRIORITY,				\
133 			      &zephyr_retained_mem_reg_api);
134 
135 DT_INST_FOREACH_STATUS_OKAY(ZEPHYR_RETAINED_MEM_REG_DEVICE)
136