1 /*
2  * Copyright (c) 2020 Seagate Technology LLC
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nxp_lpc11u6x_eeprom
8 
9 /**
10  * @file
11  * @brief EEPROM driver for NXP LPC11U6X MCUs
12  *
13  * This driver supports the on-chip EEPROM found on NXP LPC11U6x MCUs.
14  *
15  * @note This driver is only a wrapper for the IAP (In-Application Programming)
16  *       EEPROM functions.
17  */
18 
19 #include <zephyr/kernel.h>
20 #include <zephyr/drivers/eeprom.h>
21 #include <iap.h>
22 
23 #define LOG_LEVEL CONFIG_EEPROM_LOG_LEVEL
24 #include <zephyr/logging/log.h>
25 LOG_MODULE_REGISTER(eeprom_lpc11u6x);
26 
27 struct eeprom_lpc11u6x_config {
28 	size_t size;
29 };
30 
eeprom_lpc11u6x_read(const struct device * dev,off_t offset,void * data,size_t len)31 static int eeprom_lpc11u6x_read(const struct device *dev,
32 				off_t offset, void *data, size_t len)
33 {
34 	const struct eeprom_lpc11u6x_config *config = dev->config;
35 	uint32_t cmd[5];
36 	int ret;
37 
38 	if (!len) {
39 		return 0;
40 	}
41 
42 	if ((offset + len) > config->size) {
43 		LOG_WRN("attempt to read past device boundary");
44 		return -EINVAL;
45 	}
46 
47 	cmd[0] = IAP_CMD_EEPROM_READ;
48 	cmd[1] = offset;
49 	cmd[2] = (uint32_t) data;
50 	cmd[3] = len;
51 	cmd[4] = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / 1000;
52 
53 	ret = iap_cmd(cmd);
54 
55 	if (ret != IAP_STATUS_CMD_SUCCESS) {
56 		LOG_ERR("failed to read EEPROM (offset=%08x len=%d err=%d)",
57 			(unsigned int) offset, len, ret);
58 		return -EINVAL;
59 	}
60 
61 	return 0;
62 }
63 
eeprom_lpc11u6x_write(const struct device * dev,off_t offset,const void * data,size_t len)64 static int eeprom_lpc11u6x_write(const struct device *dev,
65 				 off_t offset, const void *data, size_t len)
66 {
67 	const struct eeprom_lpc11u6x_config *config = dev->config;
68 	uint32_t cmd[5];
69 	int ret;
70 
71 	if (!len) {
72 		return 0;
73 	}
74 
75 	if ((offset + len) > config->size) {
76 		LOG_WRN("attempt to write past device boundary");
77 		return -EINVAL;
78 	}
79 
80 	cmd[0] = IAP_CMD_EEPROM_WRITE;
81 	cmd[1] = offset;
82 	cmd[2] = (uint32_t) data;
83 	cmd[3] = len;
84 	cmd[4] = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / 1000;
85 
86 	ret = iap_cmd(cmd);
87 
88 	if (ret != IAP_STATUS_CMD_SUCCESS) {
89 		LOG_ERR("failed to write EEPROM (offset=%08x len=%d err=%d)",
90 			(unsigned int) offset, len, ret);
91 		return -EINVAL;
92 	}
93 
94 	return 0;
95 }
96 
eeprom_lpc11u6x_size(const struct device * dev)97 static size_t eeprom_lpc11u6x_size(const struct device *dev)
98 {
99 	const struct eeprom_lpc11u6x_config *config = dev->config;
100 
101 	return config->size;
102 }
103 
104 static const struct eeprom_driver_api eeprom_lpc11u6x_api = {
105 	.read = eeprom_lpc11u6x_read,
106 	.write = eeprom_lpc11u6x_write,
107 	.size = eeprom_lpc11u6x_size,
108 };
109 
110 static const struct eeprom_lpc11u6x_config eeprom_config = {
111 	.size = DT_INST_PROP(0, size),
112 };
113 
114 DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, &eeprom_config, POST_KERNEL,
115 		      CONFIG_EEPROM_INIT_PRIORITY, &eeprom_lpc11u6x_api);
116