1 /* $NetBSD: fire_i2c.c,v 1.5 2026/09/25 07:16:27 jdc Exp $ */ 2 3 /*- 4 * Copyright (c) 2026 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Julian Coleman. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: fire_i2c.c,v 1.5 2026/09/25 07:16:27 jdc Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/condvar.h> 37 #include <sys/device.h> 38 #include <sys/intr.h> 39 #include <sys/kernel.h> 40 #include <sys/mutex.h> 41 42 #include <machine/autoconf.h> 43 #include <machine/openfirm.h> 44 45 #include <dev/pci/pcivar.h> 46 47 #include <dev/i2c/i2cvar.h> 48 #include <sparc64/dev/fire_i2creg.h> 49 #include <sparc64/dev/iommureg.h> 50 #include <sparc64/dev/iommuvar.h> 51 #include <sparc64/dev/pyrovar.h> 52 53 #include "ioconf.h" 54 55 #define FIREI2C_DEBUG 0 56 #if FIREI2C_DEBUG > 0 57 int dlvl = 1; /* Set to 2 for verbose i2c ops output */ 58 #define DPRINTF(n) if (dlvl >= n) printf 59 #else 60 #define DPRINTF(n) if (0) printf 61 #endif 62 63 #define FIREI2C_SCL_FREQ 100000 /* Target i2c clock frequency */ 64 #define FIREI2C_OWN_ADDR 0x08 /* Our i2c slave address */ 65 66 /* i2c clocks to match possible system clock frequencies (1/1, 1/2, 1/32) */ 67 #define FIREI2C_CLK_FULL 0 68 #define FIREI2C_CLK_HALF 1 69 #define FIREI2C_CLK_TT 2 70 #define FIREI2C_CLK_LEN 3 71 72 /* i2c operations */ 73 #define FIREI2C_OP_READ 0x01 74 #define FIREI2C_OP_WRITE 0x02 75 #define FIREI2C_OP_WR_RD 0x04 76 77 /* i2c stages */ 78 #define FIREI2C_STAGE_IDLE 0x00 79 #define FIREI2C_STAGE_START 0x01 80 #define FIREI2C_STAGE_WR_ADDR 0x02 81 #define FIREI2C_STAGE_RE_ADDR 0x04 82 #define FIREI2C_STAGE_WRITE 0x08 83 #define FIREI2C_STAGE_REPSTART 0x10 84 #define FIREI2C_STAGE_READ 0x20 85 #define FIREI2C_STAGE_STOP 0x40 86 87 /* mainbus intr map/mask are only used for i2c interrupts, so put them here. */ 88 struct mainbus_interrupt_map { 89 uint64_t paddr; /* phys addr mask */ 90 uint32_t intr; /* interrupt mask */ 91 int32_t cnode; /* child node */ 92 uint32_t cintr; /* child interrupt */ 93 } __packed; 94 95 struct mainbus_interrupt_map_mask { 96 uint64_t paddr; /* phys addr mask */ 97 uint32_t intr; /* interrupt */ 98 } __packed; 99 100 struct firei2c_softc { 101 device_t sc_dev; 102 bus_space_tag_t sc_bustag; 103 bus_space_handle_t sc_regh; 104 int sc_node; 105 void *sc_inth; 106 107 uint8_t sc_i2c_clks[FIREI2C_CLK_LEN]; /* Clocks for sys bus speeds */ 108 109 struct i2c_controller sc_i2c; 110 111 kmutex_t sc_mutex; /* Interrupt mutex ... */ 112 kcondvar_t sc_cv; /* ... and condvar */ 113 114 int sc_op; /* Operation to run */ 115 int sc_stage; /* Exec stage */ 116 i2c_addr_t sc_target; /* Saved exec args */ 117 const u_int8_t *sc_cmdbuf; /* ... */ 118 size_t sc_cmdlen; /* ... */ 119 u_int8_t *sc_buf; /* ... */ 120 size_t sc_buflen; /* ... */ 121 int sc_i; /* How far through buf */ 122 int sc_err; /* Error during transaction */ 123 124 }; 125 126 static int firei2c_match(device_t, cfdata_t, void *); 127 static void firei2c_attach(device_t, device_t, void *); 128 static void firei2c_intr_establish(struct firei2c_softc *, 129 struct mainbus_attach_args *); 130 static uint8_t firei2c_clock(int); 131 static int firei2c_stop(struct firei2c_softc *); 132 static int firei2c_wait(struct firei2c_softc *, int); 133 int firei2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, 134 size_t, void *, size_t, int); 135 static int firei2c_write(struct firei2c_softc *, const uint8_t *, size_t, 136 uint8_t *, size_t, int); 137 static int firei2c_read(struct firei2c_softc *, uint8_t *, size_t, int); 138 int firei2c_intr(void *); 139 static uint8_t firei2c_reg_read(struct firei2c_softc *, bus_size_t); 140 static void firei2c_reg_write(struct firei2c_softc *, bus_size_t, uint8_t); 141 142 CFATTACH_DECL_NEW(firei2c, sizeof(struct firei2c_softc), 143 firei2c_match, firei2c_attach, NULL, NULL); 144 145 static int 146 firei2c_match(device_t parent, cfdata_t cf, void *aux) 147 { 148 struct mainbus_attach_args *ma = aux; 149 char *compat; 150 151 if (strcmp(ma->ma_name, "i2c")) 152 return 0; 153 154 compat = prom_getpropstring(ma->ma_node, "compatible"); 155 if (!strcmp(compat, "fire-i2c")) 156 return 1; 157 158 return 0; 159 } 160 161 static void 162 firei2c_attach(device_t parent, device_t self, void *aux) 163 { 164 struct firei2c_softc *sc = device_private(self); 165 struct mainbus_attach_args *ma = aux; 166 int sysclk; 167 168 sc->sc_bustag = ma->ma_bustag; 169 sc->sc_node = ma->ma_node; 170 sc->sc_dev = self; 171 172 if (ma->ma_nreg != 1) { 173 aprint_error(": register count error (%d != 1)\n", 174 ma->ma_nreg); 175 return; 176 } 177 if (ma->ma_reg[0].ur_len < FIREI2C_SRST) { 178 aprint_error(": register length error (%" PRId64 " < %d\n", 179 ma->ma_reg[0].ur_len, FIREI2C_SRST); 180 return; 181 } 182 183 if (bus_space_map(sc->sc_bustag, ma->ma_reg[0].ur_paddr, 184 ma->ma_reg[0].ur_len, 0, &sc->sc_regh)) { 185 aprint_error(": failed to map registers\n"); 186 return; 187 } 188 189 aprint_normal(": addr %" PRIx64 ": Fire/MI2C i2c controller\n", 190 ma->ma_reg[0].ur_paddr); 191 192 firei2c_intr_establish(sc, ma); 193 194 /* Calculate clock, software reset, set our address */ 195 sysclk = prom_getpropint(findroot(), "clock-frequency", 0); 196 sc->sc_i2c_clks[FIREI2C_CLK_FULL] = firei2c_clock(sysclk); 197 sc->sc_i2c_clks[FIREI2C_CLK_HALF] = firei2c_clock(sysclk / 2); 198 sc->sc_i2c_clks[FIREI2C_CLK_TT] = firei2c_clock(sysclk / 32); 199 firei2c_reg_write(sc, FIREI2C_SRST, FIREI2C_SRST_RST); 200 delay(1000); 201 firei2c_reg_write(sc, FIREI2C_CCR, sc->sc_i2c_clks[FIREI2C_CLK_FULL]); 202 firei2c_reg_write(sc, FIREI2C_ADDR, 203 FIREI2C_OWN_ADDR << FIREI2C_ADDR_SHIFT); 204 205 /* i2c setup */ 206 iic_tag_init(&sc->sc_i2c); 207 sc->sc_i2c.ic_cookie = sc; 208 sc->sc_i2c.ic_exec = firei2c_exec; 209 210 /* Synchronisation between exec and intr */ 211 mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM); 212 cv_init(&sc->sc_cv, "firei2c"); 213 sc->sc_stage = FIREI2C_STAGE_IDLE; 214 215 iicbus_attach(sc->sc_dev, &sc->sc_i2c); 216 return; 217 } 218 219 /* 220 * Use the mainbus (root) interrupt map/mask to find our interrupt number 221 * (ino 60 or 61) and pyro leaf. 222 * Both i2c interrupts must go to the same pyro leaf, but we assume that 223 * OFW has set up the ino and the leaf mapping for us. 224 */ 225 #define IMASK_LEN 3 226 #define IMAP_LEN 10 227 static void 228 firei2c_intr_establish(struct firei2c_softc *sc, 229 struct mainbus_attach_args *ma) 230 { 231 struct mainbus_interrupt_map *mb_imap; 232 struct mainbus_interrupt_map_mask *mb_imask; 233 struct pyro_softc *psc = NULL; 234 int64_t paddr; 235 u_int intr; 236 int ihandle, root, size, i; 237 238 sc->sc_inth = NULL; /* Default */ 239 ihandle = 0; 240 241 /* Find our mapped interrupt number */ 242 root = findroot(); 243 mb_imask = NULL; 244 if (prom_getprop(root, "interrupt-map-mask", 245 sizeof(int32_t), &size, (void **) &mb_imask) || 246 size != IMASK_LEN) { 247 aprint_error(": no interrupt-map-mask\n"); 248 return; 249 } 250 251 mb_imap = NULL; 252 if (prom_getprop(root, "interrupt-map", 253 sizeof(int32_t), &size, (void **) &mb_imap) || 254 size != IMAP_LEN) { 255 aprint_error(": no interrupt-map\n"); 256 return; 257 } 258 259 intr = ma->ma_interrupts[0] && mb_imask->intr; 260 DPRINTF(1)("%s: intr %x masked to %x\n", 261 device_xname(sc->sc_dev), ma->ma_interrupts[0], intr); 262 paddr = ma->ma_reg[0].ur_paddr & mb_imask->paddr; 263 DPRINTF(1)("%s: reg 0x%" PRIx64 " masked to 0x%" PRIx64 "\n", 264 device_xname(sc->sc_dev), ma->ma_reg[0].ur_paddr, paddr); 265 for (i = 0; i < 2; i++) { 266 DPRINTF(1)("%s: checking paddr 0x%" PRIx64 ", intr %x\n", 267 device_xname(sc->sc_dev), mb_imap->paddr, mb_imap->intr); 268 if (paddr == mb_imap->paddr && intr == mb_imap->intr) { 269 ihandle = mb_imap->cintr; 270 DPRINTF(1)("%s: found cintr %d, cnode 0x%x\n", 271 device_xname(sc->sc_dev), ihandle, mb_imap->cnode); 272 break; 273 } 274 mb_imap++; 275 } 276 if (ihandle == 0) { 277 aprint_error(": failed to match interrupt\n"); 278 return; 279 } 280 281 /* Find the pyro leaf with the matching cnode ) */ 282 for (i = 0; i < pyro_cd.cd_ndevs; i++) { 283 device_t dt = device_lookup(&pyro_cd, i); 284 psc = device_private(dt); 285 if (psc && psc->sc_node == mb_imap->cnode) { 286 DPRINTF(1)("%s: matched pyro %d (0x%x)\n", 287 device_xname(sc->sc_dev), i, psc->sc_node); 288 ihandle |= psc->sc_ign; 289 break; 290 } 291 } 292 if (psc == NULL) { 293 aprint_error(": failed to match pyro leaf\n"); 294 return; 295 } 296 297 sc->sc_inth = psc->intr_establish_sc(psc, 298 ihandle, IPL_BIO, firei2c_intr, sc, NULL); 299 300 if (sc->sc_inth != NULL) { 301 aprint_normal_dev(sc->sc_dev, 302 "interrupting at ivec %x on pyro%d\n", ihandle, i); 303 } 304 305 return; 306 } 307 308 /* 309 * Sampling frequency: input clock divided by 2^N (N is bits 0:2) 310 * SCL frequency: sampling frequency divided by (M + 1) * 10 (bits 3:6) 311 * i2c SCL is max 100kHz, so find the closest frequency at or below that. 312 * 313 * If the system (JBus) clock frequency changes, we must change our clock. 314 * If increasing: after the JBus change, if decreasing: before the change. 315 * This is to avoid running the i2c clock faster than the specification. 316 */ 317 static uint8_t 318 firei2c_clock(int sysclk) 319 { 320 int p, f, best_p, best_f; 321 uint32_t sample, scl; 322 uint32_t min = FIREI2C_SCL_FREQ; 323 uint8_t clkval; 324 325 best_p = 0; 326 best_f = 0; 327 for (p = 0; p <= FIREI2C_CCR_POW2_MAX; p++) { 328 if (p) 329 sample = sysclk / (2 << (p - 1)); 330 else 331 sample = sysclk; 332 for (f = 0; f <= FIREI2C_CCR_FACT_MAX; f++) { 333 scl = sample / ((f + 1) * 10); 334 if (scl <= FIREI2C_SCL_FREQ) { 335 if (FIREI2C_SCL_FREQ - scl < min) { 336 best_p = p; 337 best_f = f; 338 min = FIREI2C_SCL_FREQ - scl; 339 } 340 break; /* Already at or below SCL_FREQ */ 341 } 342 } 343 if (!min) /* Exactly SCL_FREQ */ 344 break; 345 } 346 clkval = best_p + (best_f << FIREI2C_CCR_FACT_SHIFT); 347 return clkval; 348 } 349 350 /* No interrupts for stop, so wait for idle */ 351 static int 352 firei2c_stop(struct firei2c_softc *sc) 353 { 354 int i; 355 uint8_t ctrl, val; 356 357 ctrl = FIREI2C_CTRL_ENAB | FIREI2C_CTRL_STP; 358 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl); 359 for (i = 0; i < 500; i++) { 360 val = firei2c_reg_read(sc, FIREI2C_STAT); 361 if (val == FIREI2C_STAT_IDLE) { 362 mutex_enter(&sc->sc_mutex); 363 sc->sc_stage = FIREI2C_STAGE_IDLE; 364 mutex_exit(&sc->sc_mutex); 365 return 0; 366 } 367 delay(1000); 368 } 369 /* Clear the interrupt flag if we timed out */ 370 ctrl = FIREI2C_CTRL_ENAB; 371 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl); 372 /* Set the stage to idle, even for timeout */ 373 mutex_enter(&sc->sc_mutex); 374 sc->sc_stage = FIREI2C_STAGE_IDLE; 375 mutex_exit(&sc->sc_mutex); 376 return 1; 377 } 378 379 380 static int 381 firei2c_wait(struct firei2c_softc *sc, int flags) 382 { 383 volatile uint8_t ctrl; 384 int i; 385 386 for (i = 0; i < 500; i++) { 387 ctrl = firei2c_reg_read(sc, FIREI2C_CTRL); 388 if (ctrl & FIREI2C_CTRL_IFLG) 389 return 0; 390 delay(1000); 391 } 392 return 1; 393 } 394 395 /* 396 * Flow for a "simple" read/write: 397 * 1. Send start 398 * 2. Send addr + R or W 399 * 3. Receive ACK 400 * 4. (nothing) 401 * 5. (nothing) 402 * 6R. Receive data 6W. Send data 403 * 7R. Send ACK or NAK 7W. Receive ACK or NAK 404 * either receive more (6R) or either write more (6W) or 405 * 8. Send stop 406 * 407 * Flow for read/write following a "register" write: 408 * 1. Send start 409 * 2. Send addr + W 410 * 3. Receive ACK 411 * 4. Send register 412 * 5R. Send repeat start + addr + R 5W. (nothing to do) 413 * 6R. Receive data 6W. Send data 414 * 7R. Send ACK or NAK 7W. Receive ACK or NAK 415 * either receive more (6R) or either write more (6W) or 416 * 8. Send stop 417 * 418 * After each step, we receive an interrupt notifying us of the result. 419 * We clear the interrupt flag, check the status, and set up the next step. 420 * If we're polling, we check the flag in a loop instead. 421 */ 422 int 423 firei2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr, const void *cmd, 424 size_t cmdlen, void *vbuf, size_t buflen, int flags) 425 { 426 struct firei2c_softc *sc = arg; 427 const uint8_t *cmdbuf = cmd; 428 uint8_t *buf = vbuf; 429 uint8_t ctrl, val, ack, nack; 430 unsigned deadline, rem; 431 int err; 432 433 DPRINTF(1)("%s: exec op: %d addr: 0x%x " 434 "cmdlen: %d buflen: %d flags 0x%x, intr %s, poll %s\n", 435 device_xname(sc->sc_dev), op, addr, 436 (int) cmdlen, (int) buflen, flags, 437 sc->sc_inth == NULL ? "no" : "yes", 438 flags & I2C_F_POLL ? "yes" : "no"); 439 val = firei2c_reg_read(sc, FIREI2C_STAT); 440 if (val != FIREI2C_STAT_IDLE) { 441 /* Try sending stop */ 442 DPRINTF(1)("%s: not idle, sending stop\n", 443 device_xname(sc->sc_dev)); 444 err = firei2c_stop(sc); 445 if (err) { 446 printf("%s: not idle (0x%02x)\n", 447 device_xname(sc->sc_dev), val); 448 return 1; 449 } 450 } 451 452 /* Control defaults - bus enabled, interrupts enabled */ 453 ctrl = FIREI2C_CTRL_ENAB; 454 if (sc->sc_inth != NULL && !(flags & I2C_F_POLL)) { 455 ctrl |= FIREI2C_CTRL_IEN; 456 sc->sc_target = addr; 457 sc->sc_cmdbuf = cmdbuf; 458 sc->sc_cmdlen = cmdlen; 459 sc->sc_buf = buf; 460 sc->sc_buflen = buflen; 461 sc->sc_i = 0; 462 sc->sc_err = 0; 463 if (I2C_OP_READ_P(op)) 464 if (cmdlen > 0) 465 sc->sc_op = FIREI2C_OP_WR_RD; 466 else 467 sc->sc_op = FIREI2C_OP_READ; 468 else 469 sc->sc_op = FIREI2C_OP_WRITE; 470 mutex_enter(&sc->sc_mutex); 471 sc->sc_stage = FIREI2C_STAGE_START; 472 mutex_exit(&sc->sc_mutex); 473 } 474 475 /* Send start */ 476 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl | FIREI2C_CTRL_STA); 477 478 /* Interrupt-driven */ 479 if (sc->sc_inth != NULL && !(flags & I2C_F_POLL)) { 480 /* Wait for the transfer to complete (stop). */ 481 deadline = getticks() + 482 /*timeout*/ hz / 10 + 10 * (cmdlen + buflen); 483 mutex_enter(&sc->sc_mutex); 484 while (sc->sc_stage != FIREI2C_STAGE_STOP) { 485 rem = deadline - getticks(); 486 if (!rem || rem >= INT_MAX) { 487 printf("%s: intr timeout\n", 488 device_xname(sc->sc_dev)); 489 sc->sc_stage = FIREI2C_STAGE_STOP; 490 err = sc->sc_err | 1; 491 break; 492 } 493 cv_timedwait(&sc->sc_cv, &sc->sc_mutex, rem); 494 } 495 mutex_exit(&sc->sc_mutex); 496 err = sc->sc_err; 497 goto stop; 498 } 499 500 /* 501 * If we are writing, write addr, cmd, buf. 502 * If we are reading, either: 503 * write addr, cmd, repeat-start, then read addr to buf, or: 504 * read addr to buf. 505 * Send stop 506 */ 507 err = firei2c_wait(sc, flags); 508 val = firei2c_reg_read(sc, FIREI2C_STAT); 509 if (err) { 510 printf("%s: start timeout 0x%x\n", 511 device_xname(sc->sc_dev), val); 512 goto stop; 513 } 514 if (val != FIREI2C_STAT_STA) { 515 printf("%s: start error 0x%x\n", 516 device_xname(sc->sc_dev), val); 517 err = 1; 518 goto stop; 519 } 520 521 /* Address + r/w in data, then send ctrl */ 522 val = addr << FIREI2C_DATA_SHIFT; 523 if (I2C_OP_WRITE_P(op) || cmdlen > 0) { 524 ack = FIREI2C_STAT_AWR_ACK; 525 nack = FIREI2C_STAT_AWR_NAK; 526 } else { 527 val |= 0x01; 528 ack = FIREI2C_STAT_ARE_ACK; 529 nack = FIREI2C_STAT_ARE_NAK; 530 } 531 firei2c_reg_write(sc, FIREI2C_DATA, val); 532 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl); 533 err = firei2c_wait(sc, flags); 534 val = firei2c_reg_read(sc, FIREI2C_STAT); 535 if (err) { 536 printf("%s: addr timeout 0x%x\n", 537 device_xname(sc->sc_dev), val); 538 goto stop; 539 } 540 if (val != ack) { 541 if (val != nack) /* Don't print for NACK */ 542 printf("%s: addr error 0x%x\n", 543 device_xname(sc->sc_dev), val); 544 err = 1; 545 goto stop; 546 } 547 548 err = 0; 549 if (I2C_OP_READ_P(op)) { 550 if (cmdlen > 0) { 551 /* Write register */ 552 err = firei2c_write(sc, cmd, cmdlen, 553 NULL, 0, flags); 554 if (err) 555 goto stop; 556 557 /* Send repeat start */ 558 firei2c_reg_write(sc, FIREI2C_CTRL, 559 ctrl | FIREI2C_CTRL_STA); 560 err = firei2c_wait(sc, flags); 561 val = firei2c_reg_read(sc, FIREI2C_STAT); 562 if (err) { 563 printf("%s: repeat start timeout 0x%x\n", 564 device_xname(sc->sc_dev), val); 565 goto stop; 566 } 567 if (val != FIREI2C_STAT_REPSTA) { 568 printf("%s: repeat start error 0x%x\n", 569 device_xname(sc->sc_dev), val); 570 err = 1; 571 goto stop; 572 } 573 574 /* Address + r in data, then send ctrl */ 575 val = addr << FIREI2C_DATA_SHIFT; 576 val |= 0x01; 577 ack = FIREI2C_STAT_ARE_ACK; 578 nack = FIREI2C_STAT_ARE_NAK; 579 firei2c_reg_write(sc, FIREI2C_DATA, val); 580 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl); 581 err = firei2c_wait(sc, flags); 582 val = firei2c_reg_read(sc, FIREI2C_STAT); 583 if (err) { 584 printf("%s: addr timeout 0x%x\n", 585 device_xname(sc->sc_dev), val); 586 goto stop; 587 } 588 if (val != ack) { 589 if (val != nack) 590 printf("%s: addr error 0x%x\n", 591 device_xname(sc->sc_dev), val); 592 err = 1; 593 goto stop; 594 } 595 } 596 597 /* Read data */ 598 err = firei2c_read(sc, buf, buflen, flags); 599 } else 600 /* Write data or register + data */ 601 err = firei2c_write(sc, cmd, cmdlen, buf, buflen, flags); 602 603 stop: 604 err |= firei2c_stop(sc); 605 606 return err; 607 } 608 609 static int 610 firei2c_write(struct firei2c_softc *sc, const uint8_t *cmd, size_t cmdlen, 611 uint8_t *buf, size_t buflen, int flags) 612 { 613 uint8_t ctrl, val; 614 int i, err; 615 616 DPRINTF(2)("%s: write %ld\n", 617 device_xname(sc->sc_dev), cmdlen + buflen); 618 ctrl = FIREI2C_CTRL_ENAB; 619 for (i = 0; i < cmdlen + buflen; i++) { 620 /* Bytes in data, then send ctrl */ 621 if (i < cmdlen) 622 val = cmd[i]; 623 else 624 val = buf[i - cmdlen]; 625 firei2c_reg_write(sc, FIREI2C_DATA, val); 626 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl); 627 err = firei2c_wait(sc, flags); 628 val = firei2c_reg_read(sc, FIREI2C_STAT); 629 if (err) { 630 printf("%s: write timeout 0x%x\n", 631 device_xname(sc->sc_dev), val); 632 return 1; 633 } 634 if (val != FIREI2C_STAT_DAT_ACK) { 635 if (val != FIREI2C_STAT_DAT_NAK) 636 printf("%s: write error 0x%x\n", 637 device_xname(sc->sc_dev), val); 638 return 1; 639 } 640 641 } 642 return 0; 643 } 644 645 static int 646 firei2c_read(struct firei2c_softc *sc, uint8_t *buf, size_t buflen, int flags) 647 { 648 uint8_t ctrl, val, ack; 649 int i, err; 650 651 DPRINTF(2)("%s: read %ld\n", device_xname(sc->sc_dev), buflen); 652 for (i = 0; i < buflen; i++) { 653 /* Send ACK on all but last byte */ 654 if (i < buflen - 1) { 655 ctrl = FIREI2C_CTRL_ENAB | FIREI2C_CTRL_AAK; 656 ack = FIREI2C_STAT_MDAT_ACK; 657 } else { 658 ctrl = FIREI2C_CTRL_ENAB; 659 ack = FIREI2C_STAT_MDAT_NAK; 660 } 661 /* Send ctrl, then bytes in data */ 662 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl); 663 err = firei2c_wait(sc, flags); 664 val = firei2c_reg_read(sc, FIREI2C_STAT); 665 if (err) { 666 printf("%s: read timeout 0x%x\n", 667 device_xname(sc->sc_dev), val); 668 return 1; 669 } 670 if (val != ack) { 671 printf("%s: read error 0x%x\n", 672 device_xname(sc->sc_dev), val); 673 return 1; 674 } 675 buf[i] = firei2c_reg_read(sc, FIREI2C_DATA); 676 } 677 return 0; 678 } 679 680 /* 681 * When we receive an interrupt, check the status versus the step 682 * and set up the next stage. 683 * See the comments before firei2c_exec() for the list of steps. 684 */ 685 int 686 firei2c_intr(void *arg) 687 { 688 struct firei2c_softc *sc = arg; 689 uint8_t ctrl, val; 690 691 mutex_enter(&sc->sc_mutex); 692 ctrl = firei2c_reg_read(sc, FIREI2C_CTRL); 693 if (ctrl & FIREI2C_CTRL_IFLG) { 694 /* Disable interrupts */ 695 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl & ~FIREI2C_CTRL_IEN); 696 } 697 698 if (sc->sc_stage == FIREI2C_STAGE_IDLE) { 699 DPRINTF(1)("%s: intr and idle\n", device_xname(sc->sc_dev)); 700 mutex_exit(&sc->sc_mutex); 701 return 0; 702 } 703 704 ctrl = FIREI2C_CTRL_ENAB | FIREI2C_CTRL_IEN; 705 val = firei2c_reg_read(sc, FIREI2C_STAT); 706 707 switch (sc->sc_stage) { 708 case FIREI2C_STAGE_START: 709 DPRINTF(2)("%s: intr start, op %x\n", 710 device_xname(sc->sc_dev), sc->sc_op); 711 if (val != FIREI2C_STAT_STA) { 712 printf("%s: intr start error 0x%02x\n", 713 device_xname(sc->sc_dev), val); 714 sc->sc_err = 1; 715 sc->sc_stage = FIREI2C_STAGE_STOP; 716 break; 717 } 718 719 /* Address + r/w in data, then send ctrl */ 720 val = sc->sc_target << FIREI2C_DATA_SHIFT; 721 if (sc->sc_op == FIREI2C_OP_READ) { 722 val |= 0x01; 723 sc->sc_stage = FIREI2C_STAGE_RE_ADDR; 724 } else 725 sc->sc_stage = FIREI2C_STAGE_WR_ADDR; 726 firei2c_reg_write(sc, FIREI2C_DATA, val); 727 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl); 728 break; 729 730 case FIREI2C_STAGE_WR_ADDR: 731 DPRINTF(2)("%s: intr addr(w) 0x%02x = 0x%02x\n", 732 device_xname(sc->sc_dev), sc->sc_target, val); 733 if (val != FIREI2C_STAT_AWR_ACK) { 734 if (val != FIREI2C_STAT_AWR_NAK) 735 printf("%s: intr addr(w) error 0x%02x\n", 736 device_xname(sc->sc_dev), val); 737 sc->sc_err = 1; 738 sc->sc_stage = FIREI2C_STAGE_STOP; 739 break; 740 } 741 742 sc->sc_stage = FIREI2C_STAGE_WRITE; 743 val = FIREI2C_STAT_DAT_ACK; /* For write */ 744 /* Fallthrough */ 745 746 case FIREI2C_STAGE_WRITE: 747 DPRINTF(2)("%s: intr write 0x%02x = 0x%02x\n", 748 device_xname(sc->sc_dev), sc->sc_target, val); 749 if (val != FIREI2C_STAT_DAT_ACK) { 750 if (val != FIREI2C_STAT_DAT_NAK) 751 printf("%s: intr write error 0x%02x\n", 752 device_xname(sc->sc_dev), val); 753 sc->sc_err = 1; 754 sc->sc_stage = FIREI2C_STAGE_STOP; 755 break; 756 } 757 758 /* Start the write from cmd */ 759 if (sc->sc_i < sc->sc_cmdlen) { 760 firei2c_reg_write(sc, FIREI2C_DATA, 761 sc->sc_cmdbuf[sc->sc_i]); 762 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl); 763 sc->sc_i++; 764 break; 765 } 766 767 /* If a read OP, switch with repeat start after writing cmd */ 768 if (sc->sc_op == FIREI2C_OP_WR_RD) { 769 sc->sc_i = 0; 770 sc->sc_stage = FIREI2C_STAGE_REPSTART; 771 ctrl |= FIREI2C_CTRL_STA; 772 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl); 773 break; 774 } 775 776 /* If a write OP, continue the write, now from buf */ 777 if (sc->sc_i < sc->sc_cmdlen + sc->sc_buflen) { 778 firei2c_reg_write(sc, FIREI2C_DATA, 779 sc->sc_buf[sc->sc_i - sc->sc_cmdlen]); 780 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl); 781 sc->sc_i++; 782 } else { 783 sc->sc_stage = FIREI2C_STAGE_STOP; 784 } 785 break; 786 787 case FIREI2C_STAGE_REPSTART: 788 DPRINTF(2)("%s: intr repstart 0x%02x = 0x%02x\n", 789 device_xname(sc->sc_dev), sc->sc_target, val); 790 if (val != FIREI2C_STAT_REPSTA) { 791 printf("%s: intr repstart error 0x%02x\n", 792 device_xname(sc->sc_dev), val); 793 sc->sc_err = 1; 794 sc->sc_stage = FIREI2C_STAGE_STOP; 795 break; 796 } 797 798 /* Address + r in data, then send ctrl */ 799 val = (sc->sc_target << FIREI2C_DATA_SHIFT) | 0x01; 800 sc->sc_stage = FIREI2C_STAGE_RE_ADDR; 801 firei2c_reg_write(sc, FIREI2C_DATA, val); 802 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl); 803 break; 804 805 case FIREI2C_STAGE_RE_ADDR: 806 DPRINTF(2)("%s: intr addr(r) 0x%02x = 0x%02x\n", 807 device_xname(sc->sc_dev), sc->sc_target, val); 808 if (val != FIREI2C_STAT_ARE_ACK) { 809 if (val != FIREI2C_STAT_ARE_NAK) 810 printf("%s: intr addr(r) error 0x%02x\n", 811 device_xname(sc->sc_dev), val); 812 sc->sc_err = 1; 813 sc->sc_stage = FIREI2C_STAGE_STOP; 814 break; 815 } 816 817 sc->sc_stage = FIREI2C_STAGE_READ; 818 val = FIREI2C_STAT_MDAT_NAK; /* For read */ 819 /* Fallthrough */ 820 821 case FIREI2C_STAGE_READ: 822 DPRINTF(2)("%s: intr read 0x%02x = 0x%02x\n", 823 device_xname(sc->sc_dev), sc->sc_target, val); 824 if (sc->sc_i > 0 && sc->sc_i < sc->sc_buflen) { 825 if (val != FIREI2C_STAT_MDAT_ACK) { 826 printf("%s: intr read error 0x%02x\n", 827 device_xname(sc->sc_dev), val); 828 sc->sc_err = 1; 829 sc->sc_stage = FIREI2C_STAGE_STOP; 830 break; 831 } 832 } else { 833 if (val != FIREI2C_STAT_MDAT_NAK) { 834 printf("%s: intr read error 0x%02x\n", 835 device_xname(sc->sc_dev), val); 836 sc->sc_err = 1; 837 sc->sc_stage = FIREI2C_STAGE_STOP; 838 break; 839 } 840 } 841 842 /* Data read is 1 cycle behind ctrl */ 843 if (sc->sc_i > 0 && sc->sc_i <= sc->sc_buflen) { 844 sc->sc_buf[sc->sc_i - 1] = 845 firei2c_reg_read(sc, FIREI2C_DATA); 846 } 847 848 if (sc->sc_i == sc->sc_buflen) { 849 /* Last data was read */ 850 sc->sc_stage = FIREI2C_STAGE_STOP; 851 } else { 852 /* Send ACK on all but last byte */ 853 if (sc->sc_i < sc->sc_buflen - 1) 854 ctrl |= FIREI2C_CTRL_AAK; 855 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl); 856 sc->sc_i++; 857 } 858 break; 859 } 860 861 if (sc->sc_stage == FIREI2C_STAGE_STOP) { 862 DPRINTF(2)("%s: intr stop (err=%d)\n", 863 device_xname(sc->sc_dev), sc->sc_err); 864 cv_signal(&sc->sc_cv); 865 } 866 867 mutex_exit(&sc->sc_mutex); 868 869 return 1; 870 871 } 872 873 static uint8_t 874 firei2c_reg_read(struct firei2c_softc *sc, bus_size_t reg) 875 { 876 uint32_t val; 877 bus_space_barrier(sc->sc_bustag, sc->sc_regh, reg, 8, 878 BUS_SPACE_BARRIER_READ); 879 val = bus_space_read_8(sc->sc_bustag, sc->sc_regh, reg); 880 return val & 0xff; 881 } 882 883 static void 884 firei2c_reg_write(struct firei2c_softc *sc, bus_size_t reg, uint8_t val) 885 { 886 bus_space_write_8(sc->sc_bustag, sc->sc_regh, reg, val); 887 bus_space_barrier(sc->sc_bustag, sc->sc_regh, reg, 8, 888 BUS_SPACE_BARRIER_WRITE); 889 } 890