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, ®);
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, ®);
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(®, 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(®, &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