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