xref: /illumos-gate/usr/src/uts/common/io/i2c/eeprom/at24c/at24c.c (revision 04a1c1a11476a9a84da46c1937024cde61ddb850)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2025 Oxide Computer Company
14  */
15 
16 /*
17  * AT24 series EEPROM device driver.
18  *
19  * The AT24 series of EEPROMs are a venerable line that cover several different
20  * sizes. These all have similar features:
21  *
22  *  - The EEPROM is organized in terms of pages. The size of a page can be as
23  *    small as 8 bytes or as large as 256 bytes.
24  *
25  *  - Addressing is often a combination of both the device address and a 1 or
26  *    2-byte address register. Each register location generally stores a single
27  *    byte of data. This means that a 1-byte register covers data locations
28  *    [7:0] and the 2-byte, [15:0]. If a device exceeds that, then they start
29  *    using additional I2C addresses. Let's look at a few examples:
30  *
31  *    1) The AT24C01 is a 128 byte device. It uses a 1-byte address. It uses
32  *    addr[6:0] to address all of the data. It only uses a single I2C address.
33  *
34  *    2) The AT24C32 is a 32 KiB device that uses 2-byte addresses. While it
35  *    needs a 12-bit address, because it uses a 2-byte address, it only needs to
36  *    use a single I2C address.
37  *
38  *    3) The AT24C08 is an 8 KiB device, which means it needs 1024 data
39  *    locations. It uses a single byte address register. Therefore, it specifies
40  *    addr[9:8] using the I2C address that refers to the device and addr[7:0]
41  *    using the register.
42  *
43  *    These different cases lead us to using multiple clients to cover a single
44  *    device.
45  *
46  *  - The device supports random reads. These reads can and will increment the
47  *    address register internally. This is the primary way that we support
48  *    reads.
49  *
50  *  - The device supports what it calls page writes and single byte writes. The
51  *    page writes are more interesting. Effectively a page write is where we
52  *    write multiple bytes starting from the address. The device will internally
53  *    increment this, but it will roll over when it hits the page boundary.
54  *
55  *    After a write completes, the device will no longer ack its address until
56  *    the write completes. Therefore, we need to end up polling for
57  *    completeness.
58  *
59  *  - With the above we don't employ actual I2C bus exclusion; however, the
60  *    driver does use a per-instance mutex to ensure that only one write per
61  *    device is going on at a time and that no other reads can interleave that
62  *    until the actual polling has completed.
63  */
64 
65 #include <sys/modctl.h>
66 #include <sys/conf.h>
67 #include <sys/devops.h>
68 #include <sys/ddi.h>
69 #include <sys/sunddi.h>
70 #include <sys/bitext.h>
71 #include <sys/sysmacros.h>
72 #include <sys/i2c/client.h>
73 #include <eedev.h>
74 
75 /*
76  * The default size in bytes that we use as the maximum amount of I/O that we
77  * will perform in one go.
78  */
79 #define	AT24C_MAX_IO	128
80 
81 /*
82  * This is the default time and attempts that we'll wait for a write to
83  * complete. Most devices have a 5ms timeout, but some have up to 20ms. We
84  * basically will go up to 25ms here. This isn't an absolute delay so we can
85  * make sure that if we lose the i2c bus, we still try at least 5 times.
86  */
87 static uint32_t at24c_write_to_count = 5;
88 static uint32_t at24c_write_delay_us = 5000;
89 
90 typedef struct at24c_ident {
91 	const char *ati_name;
92 	const char *ati_compat;
93 	size_t ati_size;
94 	size_t ati_page;
95 	bool ati_addr16;
96 } at24c_ident_t;
97 
98 typedef struct at24c {
99 	dev_info_t *at_dip;
100 	kmutex_t at_mutex;
101 	const at24c_ident_t *at_ident;
102 	size_t at_naddrs;
103 	i2c_client_t **at_clients;
104 	i2c_reg_hdl_t **at_regs;
105 	eedev_hdl_t *at_eedev;
106 	uint8_t at_buf[AT24C_MAX_IO];
107 } at24c_t;
108 
109 static const at24c_ident_t at24c_idents[] = {
110 	{
111 		.ati_name = "at24c01",
112 		.ati_compat = "atmel,at24c01",
113 		.ati_size = 128,
114 		.ati_page = 8,
115 		.ati_addr16 = false
116 	}, {
117 		.ati_name = "at24c02",
118 		.ati_compat = "atmel,at24c02",
119 		.ati_size = 256,
120 		.ati_page = 8,
121 		.ati_addr16 = false
122 	}, {
123 		.ati_name = "at24c04",
124 		.ati_compat = "atmel,at24c04",
125 		.ati_size = 512,
126 		.ati_page = 16,
127 		.ati_addr16 = false
128 	}, {
129 		.ati_name = "at24c08",
130 		.ati_compat = "atmel,at24c08",
131 		.ati_size = 1024,
132 		.ati_page = 16,
133 		.ati_addr16 = false
134 	}, {
135 		.ati_name = "at24c16",
136 		.ati_compat = "atmel,at24c16",
137 		.ati_size = 2 * 1024,
138 		.ati_page = 16,
139 		.ati_addr16 = false
140 	}, {
141 		.ati_name = "at24c32",
142 		.ati_compat = "atmel,at24c32",
143 		.ati_size = 4 * 1024,
144 		.ati_page = 32,
145 		.ati_addr16 = true
146 	}, {
147 		.ati_name = "at24c64",
148 		.ati_compat = "atmel,at24c64",
149 		.ati_size = 8 * 1024,
150 		.ati_page = 32,
151 		.ati_addr16 = true
152 	}, {
153 		.ati_name = "at24c128",
154 		.ati_compat = "atmel,at24c128",
155 		.ati_size = 16 * 1024,
156 		.ati_page = 64,
157 		.ati_addr16 = true
158 	}, {
159 		.ati_name = "at24c256",
160 		.ati_compat = "atmel,at24c256",
161 		.ati_size = 32 * 1024,
162 		.ati_page = 64,
163 		.ati_addr16 = true
164 	}, {
165 		.ati_name = "at24c512",
166 		.ati_compat = "atmel,at24c512",
167 		.ati_size = 64 * 1024,
168 		.ati_page = 128,
169 		.ati_addr16 = true
170 	}, {
171 		.ati_name = "at24c1024",
172 		.ati_compat = "atmel,at24c1024",
173 		.ati_size = 128 * 1024,
174 		.ati_page = 256,
175 		.ati_addr16 = true
176 	}
177 };
178 
179 /*
180  * Take a device page and offset and turn it into the corresponding I2C client.
181  * While the device is arranged in terms of pages, it is addressed in terms of
182  * bytes. This is then broken into client and the offset in that client based on
183  * whether or not we're using 8-bit or 16-bit addressing.
184  */
185 static void
at24c_page_to_addr(at24c_t * at,uint32_t page,uint32_t pageoff,uint32_t * clino,uint32_t * addrp)186 at24c_page_to_addr(at24c_t *at, uint32_t page, uint32_t pageoff,
187     uint32_t *clino, uint32_t *addrp)
188 {
189 	uint32_t addr = page * at->at_ident->ati_page + pageoff;
190 	uint32_t addrlen = at->at_ident->ati_addr16 ? 1 << 16 : 1 << 8;
191 	*clino = addr / addrlen;
192 	*addrp = addr % addrlen;
193 	VERIFY3U(*clino, <, at->at_naddrs);
194 }
195 
196 static int
at24c_read(void * arg,struct uio * uio,uint32_t page,uint32_t pageoff,uint32_t nbytes)197 at24c_read(void *arg, struct uio *uio, uint32_t page, uint32_t pageoff,
198     uint32_t nbytes)
199 {
200 	int ret;
201 	uint32_t idx, reg;
202 	i2c_error_t err;
203 	at24c_t *at = arg;
204 
205 	at24c_page_to_addr(at, page, pageoff, &idx, &reg);
206 	mutex_enter(&at->at_mutex);
207 	if (i2c_reg_get(NULL, at->at_regs[idx], reg, at->at_buf, nbytes,
208 	    &err)) {
209 		ret = uiomove(at->at_buf, nbytes, UIO_READ, uio);
210 	} else {
211 		dev_err(at->at_dip, CE_WARN, "!failed to read %u bytes on "
212 		    "client %u, addr 0x%x: 0x%x/0x%x", nbytes, idx, reg,
213 		    err.i2c_error, err.i2c_ctrl);
214 		ret = EIO;
215 	}
216 	mutex_exit(&at->at_mutex);
217 
218 	return (ret);
219 }
220 
221 /*
222  * Determine if this error is an address related NACK which means that the
223  * device is still busy.
224  */
225 static bool
at24c_poll_nack(const i2c_error_t * err)226 at24c_poll_nack(const i2c_error_t *err)
227 {
228 	if (err->i2c_error != I2C_CORE_E_CONTROLLER) {
229 		return (false);
230 	}
231 
232 	return (err->i2c_ctrl == I2C_CTRL_E_ADDR_NACK ||
233 	    err->i2c_ctrl == I2C_CTRL_E_NACK);
234 }
235 
236 static int
at24c_write(void * arg,struct uio * uio,uint32_t page,uint32_t pageoff,uint32_t nbytes)237 at24c_write(void *arg, struct uio *uio, uint32_t page, uint32_t pageoff,
238     uint32_t nbytes)
239 {
240 	int ret = EIO;
241 	uint32_t idx, reg;
242 	i2c_error_t err;
243 	at24c_t *at = arg;
244 
245 	at24c_page_to_addr(at, page, pageoff, &idx, &reg);
246 	mutex_enter(&at->at_mutex);
247 	ret = uiomove(at->at_buf, nbytes, UIO_WRITE, uio);
248 	if (ret != 0) {
249 		mutex_exit(&at->at_mutex);
250 		return (ret);
251 	}
252 
253 	if (!i2c_reg_put(NULL, at->at_regs[idx], reg, at->at_buf, nbytes,
254 	    &err)) {
255 		dev_err(at->at_dip, CE_WARN, "!failed to write %u bytes on "
256 		    "client %u, addr 0x%x: 0x%x/0x%x", nbytes, idx, reg,
257 		    err.i2c_error, err.i2c_ctrl);
258 		goto done;
259 	}
260 
261 	/*
262 	 * Now we must poll waiting to get an ack. We do this by performing a
263 	 * simple 1 byte read. The Atmel data sheets generally suggested that
264 	 * this should actually be us looking for an ack to determine what
265 	 * operation we want to be able to perform. We use a read here as we
266 	 * don't want to do a quick write and test how well different clones
267 	 * handle this.
268 	 */
269 	for (uint32_t i = 0; i < at24c_write_to_count; i++) {
270 		uint8_t val;
271 
272 		delay(drv_usectohz(at24c_write_delay_us));
273 		if (i2c_reg_get(NULL, at->at_regs[idx], 0, &val, sizeof (val),
274 		    &err)) {
275 			ret = 0;
276 			break;
277 		}
278 
279 		if (!at24c_poll_nack(&err)) {
280 			dev_err(at->at_dip, CE_WARN, "!failed to read after "
281 			    "write on client %u, addr 0x%x: 0x%x/0x%x", idx,
282 			    reg, err.i2c_error, err.i2c_ctrl);
283 			goto done;
284 		}
285 	}
286 
287 	if (ret != 0) {
288 		dev_err(at->at_dip, CE_WARN, "!timed out waiting for write ack "
289 		    "on client %u, addr 0x%x: 0x%x/0x%x",  idx, reg,
290 		    err.i2c_error, err.i2c_ctrl);
291 	}
292 
293 done:
294 	mutex_exit(&at->at_mutex);
295 	if (ret != 0) {
296 		uio->uio_resid += nbytes;
297 		uio->uio_loffset -= nbytes;
298 	}
299 	return (ret);
300 }
301 
302 static const eedev_ops_t at24c_eedev_ops = {
303 	.eo_read = at24c_read,
304 	.eo_write = at24c_write
305 };
306 
307 static bool
at24c_ident(at24c_t * at)308 at24c_ident(at24c_t *at)
309 {
310 	const char *bind = ddi_binding_name(at->at_dip);
311 	const char *name = ddi_node_name(at->at_dip);
312 
313 	for (size_t i = 0; i < ARRAY_SIZE(at24c_idents); i++) {
314 		if (strcmp(bind, at24c_idents[i].ati_name) == 0 ||
315 		    strcmp(bind, at24c_idents[i].ati_compat) == 0 ||
316 		    strcmp(name, at24c_idents[i].ati_name) == 0 ||
317 		    strcmp(name, at24c_idents[i].ati_compat) == 0) {
318 			at->at_ident = &at24c_idents[i];
319 			return (true);
320 		}
321 
322 	}
323 
324 	dev_err(at->at_dip, CE_WARN, "failed to match against node name %s "
325 	    "and binding name %s", name, bind);
326 	return (false);
327 }
328 
329 static bool
at24c_i2c_init(at24c_t * at)330 at24c_i2c_init(at24c_t *at)
331 {
332 	i2c_errno_t err;
333 	uint8_t addrlen = at->at_ident->ati_addr16 ? 16 : 8;
334 
335 	at->at_naddrs = at->at_ident->ati_size / (1 << addrlen);
336 	if ((at->at_ident->ati_size % (1 << addrlen)) != 0)
337 		at->at_naddrs++;
338 	VERIFY3U(at->at_naddrs, >, 0);
339 	at->at_clients = kmem_zalloc(at->at_naddrs * sizeof (i2c_client_t *),
340 	    KM_SLEEP);
341 	at->at_regs = kmem_zalloc(at->at_naddrs * sizeof (i2c_reg_hdl_t *),
342 	    KM_SLEEP);
343 
344 	if ((err = i2c_client_init(at->at_dip, 0, &at->at_clients[0])) !=
345 	    I2C_CORE_E_OK) {
346 		dev_err(at->at_dip, CE_WARN, "failed to create i2c client: "
347 		    "0x%x", err);
348 		return (false);
349 	}
350 
351 	for (size_t i = 1; i < at->at_naddrs; i++) {
352 		i2c_addr_t addr = *i2c_client_addr((at->at_clients[0]));
353 
354 		addr.ia_addr += i;
355 		if ((err = i2c_client_claim_addr(at->at_dip, &addr, 0,
356 		    &at->at_clients[i])) != I2C_CORE_E_OK) {
357 			dev_err(at->at_dip, CE_WARN, "failed to claim client "
358 			    "%zu address 0x%x: 0x%x", i, addr.ia_addr, err);
359 			return (false);
360 		}
361 	}
362 
363 	i2c_reg_acc_attr_t attr;
364 	bzero(&attr, sizeof (attr));
365 
366 	attr.i2cacc_version = I2C_REG_ACC_ATTR_V0;
367 	if (at->at_ident->ati_addr16) {
368 		attr.i2cacc_addr_len = 2;
369 		attr.i2cacc_addr_endian = DDI_STRUCTURE_BE_ACC;
370 	} else {
371 		attr.i2cacc_addr_len = 1;
372 	}
373 	attr.i2cacc_addr_max = (1 << addrlen) - 1;
374 	attr.i2cacc_reg_len = 1;
375 
376 	for (size_t i = 0; i < at->at_naddrs; i++) {
377 		if ((err = i2c_reg_handle_init(at->at_clients[i], &attr,
378 		    &at->at_regs[i])) != I2C_CORE_E_OK) {
379 			dev_err(at->at_dip, CE_WARN, "failed to create "
380 			    "register handle %zu: %s (0x%x)", i,
381 			    i2c_client_errtostr(at->at_clients[i], err), err);
382 			return (false);
383 		}
384 	}
385 
386 	return (true);
387 }
388 
389 static bool
at24c_eedev_init(at24c_t * at)390 at24c_eedev_init(at24c_t *at)
391 {
392 	int ret;
393 	eedev_reg_t reg;
394 
395 	bzero(&reg, sizeof (reg));
396 	reg.ereg_vers = EEDEV_REG_VERS0;
397 	reg.ereg_size = at->at_ident->ati_size;
398 
399 	/*
400 	 * The segment here is true for writes, but reads are not quite as
401 	 * constrained. However, it's simpler for everything if we specify it
402 	 * tihs way.
403 	 */
404 	reg.ereg_seg = at->at_ident->ati_page;
405 	reg.ereg_read_gran = 1;
406 	reg.ereg_write_gran = 1;
407 
408 	/*
409 	 * The maximum we can read or write will be told to us by the register
410 	 * client. This takes the address length into account for us. We can
411 	 * then further constrain this by the maximum desired I/O in the client.
412 	 * Finally, for writes, we further constrain it so we don't exceed a
413 	 * single page when writing.
414 	 */
415 	reg.ereg_max_read = MIN(i2c_reg_max_read(at->at_regs[0]), AT24C_MAX_IO);
416 	reg.ereg_max_write = MIN(i2c_reg_max_write(at->at_regs[0]),
417 	    AT24C_MAX_IO);
418 	reg.ereg_max_write = MIN(reg.ereg_max_write, at->at_ident->ati_page);
419 	reg.ereg_dip = at->at_dip;
420 	reg.ereg_driver = at;
421 	reg.ereg_ops = &at24c_eedev_ops;
422 
423 	if ((ret = eedev_create(&reg, &at->at_eedev)) != 0) {
424 		dev_err(at->at_dip, CE_WARN, "failed to create eedev device: "
425 		    "%d", ret);
426 		return (false);
427 	}
428 
429 	return (true);
430 }
431 
432 static void
at24c_cleanup(at24c_t * at)433 at24c_cleanup(at24c_t *at)
434 {
435 	eedev_fini(at->at_eedev);
436 	for (size_t i = 0; i < at->at_naddrs; i++) {
437 		i2c_reg_handle_destroy(at->at_regs[i]);
438 		i2c_client_destroy(at->at_clients[i]);
439 	}
440 
441 	if (at->at_naddrs > 0) {
442 		kmem_free(at->at_regs, sizeof (i2c_reg_hdl_t *) *
443 		    at->at_naddrs);
444 		kmem_free(at->at_clients, sizeof (i2c_client_t *) *
445 		    at->at_naddrs);
446 	}
447 
448 	mutex_destroy(&at->at_mutex);
449 	ddi_set_driver_private(at->at_dip, NULL);
450 	at->at_dip = NULL;
451 	kmem_free(at, sizeof (at24c_t));
452 }
453 
454 static int
at24c_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)455 at24c_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
456 {
457 	at24c_t *at;
458 
459 	switch (cmd) {
460 	case DDI_ATTACH:
461 		break;
462 	case DDI_RESUME:
463 		return (DDI_SUCCESS);
464 	default:
465 		return (DDI_FAILURE);
466 	}
467 
468 	at = kmem_zalloc(sizeof (at24c_t), KM_SLEEP);
469 	at->at_dip = dip;
470 	ddi_set_driver_private(dip, at);
471 	mutex_init(&at->at_mutex, NULL, MUTEX_DRIVER, NULL);
472 
473 	if (!at24c_ident(at))
474 		goto cleanup;
475 
476 	if (!at24c_i2c_init(at))
477 		goto cleanup;
478 
479 	if (!at24c_eedev_init(at))
480 		goto cleanup;
481 
482 	return (DDI_SUCCESS);
483 
484 cleanup:
485 	at24c_cleanup(at);
486 	return (DDI_FAILURE);
487 }
488 
489 static int
at24c_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)490 at24c_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
491 {
492 	at24c_t *at;
493 
494 	switch (cmd) {
495 	case DDI_DETACH:
496 		break;
497 	case DDI_SUSPEND:
498 		return (DDI_SUCCESS);
499 	default:
500 		return (DDI_FAILURE);
501 	}
502 
503 	at = ddi_get_driver_private(dip);
504 	if (at == NULL) {
505 		dev_err(dip, CE_WARN, "asked to detach, but missing private "
506 		    "data");
507 		return (DDI_FAILURE);
508 	}
509 	VERIFY3P(at->at_dip, ==, dip);
510 
511 	at24c_cleanup(at);
512 	return (DDI_SUCCESS);
513 }
514 
515 static struct dev_ops at24c_dev_ops = {
516 	.devo_rev = DEVO_REV,
517 	.devo_refcnt = 0,
518 	.devo_identify = nulldev,
519 	.devo_probe = nulldev,
520 	.devo_attach = at24c_attach,
521 	.devo_detach = at24c_detach,
522 	.devo_reset = nodev,
523 	.devo_quiesce = ddi_quiesce_not_needed
524 };
525 
526 static struct modldrv at24c_modldrv = {
527 	.drv_modops = &mod_driverops,
528 	.drv_linkinfo = "SPD5118 driver",
529 	.drv_dev_ops = &at24c_dev_ops
530 };
531 
532 static struct modlinkage at24c_modlinkage = {
533 	.ml_rev = MODREV_1,
534 	.ml_linkage = { &at24c_modldrv, NULL }
535 };
536 
537 
538 int
_init(void)539 _init(void)
540 {
541 	return (mod_install(&at24c_modlinkage));
542 }
543 
544 int
_info(struct modinfo * modinfop)545 _info(struct modinfo *modinfop)
546 {
547 	return (mod_info(&at24c_modlinkage, modinfop));
548 }
549 
550 int
_fini(void)551 _fini(void)
552 {
553 	return (mod_remove(&at24c_modlinkage));
554 }
555