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