1 /*
2 * Copyright (c) 2021 Telink Semiconductor
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT telink_b91_flash_controller
8 #define FLASH_SIZE DT_REG_SIZE(DT_INST(0, soc_nv_flash))
9
10 #include "flash.h"
11 #include <device.h>
12 #include <drivers/flash.h>
13
14
15 /* driver data structure */
16 struct flash_b91_data {
17 struct k_sem write_lock;
18 };
19
20 /* driver parameters structure */
21 static const struct flash_parameters flash_b91_parameters = {
22 .write_block_size = DT_PROP(DT_INST(0, soc_nv_flash), write_block_size),
23 .erase_value = 0xff,
24 };
25
26
27 /* Check for correct offset and length */
flash_b91_is_range_valid(off_t offset,size_t len)28 static bool flash_b91_is_range_valid(off_t offset, size_t len)
29 {
30 /* check for min value */
31 if ((offset < 0) || (len < 1)) {
32 return false;
33 }
34
35 /* check for max value */
36 if ((offset + len) > FLASH_SIZE) {
37 return false;
38 }
39
40 return true;
41 }
42
43 /* API implementation: driver initialization */
flash_b91_init(const struct device * dev)44 static int flash_b91_init(const struct device *dev)
45 {
46 struct flash_b91_data *dev_data = dev->data;
47
48 k_sem_init(&dev_data->write_lock, 1, 1);
49
50 return 0;
51 }
52
53 /* API implementation: erase */
flash_b91_erase(const struct device * dev,off_t offset,size_t len)54 static int flash_b91_erase(const struct device *dev, off_t offset, size_t len)
55 {
56 int page_nums = len / PAGE_SIZE;
57 struct flash_b91_data *dev_data = dev->data;
58
59 /* return SUCCESS if len equals 0 (required by tests/drivers/flash) */
60 if (!len) {
61 return 0;
62 }
63
64 /* check for valid range */
65 if (!flash_b91_is_range_valid(offset, len)) {
66 return -EINVAL;
67 }
68
69 /* Erase can be done only by pages */
70 if (((offset % PAGE_SIZE) != 0) || ((len % PAGE_SIZE) != 0)) {
71 return -EINVAL;
72 }
73
74 /* take semaphore */
75 if (k_sem_take(&dev_data->write_lock, K_NO_WAIT)) {
76 return -EACCES;
77 }
78
79 /* erase flash page by page */
80 for (int i = 0; i < page_nums; i++) {
81 flash_erase_page(offset);
82 offset += PAGE_SIZE;
83 }
84
85 /* release semaphore */
86 k_sem_give(&dev_data->write_lock);
87
88 return 0;
89 }
90
91 /* API implementation: write */
flash_b91_write(const struct device * dev,off_t offset,const void * data,size_t len)92 static int flash_b91_write(const struct device *dev, off_t offset,
93 const void *data, size_t len)
94 {
95 struct flash_b91_data *dev_data = dev->data;
96
97 /* return SUCCESS if len equals 0 (required by tests/drivers/flash) */
98 if (!len) {
99 return 0;
100 }
101
102 /* check for valid range */
103 if (!flash_b91_is_range_valid(offset, len)) {
104 return -EINVAL;
105 }
106
107 /* take semaphore */
108 if (k_sem_take(&dev_data->write_lock, K_NO_WAIT)) {
109 return -EACCES;
110 }
111
112 /* write flash */
113 flash_write_page(offset, len, (unsigned char *)data);
114
115 /* release semaphore */
116 k_sem_give(&dev_data->write_lock);
117
118 return 0;
119 }
120
121 /* API implementation: read */
flash_b91_read(const struct device * dev,off_t offset,void * data,size_t len)122 static int flash_b91_read(const struct device *dev, off_t offset,
123 void *data, size_t len)
124 {
125 ARG_UNUSED(dev);
126
127 /* return SUCCESS if len equals 0 (required by tests/drivers/flash) */
128 if (!len) {
129 return 0;
130 }
131
132 /* check for valid range */
133 if (!flash_b91_is_range_valid(offset, len)) {
134 return -EINVAL;
135 }
136
137 /* read flash */
138 flash_read_page(offset, len, (unsigned char *)data);
139
140 return 0;
141 }
142
143 /* API implementation: get_parameters */
144 static const struct flash_parameters *
flash_b91_get_parameters(const struct device * dev)145 flash_b91_get_parameters(const struct device *dev)
146 {
147 ARG_UNUSED(dev);
148
149 return &flash_b91_parameters;
150 }
151
152 /* API implementation: page_layout */
153 #if defined(CONFIG_FLASH_PAGE_LAYOUT)
154 static const struct flash_pages_layout dev_layout = {
155 .pages_count = FLASH_SIZE / PAGE_SIZE,
156 .pages_size = PAGE_SIZE,
157 };
158
flash_b91_pages_layout(const struct device * dev,const struct flash_pages_layout ** layout,size_t * layout_size)159 static void flash_b91_pages_layout(const struct device *dev,
160 const struct flash_pages_layout **layout,
161 size_t *layout_size)
162 {
163 *layout = &dev_layout;
164 *layout_size = 1;
165 }
166 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
167
168 static struct flash_b91_data flash_data;
169
170 static const struct flash_driver_api flash_b91_api = {
171 .erase = flash_b91_erase,
172 .write = flash_b91_write,
173 .read = flash_b91_read,
174 .get_parameters = flash_b91_get_parameters,
175 #if defined(CONFIG_FLASH_PAGE_LAYOUT)
176 .page_layout = flash_b91_pages_layout,
177 #endif
178 };
179
180 /* Driver registration */
181 DEVICE_DT_INST_DEFINE(0, flash_b91_init,
182 NULL, &flash_data, NULL, POST_KERNEL,
183 CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &flash_b91_api);
184