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