1 /*
2 * Copyright (c) 2024 Antmicro <www.antmicro.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief Driver for Fujitsu MB85RSXX FRAM over SPI.
10 */
11
12 #define DT_DRV_COMPAT fujitsu_mb85rsxx
13
14 #include <zephyr/device.h>
15 #include <zephyr/drivers/eeprom.h>
16 #include <zephyr/drivers/spi.h>
17 #include <zephyr/kernel.h>
18 #include <zephyr/sys/byteorder.h>
19
20 #include <zephyr/logging/log.h>
21 LOG_MODULE_REGISTER(mb85rsxx, CONFIG_EEPROM_LOG_LEVEL);
22
23 /* MB85RSXX instruction set */
24 #define EEPROM_MB85RSXX_WREN 0x06U /* Set Write Enable Latch */
25 #define EEPROM_MB85RSXX_WRDI 0x04U /* Reset Write Enable Latch */
26 #define EEPROM_MB85RSXX_RDSR 0x05U /* Read Status Register */
27 #define EEPROM_MB85RSXX_WRSR 0x01U /* Write Status Register */
28 #define EEPROM_MB85RSXX_READ 0x03U /* Read Memory Code */
29 #define EEPROM_MB85RSXX_WRITE 0x02U /* Write Memory Code */
30 #define EEPROM_MB85RSXX_RDID 0x9FU /* Read Device ID */
31 #define EEPROM_MB85RSXX_FSTRD 0x0BU /* Fast Read Memory Code */
32 #define EEPROM_MB85RSXX_SLEEP 0xB9U /* Sleep Mode */
33
34 /* MB85RSXX status register bits */
35 #define EEPROM_MB85RSXX_STATUS_WPEN BIT(7) /* Status Register Write Protect (RW) */
36 #define EEPROM_MB85RSXX_STATUS_BP1 BIT(3) /* Block protection 1 (RW) */
37 #define EEPROM_MB85RSXX_STATUS_BP0 BIT(2) /* Block protection 2 (RW) */
38 #define EEPROM_MB85RSXX_STATUS_WEL BIT(1) /* Write Enable Latch (RO) */
39
40 /* Fujitsu manufacturer ID (2 bytes) */
41 #define EEPROM_MB85RSXX_MAN_ID 0x04U
42 #define EEPROM_MB85RSXX_CON_CODE 0x7FU
43
44 /*
45 * MB85RSXX product ID (2 bytes); first byte provides memory size, so let's use a mask later when
46 * checking it
47 */
48 #define EEPROM_MB85RSXX_PROD_ID 0x20U
49 #define EEPROM_MB85RSXX_PROD_ID2 0x03U
50 #define EEPROM_MB85RSXX_PROD_MASK GENMASK(7, 5)
51
52 struct eeprom_mb85rsxx_config {
53 struct spi_dt_spec spi;
54 size_t size;
55 bool readonly;
56 };
57
58 struct eeprom_mb85rsxx_data {
59 struct k_mutex lock;
60 };
61
eeprom_mb85rsxx_read(const struct device * dev,off_t offset,void * buf,size_t len)62 static int eeprom_mb85rsxx_read(const struct device *dev, off_t offset, void *buf, size_t len)
63 {
64 const struct eeprom_mb85rsxx_config *config = dev->config;
65 struct eeprom_mb85rsxx_data *data = dev->data;
66 uint8_t cmd[4] = {EEPROM_MB85RSXX_READ, 0, 0, 0};
67 uint8_t *paddr = &cmd[1];
68 int err;
69
70 if (offset + len > config->size) {
71 LOG_ERR("attempt to read past device boundary");
72 return -EINVAL;
73 }
74
75 if (!len) {
76 return 0;
77 }
78
79 /* Populate address in command */
80 *paddr++ = (offset >> 16);
81 *paddr++ = (offset >> 8);
82 *paddr++ = offset;
83
84 const struct spi_buf tx_buf = {
85 .buf = cmd,
86 .len = sizeof(cmd),
87 };
88 const struct spi_buf_set tx = {
89 .buffers = &tx_buf,
90 .count = 1,
91 };
92 const struct spi_buf rx_bufs[2] = {
93 {
94 .buf = NULL,
95 .len = sizeof(cmd),
96 },
97 {
98 .buf = buf,
99 .len = len,
100 },
101 };
102 const struct spi_buf_set rx = {
103 .buffers = rx_bufs,
104 .count = ARRAY_SIZE(rx_bufs),
105 };
106
107 k_mutex_lock(&data->lock, K_FOREVER);
108
109 err = spi_transceive_dt(&config->spi, &tx, &rx);
110
111 k_mutex_unlock(&data->lock);
112
113 if (err < 0) {
114 LOG_ERR("failed to read FRAM (err %d)", err);
115 }
116
117 return err;
118 }
119
eeprom_mb85rsxx_wren(const struct device * dev)120 static int eeprom_mb85rsxx_wren(const struct device *dev)
121 {
122 const struct eeprom_mb85rsxx_config *config = dev->config;
123 uint8_t cmd = EEPROM_MB85RSXX_WREN;
124 const struct spi_buf tx_buf = {
125 .buf = &cmd,
126 .len = sizeof(cmd),
127 };
128 const struct spi_buf_set tx = {
129 .buffers = &tx_buf,
130 .count = 1,
131 };
132
133 return spi_write_dt(&config->spi, &tx);
134 }
135
eeprom_mb85rsxx_wrdi(const struct device * dev)136 static int eeprom_mb85rsxx_wrdi(const struct device *dev)
137 {
138 const struct eeprom_mb85rsxx_config *config = dev->config;
139 uint8_t cmd = EEPROM_MB85RSXX_WRDI;
140 const struct spi_buf tx_buf = {
141 .buf = &cmd,
142 .len = sizeof(cmd),
143 };
144 const struct spi_buf_set tx = {
145 .buffers = &tx_buf,
146 .count = 1,
147 };
148
149 return spi_write_dt(&config->spi, &tx);
150 }
151
eeprom_mb85rsxx_write(const struct device * dev,off_t offset,const void * buf,size_t len)152 static int eeprom_mb85rsxx_write(const struct device *dev, off_t offset, const void *buf,
153 size_t len)
154 {
155 const struct eeprom_mb85rsxx_config *config = dev->config;
156 struct eeprom_mb85rsxx_data *data = dev->data;
157 uint8_t cmd[4] = {EEPROM_MB85RSXX_WRITE, 0, 0, 0};
158 uint8_t *paddr = &cmd[1];
159 int err;
160
161 if (config->readonly) {
162 LOG_ERR("attempt to write to read-only device");
163 return -EACCES;
164 }
165
166 if (offset + len > config->size) {
167 LOG_ERR("attempt to write past device boundary");
168 return -EINVAL;
169 }
170
171 /* Populate address in command */
172 *paddr++ = (offset >> 16) & 0xFF;
173 *paddr++ = (offset >> 8) & 0xFF;
174 *paddr++ = offset & 0xFF;
175
176 const struct spi_buf tx_bufs[2] = {
177 {
178 .buf = cmd,
179 .len = sizeof(cmd),
180 },
181 {
182 .buf = (void *)buf,
183 .len = len,
184 },
185 };
186 const struct spi_buf_set tx = {
187 .buffers = tx_bufs,
188 .count = ARRAY_SIZE(tx_bufs),
189 };
190
191 k_mutex_lock(&data->lock, K_FOREVER);
192
193 err = eeprom_mb85rsxx_wren(dev);
194 if (err < 0) {
195 LOG_ERR("failed to disable write protection (err %d)", err);
196 k_mutex_unlock(&data->lock);
197 return err;
198 }
199
200 err = spi_write_dt(&config->spi, &tx);
201 if (err < 0) {
202 LOG_ERR("failed to write to FRAM (err %d)", err);
203 k_mutex_unlock(&data->lock);
204 return err;
205 }
206
207 err = eeprom_mb85rsxx_wrdi(dev);
208 if (err < 0) {
209 LOG_ERR("failed to disable write (err %d)", err);
210 }
211
212 k_mutex_unlock(&data->lock);
213
214 return err;
215 }
216
eeprom_mb85rsxx_size(const struct device * dev)217 static size_t eeprom_mb85rsxx_size(const struct device *dev)
218 {
219 const struct eeprom_mb85rsxx_config *config = dev->config;
220
221 return config->size;
222 }
223
eeprom_mb85rsxx_rdid(const struct device * dev)224 static int eeprom_mb85rsxx_rdid(const struct device *dev)
225 {
226 const struct eeprom_mb85rsxx_config *config = dev->config;
227 struct eeprom_mb85rsxx_data *data = dev->data;
228 uint8_t id[4];
229 uint8_t cmd = EEPROM_MB85RSXX_RDID;
230 int err;
231
232 const struct spi_buf tx_buf = {
233 .buf = &cmd,
234 .len = sizeof(cmd),
235 };
236 const struct spi_buf_set tx = {
237 .buffers = &tx_buf,
238 .count = 1,
239 };
240 const struct spi_buf rx_bufs[2] = {
241 {
242 .buf = NULL,
243 .len = sizeof(cmd),
244 },
245 {
246 .buf = id,
247 .len = sizeof(id),
248 },
249 };
250 const struct spi_buf_set rx = {
251 .buffers = rx_bufs,
252 .count = ARRAY_SIZE(rx_bufs),
253 };
254 k_mutex_lock(&data->lock, K_FOREVER);
255 err = spi_transceive_dt(&config->spi, &tx, &rx);
256 k_mutex_unlock(&data->lock);
257
258 if (err < 0) {
259 LOG_ERR("failed to read RDID (err %d)", err);
260 return err;
261 }
262
263 /* Validate Manufacturer ID and Product ID */
264 if (id[0] != EEPROM_MB85RSXX_MAN_ID
265 || id[1] != EEPROM_MB85RSXX_CON_CODE
266 || (id[2] & EEPROM_MB85RSXX_PROD_MASK) != EEPROM_MB85RSXX_PROD_ID
267 || id[3] != EEPROM_MB85RSXX_PROD_ID2) {
268 LOG_ERR("invalid device ID: %02X %02X %02X %02X", id[0], id[1], id[2], id[3]);
269 return -EIO;
270 }
271
272 LOG_INF("device ID read successfully: %02X %02X %02X %02X", id[0], id[1], id[2], id[3]);
273 return 0;
274 }
275
eeprom_mb85rsxx_init(const struct device * dev)276 static int eeprom_mb85rsxx_init(const struct device *dev)
277 {
278 const struct eeprom_mb85rsxx_config *config = dev->config;
279 struct eeprom_mb85rsxx_data *data = dev->data;
280 int err;
281
282 k_mutex_init(&data->lock);
283
284 if (!spi_is_ready_dt(&config->spi)) {
285 LOG_ERR("SPI bus not ready");
286 return -EINVAL;
287 }
288
289 err = eeprom_mb85rsxx_rdid(dev);
290 if (err < 0) {
291 LOG_ERR("Failed to initialize device, RDID check failed (err %d)", err);
292 return err;
293 }
294
295 return 0;
296 }
297
298 static DEVICE_API(eeprom, mb85rsxx_driver_api) = {
299 .read = &eeprom_mb85rsxx_read,
300 .write = &eeprom_mb85rsxx_write,
301 .size = &eeprom_mb85rsxx_size,
302 };
303
304 #define MB85RSXX_INIT(inst) \
305 static struct eeprom_mb85rsxx_data eeprom_mb85rsxx_data_##inst; \
306 \
307 static const struct eeprom_mb85rsxx_config eeprom_mb85rsxx_config_##inst = { \
308 .spi = SPI_DT_SPEC_INST_GET( \
309 inst, SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8), 0), \
310 .size = DT_INST_PROP(inst, size), \
311 .readonly = DT_INST_PROP(inst, read_only), \
312 }; \
313 \
314 DEVICE_DT_INST_DEFINE(inst, eeprom_mb85rsxx_init, NULL, &eeprom_mb85rsxx_data_##inst, \
315 &eeprom_mb85rsxx_config_##inst, POST_KERNEL, \
316 CONFIG_EEPROM_INIT_PRIORITY, &mb85rsxx_driver_api);
317
318 DT_INST_FOREACH_STATUS_OKAY(MB85RSXX_INIT)
319