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