Home | History | Annotate | Line # | Download | only in dev
fire_i2c.c revision 1.1
      1 /* $NetBSD: fire_i2c.c,v 1.1 2026/06/04 13:43:24 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.1 2026/06/04 13:43:24 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/mutex.h>
     40 
     41 #include <machine/autoconf.h>
     42 #include <machine/openfirm.h>
     43 
     44 #include <dev/i2c/i2cvar.h>
     45 #include <arch/sparc64/dev/fire_i2creg.h>
     46 
     47 #define FIREI2C_DEBUG 0
     48 #if FIREI2C_DEBUG > 0
     49 #define DPRINTF printf
     50 #else
     51 #define DPRINTF if (0) printf
     52 #endif
     53 
     54 #define FIREI2C_SCL_FREQ	100000
     55 #define FIREI2C_OWN_ADDR	0x08
     56 
     57 #define FIREI2C_CLK_FULL	0
     58 #define FIREI2C_CLK_HALF	1
     59 #define FIREI2C_CLK_TT		2
     60 #define FIREI2C_CLK_LEN		3
     61 
     62 struct firei2c_softc {
     63 	device_t sc_dev;
     64 	bus_space_tag_t sc_bustag;
     65 	bus_space_handle_t sc_regh;
     66 	int sc_node;
     67 	void *sc_inth;
     68 	uint8_t sc_i2c_clks[FIREI2C_CLK_LEN];
     69 	struct i2c_controller sc_i2c;
     70 	kmutex_t sc_mutex;
     71 	kcondvar_t sc_cv;
     72 };
     73 
     74 static int firei2c_match(device_t, cfdata_t, void *);
     75 static void firei2c_attach(device_t, device_t, void *);
     76 static uint8_t firei2c_clock(int);
     77 static int firei2c_stop(struct firei2c_softc *);
     78 static int firei2c_wait(struct firei2c_softc *, int);
     79 int firei2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
     80     size_t, void *, size_t, int);
     81 static int firei2c_write(struct firei2c_softc *, const uint8_t *, size_t,
     82     uint8_t *, size_t, int, int);
     83 static int firei2c_read(struct firei2c_softc *, uint8_t *, size_t, int, int);
     84 int firei2c_intr(void *);
     85 static uint8_t firei2c_reg_read(struct firei2c_softc *, bus_size_t);
     86 static void firei2c_reg_write(struct firei2c_softc *, bus_size_t, uint8_t);
     87 
     88 CFATTACH_DECL_NEW(firei2c, sizeof(struct firei2c_softc),
     89 	firei2c_match, firei2c_attach, NULL, NULL);
     90 
     91 static int
     92 firei2c_match(device_t parent, cfdata_t cf, void *aux)
     93 {
     94 	struct mainbus_attach_args *ma = aux;
     95 	char *compat;
     96 
     97 	if (strcmp(ma->ma_name, "i2c"))
     98 		return 0;
     99 
    100 	compat = prom_getpropstring(ma->ma_node, "compatible");
    101 	if (!strcmp(compat, "fire-i2c"))
    102 		return 1;
    103 
    104 	return 0;
    105 }
    106 
    107 static void
    108 firei2c_attach(device_t parent, device_t self, void *aux)
    109 {
    110 	struct firei2c_softc *sc = device_private(self);
    111 	struct mainbus_attach_args *ma = aux;
    112 	int  sysclk;
    113 
    114 	sc->sc_bustag = ma->ma_bustag;
    115 	sc->sc_node = ma->ma_node;
    116 	sc->sc_dev = self;
    117 
    118 	if (ma->ma_nreg != 1) {
    119 		aprint_error(": register count error (%d != 1)\n",
    120 		    ma->ma_nreg);
    121 		return;
    122 	}
    123 	if (ma->ma_reg[0].ur_len < FIREI2C_SRST) {
    124 		aprint_error(": register length error (%ld < %d\n",
    125 		    ma->ma_reg[0].ur_len, FIREI2C_SRST);
    126 		return;
    127 	}
    128 
    129 	if (bus_space_map(sc->sc_bustag, ma->ma_reg[0].ur_paddr,
    130 	    ma->ma_reg[0].ur_len, 0, &sc->sc_regh)) {
    131 		aprint_error(": failed to map registers\n");
    132 		return;
    133 	}
    134 
    135 	sc->sc_inth = NULL;
    136 /* XXX need to set up interrupt mapping before we can enable them here
    137    Both i2c interrupts must go to the same Pyro leaf.
    138 
    139 	sc->sc_inth = bus_intr_establish(sc->sc_bustag, *ma->ma_interrupts,
    140 	    IPL_VM, firei2c_intr, sc);
    141 
    142 	if (sc->sc_inth == NULL) {
    143 		aprint_error(": failed to establish interrupt\n");
    144 		return;
    145 	}
    146 */
    147 
    148 	aprint_normal(": addr %" PRIx64 ": Fire/MI2C i2c controller\n",
    149 	    ma->ma_reg[0].ur_paddr);
    150 /* XXX interrupts
    151 	aprint_normal_dev(self, "interrupting at %x\n", *ma->ma_interrupts);
    152 */
    153 
    154 	/* Calculate clock, software reset, set our addr, enable interrupts */
    155 	sysclk = prom_getpropint(findroot(), "clock-frequency", 0);
    156 	sc->sc_i2c_clks[FIREI2C_CLK_FULL] = firei2c_clock(sysclk);
    157 	sc->sc_i2c_clks[FIREI2C_CLK_HALF] = firei2c_clock(sysclk / 2);
    158 	sc->sc_i2c_clks[FIREI2C_CLK_TT] = firei2c_clock(sysclk / 32);
    159 	firei2c_reg_write(sc, FIREI2C_SRST, FIREI2C_SRST_RST);
    160 	delay(1000);
    161 	firei2c_reg_write(sc, FIREI2C_CCR, sc->sc_i2c_clks[FIREI2C_CLK_FULL]);
    162 	firei2c_reg_write(sc, FIREI2C_ADDR,
    163 	    FIREI2C_OWN_ADDR << FIREI2C_ADDR_SHIFT);
    164 
    165 	/* i2c setup */
    166 	iic_tag_init(&sc->sc_i2c);
    167 	sc->sc_i2c.ic_cookie = sc;
    168 	sc->sc_i2c.ic_exec = firei2c_exec;
    169 
    170 	/* Synchronisation between exec and intr */
    171 	mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM);
    172 	cv_init(&sc->sc_cv, "firei2c");
    173 
    174 	iicbus_attach(sc->sc_dev, &sc->sc_i2c);
    175 	return;
    176 }
    177 
    178 /*
    179  * Sampling frequency: input clock divided by 2^N (N is bits 0:2)
    180  * SCL frequency: sampling frequency divided by (M + 1) * 10 (bits 3:6)
    181  * i2c SCL is max 100kHz, so find the closest frequency at or below that.
    182  *
    183  * If the system (JBus) clock frequency changes, we must change our clock.
    184  * If increasing: after the JBus change, if decreasing: before the change.
    185  * This is to avoid running the i2c clock faster than the specification.
    186  */
    187 static uint8_t
    188 firei2c_clock(int sysclk)
    189 {
    190 	int p, f, best_p, best_f;
    191 	uint32_t sample, scl;
    192 	uint32_t min = FIREI2C_SCL_FREQ;
    193 	uint8_t clkval;
    194 
    195 	best_p = 0;
    196 	best_f = 0;
    197 	for (p = 0; p <= FIREI2C_CCR_POW2_MAX; p++) {
    198 		if (p)
    199 			sample = sysclk / (2 << (p - 1));
    200 		else
    201 			sample = sysclk;
    202 		for (f = 0; f <= FIREI2C_CCR_FACT_MAX; f++) {
    203 			scl = sample / ((f + 1) * 10);
    204 			if (scl <= FIREI2C_SCL_FREQ) {
    205 				if (FIREI2C_SCL_FREQ - scl < min) {
    206 					best_p = p;
    207 					best_f = f;
    208 					min = FIREI2C_SCL_FREQ - scl;
    209 				}
    210 				break;	/* Already at or below SCL_FREQ */
    211 			}
    212 		}
    213 		if (!min)	/* Exactly SCL_FREQ */
    214 			break;
    215 	}
    216 	clkval = best_p + (best_f << FIREI2C_CCR_FACT_SHIFT);
    217 	return clkval;
    218 }
    219 
    220 /* No interrupts for stop, so wait for idle */
    221 static int
    222 firei2c_stop(struct firei2c_softc *sc)
    223 {
    224 	int i;
    225 	uint8_t ctrl, val;
    226 
    227 	ctrl = FIREI2C_CTRL_ENAB | FIREI2C_CTRL_STP;
    228 	firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
    229 	for (i = 0; i < 500; i++) {
    230 		val = firei2c_reg_read(sc, FIREI2C_STAT);
    231 		if (val == FIREI2C_STAT_IDLE)
    232 			return 0;
    233 		delay(1000);
    234 	}
    235 	/* Clear the interrupt flag if we timed out */
    236 	ctrl = FIREI2C_CTRL_ENAB;
    237 	firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
    238 	return 1;
    239 }
    240 
    241 
    242 static int
    243 firei2c_wait(struct firei2c_softc *sc, int flags)
    244 {
    245 	volatile uint8_t ctrl;
    246 	int i;
    247 
    248 	if (sc->sc_inth == NULL || flags & I2C_F_POLL) {
    249 		for (i = 0; i < 500; i++) {
    250 			ctrl = firei2c_reg_read(sc, FIREI2C_CTRL);
    251 			if (ctrl & FIREI2C_CTRL_IFLG)
    252 				return 0;
    253 			delay(1000);
    254 		}
    255 		return 1;
    256 	} else {
    257 		mutex_enter(&sc->sc_mutex);
    258 		if (cv_timedwait(&sc->sc_cv, &sc->sc_mutex, hz / 2)) {
    259 			mutex_exit(&sc->sc_mutex);
    260 			return 1;
    261 		}
    262 		mutex_exit(&sc->sc_mutex);
    263 		return 0;
    264 	}
    265 }
    266 
    267 /*
    268  * Flow for a "simple" read/write:
    269  *   1.  Send start
    270  *   2.  Send addr + R or W
    271  *   3.  Receive ACK
    272  *   4.  (nothing)
    273  *   5.  (nothing)
    274  *   6R. Receive data			6W.  Send data
    275  *   7R. Send ACK or NAK		7W.  Receive ACK or NAK
    276  *       either receive more (6R) or	     either write more (6W) or
    277  *   8.  Send stop
    278  *
    279  * Flow for read/write following a "register" write:
    280  *   1.  Send start
    281  *   2.  Send addr + W
    282  *   3.  Receive ACK
    283  *   4.  Send register
    284  *   5R. Send repeat start + addr + R	5W.  (nothing to do)
    285  *   6R. Receive data			6W.  Send data
    286  *   7R. Send ACK or NAK		7W.  Receive ACK or NAK
    287  *       either receive more (6R) or	     either write more (6W) or
    288  *   8.  Send stop
    289  *
    290  * After each step, we receive an interrupt notifying us of the result.
    291  * We check the status, set up the next step, then clear the interrupt flag.
    292  */
    293 int
    294 firei2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr, const void *cmd,
    295     size_t cmdlen, void *vbuf, size_t buflen, int flags)
    296 {
    297 	struct firei2c_softc *sc = arg;
    298 	uint8_t *buf = vbuf;
    299 	uint8_t ctrl, val, ack, nack;
    300 	int err;
    301 
    302 	DPRINTF("%s: exec op: %d addr: 0x%x cmdlen: %d buflen: %d flags 0x%x\n",
    303 	    device_xname(sc->sc_dev), op, addr,
    304 	    (int) cmdlen, (int) buflen, flags);
    305 
    306 	/*
    307 	 * Send start
    308  	 * If we are writing, write addr, cmd, buf.
    309  	 * If we are reading, either:
    310  	 *   write addr, cmd, repeat-start, then read addr to buf, or:
    311  	 *   read addr to buf.
    312 	 * Send stop
    313  	 */
    314 
    315 	/* Control defaults - bus enabled, interrupts enabled */
    316 	ctrl = FIREI2C_CTRL_ENAB;
    317 	if (sc->sc_inth != NULL && !(flags & I2C_F_POLL))
    318 		ctrl |= FIREI2C_CTRL_IEN;
    319 
    320 	val = firei2c_reg_read(sc, FIREI2C_STAT);
    321 	if (val != FIREI2C_STAT_IDLE) {
    322 		/* Try sending stop */
    323 		DPRINTF("%s: not idle, sending stop\n",
    324 		    device_xname(sc->sc_dev));
    325 		err = firei2c_stop(sc);
    326 		if (err) {
    327 			printf("%s: not idle (0x%02x)\n",
    328 			    device_xname(sc->sc_dev), val);
    329 			return 1;
    330 		}
    331 	}
    332 
    333 	/* Send start */
    334 	val = ctrl | FIREI2C_CTRL_STA;
    335 	firei2c_reg_write(sc, FIREI2C_CTRL, val);
    336 	err = firei2c_wait(sc, flags);
    337 	val = firei2c_reg_read(sc, FIREI2C_STAT);
    338 	if (err) {
    339 		printf("%s: start timeout 0x%x\n",
    340 		    device_xname(sc->sc_dev), val);
    341 		goto stop;
    342 	}
    343 	if (val != FIREI2C_STAT_STA) {
    344 		printf("%s: start error 0x%x\n",
    345 		    device_xname(sc->sc_dev), val);
    346 		err = 1;
    347 		goto stop;
    348 	}
    349 
    350 	/* Address + r/w in data, then clear interrupt flag in ctrl */
    351 	val = (addr & 0x7f) << FIREI2C_DATA_SHIFT;
    352 	if (I2C_OP_WRITE_P(op) || cmdlen > 0) {
    353 		ack = FIREI2C_STAT_AWR_ACK;
    354 		nack = FIREI2C_STAT_AWR_NAK;
    355 	} else {
    356 		val |= 0x01;
    357 		ack = FIREI2C_STAT_ARE_ACK;
    358 		nack = FIREI2C_STAT_ARE_NAK;
    359 	}
    360 	firei2c_reg_write(sc, FIREI2C_DATA, val);
    361 	firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
    362 	err = firei2c_wait(sc, flags);
    363 	val = firei2c_reg_read(sc, FIREI2C_STAT);
    364 	if (err) {
    365 		printf("%s: addr timeout 0x%x\n",
    366 		    device_xname(sc->sc_dev), val);
    367 		goto stop;
    368 	}
    369 	if (val != ack) {
    370 		if (val != nack)	/* Don't print for NACK */
    371 			printf("%s: addr error 0x%x\n",
    372 			    device_xname(sc->sc_dev), val);
    373 		err = 1;
    374 		goto stop;
    375 	}
    376 
    377 	err = 0;
    378 	if (I2C_OP_READ_P(op)) {
    379 		if (cmdlen > 0) {
    380 			/* Write register */
    381 			err = firei2c_write(sc, cmd, cmdlen,
    382 			    NULL, 0, ctrl, flags);
    383 			if (err)
    384 				goto stop;
    385 
    386 			/* Send repeat start */
    387 			val = ctrl | FIREI2C_CTRL_STA;
    388 			firei2c_reg_write(sc, FIREI2C_CTRL, val);
    389 			err = firei2c_wait(sc, flags);
    390 			val = firei2c_reg_read(sc, FIREI2C_STAT);
    391 			if (err) {
    392 				printf("%s: repeat start timeout 0x%x\n",
    393 				    device_xname(sc->sc_dev), val);
    394 				goto stop;
    395 			}
    396 			if (val != FIREI2C_STAT_REPSTA) {
    397 				printf("%s: repeat start error 0x%x\n",
    398 				    device_xname(sc->sc_dev), val);
    399 				err = 1;
    400 				goto stop;
    401 			}
    402 
    403 			/* Address + r in data, then clear intr flag in ctrl */
    404 			val = (addr & 0x7f) << FIREI2C_DATA_SHIFT;
    405 			val |= 0x01;
    406 			ack = FIREI2C_STAT_ARE_ACK;
    407 			nack = FIREI2C_STAT_ARE_NAK;
    408 			firei2c_reg_write(sc, FIREI2C_DATA, val);
    409 			firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
    410 			err = firei2c_wait(sc, flags);
    411 			val = firei2c_reg_read(sc, FIREI2C_STAT);
    412 			if (err) {
    413 				printf("%s: addr timeout 0x%x\n",
    414 				    device_xname(sc->sc_dev), val);
    415 				goto stop;
    416 			}
    417 			if (val != ack) {
    418 				if (val != nack)
    419 					printf("%s: addr error 0x%x\n",
    420 					    device_xname(sc->sc_dev), val);
    421 				err = 1;
    422 				goto stop;
    423 			}
    424 		}
    425 
    426 		/* Read data */
    427 		err = firei2c_read(sc, buf, buflen, ctrl, flags);
    428 	} else
    429 		/* Write data or register + data */
    430 		err = firei2c_write(sc, cmd, cmdlen, buf, buflen, ctrl, flags);
    431 
    432 stop:
    433 	err |= firei2c_stop(sc);
    434 
    435 	return err;
    436 }
    437 
    438 static int
    439 firei2c_write(struct firei2c_softc *sc, const uint8_t *cmd, size_t cmdlen,
    440     uint8_t *buf, size_t buflen, int ctrl, int flags)
    441 {
    442 	uint8_t val;
    443 	int i, err;
    444 
    445 	for (i = 0; i < cmdlen + buflen; i++) {
    446 		/* Bytes in data, then clear interrupt flag in ctrl */
    447 		if (i < cmdlen)
    448 			val = cmd[i];
    449 		else
    450 			val = buf[i - cmdlen];
    451 		firei2c_reg_write(sc, FIREI2C_DATA, val);
    452 		firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
    453 		err = firei2c_wait(sc, flags);
    454 		val = firei2c_reg_read(sc, FIREI2C_STAT);
    455 		if (err) {
    456 			printf("%s: write timeout 0x%x\n",
    457 			    device_xname(sc->sc_dev), val);
    458 			return 1;
    459 		}
    460 		if (val != FIREI2C_STAT_DAT_ACK) {
    461 			if (val != FIREI2C_STAT_DAT_NAK)
    462 				printf("%s: write error 0x%x\n",
    463 				    device_xname(sc->sc_dev), val);
    464 			return 1;
    465 		}
    466 
    467 	}
    468 	return 0;
    469 }
    470 
    471 static int
    472 firei2c_read(struct firei2c_softc *sc, uint8_t *buf, size_t buflen,
    473     int ctrl, int flags)
    474 {
    475 	uint8_t val, ack;
    476 	int i, err;
    477 
    478 	for (i = 0; i < buflen; i++) {
    479 		/* Send ACK on all but last byte */
    480 		if (i < buflen - 1) {
    481 			val = ctrl | FIREI2C_CTRL_AAK;
    482 			ack = FIREI2C_STAT_MDAT_ACK;
    483 		} else {
    484 			val = ctrl;
    485 			ack = FIREI2C_STAT_MDAT_NAK;
    486 		}
    487 		/* Clear interrupt flag in ctrl, bytes in data */
    488 		firei2c_reg_write(sc, FIREI2C_CTRL, val);
    489 		err = firei2c_wait(sc, flags);
    490 		val = firei2c_reg_read(sc, FIREI2C_STAT);
    491 		if (err) {
    492 			printf("%s: read timeout 0x%x\n",
    493 			    device_xname(sc->sc_dev), val);
    494 			return 1;
    495 		}
    496 		if (val != ack) {
    497 			printf("%s: read error 0x%x\n",
    498 			    device_xname(sc->sc_dev), val);
    499 			return 1;
    500 		}
    501 		buf[i] = firei2c_reg_read(sc, FIREI2C_DATA);
    502 	}
    503 	return 0;
    504 }
    505 
    506 int
    507 firei2c_intr(void *arg)
    508 {
    509 	struct firei2c_softc *sc = arg;
    510 	uint8_t ctrl;
    511 
    512 	mutex_enter(&sc->sc_mutex);
    513 	ctrl = firei2c_reg_read(sc, FIREI2C_CTRL);
    514 	if (ctrl & FIREI2C_CTRL_IFLG) {
    515 		/* Disable interrupts */
    516 		firei2c_reg_write(sc, FIREI2C_CTRL, ctrl & ~FIREI2C_CTRL_IEN);
    517 		cv_signal(&sc->sc_cv);
    518 		mutex_exit(&sc->sc_mutex);
    519 		return 1;	/* Handled */
    520 	}
    521 	mutex_exit(&sc->sc_mutex);
    522 	return 0;
    523 }
    524 
    525 static uint8_t
    526 firei2c_reg_read(struct firei2c_softc *sc, bus_size_t reg)
    527 {
    528 	uint32_t val;
    529 	bus_space_barrier(sc->sc_bustag, sc->sc_regh, reg, 8,
    530 	    BUS_SPACE_BARRIER_READ);
    531 	val = bus_space_read_8(sc->sc_bustag, sc->sc_regh, reg);
    532 	return val & 0xff;
    533 }
    534 
    535 static void
    536 firei2c_reg_write(struct firei2c_softc *sc, bus_size_t reg, uint8_t val)
    537 {
    538 	bus_space_write_8(sc->sc_bustag, sc->sc_regh, reg, val);
    539 	bus_space_barrier(sc->sc_bustag, sc->sc_regh, reg, 8,
    540 	    BUS_SPACE_BARRIER_WRITE);
    541 }
    542