xref: /linux/drivers/misc/eeprom/m24lr.c (revision 6093a688a07da07808f0122f9aa2a3eed250d853)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * m24lr.c - Sysfs control interface for ST M24LR series RFID/NFC chips
4  *
5  * Copyright (c) 2025 Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
6  *
7  * This driver implements both the sysfs-based control interface and EEPROM
8  * access for STMicroelectronics M24LR series chips (e.g., M24LR04E-R).
9  * It provides access to control registers for features such as password
10  * authentication, memory protection, and device configuration. In addition,
11  * it manages read and write operations to the EEPROM region of the chip.
12  */
13 
14 #include <linux/device.h>
15 #include <linux/i2c.h>
16 #include <linux/module.h>
17 #include <linux/nvmem-provider.h>
18 #include <linux/of.h>
19 #include <linux/of_device.h>
20 #include <linux/regmap.h>
21 
22 #define M24LR_WRITE_TIMEOUT	  25u
23 #define M24LR_READ_TIMEOUT	  (M24LR_WRITE_TIMEOUT)
24 
25 /**
26  * struct m24lr_chip - describes chip-specific sysfs layout
27  * @sss_len:       the length of the sss region
28  * @page_size:	   chip-specific limit on the maximum number of bytes allowed
29  *		   in a single write operation.
30  * @eeprom_size:   size of the EEPROM in byte
31  *
32  * Supports multiple M24LR chip variants (e.g., M24LRxx) by allowing each
33  * to define its own set of sysfs attributes, depending on its available
34  * registers and features.
35  */
36 struct m24lr_chip {
37 	unsigned int sss_len;
38 	unsigned int page_size;
39 	unsigned int eeprom_size;
40 };
41 
42 /**
43  * struct m24lr - core driver data for M24LR chip control
44  * @uid:           64 bits unique identifier stored in the device
45  * @sss_len:       the length of the sss region
46  * @page_size:	   chip-specific limit on the maximum number of bytes allowed
47  *		   in a single write operation.
48  * @eeprom_size:   size of the EEPROM in byte
49  * @ctl_regmap:	   regmap interface for accessing the system parameter sector
50  * @eeprom_regmap: regmap interface for accessing the EEPROM
51  * @lock:	   mutex to synchronize operations to the device
52  *
53  * Central data structure holding the state and resources used by the
54  * M24LR device driver.
55  */
56 struct m24lr {
57 	u64 uid;
58 	unsigned int sss_len;
59 	unsigned int page_size;
60 	unsigned int eeprom_size;
61 	struct regmap *ctl_regmap;
62 	struct regmap *eeprom_regmap;
63 	struct mutex lock;	 /* synchronize operations to the device */
64 };
65 
66 static const struct regmap_range m24lr_ctl_vo_ranges[] = {
67 	regmap_reg_range(0, 63),
68 };
69 
70 static const struct regmap_access_table m24lr_ctl_vo_table = {
71 	.yes_ranges = m24lr_ctl_vo_ranges,
72 	.n_yes_ranges = ARRAY_SIZE(m24lr_ctl_vo_ranges),
73 };
74 
75 static const struct regmap_config m24lr_ctl_regmap_conf = {
76 	.name = "m24lr_ctl",
77 	.reg_stride = 1,
78 	.reg_bits = 16,
79 	.val_bits = 8,
80 	.disable_locking = false,
81 	.cache_type = REGCACHE_RBTREE,/* Flat can't be used, there's huge gap */
82 	.volatile_table = &m24lr_ctl_vo_table,
83 };
84 
85 /* Chip descriptor for M24LR04E-R variant */
86 static const struct m24lr_chip m24lr04e_r_chip = {
87 	.page_size = 4,
88 	.eeprom_size = 512,
89 	.sss_len = 4,
90 };
91 
92 /* Chip descriptor for M24LR16E-R variant */
93 static const struct m24lr_chip m24lr16e_r_chip = {
94 	.page_size = 4,
95 	.eeprom_size = 2048,
96 	.sss_len = 16,
97 };
98 
99 /* Chip descriptor for M24LR64E-R variant */
100 static const struct m24lr_chip m24lr64e_r_chip = {
101 	.page_size = 4,
102 	.eeprom_size = 8192,
103 	.sss_len = 64,
104 };
105 
106 static const struct i2c_device_id m24lr_ids[] = {
107 	{ "m24lr04e-r", (kernel_ulong_t)&m24lr04e_r_chip},
108 	{ "m24lr16e-r", (kernel_ulong_t)&m24lr16e_r_chip},
109 	{ "m24lr64e-r", (kernel_ulong_t)&m24lr64e_r_chip},
110 	{ }
111 };
112 MODULE_DEVICE_TABLE(i2c, m24lr_ids);
113 
114 static const struct of_device_id m24lr_of_match[] = {
115 	{ .compatible = "st,m24lr04e-r", .data = &m24lr04e_r_chip},
116 	{ .compatible = "st,m24lr16e-r", .data = &m24lr16e_r_chip},
117 	{ .compatible = "st,m24lr64e-r", .data = &m24lr64e_r_chip},
118 	{ }
119 };
120 MODULE_DEVICE_TABLE(of, m24lr_of_match);
121 
122 /**
123  * m24lr_regmap_read - read data using regmap with retry on failure
124  * @regmap:  regmap instance for the device
125  * @buf:     buffer to store the read data
126  * @size:    number of bytes to read
127  * @offset:  starting register address
128  *
129  * Attempts to read a block of data from the device with retries and timeout.
130  * Some M24LR chips may transiently NACK reads (e.g., during internal write
131  * cycles), so this function retries with a short sleep until the timeout
132  * expires.
133  *
134  * Returns:
135  *	 Number of bytes read on success,
136  *	 -ETIMEDOUT if the read fails within the timeout window.
137  */
138 static ssize_t m24lr_regmap_read(struct regmap *regmap, u8 *buf,
139 				 size_t size, unsigned int offset)
140 {
141 	int err;
142 	unsigned long timeout, read_time;
143 	ssize_t ret = -ETIMEDOUT;
144 
145 	timeout = jiffies + msecs_to_jiffies(M24LR_READ_TIMEOUT);
146 	do {
147 		read_time = jiffies;
148 
149 		err = regmap_bulk_read(regmap, offset, buf, size);
150 		if (!err) {
151 			ret = size;
152 			break;
153 		}
154 
155 		usleep_range(1000, 2000);
156 	} while (time_before(read_time, timeout));
157 
158 	return ret;
159 }
160 
161 /**
162  * m24lr_regmap_write - write data using regmap with retry on failure
163  * @regmap: regmap instance for the device
164  * @buf:    buffer containing the data to write
165  * @size:   number of bytes to write
166  * @offset: starting register address
167  *
168  * Attempts to write a block of data to the device with retries and a timeout.
169  * Some M24LR devices may NACK I2C writes while an internal write operation
170  * is in progress. This function retries the write operation with a short delay
171  * until it succeeds or the timeout is reached.
172  *
173  * Returns:
174  *	 Number of bytes written on success,
175  *	 -ETIMEDOUT if the write fails within the timeout window.
176  */
177 static ssize_t m24lr_regmap_write(struct regmap *regmap, const u8 *buf,
178 				  size_t size, unsigned int offset)
179 {
180 	int err;
181 	unsigned long timeout, write_time;
182 	ssize_t ret = -ETIMEDOUT;
183 
184 	timeout = jiffies + msecs_to_jiffies(M24LR_WRITE_TIMEOUT);
185 
186 	do {
187 		write_time = jiffies;
188 
189 		err = regmap_bulk_write(regmap, offset, buf, size);
190 		if (!err) {
191 			ret = size;
192 			break;
193 		}
194 
195 		usleep_range(1000, 2000);
196 	} while (time_before(write_time, timeout));
197 
198 	return ret;
199 }
200 
201 static ssize_t m24lr_read(struct m24lr *m24lr, u8 *buf, size_t size,
202 			  unsigned int offset, bool is_eeprom)
203 {
204 	struct regmap *regmap;
205 	ssize_t ret;
206 
207 	if (is_eeprom)
208 		regmap = m24lr->eeprom_regmap;
209 	else
210 		regmap = m24lr->ctl_regmap;
211 
212 	mutex_lock(&m24lr->lock);
213 	ret = m24lr_regmap_read(regmap, buf, size, offset);
214 	mutex_unlock(&m24lr->lock);
215 
216 	return ret;
217 }
218 
219 /**
220  * m24lr_write - write buffer to M24LR device with page alignment handling
221  * @m24lr:     pointer to driver context
222  * @buf:       data buffer to write
223  * @size:      number of bytes to write
224  * @offset:    target register address in the device
225  * @is_eeprom: true if the write should target the EEPROM,
226  *             false if it should target the system parameters sector.
227  *
228  * Writes data to the M24LR device using regmap, split into chunks no larger
229  * than page_size to respect device-specific write limitations (e.g., page
230  * size or I2C hold-time concerns). Each chunk is aligned to the page boundary
231  * defined by page_size.
232  *
233  * Returns:
234  *	 Total number of bytes written on success,
235  *	 A negative error code if any write fails.
236  */
237 static ssize_t m24lr_write(struct m24lr *m24lr, const u8 *buf, size_t size,
238 			   unsigned int offset, bool is_eeprom)
239 {
240 	unsigned int n, next_sector;
241 	struct regmap *regmap;
242 	ssize_t ret = 0;
243 	ssize_t err;
244 
245 	if (is_eeprom)
246 		regmap = m24lr->eeprom_regmap;
247 	else
248 		regmap = m24lr->ctl_regmap;
249 
250 	n = min_t(unsigned int, size, m24lr->page_size);
251 	next_sector = roundup(offset + 1, m24lr->page_size);
252 	if (offset + n > next_sector)
253 		n = next_sector - offset;
254 
255 	mutex_lock(&m24lr->lock);
256 	while (n) {
257 		err = m24lr_regmap_write(regmap, buf + offset, n, offset);
258 		if (IS_ERR_VALUE(err)) {
259 			if (!ret)
260 				ret = err;
261 
262 			break;
263 		}
264 
265 		offset += n;
266 		size -= n;
267 		ret += n;
268 		n = min_t(unsigned int, size, m24lr->page_size);
269 	}
270 	mutex_unlock(&m24lr->lock);
271 
272 	return ret;
273 }
274 
275 /**
276  * m24lr_write_pass - Write password to M24LR043-R using secure format
277  * @m24lr: Pointer to device control structure
278  * @buf:   Input buffer containing hex-encoded password
279  * @count: Number of bytes in @buf
280  * @code:  Operation code to embed between password copies
281  *
282  * This function parses a 4-byte password, encodes it in  big-endian format,
283  * and constructs a 9-byte sequence of the form:
284  *
285  *	  [BE(password), code, BE(password)]
286  *
287  * The result is written to register 0x0900 (2304), which is the password
288  * register in M24LR04E-R chip.
289  *
290  * Return: Number of bytes written on success, or negative error code on failure
291  */
292 static ssize_t m24lr_write_pass(struct m24lr *m24lr, const char *buf,
293 				size_t count, u8 code)
294 {
295 	__be32 be_pass;
296 	u8 output[9];
297 	ssize_t ret;
298 	u32 pass;
299 	int err;
300 
301 	if (!count)
302 		return -EINVAL;
303 
304 	if (count > 8)
305 		return -EINVAL;
306 
307 	err = kstrtou32(buf, 16, &pass);
308 	if (err)
309 		return err;
310 
311 	be_pass = cpu_to_be32(pass);
312 
313 	memcpy(output, &be_pass, sizeof(be_pass));
314 	output[4] = code;
315 	memcpy(output + 5, &be_pass, sizeof(be_pass));
316 
317 	mutex_lock(&m24lr->lock);
318 	ret = m24lr_regmap_write(m24lr->ctl_regmap, output, 9, 2304);
319 	mutex_unlock(&m24lr->lock);
320 
321 	return ret;
322 }
323 
324 static ssize_t m24lr_read_reg_le(struct m24lr *m24lr, u64 *val,
325 				 unsigned int reg_addr,
326 				 unsigned int reg_size)
327 {
328 	ssize_t ret;
329 	__le64 input = 0;
330 
331 	ret = m24lr_read(m24lr, (u8 *)&input, reg_size, reg_addr, false);
332 	if (IS_ERR_VALUE(ret))
333 		return ret;
334 
335 	if (ret != reg_size)
336 		return -EINVAL;
337 
338 	switch (reg_size) {
339 	case 1:
340 		*val = *(u8 *)&input;
341 		break;
342 	case 2:
343 		*val = le16_to_cpu((__le16)input);
344 		break;
345 	case 4:
346 		*val = le32_to_cpu((__le32)input);
347 		break;
348 	case 8:
349 		*val = le64_to_cpu((__le64)input);
350 		break;
351 	default:
352 		return -EINVAL;
353 	}
354 
355 	return 0;
356 }
357 
358 static int m24lr_nvmem_read(void *priv, unsigned int offset, void *val,
359 			    size_t bytes)
360 {
361 	ssize_t err;
362 	struct m24lr *m24lr = priv;
363 
364 	if (!bytes)
365 		return bytes;
366 
367 	if (offset + bytes > m24lr->eeprom_size)
368 		return -EINVAL;
369 
370 	err = m24lr_read(m24lr, val, bytes, offset, true);
371 	if (IS_ERR_VALUE(err))
372 		return err;
373 
374 	return 0;
375 }
376 
377 static int m24lr_nvmem_write(void *priv, unsigned int offset, void *val,
378 			     size_t bytes)
379 {
380 	ssize_t err;
381 	struct m24lr *m24lr = priv;
382 
383 	if (!bytes)
384 		return -EINVAL;
385 
386 	if (offset + bytes > m24lr->eeprom_size)
387 		return -EINVAL;
388 
389 	err = m24lr_write(m24lr, val, bytes, offset, true);
390 	if (IS_ERR_VALUE(err))
391 		return err;
392 
393 	return 0;
394 }
395 
396 static ssize_t m24lr_ctl_sss_read(struct file *filep, struct kobject *kobj,
397 				  const struct bin_attribute *attr, char *buf,
398 				  loff_t offset, size_t count)
399 {
400 	struct m24lr *m24lr = attr->private;
401 
402 	if (!count)
403 		return count;
404 
405 	if (size_add(offset, count) > m24lr->sss_len)
406 		return -EINVAL;
407 
408 	return m24lr_read(m24lr, buf, count, offset, false);
409 }
410 
411 static ssize_t m24lr_ctl_sss_write(struct file *filep, struct kobject *kobj,
412 				   const struct bin_attribute *attr, char *buf,
413 				   loff_t offset, size_t count)
414 {
415 	struct m24lr *m24lr = attr->private;
416 
417 	if (!count)
418 		return -EINVAL;
419 
420 	if (size_add(offset, count) > m24lr->sss_len)
421 		return -EINVAL;
422 
423 	return m24lr_write(m24lr, buf, count, offset, false);
424 }
425 static BIN_ATTR(sss, 0600, m24lr_ctl_sss_read, m24lr_ctl_sss_write, 0);
426 
427 static ssize_t new_pass_store(struct device *dev, struct device_attribute *attr,
428 			      const char *buf, size_t count)
429 {
430 	struct m24lr *m24lr = i2c_get_clientdata(to_i2c_client(dev));
431 
432 	return m24lr_write_pass(m24lr, buf, count, 7);
433 }
434 static DEVICE_ATTR_WO(new_pass);
435 
436 static ssize_t unlock_store(struct device *dev, struct device_attribute *attr,
437 			    const char *buf, size_t count)
438 {
439 	struct m24lr *m24lr = i2c_get_clientdata(to_i2c_client(dev));
440 
441 	return m24lr_write_pass(m24lr, buf, count, 9);
442 }
443 static DEVICE_ATTR_WO(unlock);
444 
445 static ssize_t uid_show(struct device *dev, struct device_attribute *attr,
446 			char *buf)
447 {
448 	struct m24lr *m24lr = i2c_get_clientdata(to_i2c_client(dev));
449 
450 	return sysfs_emit(buf, "%llx\n", m24lr->uid);
451 }
452 static DEVICE_ATTR_RO(uid);
453 
454 static ssize_t total_sectors_show(struct device *dev,
455 				  struct device_attribute *attr, char *buf)
456 {
457 	struct m24lr *m24lr = i2c_get_clientdata(to_i2c_client(dev));
458 
459 	return sysfs_emit(buf, "%x\n", m24lr->sss_len);
460 }
461 static DEVICE_ATTR_RO(total_sectors);
462 
463 static struct attribute *m24lr_ctl_dev_attrs[] = {
464 	&dev_attr_unlock.attr,
465 	&dev_attr_new_pass.attr,
466 	&dev_attr_uid.attr,
467 	&dev_attr_total_sectors.attr,
468 	NULL,
469 };
470 
471 static const struct m24lr_chip *m24lr_get_chip(struct device *dev)
472 {
473 	const struct m24lr_chip *ret;
474 	const struct i2c_device_id *id;
475 
476 	id = i2c_match_id(m24lr_ids, to_i2c_client(dev));
477 
478 	if (dev->of_node && of_match_device(m24lr_of_match, dev))
479 		ret = of_device_get_match_data(dev);
480 	else if (id)
481 		ret = (void *)id->driver_data;
482 	else
483 		ret = acpi_device_get_match_data(dev);
484 
485 	return ret;
486 }
487 
488 static int m24lr_probe(struct i2c_client *client)
489 {
490 	struct regmap_config eeprom_regmap_conf = {0};
491 	struct nvmem_config nvmem_conf = {0};
492 	struct device *dev = &client->dev;
493 	struct i2c_client *eeprom_client;
494 	const struct m24lr_chip *chip;
495 	struct regmap *eeprom_regmap;
496 	struct nvmem_device *nvmem;
497 	struct regmap *ctl_regmap;
498 	struct m24lr *m24lr;
499 	u32 regs[2];
500 	long err;
501 
502 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
503 		return -EOPNOTSUPP;
504 
505 	chip = m24lr_get_chip(dev);
506 	if (!chip)
507 		return -ENODEV;
508 
509 	m24lr = devm_kzalloc(dev, sizeof(struct m24lr), GFP_KERNEL);
510 	if (!m24lr)
511 		return -ENOMEM;
512 
513 	err = device_property_read_u32_array(dev, "reg", regs, ARRAY_SIZE(regs));
514 	if (err)
515 		return dev_err_probe(dev, err, "Failed to read 'reg' property\n");
516 
517 	/* Create a second I2C client for the eeprom interface */
518 	eeprom_client = devm_i2c_new_dummy_device(dev, client->adapter, regs[1]);
519 	if (IS_ERR(eeprom_client))
520 		return dev_err_probe(dev, PTR_ERR(eeprom_client),
521 				     "Failed to create dummy I2C client for the EEPROM\n");
522 
523 	ctl_regmap = devm_regmap_init_i2c(client, &m24lr_ctl_regmap_conf);
524 	if (IS_ERR(ctl_regmap))
525 		return dev_err_probe(dev, PTR_ERR(ctl_regmap),
526 				      "Failed to init regmap\n");
527 
528 	eeprom_regmap_conf.name = "m24lr_eeprom";
529 	eeprom_regmap_conf.reg_bits = 16;
530 	eeprom_regmap_conf.val_bits = 8;
531 	eeprom_regmap_conf.disable_locking = true;
532 	eeprom_regmap_conf.max_register = chip->eeprom_size - 1;
533 
534 	eeprom_regmap = devm_regmap_init_i2c(eeprom_client,
535 					     &eeprom_regmap_conf);
536 	if (IS_ERR(eeprom_regmap))
537 		return dev_err_probe(dev, PTR_ERR(eeprom_regmap),
538 				     "Failed to init regmap\n");
539 
540 	mutex_init(&m24lr->lock);
541 	m24lr->sss_len = chip->sss_len;
542 	m24lr->page_size = chip->page_size;
543 	m24lr->eeprom_size = chip->eeprom_size;
544 	m24lr->eeprom_regmap = eeprom_regmap;
545 	m24lr->ctl_regmap = ctl_regmap;
546 
547 	nvmem_conf.dev = &eeprom_client->dev;
548 	nvmem_conf.owner = THIS_MODULE;
549 	nvmem_conf.type = NVMEM_TYPE_EEPROM;
550 	nvmem_conf.reg_read = m24lr_nvmem_read;
551 	nvmem_conf.reg_write = m24lr_nvmem_write;
552 	nvmem_conf.size = chip->eeprom_size;
553 	nvmem_conf.word_size = 1;
554 	nvmem_conf.stride = 1;
555 	nvmem_conf.priv = m24lr;
556 
557 	nvmem = devm_nvmem_register(dev, &nvmem_conf);
558 	if (IS_ERR(nvmem))
559 		return dev_err_probe(dev, PTR_ERR(nvmem),
560 				     "Failed to register nvmem\n");
561 
562 	i2c_set_clientdata(client, m24lr);
563 	i2c_set_clientdata(eeprom_client, m24lr);
564 
565 	bin_attr_sss.size = chip->sss_len;
566 	bin_attr_sss.private = m24lr;
567 	err = sysfs_create_bin_file(&dev->kobj, &bin_attr_sss);
568 	if (err)
569 		return dev_err_probe(dev, err,
570 				     "Failed to create sss bin file\n");
571 
572 	/* test by reading the uid, if success store it */
573 	err = m24lr_read_reg_le(m24lr, &m24lr->uid, 2324, sizeof(m24lr->uid));
574 	if (IS_ERR_VALUE(err))
575 		goto remove_bin_file;
576 
577 	return 0;
578 
579 remove_bin_file:
580 	sysfs_remove_bin_file(&dev->kobj, &bin_attr_sss);
581 
582 	return err;
583 }
584 
585 static void m24lr_remove(struct i2c_client *client)
586 {
587 	sysfs_remove_bin_file(&client->dev.kobj, &bin_attr_sss);
588 }
589 
590 ATTRIBUTE_GROUPS(m24lr_ctl_dev);
591 
592 static struct i2c_driver m24lr_driver = {
593 	.driver = {
594 		.name = "m24lr",
595 		.of_match_table = m24lr_of_match,
596 		.dev_groups = m24lr_ctl_dev_groups,
597 	},
598 	.probe	  = m24lr_probe,
599 	.remove = m24lr_remove,
600 	.id_table = m24lr_ids,
601 };
602 module_i2c_driver(m24lr_driver);
603 
604 MODULE_AUTHOR("Abd-Alrhman Masalkhi");
605 MODULE_DESCRIPTION("st m24lr control driver");
606 MODULE_LICENSE("GPL");
607