1 /*
2  * Copyright (c) 2020 Laczen
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /*
8  * This driver emulates an EEPROM device in flash.
9  *
10  * The emulation represents the EEPROM in flash as a region that is a direct
11  * map of the EEPROM data (EEPROM data) followed by a region where changes to
12  * the EEPROM data (EEPROM changes) are stored. The combination of EEPROM data
13  * and EEPROM changes form a EEPROM page (see drawing below). Changes to EEPROM
14  * data are written as address-data combinations. The size of such a combination
15  * is determined by the flash write block size and the size of the EEPROM
16  * (required address space), with a minimum of 4 byte.
17  *
18  * When there is no more space to store changes a new EEPROM page is taken into
19  * use. This copies the existing data to the EEPROM data area of the new page.
20  * During this copying the write that is performed is applied at the same time.
21  * The old page is then invalidated.
22  *
23  * The EEPROM page needs to be a multiple of a flash page size. Multiple EEPROM
24  * pages are also supported and increases the number of writes that can be
25  * performed.
26  *
27  * The representation of the EEPROM on flash is shown in the next graph.
28  *
29  *  |-----------------------------------------------------------------------|
30  *  ||----------------------| |----------------------| |-------------------||
31  *  || EEPROM data          | |                      | |-Flash page--------||
32  *  ||                      | |                      |                      |
33  *  || size = EEPROM size   | |                      |                      |
34  *  ||----------------------| |----------------------|    ...               |
35  *  || EEPROM changes:      | |                      |                      |
36  *  || (address, new data)  | |                      |                      |
37  *  ||                      | |                      |                      |
38  *  ||                    XX| |                    XX|                      |
39  *  ||--EEPROM page 0-------| |--EEPROM page 1-------|                      |
40  *  |------------------------------------------------------------Partition--|
41  *  XX: page validity marker: all 0x00: page invalid
42  *
43  * Internally the address of an EEPROM byte is represented by a uint32_t (this
44  * should be sufficient in all cases). In case the EEPROM size is smaller than
45  * 64kB only a uint16_t is used to store changes. In this case the change stored
46  * for a 4 byte flash write block size are a combination of 2 byte address and
47  * 2 byte data.
48  *
49  * The EEPROM size, pagesize and the flash partition used for the EEPROM are
50  * defined in the dts. The flash partition should allow at least two EEPROM
51  * pages.
52  *
53  */
54 
55 #define DT_DRV_COMPAT zephyr_emu_eeprom
56 
57 #define EEPROM_EMU_VERSION 0
58 #define EEPROM_EMU_MAGIC 0x45454d55 /* EEMU in hex */
59 
60 #include <zephyr/drivers/eeprom.h>
61 #include <zephyr/drivers/flash.h>
62 #include <zephyr/kernel.h>
63 #define LOG_LEVEL CONFIG_EEPROM_LOG_LEVEL
64 #include <zephyr/logging/log.h>
65 LOG_MODULE_REGISTER(eeprom_emulator);
66 
67 struct eeprom_emu_config {
68 	/* EEPROM size */
69 	size_t size;
70 	/* EEPROM is read-only */
71 	bool readonly;
72 	/* Page size used to emulate the EEPROM, contains one area of EEPROM
73 	 * size and a area to store changes.
74 	 */
75 	size_t page_size;
76 	/* Offset of the flash partition used to emulate the EEPROM */
77 	off_t flash_offset;
78 	/* Size of the flash partition to emulate the EEPROM */
79 	size_t flash_size;
80 	/* Delay the erase of EEPROM pages until the complete partition is used.
81 	 */
82 	bool partitionerase;
83 	/* Size of a change block */
84 	uint8_t flash_cbs;
85 	uint8_t *rambuf;
86 	/* Device of the flash partition used to emulate the EEPROM */
87 	const struct device *flash_dev;
88 };
89 
90 struct eeprom_emu_data {
91 	/* Offset in current (EEPROM) page where next change is written */
92 	off_t write_offset;
93 	/* Offset of the current (EEPROM) page */
94 	off_t page_offset;
95 	struct k_mutex lock;
96 };
97 
98 /* read/write context */
99 struct eeprom_emu_ctx {
100 	const void *data; /* pointer to data */
101 	const size_t len; /* data length */
102 	const off_t address; /* eeprom address */
103 	size_t rlen; /* data remaining (unprocessed) length */
104 };
105 
106 /*
107  * basic flash read, only used with offset aligned to flash write block size
108  */
eeprom_emu_flash_read(const struct device * dev,off_t offset,uint8_t * blk,size_t len)109 static inline int eeprom_emu_flash_read(const struct device *dev, off_t offset,
110 					uint8_t *blk, size_t len)
111 {
112 	const struct eeprom_emu_config *dev_config = dev->config;
113 
114 	return flash_read(dev_config->flash_dev, dev_config->flash_offset +
115 			  offset, blk, len);
116 }
117 
118 /*
119  * basic flash write, only used with offset aligned to flash write block size
120  */
eeprom_emu_flash_write(const struct device * dev,off_t offset,const uint8_t * blk,size_t len)121 static inline int eeprom_emu_flash_write(const struct device *dev, off_t offset,
122 				   const uint8_t *blk, size_t len)
123 {
124 	const struct eeprom_emu_config *dev_config = dev->config;
125 	int rc;
126 
127 	rc = flash_write(dev_config->flash_dev, dev_config->flash_offset +
128 			 offset, blk, len);
129 	return rc;
130 }
131 
132 /*
133  * basic flash erase, only used with offset aligned to flash page and len a
134  * multiple of the flash page size
135  */
eeprom_emu_flash_erase(const struct device * dev,off_t offset,size_t len)136 static inline int eeprom_emu_flash_erase(const struct device *dev, off_t offset,
137 				   size_t len)
138 {
139 	const struct eeprom_emu_config *dev_config = dev->config;
140 	int rc;
141 
142 	rc = flash_erase(dev_config->flash_dev, dev_config->flash_offset +
143 			 offset, len);
144 	return rc;
145 }
146 
147 /*
148  * eeprom_emu_page_invalidate: invalidate a page by writing all zeros at the end
149  */
eeprom_emu_page_invalidate(const struct device * dev,off_t offset)150 static int eeprom_emu_page_invalidate(const struct device *dev, off_t offset)
151 {
152 	const struct eeprom_emu_config *dev_config = dev->config;
153 	uint8_t buf[dev_config->flash_cbs];
154 
155 	LOG_DBG("Invalidating page at [0x%tx]", (ptrdiff_t)offset);
156 
157 	memset(buf, 0x00, sizeof(buf));
158 
159 	offset += (dev_config->page_size - sizeof(buf));
160 	return eeprom_emu_flash_write(dev, offset, buf, sizeof(buf));
161 }
162 
163 /*
164  * eeprom_emu_get_address: read the address from a change block
165  */
eeprom_emu_get_address(const struct device * dev,const uint8_t * blk)166 static uint32_t eeprom_emu_get_address(const struct device *dev,
167 				       const uint8_t *blk)
168 {
169 	const struct eeprom_emu_config *dev_config = dev->config;
170 	uint32_t address = 0U;
171 
172 	blk += dev_config->flash_cbs / 2;
173 	for (int i = 0; i < sizeof(address); i++) {
174 		if (2 * i == dev_config->flash_cbs) {
175 			break;
176 		}
177 
178 		address += ((uint32_t)(*blk) << (8 * i));
179 		blk++;
180 	}
181 
182 	return address;
183 }
184 
185 /*
186  * eeprom_emu_set_change: create change blocks from data in blk and address
187  */
eeprom_emu_set_change(const struct device * dev,const uint32_t address,const uint8_t * data,uint8_t * blk)188 static void eeprom_emu_set_change(const struct device *dev,
189 				  const uint32_t address, const uint8_t *data,
190 				  uint8_t *blk)
191 {
192 	const struct eeprom_emu_config *dev_config = dev->config;
193 
194 	for (int i = 0; i < (dev_config->flash_cbs / 2); i++) {
195 		(*blk++) = (*data++);
196 	}
197 
198 	for (int i = 0; i < (dev_config->flash_cbs / 2); i++) {
199 		if (i < sizeof(address)) {
200 			(*blk++) = (uint8_t)(((address >> (8 * i)) & 0xff));
201 		} else {
202 			(*blk++) = 0xff;
203 		}
204 
205 	}
206 
207 }
208 
209 /*
210  * eeprom_emu_is_word_used: check if word is not empty
211  */
eeprom_emu_is_word_used(const struct device * dev,const uint8_t * blk)212 static int eeprom_emu_is_word_used(const struct device *dev, const uint8_t *blk)
213 {
214 	const struct eeprom_emu_config *dev_config = dev->config;
215 
216 	for (int i = 0; i < dev_config->flash_cbs; i++) {
217 		if ((*blk++) != 0xff) {
218 			return 1;
219 		}
220 
221 	}
222 
223 	return 0;
224 }
225 
226 /*
227  * eeprom_emu_word_read: read basic word (cbs byte of data) item from
228  * address directly from flash.
229  */
eeprom_emu_word_read(const struct device * dev,off_t address,uint8_t * data)230 static int eeprom_emu_word_read(const struct device *dev, off_t address,
231 				uint8_t *data)
232 {
233 	const struct eeprom_emu_config *dev_config = dev->config;
234 	const struct eeprom_emu_data *dev_data = dev->data;
235 	uint8_t buf[dev_config->flash_cbs];
236 	off_t direct_address;
237 	int rc;
238 
239 	direct_address = dev_data->page_offset + address;
240 
241 	/* Direct flash read */
242 	rc = eeprom_emu_flash_read(dev, direct_address, data, sizeof(buf));
243 	if (rc) {
244 		return rc;
245 	}
246 
247 	/* Process changes written to flash */
248 	off_t offset, ch_address;
249 	bool mc1 = false, mc2 = false;
250 
251 	offset = dev_data->write_offset;
252 	while (((!mc1) || (!mc2)) && (offset > dev_config->size)) {
253 		offset -= sizeof(buf);
254 		/* read the change */
255 		rc = eeprom_emu_flash_read(dev, dev_data->page_offset + offset,
256 					   buf, sizeof(buf));
257 		if (rc) {
258 			return rc;
259 		}
260 
261 		/* get the address from a change block */
262 		ch_address = eeprom_emu_get_address(dev, buf);
263 		if ((!mc1) && (ch_address == address)) {
264 			memcpy(data, buf, sizeof(buf)/2);
265 			mc1 = true;
266 		}
267 
268 		if ((!mc2) && (ch_address == (address + sizeof(buf)/2))) {
269 			memcpy(data + sizeof(buf)/2, buf, sizeof(buf)/2);
270 			mc2 = true;
271 		}
272 
273 	}
274 
275 	return rc;
276 }
277 
278 /* Update data specified in ctx from flash */
eeprom_emu_flash_get(const struct device * dev,struct eeprom_emu_ctx * ctx)279 static int eeprom_emu_flash_get(const struct device *dev,
280 				struct eeprom_emu_ctx *ctx)
281 {
282 	const struct eeprom_emu_config *dev_config = dev->config;
283 	off_t address = ctx->address + ctx->len - ctx->rlen;
284 	uint8_t *data8 = (uint8_t *)(ctx->data);
285 	uint8_t buf[dev_config->flash_cbs];
286 	const off_t addr_jmp = address & (sizeof(buf) - 1);
287 	size_t len;
288 	int rc;
289 
290 	data8 += (ctx->len - ctx->rlen);
291 	len = MIN((sizeof(buf) - addr_jmp), ctx->rlen);
292 	rc = eeprom_emu_word_read(dev, address - addr_jmp, buf);
293 	if (rc) {
294 		return rc;
295 	}
296 
297 	memcpy(data8, buf + addr_jmp, len);
298 	ctx->rlen -= len;
299 
300 	return rc;
301 }
302 
303 /*
304  * eeprom_emu_compactor: start a new EEPROM page and copy existing data to the
305  * new page. During copy update the data with present write data. Invalidate
306  * the old page.
307  */
eeprom_emu_compactor(const struct device * dev,struct eeprom_emu_ctx * ctx)308 static int eeprom_emu_compactor(const struct device *dev,
309 				struct eeprom_emu_ctx *ctx)
310 {
311 	const struct eeprom_emu_config *dev_config = dev->config;
312 	struct eeprom_emu_data *dev_data = dev->data;
313 	off_t next_page_offset;
314 	int rc = 0;
315 
316 	LOG_DBG("Compactor called for page at [0x%tx]",
317 		(ptrdiff_t)dev_data->page_offset);
318 
319 	next_page_offset = dev_data->page_offset + dev_config->page_size;
320 	if (next_page_offset >= dev_config->flash_size) {
321 		next_page_offset = 0;
322 	}
323 
324 	if (!dev_config->partitionerase) {
325 		/* erase the new page */
326 		rc = eeprom_emu_flash_erase(dev, next_page_offset,
327 					    dev_config->page_size);
328 	} else if (next_page_offset == 0) {
329 		/* erase the entire partition */
330 		rc = eeprom_emu_flash_erase(dev, next_page_offset,
331 					    dev_config->flash_size);
332 	} else {
333 		rc = 0;
334 	}
335 
336 	if (rc) {
337 		return rc;
338 	}
339 
340 	if (dev_config->rambuf && (ctx != NULL)) {
341 		rc = eeprom_emu_flash_write(dev, next_page_offset,
342 					    dev_config->rambuf,
343 					    dev_config->size);
344 		if (rc) {
345 			return rc;
346 		}
347 
348 		ctx->rlen = 0;
349 	} else {
350 		off_t rd_offset = 0;
351 		uint8_t buf[dev_config->flash_cbs];
352 
353 		/* reset the context if available */
354 		if (ctx != NULL) {
355 			ctx->rlen = ctx->len;
356 		}
357 
358 		/* copy existing data */
359 		while (rd_offset < dev_config->size) {
360 
361 			rc = eeprom_emu_word_read(dev, rd_offset, buf);
362 			if (rc) {
363 				return rc;
364 			}
365 
366 			if ((ctx != NULL) && (ctx->len) &&
367 			    (rd_offset > (ctx->address - sizeof(buf))))  {
368 				/* overwrite buf data with context data */
369 				uint8_t *data8 = (uint8_t *)(ctx->data);
370 				off_t address, addr_jmp;
371 				size_t len;
372 
373 				address = ctx->address + ctx->len - ctx->rlen;
374 				addr_jmp = address & (sizeof(buf) - 1);
375 				len = MIN((sizeof(buf) - addr_jmp), ctx->rlen);
376 				data8 += (ctx->len - ctx->rlen);
377 				memcpy(buf + addr_jmp, data8, len);
378 				ctx->rlen -= len;
379 			}
380 
381 			if (eeprom_emu_is_word_used(dev, buf)) {
382 				rc = eeprom_emu_flash_write(dev,
383 							    next_page_offset +
384 							    rd_offset, buf,
385 							    sizeof(buf));
386 				if (rc) {
387 					return rc;
388 				}
389 
390 			}
391 
392 			rd_offset += sizeof(buf);
393 		}
394 
395 	}
396 
397 	if ((dev_config->partitionerase) && (next_page_offset == 0)) {
398 		/* no need to invalidate previous page as it has been deleted */
399 		rc = 0;
400 	} else {
401 		/* invalidate the old page */
402 		rc = eeprom_emu_page_invalidate(dev, dev_data->page_offset);
403 	}
404 
405 	if (!rc) {
406 		dev_data->write_offset = dev_config->size;
407 		dev_data->page_offset = next_page_offset;
408 	}
409 	return rc;
410 }
411 
412 /*
413  * eeprom_emu_word_write: write basic word (cbs bytes of data) item to address,
414  */
eeprom_emu_word_write(const struct device * dev,off_t address,const uint8_t * data,struct eeprom_emu_ctx * ctx)415 static int eeprom_emu_word_write(const struct device *dev, off_t address,
416 				 const uint8_t *data,
417 				 struct eeprom_emu_ctx *ctx)
418 {
419 	const struct eeprom_emu_config *dev_config = dev->config;
420 	struct eeprom_emu_data *dev_data = dev->data;
421 	uint8_t buf[dev_config->flash_cbs], tmp[dev_config->flash_cbs];
422 	off_t direct_address, wraddr;
423 	int rc;
424 
425 	direct_address = dev_data->page_offset + address;
426 
427 	rc = eeprom_emu_flash_read(dev, direct_address, buf, sizeof(buf));
428 	if (rc) {
429 		return rc;
430 	}
431 
432 	if (!eeprom_emu_is_word_used(dev, buf)) {
433 		if (eeprom_emu_is_word_used(dev, data)) {
434 			rc = eeprom_emu_flash_write(dev, direct_address, data,
435 						    sizeof(buf));
436 		}
437 
438 		return rc;
439 	}
440 
441 	rc = eeprom_emu_word_read(dev, address, buf);
442 	if (rc) {
443 		return rc;
444 	}
445 
446 	if (!memcmp(buf, data, sizeof(buf))) {
447 		/* data has not changed */
448 		return rc;
449 	}
450 
451 	wraddr = address;
452 	/* store change */
453 	for (uint8_t i = 0; i < 2; i++) {
454 		if (memcmp(&buf[i*sizeof(buf)/2], data, sizeof(buf)/2)) {
455 			eeprom_emu_set_change(dev, wraddr, data, tmp);
456 			rc = eeprom_emu_flash_write(dev, dev_data->page_offset +
457 						    dev_data->write_offset, tmp,
458 						    sizeof(buf));
459 			if (rc) {
460 				return rc;
461 			}
462 
463 			dev_data->write_offset += sizeof(buf);
464 			if ((dev_data->write_offset + sizeof(buf)) >=
465 			    dev_config->page_size) {
466 				rc = eeprom_emu_compactor(dev, ctx);
467 				return rc;
468 
469 			}
470 
471 		}
472 
473 		data += sizeof(buf)/2;
474 		wraddr += sizeof(buf)/2;
475 	}
476 
477 	return rc;
478 }
479 
480 /* Update flash with data specified in ctx */
eeprom_emu_flash_set(const struct device * dev,struct eeprom_emu_ctx * ctx)481 static int eeprom_emu_flash_set(const struct device *dev,
482 				struct eeprom_emu_ctx *ctx)
483 {
484 	const struct eeprom_emu_config *dev_config = dev->config;
485 	off_t address = ctx->address + ctx->len - ctx->rlen;
486 	uint8_t *data8 = (uint8_t *)(ctx->data);
487 	uint8_t buf[dev_config->flash_cbs];
488 	const off_t addr_jmp = address & (sizeof(buf) - 1);
489 	size_t len;
490 	int rc;
491 
492 	data8 += (ctx->len - ctx->rlen);
493 	len = MIN((sizeof(buf) - addr_jmp), ctx->rlen);
494 	rc = eeprom_emu_word_read(dev, address - addr_jmp, buf);
495 	if (rc) {
496 		return rc;
497 	}
498 
499 	memcpy(buf + addr_jmp, data8, len);
500 	rc = eeprom_emu_word_write(dev, address - addr_jmp, buf, ctx);
501 	if (rc) {
502 		return rc;
503 	}
504 
505 	if (ctx->rlen) {
506 		ctx->rlen -= len;
507 	}
508 
509 	return rc;
510 }
511 
eeprom_emu_range_is_valid(const struct device * dev,off_t address,size_t len)512 static int eeprom_emu_range_is_valid(const struct device *dev, off_t address,
513 				     size_t len)
514 {
515 	const struct eeprom_emu_config *dev_config = dev->config;
516 
517 	if ((address + len) <= dev_config->size) {
518 		return 1;
519 	}
520 
521 	return 0;
522 }
523 
eeprom_emu_read(const struct device * dev,off_t address,void * data,size_t len)524 static int eeprom_emu_read(const struct device *dev, off_t address, void *data,
525 			   size_t len)
526 {
527 	const struct eeprom_emu_config *dev_config = dev->config;
528 	struct eeprom_emu_data *dev_data = dev->data;
529 	struct eeprom_emu_ctx ctx = {
530 		.data = data,
531 		.len = len,
532 		.address = address,
533 		.rlen = len,
534 	};
535 	int rc = 0;
536 
537 	/* Nothing to do */
538 	if (!len) {
539 		return 0;
540 	}
541 
542 	/* Error checking */
543 	if ((!data) || (!eeprom_emu_range_is_valid(dev, address, len))) {
544 		return -EINVAL;
545 	}
546 
547 	if (!device_is_ready(dev_config->flash_dev)) {
548 		LOG_ERR("flash device is not ready");
549 		return -EIO;
550 	}
551 
552 	/* Handle normal case */
553 	LOG_DBG("EEPROM read at [0x%tx] length[%zu]", (ptrdiff_t)address, len);
554 	k_mutex_lock(&dev_data->lock, K_FOREVER);
555 
556 	/* read from rambuffer if possible */
557 	if (dev_config->rambuf) {
558 		memcpy(data, dev_config->rambuf + address, len);
559 	} else {
560 		/* read from flash if no rambuffer */
561 		while (ctx.rlen) {
562 			rc = eeprom_emu_flash_get(dev, &ctx);
563 			if (rc) {
564 				break;
565 			}
566 
567 		}
568 	}
569 
570 	k_mutex_unlock(&dev_data->lock);
571 
572 	return rc;
573 }
574 
eeprom_emu_write(const struct device * dev,off_t address,const void * data,size_t len)575 static int eeprom_emu_write(const struct device *dev, off_t address,
576 			    const void *data, size_t len)
577 {
578 	const struct eeprom_emu_config *dev_config = dev->config;
579 	struct eeprom_emu_data *dev_data = dev->data;
580 	struct eeprom_emu_ctx ctx = {
581 		.data = data,
582 		.len = len,
583 		.address = address,
584 		.rlen = len,
585 	};
586 	int rc = 0;
587 
588 	/* Nothing to do */
589 	if (!len) {
590 		return 0;
591 	}
592 
593 	/* Error checking */
594 	if ((!data) || (!eeprom_emu_range_is_valid(dev, address, len))) {
595 		return -EINVAL;
596 	}
597 
598 	if (dev_config->readonly) {
599 		LOG_ERR("attempt to write to read-only device");
600 		return -EACCES;
601 	}
602 
603 	if (!device_is_ready(dev_config->flash_dev)) {
604 		LOG_ERR("flash device is not ready");
605 		return -EIO;
606 	}
607 
608 	/* Handle normal case */
609 	LOG_DBG("EEPROM write at [0x%tx] length[%zu]", (ptrdiff_t)address, len);
610 
611 	k_mutex_lock(&dev_data->lock, K_FOREVER);
612 
613 	/* first update the rambuffer */
614 	if (dev_config->rambuf) {
615 		memcpy(dev_config->rambuf + address, data, len);
616 	}
617 
618 	/* second update the flash */
619 	while (ctx.rlen) {
620 		rc = eeprom_emu_flash_set(dev, &ctx);
621 		if (rc) {
622 			break;
623 		}
624 
625 	}
626 
627 	k_mutex_unlock(&dev_data->lock);
628 
629 	return rc;
630 }
631 
eeprom_emu_size(const struct device * dev)632 static size_t eeprom_emu_size(const struct device *dev)
633 {
634 	const struct eeprom_emu_config *dev_config = dev->config;
635 
636 	return dev_config->size;
637 }
638 
eeprom_emu_init(const struct device * dev)639 static int eeprom_emu_init(const struct device *dev)
640 {
641 	const struct eeprom_emu_config *dev_config = dev->config;
642 	struct eeprom_emu_data *dev_data = dev->data;
643 	off_t offset;
644 	uint8_t buf[dev_config->flash_cbs];
645 	int rc = 0;
646 
647 	k_mutex_init(&dev_data->lock);
648 	if (!device_is_ready(dev_config->flash_dev)) {
649 		__ASSERT(0, "Could not get flash device binding");
650 		return -ENODEV;
651 	}
652 
653 	/* Find the page offset */
654 	dev_data->page_offset = 0U;
655 	dev_data->write_offset = dev_config->page_size - sizeof(buf);
656 	while (dev_data->page_offset < dev_config->flash_size) {
657 		offset = dev_data->page_offset + dev_data->write_offset;
658 		rc = eeprom_emu_flash_read(dev, offset, buf, sizeof(buf));
659 		if (rc) {
660 			return rc;
661 		}
662 
663 		if (!eeprom_emu_is_word_used(dev, buf)) {
664 			break;
665 		}
666 
667 		dev_data->page_offset += dev_config->page_size;
668 	}
669 
670 	if (dev_data->page_offset == dev_config->flash_size) {
671 		__ASSERT(0, "All pages are invalid, is this a EEPROM area?");
672 		return -EINVAL;
673 	}
674 
675 	dev_data->write_offset = dev_config->size;
676 
677 	/* Update the write offset */
678 	while ((dev_data->write_offset + sizeof(buf)) < dev_config->page_size) {
679 		offset = dev_data->page_offset + dev_data->write_offset;
680 		rc = eeprom_emu_flash_read(dev, offset, buf, sizeof(buf));
681 		if (rc) {
682 			return rc;
683 		}
684 
685 		if (!eeprom_emu_is_word_used(dev, buf)) {
686 			break;
687 		}
688 
689 		dev_data->write_offset += sizeof(buf);
690 	}
691 
692 	/* dev_data->write_offset reaches last possible location, compaction
693 	 * might have been interrupted: call eeprom_emu_compactor again, but
694 	 * only in case we are using a write-enabled eeprom
695 	 */
696 	if ((!dev_config->readonly) &&
697 	    ((dev_data->write_offset + sizeof(buf)) >= dev_config->page_size)) {
698 		rc = eeprom_emu_compactor(dev, NULL);
699 		if (rc) {
700 			return rc;
701 		}
702 
703 	}
704 
705 	/* Fill the ram buffer if enabled */
706 	if (dev_config->rambuf) {
707 		offset = 0;
708 		while (offset < dev_config->size) {
709 			rc = eeprom_emu_word_read(dev, offset, buf);
710 			if (rc) {
711 				return rc;
712 			}
713 
714 			memcpy(dev_config->rambuf + offset, buf, sizeof(buf));
715 			offset += sizeof(buf);
716 		}
717 
718 	}
719 
720 	return rc;
721 }
722 
723 static const struct eeprom_driver_api eeprom_emu_api = {
724 	.read = eeprom_emu_read,
725 	.write = eeprom_emu_write,
726 	.size = eeprom_emu_size,
727 };
728 
729 #define EEPROM_PARTITION(n) DT_INST_PHANDLE_BY_IDX(n, partition, 0)
730 
731 #define PART_WBS(part) \
732 	DT_PROP(COND_CODE_1(DT_NODE_HAS_COMPAT(DT_GPARENT(part), soc_nv_flash),\
733 		(DT_GPARENT(part)), (DT_PARENT(part))), write_block_size)
734 
735 #define PART_CBS(part, size) (PART_WBS(part) < 4) ? \
736 	((size > (2^16)) ? 8 : 4) : PART_WBS(part)
737 
738 #define PART_DEV_ID(part) \
739 	COND_CODE_1(DT_NODE_HAS_COMPAT(DT_GPARENT(part), soc_nv_flash), \
740 		 (DT_PARENT(DT_GPARENT(part))), (DT_GPARENT(part)))
741 
742 #define PART_DEV(part) \
743 	DEVICE_DT_GET(PART_DEV_ID(part))
744 
745 #define RECALC_SIZE(size, cbs) \
746 	(size % cbs) ? ((size + cbs - 1) & ~(cbs - 1)) : size
747 
748 #define ASSERT_SIZE_PAGESIZE_VALID(size, pagesize, readonly) \
749 	BUILD_ASSERT(readonly ? (size <= pagesize) : (4*size <= 3*pagesize), \
750 		     "EEPROM size to big for pagesize")
751 
752 #define ASSERT_PAGESIZE_PARTSIZE_VALID(pagesize, partsize) \
753 	BUILD_ASSERT(partsize % pagesize == 0U, \
754 		     "Partition size not a multiple of pagesize")
755 
756 #define ASSERT_PAGESIZE_SIZE(pagesize, partsize, onepage) \
757 	BUILD_ASSERT(onepage ? (partsize >= pagesize) : (partsize > pagesize),\
758 		     "Partition size to small")
759 
760 #define EEPROM_EMU_READ_ONLY(n) \
761 	DT_INST_PROP(n, read_only) || \
762 	DT_PROP(EEPROM_PARTITION(n), read_only)
763 
764 #define EEPROM_EMU_ONEPAGE(n) \
765 	EEPROM_EMU_READ_ONLY(n) || DT_INST_PROP(n, partition_erase)
766 
767 #define EEPROM_EMU_ENABLE_RAMBUF(n) \
768 	COND_CODE_1(DT_INST_PROP(n, rambuf), (1), \
769 		(COND_CODE_1(DT_INST_PROP(n, partition_erase), (1), (0))))
770 
771 #define EEPROM_EMU_RAMBUF(n) \
772 	COND_CODE_0(EEPROM_EMU_ENABLE_RAMBUF(n), (), \
773 		(static uint8_t eeprom_emu_##n##_rambuf[DT_INST_PROP(n, size)];))
774 
775 #define EEPROM_EMU_RAMBUF_LINK(n) \
776 	COND_CODE_0(EEPROM_EMU_ENABLE_RAMBUF(n), (NULL), \
777 		(eeprom_emu_##n##_rambuf))
778 
779 #define EEPROM_EMU_INIT(n) \
780 	ASSERT_SIZE_PAGESIZE_VALID(DT_INST_PROP(n, size), \
781 		DT_INST_PROP(n, pagesize), EEPROM_EMU_ONEPAGE(n)); \
782 	ASSERT_PAGESIZE_PARTSIZE_VALID(DT_INST_PROP(n, pagesize), \
783 		DT_REG_SIZE(EEPROM_PARTITION(n))); \
784 	ASSERT_PAGESIZE_SIZE(DT_INST_PROP(n, pagesize), \
785 		DT_REG_SIZE(EEPROM_PARTITION(n)), EEPROM_EMU_ONEPAGE(n)); \
786 	EEPROM_EMU_RAMBUF(n) \
787 	static const struct eeprom_emu_config eeprom_emu_##n##_config = { \
788 		.size = RECALC_SIZE( \
789 			DT_INST_PROP(n, size), \
790 			(PART_CBS(EEPROM_PARTITION(n), DT_INST_PROP(n, size))) \
791 			), \
792 		.readonly = EEPROM_EMU_READ_ONLY(n), \
793 		.page_size = DT_INST_PROP(n, pagesize), \
794 		.flash_offset = DT_REG_ADDR(EEPROM_PARTITION(n)), \
795 		.flash_size = DT_REG_SIZE(EEPROM_PARTITION(n)), \
796 		.partitionerase = DT_INST_PROP(n, partition_erase), \
797 		.flash_cbs = PART_CBS(EEPROM_PARTITION(n), \
798 				      DT_INST_PROP(n, size)), \
799 		.flash_dev = PART_DEV(EEPROM_PARTITION(n)),\
800 		.rambuf = EEPROM_EMU_RAMBUF_LINK(n), \
801 	}; \
802 	static struct eeprom_emu_data eeprom_emu_##n##_data; \
803 	DEVICE_DT_INST_DEFINE(n, &eeprom_emu_init, \
804 		NULL, &eeprom_emu_##n##_data, \
805 		&eeprom_emu_##n##_config, POST_KERNEL, \
806 		CONFIG_EEPROM_INIT_PRIORITY, &eeprom_emu_api); \
807 
808 DT_INST_FOREACH_STATUS_OKAY(EEPROM_EMU_INIT)
809