1 /*
2 * Copyright (c) 2023-2024 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 "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
56 address += cfg->flash_base;
57 MXC_FLC_Read(address, buffer, length);
58 return 0;
59 }
60
api_write(const struct device * dev,off_t address,const void * buffer,size_t length)61 static int api_write(const struct device *dev, off_t address, const void *buffer, size_t length)
62 {
63 const struct max32_flash_dev_config *const cfg = dev->config;
64 int ret = 0;
65
66 max32_sem_take(dev);
67
68 address += cfg->flash_base;
69 ret = MXC_FLC_Write(address, length, (uint32_t *)buffer);
70
71 max32_sem_give(dev);
72
73 return ret != 0 ? -EIO : 0;
74 }
75
api_erase(const struct device * dev,off_t start,size_t len)76 static int api_erase(const struct device *dev, off_t start, size_t len)
77 {
78 const struct max32_flash_dev_config *const cfg = dev->config;
79 uint32_t page_size = cfg->flash_erase_blk_sz;
80 uint32_t addr = (start + cfg->flash_base);
81 int ret = 0;
82
83 max32_sem_take(dev);
84
85 while (len) {
86 ret = MXC_FLC_PageErase(addr);
87 if (ret) {
88 break;
89 }
90
91 addr += page_size;
92 if (len > page_size) {
93 len -= page_size;
94 } else {
95 len = 0;
96 }
97 }
98
99 max32_sem_give(dev);
100
101 return ret != 0 ? -EIO : 0;
102 }
103
104 #if CONFIG_FLASH_PAGE_LAYOUT
api_page_layout(const struct device * dev,const struct flash_pages_layout ** layout,size_t * layout_size)105 static void api_page_layout(const struct device *dev, const struct flash_pages_layout **layout,
106 size_t *layout_size)
107 {
108 const struct max32_flash_dev_config *const cfg = dev->config;
109
110 *layout = &cfg->pages_layouts;
111 *layout_size = 1;
112 }
113 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
114
api_get_parameters(const struct device * dev)115 static const struct flash_parameters *api_get_parameters(const struct device *dev)
116 {
117 const struct max32_flash_dev_config *const cfg = dev->config;
118
119 return &cfg->parameters;
120 }
121
flash_max32_init(const struct device * dev)122 static int flash_max32_init(const struct device *dev)
123 {
124 int ret = MXC_FLC_Init();
125
126 #ifdef CONFIG_MULTITHREADING
127 struct max32_flash_dev_data *data = dev->data;
128
129 /* Mutex for flash controller */
130 k_sem_init(&data->sem, 1, 1);
131 #endif
132 return ret != 0 ? -EIO : 0;
133 }
134
135 static DEVICE_API(flash, flash_max32_driver_api) = {
136 .read = api_read,
137 .write = api_write,
138 .erase = api_erase,
139 .get_parameters = api_get_parameters,
140 #ifdef CONFIG_FLASH_PAGE_LAYOUT
141 .page_layout = api_page_layout,
142 #endif
143 };
144
145 #if CONFIG_FLASH_PAGE_LAYOUT
146 #define FLASH_MAX32_CONFIG_PAGE_LAYOUT(n) \
147 .pages_layouts = { \
148 .pages_count = DT_INST_FOREACH_CHILD(n, GET_FLASH_SIZE) / \
149 DT_INST_FOREACH_CHILD(n, GET_ERASE_BLOCK_SIZE), \
150 .pages_size = DT_INST_FOREACH_CHILD(n, GET_ERASE_BLOCK_SIZE), \
151 },
152 #else
153 #define FLASH_MAX32_CONFIG_PAGE_LAYOUT(n)
154 #endif
155
156 #define GET_WRITE_BLOCK_SIZE(n) DT_PROP(n, write_block_size)
157 #define GET_ERASE_BLOCK_SIZE(n) DT_PROP(n, erase_block_size)
158 #define GET_FLASH_BASE(n) DT_REG_ADDR(n)
159 #define GET_FLASH_SIZE(n) DT_REG_SIZE(n)
160
161 #define DEFINE_FLASH_MAX32(_num) \
162 static const struct max32_flash_dev_config max32_flash_dev_cfg_##_num = { \
163 .flash_base = DT_INST_FOREACH_CHILD(_num, GET_FLASH_BASE), \
164 .flash_erase_blk_sz = DT_INST_FOREACH_CHILD(_num, GET_ERASE_BLOCK_SIZE), \
165 .parameters = \
166 { \
167 .write_block_size = \
168 DT_INST_FOREACH_CHILD(_num, GET_WRITE_BLOCK_SIZE), \
169 .erase_value = 0xFF, \
170 }, \
171 FLASH_MAX32_CONFIG_PAGE_LAYOUT(_num)}; \
172 static struct max32_flash_dev_data max32_flash_dev_data_##_num; \
173 DEVICE_DT_INST_DEFINE(_num, flash_max32_init, NULL, &max32_flash_dev_data_##_num, \
174 &max32_flash_dev_cfg_##_num, POST_KERNEL, \
175 CONFIG_FLASH_INIT_PRIORITY, &flash_max32_driver_api);
176
177 DT_INST_FOREACH_STATUS_OKAY(DEFINE_FLASH_MAX32)
178