xref: /freebsd/sys/dev/iicbus/controller/qcom/geni_iic.c (revision 76113680635ea0c5972cbe8624a7d0d86270f569)
1 /*
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2025 Poul-Henning Kamp <phk@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  *
27  * QualComm GENI I2C controller
28  *
29  * The GENI is actually a multi-protocol serial controller, so a lot of
30  * this can probably be shared if we ever get to those protocols.
31  *
32  * The best open "documentation" of the hardware is the Linux device driver
33  * from which much was learned, and we tip our hat to the authors of it.
34  */
35 
36 #include <sys/cdefs.h>
37 
38 #include "opt_acpi.h"
39 
40 #include <sys/param.h>
41 #include <sys/kernel.h>
42 #include <sys/module.h>
43 #include <sys/endian.h>
44 #include <sys/time.h>
45 #include <sys/lock.h>
46 #include <sys/mutex.h>
47 #include <sys/sysctl.h>
48 #include <sys/sx.h>
49 #include <sys/bus.h>
50 
51 #include <machine/bus.h>
52 #include <sys/rman.h>
53 
54 #include <dev/iicbus/iicbus.h>
55 #include <dev/iicbus/iiconf.h>
56 
57 #include <dev/iicbus/controller/qcom/geni_iic_var.h>
58 
59 #define GENI_ALL_REGISTERS(THIS_MACRO) \
60 	THIS_MACRO(GENI_FORCE_DEFAULT_REG,	0x020) \
61 	THIS_MACRO(GENI_OUTPUT_CTRL,		0x024) \
62 	THIS_MACRO(GENI_STATUS,			0x040) \
63 	THIS_MACRO(GENI_SER_M_CLK_CFG,		0x048) \
64 	THIS_MACRO(GENI_SER_S_CLK_CFG,		0x04c) \
65 	THIS_MACRO(GENI_IF_DISABLE_RO,		0x064) \
66 	THIS_MACRO(GENI_FW_REVISION_RO,		0x068) \
67 	THIS_MACRO(GENI_CLK_SEL,		0x07c) \
68 	THIS_MACRO(GENI_CFG_SEQ_START,		0x084) \
69 	THIS_MACRO(GENI_BYTE_GRANULARITY,	0x254) \
70 	THIS_MACRO(GENI_DMA_MODE_EN,		0x258) \
71 	THIS_MACRO(GENI_TX_PACKING_CFG0,	0x260) \
72 	THIS_MACRO(GENI_TX_PACKING_CFG1,	0x264) \
73 	THIS_MACRO(GENI_I2C_TX_TRANS_LEN,	0x26c) \
74 	THIS_MACRO(GENI_I2C_RX_TRANS_LEN,	0x270) \
75 	THIS_MACRO(GENI_I2C_SCL_COUNTERS,	0x278) \
76 	THIS_MACRO(GENI_RX_PACKING_CFG0,	0x284) \
77 	THIS_MACRO(GENI_RX_PACKING_CFG1,	0x288) \
78 	THIS_MACRO(GENI_M_CMD0,			0x600) \
79 	THIS_MACRO(GENI_M_CMD_CTRL_REG,		0x604) \
80 	THIS_MACRO(GENI_M_IRQ_STATUS,		0x610) \
81 	THIS_MACRO(GENI_M_IRQ_EN,		0x614) \
82 	THIS_MACRO(GENI_M_IRQ_CLEAR,		0x618) \
83 	THIS_MACRO(GENI_M_IRQ_EN_SET,		0x61c) \
84 	THIS_MACRO(GENI_M_IRQ_EN_CLEAR,		0x620) \
85 	THIS_MACRO(GENI_S_CMD0,			0x630) \
86 	THIS_MACRO(GENI_S_CMD_CTRL_REG,		0x634) \
87 	THIS_MACRO(GENI_S_IRQ_STATUS,		0x640) \
88 	THIS_MACRO(GENI_S_IRQ_EN,		0x644) \
89 	THIS_MACRO(GENI_S_IRQ_CLEAR,		0x648) \
90 	THIS_MACRO(GENI_S_IRQ_EN_SET,		0x64c) \
91 	THIS_MACRO(GENI_S_IRQ_EN_CLEAR,		0x650) \
92 	THIS_MACRO(GENI_TX_FIFOn,		0x700) \
93 	THIS_MACRO(GENI_RX_FIFOn,		0x780) \
94 	THIS_MACRO(GENI_TX_FIFO_STATUS,		0x800) \
95 	THIS_MACRO(GENI_RX_FIFO_STATUS,		0x804) \
96 	THIS_MACRO(GENI_TX_WATERMARK_REG,	0x80c) \
97 	THIS_MACRO(GENI_RX_WATERMARK_REG,	0x810) \
98 	THIS_MACRO(GENI_RX_RFR_WATERMARK_REG,	0x814) \
99 	THIS_MACRO(GENI_IOS,			0x908) \
100 	THIS_MACRO(GENI_M_GP_LENGTH,		0x910) \
101 	THIS_MACRO(GENI_S_GP_LENGTH,		0x914) \
102 	THIS_MACRO(GENI_DMA_TX_IRQ_STAT,	0xc40) \
103 	THIS_MACRO(GENI_DMA_TX_IRQ_CLR,		0xc44) \
104 	THIS_MACRO(GENI_DMA_TX_IRQ_EN,		0xc48) \
105 	THIS_MACRO(GENI_DMA_TX_IRQ_EN_CLR,	0xc4c) \
106 	THIS_MACRO(GENI_DMA_TX_IRQ_EN_SET,	0xc50) \
107 	THIS_MACRO(GENI_DMA_TX_FSM_RST,		0xc58) \
108 	THIS_MACRO(GENI_DMA_RX_IRQ_STAT,	0xd40) \
109 	THIS_MACRO(GENI_DMA_RX_IRQ_CLR,		0xd44) \
110 	THIS_MACRO(GENI_DMA_RX_IRQ_EN,		0xd48) \
111 	THIS_MACRO(GENI_DMA_RX_IRQ_EN_CLR,	0xd4c) \
112 	THIS_MACRO(GENI_DMA_RX_IRQ_EN_SET,	0xd50) \
113 	THIS_MACRO(GENI_DMA_RX_LEN_IN,		0xd54) \
114 	THIS_MACRO(GENI_DMA_RX_FSM_RST,		0xd58) \
115 	THIS_MACRO(GENI_IRQ_EN,			0xe1c) \
116 	THIS_MACRO(GENI_HW_PARAM_0,		0xe24) \
117 	THIS_MACRO(GENI_HW_PARAM_1,		0xe28)
118 
119 enum geni_registers {
120 #define ITER_MACRO(name, offset) name = offset,
121 	GENI_ALL_REGISTERS(ITER_MACRO)
122 #undef ITER_MACRO
123 };
124 
125 #define RD(sc, reg) bus_read_4((sc)->regs_res, reg)
126 #define WR(sc, reg, val) bus_write_4((sc)->regs_res, reg, val)
127 
128 static void
geni_dump_regs(geniiic_softc_t * sc)129 geni_dump_regs(geniiic_softc_t *sc)
130 {
131 	device_printf(sc->dev, "Register Dump\n");
132 #define DUMP_MACRO(name, offset) \
133 	device_printf(sc->dev, \
134 	    "    %08x %04x " #name "\n", \
135 	    RD(sc, offset), offset);
136 	GENI_ALL_REGISTERS(DUMP_MACRO)
137 #undef DUMP_MACRO
138 }
139 
140 static unsigned geniiic_debug_units = 0;
141 
142 static SYSCTL_NODE(_hw, OID_AUTO, geniiic, CTLFLAG_RW, 0, "GENI I2C");
143 SYSCTL_INT(_hw_geniiic, OID_AUTO, debug_units, CTLFLAG_RWTUN,
144     &geniiic_debug_units, 1, "Bitmask of units to debug");
145 
146 
147 static driver_filter_t geniiic_intr;
148 
149 static int
geniiic_intr(void * cookie)150 geniiic_intr(void *cookie)
151 {
152 	uint32_t m_status, rx_fifo_status;
153 	int retval = FILTER_STRAY;
154 	geniiic_softc_t *sc = cookie;
155 
156 	mtx_lock_spin(&sc->intr_lock);
157 	m_status = RD(sc, GENI_M_IRQ_STATUS);
158 
159 	rx_fifo_status = RD(sc, GENI_RX_FIFO_STATUS);
160 	if (sc->rx_buf != NULL && rx_fifo_status & 0x3f) {
161 
162 		// Number of whole FIFO words, each 4 bytes
163 		unsigned gotlen = (((rx_fifo_status & 0x3f) << 2)-1) * 4;
164 
165 		// Valid bytes in the last FIFO word
166 		// (Field is 3 bits, we'll only ever see 0…3)
167 		gotlen +=  (rx_fifo_status >> 28) & 0x7;
168 
169 		unsigned cnt;
170 		for (cnt = 0; cnt < (rx_fifo_status & 0x3f); cnt++) {
171 			uint32_t data = RD(sc, GENI_RX_FIFOn);
172 			unsigned u;
173 			for (u = 0; u < 4 && sc->rx_len && gotlen; u++) {
174 				*sc->rx_buf++ = data & 0xff;
175 				data >>= 8;
176 				sc->rx_len--;
177 				gotlen--;
178 			}
179 		}
180 	}
181 	if (m_status & (1<<26)) {
182 		WR(sc, GENI_M_IRQ_CLEAR, (1<<26));
183 		retval = FILTER_HANDLED;
184 	}
185 
186 	if (m_status & (1<<0)) {
187 		sc->rx_complete = true;
188 		WR(sc, GENI_M_IRQ_EN_CLEAR, (1<<0));
189 		WR(sc, GENI_M_IRQ_EN_CLEAR, (1<<26));
190 		WR(sc, GENI_M_IRQ_CLEAR, (1<<0));
191 		wakeup(sc);
192 		retval = FILTER_HANDLED;
193 	}
194 	sc->cmd_status = m_status;
195 
196 	if (sc->rx_buf == NULL) {
197 		device_printf(sc->dev,
198 		    "Interrupt m_stat %x rx_fifo_status %x retval %d\n",
199 		    m_status, rx_fifo_status, retval);
200 		WR(sc, GENI_M_IRQ_EN, 0);
201 		WR(sc, GENI_M_IRQ_CLEAR, m_status);
202 		device_printf(sc->dev,
203 		    "Interrupt M_IRQ_STATUS 0x%x M_IRQ_EN 0x%x\n",
204 		    RD(sc, GENI_M_IRQ_STATUS), RD(sc, GENI_M_IRQ_EN));
205 		device_printf(sc->dev,
206 		    "Interrupt S_IRQ_STATUS 0x%x S_IRQ_EN 0x%x\n",
207 		    RD(sc, GENI_S_IRQ_STATUS), RD(sc, GENI_S_IRQ_EN));
208 		device_printf(sc->dev,
209 		    "Interrupt DMA_TX_IRQ_STAT 0x%x DMA_RX_IRQ_STAT 0x%x\n",
210 		    RD(sc, GENI_DMA_TX_IRQ_STAT), RD(sc, GENI_DMA_RX_IRQ_STAT));
211 		device_printf(sc->dev,
212 		    "Interrupt DMA_TX_IRQ_EN 0x%x DMA_RX_IRQ_EN 0x%x\n",
213 		    RD(sc, GENI_DMA_TX_IRQ_EN), RD(sc, GENI_DMA_RX_IRQ_EN));
214 		WR(sc, GENI_DMA_TX_IRQ_EN_CLR, RD(sc, GENI_DMA_TX_IRQ_STAT));
215 		WR(sc, GENI_DMA_TX_IRQ_CLR, RD(sc, GENI_DMA_TX_IRQ_STAT));
216 		WR(sc, GENI_DMA_RX_IRQ_EN_CLR, RD(sc, GENI_DMA_RX_IRQ_STAT));
217 		WR(sc, GENI_DMA_RX_IRQ_CLR, RD(sc, GENI_DMA_RX_IRQ_STAT));
218 	}
219 	mtx_unlock_spin(&sc->intr_lock);
220 	return(retval);
221 }
222 
223 static int
geniiic_wait_m_ireq(geniiic_softc_t * sc,uint32_t bits)224 geniiic_wait_m_ireq(geniiic_softc_t *sc, uint32_t bits)
225 {
226 	uint32_t status;
227 	int timeout;
228 
229 	for (timeout = 0; timeout < 10000; timeout++) {
230 		status = RD(sc, GENI_M_IRQ_STATUS);
231 		if (status & bits) {
232 			return (0);
233 		}
234 		DELAY(10);
235 	}
236 	return (IIC_ETIMEOUT);
237 }
238 
239 static int
geniiic_read(geniiic_softc_t * sc,uint8_t slave,uint8_t * buf,uint16_t len,bool nonfinal)240 geniiic_read(geniiic_softc_t *sc,
241     uint8_t slave, uint8_t *buf, uint16_t len, bool nonfinal)
242 {
243 	uint32_t cmd, istatus;
244 
245 	istatus = RD(sc, GENI_M_IRQ_STATUS);
246 	WR(sc, GENI_M_IRQ_CLEAR, istatus);
247 
248 	sc->rx_complete = false;
249 	sc->rx_fifo = false;
250 	sc->rx_buf = buf;
251 	sc->rx_len = len;
252 	WR(sc, GENI_I2C_RX_TRANS_LEN, len);
253 
254 	// GENI_M_CMD0_OPCODE_I2C_READ << M_OPCODE_SHFT
255 	cmd = (0x2 << 27);
256 
257 	// GENI_M_CMD0_SLV_ADDR_SHIFT
258 	cmd |= slave << 9;
259 
260 	if (nonfinal) {
261 		// GENI_M_CMD0_STOP_STRETCH
262 		cmd |= (1<<2);
263 	}
264 	WR(sc, GENI_RX_WATERMARK_REG, sc->rx_fifo_size - 4);
265 
266 	// CMD_DONE, RX_FIFO_WATERMARK
267 	WR(sc, GENI_M_IRQ_EN, (1<<0) | (1<<26));
268 
269 	// M_IRQ
270 	WR(sc, GENI_IRQ_EN, (1<<2));
271 
272 	WR(sc, GENI_M_CMD0, cmd);
273 
274 	mtx_lock_spin(&sc->intr_lock);
275 	sc->rx_fifo = false;
276 	unsigned msec;
277 	for (msec = 0; msec < 100; msec++) {
278 		msleep_spin_sbt(sc, &sc->intr_lock,
279 		    "geniwait", SBT_1MS, SBT_1MS / 10, 0);
280 		if (sc->rx_complete)
281 			break;
282 	}
283 	if (msec > sc->worst) {
284 		device_printf(sc->dev,
285 		    "Tworst from %u to %u\n", sc->worst, msec);
286 		if (msec != 100)
287 		    sc->worst = msec;
288 	}
289 
290 	if (!sc->rx_complete) {
291 		// S_GENI_CMD_CANCEL
292 		WR(sc, GENI_M_CMD_CTRL_REG, (1<<2));
293 
294 		WR(sc, GENI_IRQ_EN, 0);
295 		device_printf(sc->dev,
296 		    "Incomplete read (residual %x)\n", sc->rx_len);
297 	}
298 
299 	sc->rx_buf = NULL;
300 	len = sc->rx_len;
301 	sc->rx_len = 0;
302 
303 	mtx_unlock_spin(&sc->intr_lock);
304 
305 #define COMPLAIN(about) \
306 	device_printf(sc->dev, \
307 	    "read " about " slave=0x%x len=0x%x, cmd=0x%x cmd_status=0x%x\n", \
308 	    slave, len, cmd, sc->cmd_status \
309 	)
310 
311 	if (geniiic_debug_units) {
312 		unsigned unit = device_get_unit(sc->dev);
313 		if (unit < 32 && geniiic_debug_units & (1<<unit) && len == 0) {
314 			COMPLAIN("OK");
315 			return(IIC_NOERR);
316 		}
317 	}
318 	if (len == 0)
319 		return(IIC_NOERR);
320 
321 	if (sc->cmd_status & (1<<10)) {
322 		COMPLAIN("ESTATUS");
323 		return(IIC_ESTATUS);
324 	}
325 	if (len) {
326 		COMPLAIN("EUNDERFLOW");
327 		return(IIC_EUNDERFLOW);
328 	}
329 	COMPLAIN("EBUSERR");
330 	return (IIC_EBUSERR);
331 #undef COMPLAIN
332 }
333 
334 static int
geniiic_write(geniiic_softc_t * sc,uint8_t slave,uint8_t * buf,uint16_t len,bool nonfinal)335 geniiic_write(geniiic_softc_t *sc,
336     uint8_t slave, uint8_t *buf, uint16_t len, bool nonfinal)
337 {
338 	uint32_t status, data, cmd;
339 	int timeout, error;
340 
341 	status = RD(sc, GENI_M_IRQ_STATUS);
342 	WR(sc, GENI_M_IRQ_CLEAR, status);
343 
344 	WR(sc, GENI_I2C_TX_TRANS_LEN, len);
345 
346 	// GENI_M_CMD0_OPCODE_I2C_WRITE << M_OPCODE_SHFT
347 	cmd = (0x1 << 27);
348 
349 	// GENI_M_CMD0_SLV_ADDR_SHIFT
350 	cmd |= slave << 9;
351 
352 	if (nonfinal) {
353 		// GENI_M_CMD0_STOP_STRETCH
354 		cmd |= (1<<2);
355 	}
356 	WR(sc, GENI_M_CMD0, cmd);
357 	for(timeout = 0; len > 0 && timeout < 100; timeout++) {
358 		status = RD(sc, GENI_TX_FIFO_STATUS);
359 		if (status < 16) {
360 			data = 0;
361 			if (len) { data |= *buf <<  0; buf++; len--; }
362 			if (len) { data |= *buf <<  8; buf++; len--; }
363 			if (len) { data |= *buf << 16; buf++; len--; }
364 			if (len) { data |= *buf << 24; buf++; len--; }
365 			WR(sc, GENI_TX_FIFOn, data);
366 		} else {
367 			DELAY(10);
368 		}
369 	}
370 
371 	// GENI_M_IRQ_CMD_DONE
372 	error = geniiic_wait_m_ireq(sc, 1);
373 
374 	if (len == 0 && error == 0)
375 		return(IIC_NOERR);
376 	device_printf(sc->dev,
377 	    "write ERR len=%d, error=%d cmd=0x%x\n", len, error, cmd);
378 	return (IIC_EBUSERR);
379 }
380 
381 static void
geniiic_dumpmsg(device_t dev,struct iic_msg * msgs,uint32_t nmsgs)382 geniiic_dumpmsg(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
383 {
384 	unsigned u;
385 
386 	device_printf(dev, "transfer:\n");
387 	for (u = 0; u < nmsgs; u++) {
388 		device_printf(dev,
389 		    "  [%d] slave=0x%x, flags=0x%x len=0x%x buf=%p\n",
390 		    u, msgs[u].slave, msgs[u].flags, msgs[u].len, msgs[u].buf
391 		);
392 	}
393 }
394 
395 int
geniiic_transfer(device_t dev,struct iic_msg * msgs,uint32_t nmsgs)396 geniiic_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
397 {
398 	geniiic_softc_t *sc = device_get_softc(dev);
399 	unsigned u;
400 	int error;
401 
402 	if (sc->nfail > 4) {
403 		pause_sbt("geniic_fail", SBT_1S * 5, SBT_1S, 0);
404 		return (IIC_ERESOURCE);
405 	}
406 
407 	sx_xlock(&sc->real_bus_lock);
408 
409 	if (geniiic_debug_units) {
410 		unsigned unit = device_get_unit(dev);
411 		if (unit < 32 && geniiic_debug_units & (1<<unit)) {
412 			geniiic_dumpmsg(dev, msgs, nmsgs);
413 		}
414 	}
415 
416 	error = 0;
417 	for (u = 0; u < nmsgs; u++) {
418 		bool nonfinal =
419 		    (u < nmsgs - 1) && (msgs[u].flags & IIC_M_NOSTOP);
420 		unsigned slave = msgs[u].slave >> 1;
421 		if (msgs[u].flags & IIC_M_RD) {
422 			error = geniiic_read(sc,
423 			    slave, msgs[u].buf, msgs[u].len, nonfinal);
424 		} else {
425 			error = geniiic_write(sc,
426 			    slave, msgs[u].buf, msgs[u].len, nonfinal);
427 		}
428 	}
429 	if (error) {
430 		device_printf(dev, "transfer error %d\n", error);
431 		geniiic_dumpmsg(dev, msgs, nmsgs);
432 	}
433 	if (error) {
434 		geniiic_reset(dev, 0, 0, NULL);
435 	}
436 	if (error)
437 		sc->nfail++;
438 	else
439 		sc->nfail = 0;
440 	sx_xunlock(&sc->real_bus_lock);
441 	return (error);
442 }
443 
444 int
geniiic_reset(device_t dev,u_char speed,u_char addr,u_char * oldaddr)445 geniiic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
446 {
447 	geniiic_softc_t *sc = device_get_softc(dev);
448 	unsigned u;
449 
450 	device_printf(dev, "reset\n");
451 	WR(sc, GENI_M_IRQ_EN, 0);
452 	WR(sc, GENI_M_IRQ_CLEAR, ~0);
453 	WR(sc, GENI_DMA_TX_IRQ_EN_CLR, ~0);
454 	WR(sc, GENI_DMA_TX_IRQ_CLR, ~0);
455 	WR(sc, GENI_DMA_RX_IRQ_EN_CLR, ~0);
456 	WR(sc, GENI_DMA_RX_IRQ_CLR, ~0);
457 
458 	// S_GENI_CMD_ABORT
459 	WR(sc, GENI_M_CMD_CTRL_REG, (1<<1));
460 
461 	WR(sc, GENI_DMA_RX_FSM_RST, 1);
462 	for (u = 0; u < 1000; u++) {
463 		if (RD(sc, GENI_DMA_RX_IRQ_STAT) & 0x8)
464 			break;
465 		DELAY(10);
466 	}
467 	if (u > 0)
468 		device_printf(dev, "RXRESET time %u\n", u);
469 	WR(sc, GENI_DMA_TX_FSM_RST, 1);
470 	for (u = 0; u < 1000; u++) {
471 		if (RD(sc, GENI_DMA_TX_IRQ_STAT) & 0x8)
472 			break;
473 		DELAY(10);
474 	}
475 	if (u > 0)
476 		device_printf(dev, "TXRESET time %u\n", u);
477 	return (0);
478 }
479 
480 int
geniiic_callback(device_t dev,int index,caddr_t data)481 geniiic_callback(device_t dev, int index, caddr_t data)
482 {
483 	geniiic_softc_t *sc = device_get_softc(dev);
484 	int error = 0;
485 
486 	return(0);
487 	switch (index) {
488 	case IIC_REQUEST_BUS:
489 		if (sx_try_xlock(&sc->bus_lock) == 0)
490 			error = IIC_EBUSBSY;
491 		else
492 			sc->bus_locked = true;
493 		break;
494 
495 	case IIC_RELEASE_BUS:
496 		if (!sc->bus_locked) {
497 			device_printf(dev, "Unlocking unlocked bus\n");
498 		}
499 		sc->bus_locked = false;
500 		sx_xunlock(&sc->bus_lock);
501 		break;
502 
503 	default:
504 		device_printf(dev, "callback unknown %d\n", index);
505 		error = errno2iic(EINVAL);
506 	}
507 
508 	return (error);
509 }
510 
511 int
geniiic_attach(geniiic_softc_t * sc)512 geniiic_attach(geniiic_softc_t *sc)
513 {
514 	int error = 0;
515 
516 	if (bootverbose)
517 		geni_dump_regs(sc);
518 	mtx_init(&sc->intr_lock, "geniiic intr lock", NULL, MTX_SPIN);
519 	sx_init(&sc->real_bus_lock, "geniiic real bus lock");
520 	sx_init(&sc->bus_lock, "geniiic bus lock");
521 
522 	sc->rx_fifo_size = (RD(sc, GENI_HW_PARAM_1) >> 16) & 0x3f;
523 	device_printf(sc->dev, "  RX fifo size= 0x%x\n", sc->rx_fifo_size);
524 
525 	// We might want to set/check the following registers:
526 	//	GENI_BYTE_GRANULARITY	(0x00000000)
527 	//	GENI_TX_PACKING_CFG0	(0x0007f8fe)
528 	//	GENI_TX_PACKING_CFG1	(000ffefe)
529 	//	GENI_RX_PACKING_CFG0	(0x0007f8fe)
530 	//	GENI_RX_PACKING_CFG1	(000ffefe)
531 
532 	sc->iicbus = device_add_child(sc->dev, "iicbus", DEVICE_UNIT_ANY);
533 	if (sc->iicbus == NULL) {
534 		device_printf(sc->dev, "iicbus driver not found\n");
535 		return(ENXIO);
536 	}
537 
538 	error = bus_setup_intr(sc->dev,
539 	    sc->intr_res, INTR_TYPE_MISC | INTR_MPSAFE,
540 	    geniiic_intr, NULL, sc, &sc->intr_handle);
541 	if (error) {
542 		device_printf(sc->dev,
543 		    "Unable to setup irq: error %d\n", error);
544 	}
545 
546 	bus_attach_children(sc->dev);
547 	return (error);
548 }
549 
550 int
geniiic_detach(geniiic_softc_t * sc)551 geniiic_detach(geniiic_softc_t *sc)
552 {
553 	int error = 0;
554 
555 	error = bus_generic_detach(sc->dev);
556 	if (error)
557 		return (error);
558 
559 	WR(sc, GENI_M_IRQ_EN, 0);
560 
561 	if (sc->intr_handle) {
562 		bus_teardown_intr(sc->dev, sc->intr_res, sc->intr_handle);
563 	}
564 
565 	sx_xlock(&sc->bus_lock);
566 	sx_xlock(&sc->real_bus_lock);
567 
568 	geniiic_reset(sc->dev, 0, 0, NULL);
569 	sc->iicbus = NULL;
570 	sc->intr_handle = NULL;
571 
572 	sx_xunlock(&sc->real_bus_lock);
573 	sx_xunlock(&sc->bus_lock);
574 
575 	sx_destroy(&sc->real_bus_lock);
576 	sx_destroy(&sc->bus_lock);
577 
578 	mtx_destroy(&sc->intr_lock);
579 	return (error);
580 }
581 
582 int
geniiic_suspend(geniiic_softc_t * sc)583 geniiic_suspend(geniiic_softc_t *sc)
584 {
585 	int error;
586 
587 	device_printf(sc->dev, "suspend method is NO-OP (good luck!)\n");
588 
589 	error = bus_generic_suspend(sc->dev);
590 
591 	return (error);
592 }
593 
geniiic_resume(geniiic_softc_t * sc)594 int geniiic_resume(geniiic_softc_t *sc)
595 {
596 	int error;
597 
598 	device_printf(sc->dev, "resume method is NO-OP (good luck!)\n");
599 
600 	error = bus_generic_resume(sc->dev);
601 
602 	return (error);
603 }
604 
605 DRIVER_MODULE(iicbus, geniiic, iicbus_driver, NULL, NULL);
606 DRIVER_MODULE(acpi_iicbus, geniiic, acpi_iicbus_driver, NULL, NULL);
607 MODULE_DEPEND(geniiic, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
608 MODULE_VERSION(geniiic, 1);
609