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