1 /*
2  * Copyright (c) 2023-2025 Analog Devices, Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT adi_max32_flash_controller
8 
9 #include <zephyr/kernel.h>
10 #include <zephyr/device.h>
11 #include <zephyr/drivers/flash.h>
12 #include <zephyr/init.h>
13 
14 #include "wrap_max32_flc.h"
15 
16 struct max32_flash_dev_config {
17 	uint32_t flash_base;
18 	uint32_t flash_erase_blk_sz;
19 	struct flash_parameters parameters;
20 #if CONFIG_FLASH_PAGE_LAYOUT
21 	struct flash_pages_layout pages_layouts;
22 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
23 };
24 
25 struct max32_flash_dev_data {
26 #ifdef CONFIG_MULTITHREADING
27 	struct k_sem sem;
28 #endif
29 };
30 
31 #ifdef CONFIG_MULTITHREADING
max32_sem_take(const struct device * dev)32 static inline void max32_sem_take(const struct device *dev)
33 {
34 	struct max32_flash_dev_data *data = dev->data;
35 
36 	k_sem_take(&data->sem, K_FOREVER);
37 }
38 
max32_sem_give(const struct device * dev)39 static inline void max32_sem_give(const struct device *dev)
40 {
41 	struct max32_flash_dev_data *data = dev->data;
42 
43 	k_sem_give(&data->sem);
44 }
45 #else
46 
47 #define max32_sem_take(dev)
48 #define max32_sem_give(dev)
49 
50 #endif /* CONFIG_MULTITHREADING */
51 
api_read(const struct device * dev,off_t address,void * buffer,size_t length)52 static int api_read(const struct device *dev, off_t address, void *buffer, size_t length)
53 {
54 	const struct max32_flash_dev_config *const cfg = dev->config;
55 	int ret = 0;
56 	unsigned int key = 0;
57 
58 	address += cfg->flash_base;
59 
60 	key = irq_lock();
61 
62 	ret = Wrap_MXC_FLC_Read(address, buffer, length);
63 
64 	irq_unlock(key);
65 
66 	return ret != 0 ? -EIO : 0;
67 }
68 
api_write(const struct device * dev,off_t address,const void * buffer,size_t length)69 static int api_write(const struct device *dev, off_t address, const void *buffer, size_t length)
70 {
71 	const struct max32_flash_dev_config *const cfg = dev->config;
72 	int ret = 0;
73 	unsigned int key = 0;
74 
75 	max32_sem_take(dev);
76 
77 	address += cfg->flash_base;
78 
79 	key = irq_lock();
80 
81 	ret = Wrap_MXC_FLC_Write(address, length, (uint32_t *)buffer);
82 
83 	irq_unlock(key);
84 
85 	max32_sem_give(dev);
86 
87 	return ret != 0 ? -EIO : 0;
88 }
89 
api_erase(const struct device * dev,off_t start,size_t len)90 static int api_erase(const struct device *dev, off_t start, size_t len)
91 {
92 	const struct max32_flash_dev_config *const cfg = dev->config;
93 	uint32_t page_size = cfg->flash_erase_blk_sz;
94 	uint32_t addr = (start + cfg->flash_base);
95 	int ret = 0;
96 	unsigned int key = 0;
97 
98 	max32_sem_take(dev);
99 
100 	key = irq_lock();
101 	while (len) {
102 		ret = MXC_FLC_PageErase(addr);
103 		if (ret) {
104 			break;
105 		}
106 
107 		addr += page_size;
108 		if (len > page_size) {
109 			len -= page_size;
110 		} else {
111 			len = 0;
112 		}
113 	}
114 	irq_unlock(key);
115 
116 	max32_sem_give(dev);
117 
118 	return ret != 0 ? -EIO : 0;
119 }
120 
121 #if CONFIG_FLASH_PAGE_LAYOUT
api_page_layout(const struct device * dev,const struct flash_pages_layout ** layout,size_t * layout_size)122 static void api_page_layout(const struct device *dev, const struct flash_pages_layout **layout,
123 			    size_t *layout_size)
124 {
125 	const struct max32_flash_dev_config *const cfg = dev->config;
126 
127 	*layout = &cfg->pages_layouts;
128 	*layout_size = 1;
129 }
130 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
131 
api_get_parameters(const struct device * dev)132 static const struct flash_parameters *api_get_parameters(const struct device *dev)
133 {
134 	const struct max32_flash_dev_config *const cfg = dev->config;
135 
136 	return &cfg->parameters;
137 }
138 
flash_max32_init(const struct device * dev)139 static int flash_max32_init(const struct device *dev)
140 {
141 	int ret = MXC_FLC_Init();
142 
143 #ifdef CONFIG_MULTITHREADING
144 	struct max32_flash_dev_data *data = dev->data;
145 
146 	/* Mutex for flash controller */
147 	k_sem_init(&data->sem, 1, 1);
148 #endif
149 	return ret != 0 ? -EIO : 0;
150 }
151 
152 static DEVICE_API(flash, flash_max32_driver_api) = {
153 	.read = api_read,
154 	.write = api_write,
155 	.erase = api_erase,
156 	.get_parameters = api_get_parameters,
157 #ifdef CONFIG_FLASH_PAGE_LAYOUT
158 	.page_layout = api_page_layout,
159 #endif
160 };
161 
162 #if CONFIG_FLASH_PAGE_LAYOUT
163 #define FLASH_MAX32_CONFIG_PAGE_LAYOUT(n)                                                          \
164 	.pages_layouts = {                                                                         \
165 		.pages_count = DT_INST_FOREACH_CHILD(n, GET_FLASH_SIZE) /                          \
166 			       DT_INST_FOREACH_CHILD(n, GET_ERASE_BLOCK_SIZE),                     \
167 		.pages_size = DT_INST_FOREACH_CHILD(n, GET_ERASE_BLOCK_SIZE),                      \
168 	},
169 #else
170 #define FLASH_MAX32_CONFIG_PAGE_LAYOUT(n)
171 #endif
172 
173 #define GET_WRITE_BLOCK_SIZE(n) DT_PROP(n, write_block_size)
174 #define GET_ERASE_BLOCK_SIZE(n) DT_PROP(n, erase_block_size)
175 #define GET_FLASH_BASE(n)       DT_REG_ADDR(n)
176 #define GET_FLASH_SIZE(n)       DT_REG_SIZE(n)
177 
178 #define DEFINE_FLASH_MAX32(_num)                                                                   \
179 	static const struct max32_flash_dev_config max32_flash_dev_cfg_##_num = {                  \
180 		.flash_base = DT_INST_FOREACH_CHILD(_num, GET_FLASH_BASE),                         \
181 		.flash_erase_blk_sz = DT_INST_FOREACH_CHILD(_num, GET_ERASE_BLOCK_SIZE),           \
182 		.parameters =                                                                      \
183 			{                                                                          \
184 				.write_block_size =                                                \
185 					DT_INST_FOREACH_CHILD(_num, GET_WRITE_BLOCK_SIZE),         \
186 				.erase_value = 0xFF,                                               \
187 			},                                                                         \
188 		FLASH_MAX32_CONFIG_PAGE_LAYOUT(_num)};                                             \
189 	static struct max32_flash_dev_data max32_flash_dev_data_##_num;                            \
190 	DEVICE_DT_INST_DEFINE(_num, flash_max32_init, NULL, &max32_flash_dev_data_##_num,          \
191 			      &max32_flash_dev_cfg_##_num, POST_KERNEL,                            \
192 			      CONFIG_FLASH_INIT_PRIORITY, &flash_max32_driver_api);
193 
194 DT_INST_FOREACH_STATUS_OKAY(DEFINE_FLASH_MAX32)
195