1 /*
2 * Copyright (c) 2019 Vestas Wind Systems A/S
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief Driver for Atmel AT24 I2C and Atmel AT25 SPI EEPROMs.
10 */
11
12 #include <zephyr/drivers/eeprom.h>
13 #include <zephyr/drivers/gpio.h>
14 #include <zephyr/drivers/i2c.h>
15 #include <zephyr/drivers/spi.h>
16 #include <zephyr/sys/byteorder.h>
17 #include <zephyr/kernel.h>
18
19 #define LOG_LEVEL CONFIG_EEPROM_LOG_LEVEL
20 #include <zephyr/logging/log.h>
21 LOG_MODULE_REGISTER(eeprom_at2x);
22
23 /* AT25 instruction set */
24 #define EEPROM_AT25_WRSR 0x01U /* Write STATUS register */
25 #define EEPROM_AT25_WRITE 0x02U /* Write data to memory array */
26 #define EEPROM_AT25_READ 0x03U /* Read data from memory array */
27 #define EEPROM_AT25_WRDI 0x04U /* Reset the write enable latch */
28 #define EEPROM_AT25_RDSR 0x05U /* Read STATUS register */
29 #define EEPROM_AT25_WREN 0x06U /* Set the write enable latch */
30
31 /* AT25 status register bits */
32 #define EEPROM_AT25_STATUS_WIP BIT(0) /* Write-In-Process (RO) */
33 #define EEPROM_AT25_STATUS_WEL BIT(1) /* Write Enable Latch (RO) */
34 #define EEPROM_AT25_STATUS_BP0 BIT(2) /* Block Protection 0 (RW) */
35 #define EEPROM_AT25_STATUS_BP1 BIT(3) /* Block Protection 1 (RW) */
36
37 #define HAS_WP_OR(id) DT_NODE_HAS_PROP(id, wp_gpios) ||
38 #define ANY_INST_HAS_WP_GPIOS (DT_FOREACH_STATUS_OKAY(atmel_at24, HAS_WP_OR) \
39 DT_FOREACH_STATUS_OKAY(atmel_at25, HAS_WP_OR) 0)
40
41 struct eeprom_at2x_config {
42 union {
43 #ifdef CONFIG_EEPROM_AT24
44 struct i2c_dt_spec i2c;
45 #endif /* CONFIG_EEPROM_AT24 */
46 #ifdef CONFIG_EEPROM_AT25
47 struct spi_dt_spec spi;
48 #endif /* CONFIG_EEPROM_AT25 */
49 } bus;
50 #if ANY_INST_HAS_WP_GPIOS
51 struct gpio_dt_spec wp_gpio;
52 #endif /* ANY_INST_HAS_WP_GPIOS */
53 size_t size;
54 size_t pagesize;
55 uint8_t addr_width;
56 bool readonly;
57 uint16_t timeout;
58 bool (*bus_is_ready)(const struct device *dev);
59 eeprom_api_read read_fn;
60 eeprom_api_write write_fn;
61 };
62
63 struct eeprom_at2x_data {
64 struct k_mutex lock;
65 };
66
67 #if ANY_INST_HAS_WP_GPIOS
eeprom_at2x_write_protect(const struct device * dev)68 static inline int eeprom_at2x_write_protect(const struct device *dev)
69 {
70 const struct eeprom_at2x_config *config = dev->config;
71
72 if (!config->wp_gpio.port) {
73 return 0;
74 }
75
76 return gpio_pin_set_dt(&config->wp_gpio, 1);
77 }
78
eeprom_at2x_write_enable(const struct device * dev)79 static inline int eeprom_at2x_write_enable(const struct device *dev)
80 {
81 const struct eeprom_at2x_config *config = dev->config;
82
83 if (!config->wp_gpio.port) {
84 return 0;
85 }
86
87 return gpio_pin_set_dt(&config->wp_gpio, 0);
88 }
89 #endif /* ANY_INST_HAS_WP_GPIOS */
90
eeprom_at2x_read(const struct device * dev,off_t offset,void * buf,size_t len)91 static int eeprom_at2x_read(const struct device *dev, off_t offset, void *buf,
92 size_t len)
93 {
94 const struct eeprom_at2x_config *config = dev->config;
95 struct eeprom_at2x_data *data = dev->data;
96 uint8_t *pbuf = buf;
97 int ret;
98
99 if (!len) {
100 return 0;
101 }
102
103 if ((offset + len) > config->size) {
104 LOG_WRN("attempt to read past device boundary");
105 return -EINVAL;
106 }
107
108 k_mutex_lock(&data->lock, K_FOREVER);
109 while (len) {
110 ret = config->read_fn(dev, offset, pbuf, len);
111 if (ret < 0) {
112 LOG_ERR("failed to read EEPROM (err %d)", ret);
113 k_mutex_unlock(&data->lock);
114 return ret;
115 }
116
117 pbuf += ret;
118 offset += ret;
119 len -= ret;
120 }
121
122 k_mutex_unlock(&data->lock);
123
124 return 0;
125 }
126
eeprom_at2x_limit_write_count(const struct device * dev,off_t offset,size_t len)127 static size_t eeprom_at2x_limit_write_count(const struct device *dev,
128 off_t offset,
129 size_t len)
130 {
131 const struct eeprom_at2x_config *config = dev->config;
132 size_t count = len;
133 off_t page_boundary;
134
135 /* We can at most write one page at a time */
136 if (count > config->pagesize) {
137 count = config->pagesize;
138 }
139
140 /* Writes can not cross a page boundary */
141 page_boundary = ROUND_UP(offset + 1, config->pagesize);
142 if (offset + count > page_boundary) {
143 count = page_boundary - offset;
144 }
145
146 return count;
147 }
148
eeprom_at2x_write(const struct device * dev,off_t offset,const void * buf,size_t len)149 static int eeprom_at2x_write(const struct device *dev, off_t offset,
150 const void *buf,
151 size_t len)
152 {
153 const struct eeprom_at2x_config *config = dev->config;
154 struct eeprom_at2x_data *data = dev->data;
155 const uint8_t *pbuf = buf;
156 int ret;
157
158 if (config->readonly) {
159 LOG_WRN("attempt to write to read-only device");
160 return -EACCES;
161 }
162
163 if (!len) {
164 return 0;
165 }
166
167 if ((offset + len) > config->size) {
168 LOG_WRN("attempt to write past device boundary");
169 return -EINVAL;
170 }
171
172 k_mutex_lock(&data->lock, K_FOREVER);
173
174 #if ANY_INST_HAS_WP_GPIOS
175 ret = eeprom_at2x_write_enable(dev);
176 if (ret) {
177 LOG_ERR("failed to write-enable EEPROM (err %d)", ret);
178 k_mutex_unlock(&data->lock);
179 return ret;
180 }
181 #endif /* ANY_INST_HAS_WP_GPIOS */
182
183 while (len) {
184 ret = config->write_fn(dev, offset, pbuf, len);
185 if (ret < 0) {
186 LOG_ERR("failed to write to EEPROM (err %d)", ret);
187 #if ANY_INST_HAS_WP_GPIOS
188 eeprom_at2x_write_protect(dev);
189 #endif /* ANY_INST_HAS_WP_GPIOS */
190 k_mutex_unlock(&data->lock);
191 return ret;
192 }
193
194 pbuf += ret;
195 offset += ret;
196 len -= ret;
197 }
198
199 #if ANY_INST_HAS_WP_GPIOS
200 ret = eeprom_at2x_write_protect(dev);
201 if (ret) {
202 LOG_ERR("failed to write-protect EEPROM (err %d)", ret);
203 }
204 #else
205 ret = 0;
206 #endif /* ANY_INST_HAS_WP_GPIOS */
207
208 k_mutex_unlock(&data->lock);
209
210 return ret;
211 }
212
eeprom_at2x_size(const struct device * dev)213 static size_t eeprom_at2x_size(const struct device *dev)
214 {
215 const struct eeprom_at2x_config *config = dev->config;
216
217 return config->size;
218 }
219
220 #ifdef CONFIG_EEPROM_AT24
221
eeprom_at24_bus_is_ready(const struct device * dev)222 static bool eeprom_at24_bus_is_ready(const struct device *dev)
223 {
224 const struct eeprom_at2x_config *config = dev->config;
225
226 return device_is_ready(config->bus.i2c.bus);
227 }
228
229 /**
230 * @brief translate an offset to a device address / offset pair
231 *
232 * It allows to address several devices as a continuous memory region
233 * but also to address higher part of eeprom for chips
234 * with more than 2^(addr_width) adressable word.
235 */
eeprom_at24_translate_offset(const struct device * dev,off_t * offset)236 static uint16_t eeprom_at24_translate_offset(const struct device *dev,
237 off_t *offset)
238 {
239 const struct eeprom_at2x_config *config = dev->config;
240
241 const uint16_t addr_incr = *offset >> config->addr_width;
242 *offset &= BIT_MASK(config->addr_width);
243
244 return config->bus.i2c.addr + addr_incr;
245 }
246
eeprom_at24_adjust_read_count(const struct device * dev,off_t offset,size_t len)247 static size_t eeprom_at24_adjust_read_count(const struct device *dev,
248 off_t offset, size_t len)
249 {
250 const struct eeprom_at2x_config *config = dev->config;
251 const size_t remainder = BIT(config->addr_width) - offset;
252
253 if (len > remainder) {
254 len = remainder;
255 }
256
257 return len;
258 }
259
eeprom_at24_read(const struct device * dev,off_t offset,void * buf,size_t len)260 static int eeprom_at24_read(const struct device *dev, off_t offset, void *buf,
261 size_t len)
262 {
263 const struct eeprom_at2x_config *config = dev->config;
264 int64_t timeout;
265 uint8_t addr[2];
266 uint16_t bus_addr;
267 int err;
268
269 bus_addr = eeprom_at24_translate_offset(dev, &offset);
270
271 if (config->addr_width == 16) {
272 sys_put_be16(offset, addr);
273 } else {
274 addr[0] = offset & BIT_MASK(8);
275 }
276
277 len = eeprom_at24_adjust_read_count(dev, offset, len);
278
279 /*
280 * A write cycle may be in progress so reads must be attempted
281 * until the current write cycle should be completed.
282 */
283 timeout = k_uptime_get() + config->timeout;
284 while (1) {
285 int64_t now = k_uptime_get();
286 err = i2c_write_read(config->bus.i2c.bus, bus_addr,
287 addr, config->addr_width / 8,
288 buf, len);
289 if (!err || now > timeout) {
290 break;
291 }
292 k_sleep(K_MSEC(1));
293 }
294
295 if (err < 0) {
296 return err;
297 }
298
299 return len;
300 }
301
eeprom_at24_write(const struct device * dev,off_t offset,const void * buf,size_t len)302 static int eeprom_at24_write(const struct device *dev, off_t offset,
303 const void *buf, size_t len)
304 {
305 const struct eeprom_at2x_config *config = dev->config;
306 int count = eeprom_at2x_limit_write_count(dev, offset, len);
307 uint8_t block[config->addr_width / 8 + count];
308 int64_t timeout;
309 uint16_t bus_addr;
310 int i = 0;
311 int err;
312
313 bus_addr = eeprom_at24_translate_offset(dev, &offset);
314
315 /*
316 * Not all I2C EEPROMs support repeated start so the
317 * address (offset) and data (buf) must be provided in one
318 * write transaction (block).
319 */
320 if (config->addr_width == 16) {
321 block[i++] = offset >> 8;
322 }
323 block[i++] = offset;
324 memcpy(&block[i], buf, count);
325
326 /*
327 * A write cycle may already be in progress so writes must be
328 * attempted until the previous write cycle should be
329 * completed.
330 */
331 timeout = k_uptime_get() + config->timeout;
332 while (1) {
333 int64_t now = k_uptime_get();
334 err = i2c_write(config->bus.i2c.bus, block, sizeof(block),
335 bus_addr);
336 if (!err || now > timeout) {
337 break;
338 }
339 k_sleep(K_MSEC(1));
340 }
341
342 if (err < 0) {
343 return err;
344 }
345
346 return count;
347 }
348 #endif /* CONFIG_EEPROM_AT24 */
349
350 #ifdef CONFIG_EEPROM_AT25
351
eeprom_at25_bus_is_ready(const struct device * dev)352 static bool eeprom_at25_bus_is_ready(const struct device *dev)
353 {
354 const struct eeprom_at2x_config *config = dev->config;
355
356 return spi_is_ready_dt(&config->bus.spi);
357 }
358
eeprom_at25_rdsr(const struct device * dev,uint8_t * status)359 static int eeprom_at25_rdsr(const struct device *dev, uint8_t *status)
360 {
361 const struct eeprom_at2x_config *config = dev->config;
362 uint8_t rdsr[2] = { EEPROM_AT25_RDSR, 0 };
363 uint8_t sr[2];
364 int err;
365 const struct spi_buf tx_buf = {
366 .buf = rdsr,
367 .len = sizeof(rdsr),
368 };
369 const struct spi_buf_set tx = {
370 .buffers = &tx_buf,
371 .count = 1,
372 };
373 const struct spi_buf rx_buf = {
374 .buf = sr,
375 .len = sizeof(sr),
376 };
377 const struct spi_buf_set rx = {
378 .buffers = &rx_buf,
379 .count = 1,
380 };
381
382 err = spi_transceive_dt(&config->bus.spi, &tx, &rx);
383 if (!err) {
384 *status = sr[1];
385 }
386
387 return err;
388 }
389
eeprom_at25_wait_for_idle(const struct device * dev)390 static int eeprom_at25_wait_for_idle(const struct device *dev)
391 {
392 const struct eeprom_at2x_config *config = dev->config;
393 int64_t timeout;
394 uint8_t status;
395 int err;
396
397 timeout = k_uptime_get() + config->timeout;
398 while (1) {
399 int64_t now = k_uptime_get();
400 err = eeprom_at25_rdsr(dev, &status);
401 if (err) {
402 LOG_ERR("Could not read status register (err %d)", err);
403 return err;
404 }
405
406 if (!(status & EEPROM_AT25_STATUS_WIP)) {
407 return 0;
408 }
409 if (now > timeout) {
410 break;
411 }
412 k_sleep(K_MSEC(1));
413 }
414
415 return -EBUSY;
416 }
417
eeprom_at25_read(const struct device * dev,off_t offset,void * buf,size_t len)418 static int eeprom_at25_read(const struct device *dev, off_t offset, void *buf,
419 size_t len)
420 {
421 const struct eeprom_at2x_config *config = dev->config;
422 struct eeprom_at2x_data *data = dev->data;
423 size_t cmd_len = 1 + config->addr_width / 8;
424 uint8_t cmd[4] = { EEPROM_AT25_READ, 0, 0, 0 };
425 uint8_t *paddr;
426 int err;
427 const struct spi_buf tx_buf = {
428 .buf = cmd,
429 .len = cmd_len,
430 };
431 const struct spi_buf_set tx = {
432 .buffers = &tx_buf,
433 .count = 1,
434 };
435 const struct spi_buf rx_bufs[2] = {
436 {
437 .buf = NULL,
438 .len = cmd_len,
439 },
440 {
441 .buf = buf,
442 .len = len,
443 },
444 };
445 const struct spi_buf_set rx = {
446 .buffers = rx_bufs,
447 .count = ARRAY_SIZE(rx_bufs),
448 };
449
450 if (!len) {
451 return 0;
452 }
453
454 if ((offset + len) > config->size) {
455 LOG_WRN("attempt to read past device boundary");
456 return -EINVAL;
457 }
458
459 paddr = &cmd[1];
460 switch (config->addr_width) {
461 case 24:
462 *paddr++ = offset >> 16;
463 __fallthrough;
464 case 16:
465 *paddr++ = offset >> 8;
466 __fallthrough;
467 case 8:
468 *paddr++ = offset;
469 break;
470 default:
471 __ASSERT(0, "invalid address width");
472 }
473
474 err = eeprom_at25_wait_for_idle(dev);
475 if (err) {
476 LOG_ERR("EEPROM idle wait failed (err %d)", err);
477 k_mutex_unlock(&data->lock);
478 return err;
479 }
480
481 err = spi_transceive_dt(&config->bus.spi, &tx, &rx);
482 if (err < 0) {
483 return err;
484 }
485
486 return len;
487 }
488
eeprom_at25_wren(const struct device * dev)489 static int eeprom_at25_wren(const struct device *dev)
490 {
491 const struct eeprom_at2x_config *config = dev->config;
492 uint8_t cmd = EEPROM_AT25_WREN;
493 const struct spi_buf tx_buf = {
494 .buf = &cmd,
495 .len = 1,
496 };
497 const struct spi_buf_set tx = {
498 .buffers = &tx_buf,
499 .count = 1,
500 };
501
502 return spi_write_dt(&config->bus.spi, &tx);
503 }
504
eeprom_at25_write(const struct device * dev,off_t offset,const void * buf,size_t len)505 static int eeprom_at25_write(const struct device *dev, off_t offset,
506 const void *buf, size_t len)
507 {
508 const struct eeprom_at2x_config *config = dev->config;
509 int count = eeprom_at2x_limit_write_count(dev, offset, len);
510 uint8_t cmd[4] = { EEPROM_AT25_WRITE, 0, 0, 0 };
511 size_t cmd_len = 1 + config->addr_width / 8;
512 uint8_t *paddr;
513 int err;
514 const struct spi_buf tx_bufs[2] = {
515 {
516 .buf = cmd,
517 .len = cmd_len,
518 },
519 {
520 .buf = (void *)buf,
521 .len = count,
522 },
523 };
524 const struct spi_buf_set tx = {
525 .buffers = tx_bufs,
526 .count = ARRAY_SIZE(tx_bufs),
527 };
528
529 paddr = &cmd[1];
530 switch (config->addr_width) {
531 case 24:
532 *paddr++ = offset >> 16;
533 __fallthrough;
534 case 16:
535 *paddr++ = offset >> 8;
536 __fallthrough;
537 case 8:
538 *paddr++ = offset;
539 break;
540 default:
541 __ASSERT(0, "invalid address width");
542 }
543
544 err = eeprom_at25_wait_for_idle(dev);
545 if (err) {
546 LOG_ERR("EEPROM idle wait failed (err %d)", err);
547 return err;
548 }
549
550 err = eeprom_at25_wren(dev);
551 if (err) {
552 LOG_ERR("failed to disable write protection (err %d)", err);
553 return err;
554 }
555
556 err = spi_transceive_dt(&config->bus.spi, &tx, NULL);
557 if (err) {
558 return err;
559 }
560
561 return count;
562 }
563 #endif /* CONFIG_EEPROM_AT25 */
564
eeprom_at2x_init(const struct device * dev)565 static int eeprom_at2x_init(const struct device *dev)
566 {
567 const struct eeprom_at2x_config *config = dev->config;
568 struct eeprom_at2x_data *data = dev->data;
569
570 k_mutex_init(&data->lock);
571
572 if (!config->bus_is_ready(dev)) {
573 LOG_ERR("parent bus device not ready");
574 return -EINVAL;
575 }
576
577 #if ANY_INST_HAS_WP_GPIOS
578 if (config->wp_gpio.port) {
579 int err;
580 if (!gpio_is_ready_dt(&config->wp_gpio)) {
581 LOG_ERR("wp gpio device not ready");
582 return -EINVAL;
583 }
584
585 err = gpio_pin_configure_dt(&config->wp_gpio, GPIO_OUTPUT_ACTIVE);
586 if (err) {
587 LOG_ERR("failed to configure WP GPIO pin (err %d)", err);
588 return err;
589 }
590 }
591 #endif /* ANY_INST_HAS_WP_GPIOS */
592
593 return 0;
594 }
595
596 static const struct eeprom_driver_api eeprom_at2x_api = {
597 .read = eeprom_at2x_read,
598 .write = eeprom_at2x_write,
599 .size = eeprom_at2x_size,
600 };
601
602 #define ASSERT_AT24_ADDR_W_VALID(w) \
603 BUILD_ASSERT(w == 8U || w == 16U, \
604 "Unsupported address width")
605
606 #define ASSERT_AT25_ADDR_W_VALID(w) \
607 BUILD_ASSERT(w == 8U || w == 16U || w == 24U, \
608 "Unsupported address width")
609
610 #define ASSERT_PAGESIZE_IS_POWER_OF_2(page) \
611 BUILD_ASSERT((page != 0U) && ((page & (page - 1)) == 0U), \
612 "Page size is not a power of two")
613
614 #define ASSERT_SIZE_PAGESIZE_VALID(size, page) \
615 BUILD_ASSERT(size % page == 0U, \
616 "Size is not an integer multiple of page size")
617
618 #define INST_DT_AT2X(inst, t) DT_INST(inst, atmel_at##t)
619
620 #define EEPROM_AT24_BUS(n, t) \
621 { .i2c = I2C_DT_SPEC_GET(INST_DT_AT2X(n, t)) }
622
623 #define EEPROM_AT25_BUS(n, t) \
624 { .spi = SPI_DT_SPEC_GET(INST_DT_AT2X(n, t), \
625 SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | \
626 SPI_WORD_SET(8), 0) }
627
628 #define EEPROM_AT2X_WP_GPIOS(id) \
629 IF_ENABLED(DT_NODE_HAS_PROP(id, wp_gpios), \
630 (.wp_gpio = GPIO_DT_SPEC_GET(id, wp_gpios),))
631
632 #define EEPROM_AT2X_DEVICE(n, t) \
633 ASSERT_PAGESIZE_IS_POWER_OF_2(DT_PROP(INST_DT_AT2X(n, t), pagesize)); \
634 ASSERT_SIZE_PAGESIZE_VALID(DT_PROP(INST_DT_AT2X(n, t), size), \
635 DT_PROP(INST_DT_AT2X(n, t), pagesize)); \
636 ASSERT_AT##t##_ADDR_W_VALID(DT_PROP(INST_DT_AT2X(n, t), \
637 address_width)); \
638 static const struct eeprom_at2x_config eeprom_at##t##_config_##n = { \
639 .bus = EEPROM_AT##t##_BUS(n, t), \
640 EEPROM_AT2X_WP_GPIOS(INST_DT_AT2X(n, t)) \
641 .size = DT_PROP(INST_DT_AT2X(n, t), size), \
642 .pagesize = DT_PROP(INST_DT_AT2X(n, t), pagesize), \
643 .addr_width = DT_PROP(INST_DT_AT2X(n, t), address_width), \
644 .readonly = DT_PROP(INST_DT_AT2X(n, t), read_only), \
645 .timeout = DT_PROP(INST_DT_AT2X(n, t), timeout), \
646 .bus_is_ready = eeprom_at##t##_bus_is_ready, \
647 .read_fn = eeprom_at##t##_read, \
648 .write_fn = eeprom_at##t##_write, \
649 }; \
650 static struct eeprom_at2x_data eeprom_at##t##_data_##n; \
651 DEVICE_DT_DEFINE(INST_DT_AT2X(n, t), &eeprom_at2x_init, \
652 NULL, &eeprom_at##t##_data_##n, \
653 &eeprom_at##t##_config_##n, POST_KERNEL, \
654 CONFIG_EEPROM_AT2X_INIT_PRIORITY, \
655 &eeprom_at2x_api)
656
657 #define EEPROM_AT24_DEVICE(n) EEPROM_AT2X_DEVICE(n, 24)
658 #define EEPROM_AT25_DEVICE(n) EEPROM_AT2X_DEVICE(n, 25)
659
660 #define CALL_WITH_ARG(arg, expr) expr(arg);
661
662 #define INST_DT_AT2X_FOREACH(t, inst_expr) \
663 LISTIFY(DT_NUM_INST_STATUS_OKAY(atmel_at##t), \
664 CALL_WITH_ARG, (), inst_expr)
665
666 #ifdef CONFIG_EEPROM_AT24
667 INST_DT_AT2X_FOREACH(24, EEPROM_AT24_DEVICE);
668 #endif
669
670 #ifdef CONFIG_EEPROM_AT25
671 INST_DT_AT2X_FOREACH(25, EEPROM_AT25_DEVICE);
672 #endif
673