1*9fdf0c62Smpi /* $OpenBSD: rkiic.c,v 1.7 2021/10/24 17:52:26 mpi Exp $ */
2d1cecf06Skettenis /*
3d1cecf06Skettenis * Copyright (c) 2017 Mark Kettenis <kettenis@openbsd.org>
4d1cecf06Skettenis *
5d1cecf06Skettenis * Permission to use, copy, modify, and distribute this software for any
6d1cecf06Skettenis * purpose with or without fee is hereby granted, provided that the above
7d1cecf06Skettenis * copyright notice and this permission notice appear in all copies.
8d1cecf06Skettenis *
9d1cecf06Skettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10d1cecf06Skettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11d1cecf06Skettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12d1cecf06Skettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13d1cecf06Skettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14d1cecf06Skettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15d1cecf06Skettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16d1cecf06Skettenis */
17d1cecf06Skettenis
18d1cecf06Skettenis #include <sys/param.h>
19d1cecf06Skettenis #include <sys/systm.h>
20d1cecf06Skettenis #include <sys/device.h>
21d1cecf06Skettenis
22d1cecf06Skettenis #include <machine/intr.h>
23d1cecf06Skettenis #include <machine/bus.h>
24d1cecf06Skettenis #include <machine/fdt.h>
25d1cecf06Skettenis
26d1cecf06Skettenis #define _I2C_PRIVATE
27d1cecf06Skettenis #include <dev/i2c/i2cvar.h>
28d1cecf06Skettenis
29d1cecf06Skettenis #include <dev/ofw/openfirm.h>
30d1cecf06Skettenis #include <dev/ofw/ofw_clock.h>
31798f1d07Skettenis #include <dev/ofw/ofw_misc.h>
32d1cecf06Skettenis #include <dev/ofw/ofw_pinctrl.h>
33d1cecf06Skettenis #include <dev/ofw/fdt.h>
34d1cecf06Skettenis
35d1cecf06Skettenis /* Registers. */
36d1cecf06Skettenis #define RKI2C_CON 0x0000
37d1cecf06Skettenis #define RKI2C_CON_ACT2NAK (1 << 6)
38d1cecf06Skettenis #define RKI2C_CON_ACK (0 << 5)
39d1cecf06Skettenis #define RKI2C_CON_NAK (1 << 5)
40d1cecf06Skettenis #define RKI2C_CON_STOP (1 << 4)
41d1cecf06Skettenis #define RKI2C_CON_START (1 << 3)
42d1cecf06Skettenis #define RKI2C_CON_I2C_MODE_MASK (3 << 1)
43d1cecf06Skettenis #define RKI2C_CON_I2C_MODE_TX (0 << 1)
44d1cecf06Skettenis #define RKI2C_CON_I2C_MODE_RRX (1 << 1)
45d1cecf06Skettenis #define RKI2C_CON_I2C_MODE_RX (2 << 1)
46d1cecf06Skettenis #define RKI2C_CON_I2C_MODE_BROKEN (3 << 1)
47d1cecf06Skettenis #define RKI2C_CON_I2C_EN (1 << 0)
48d1cecf06Skettenis #define RKI2C_CLKDIV 0x0004
49d1cecf06Skettenis #define RKI2C_MRXADDR 0x0008
50d1cecf06Skettenis #define RKI2C_MRXADDR_ADDLVLD (1 << 24)
51d1cecf06Skettenis #define RKI2C_MRXRADDR 0x000c
52d1cecf06Skettenis #define RKI2C_MRXRADDR_SRADDLVLD (1 << 24)
53d1cecf06Skettenis #define RKI2C_MTXCNT 0x0010
54d1cecf06Skettenis #define RKI2C_MRXCNT 0x0014
55d1cecf06Skettenis #define RKI2C_IEN 0x0018
56d1cecf06Skettenis #define RKI2C_IEN_START (1 << 4)
57d1cecf06Skettenis #define RKI2C_IPD 0x001c
58d1cecf06Skettenis #define RKI2C_IPD_STOP (1 << 5)
59d1cecf06Skettenis #define RKI2C_IPD_START (1 << 4)
60d1cecf06Skettenis #define RKI2C_IPD_MBRF (1 << 3)
61d1cecf06Skettenis #define RKI2C_IPD_MBTF (1 << 2)
62d1cecf06Skettenis #define RKI2C_IPD_ALL 0xff
63d1cecf06Skettenis #define RKI2C_FCNT 0x0020
64d1cecf06Skettenis #define RKI2C_SCL_OE_DB 0x0024
65d1cecf06Skettenis #define RKI2C_TXDATA0 0x0100
66d1cecf06Skettenis #define RKI2C_RXDATA0 0x0200
67d1cecf06Skettenis #define RKI2C_ST 0x0220
68d1cecf06Skettenis
69d1cecf06Skettenis #define HREAD4(sc, reg) \
70d1cecf06Skettenis (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
71d1cecf06Skettenis #define HWRITE4(sc, reg, val) \
72d1cecf06Skettenis bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
73d1cecf06Skettenis #define HSET4(sc, reg, bits) \
74d1cecf06Skettenis HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
75d1cecf06Skettenis #define HCLR4(sc, reg, bits) \
76d1cecf06Skettenis HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
77d1cecf06Skettenis
78d1cecf06Skettenis struct rkiic_softc {
79d1cecf06Skettenis struct device sc_dev;
80d1cecf06Skettenis bus_space_tag_t sc_iot;
81d1cecf06Skettenis bus_space_handle_t sc_ioh;
82d1cecf06Skettenis
83d1cecf06Skettenis int sc_node;
84d1cecf06Skettenis struct i2c_controller sc_ic;
85798f1d07Skettenis struct i2c_bus sc_ib;
86d1cecf06Skettenis };
87d1cecf06Skettenis
88d1cecf06Skettenis int rkiic_match(struct device *, void *, void *);
89d1cecf06Skettenis void rkiic_attach(struct device *, struct device *, void *);
90d1cecf06Skettenis
91*9fdf0c62Smpi const struct cfattach rkiic_ca = {
92d1cecf06Skettenis sizeof (struct rkiic_softc), rkiic_match, rkiic_attach
93d1cecf06Skettenis };
94d1cecf06Skettenis
95d1cecf06Skettenis struct cfdriver rkiic_cd = {
96d1cecf06Skettenis NULL, "rkiic", DV_DULL
97d1cecf06Skettenis };
98d1cecf06Skettenis
99d1cecf06Skettenis int rkiic_acquire_bus(void *, int);
100d1cecf06Skettenis void rkiic_release_bus(void *, int);
101d1cecf06Skettenis int rkiic_send_start(void *, int);
102d1cecf06Skettenis int rkiic_send_stop(void *, int);
103d1cecf06Skettenis int rkiic_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
104d1cecf06Skettenis void *, size_t, int);
105d1cecf06Skettenis
106d1cecf06Skettenis void rkiic_bus_scan(struct device *, struct i2cbus_attach_args *, void *);
107d1cecf06Skettenis
108d1cecf06Skettenis int
rkiic_match(struct device * parent,void * match,void * aux)109d1cecf06Skettenis rkiic_match(struct device *parent, void *match, void *aux)
110d1cecf06Skettenis {
111d1cecf06Skettenis struct fdt_attach_args *faa = aux;
112d1cecf06Skettenis
113bc186453Skettenis return (OF_is_compatible(faa->fa_node, "rockchip,rk3288-i2c") ||
114f98dd03bSkettenis OF_is_compatible(faa->fa_node, "rockchip,rk3328-i2c") ||
115bc186453Skettenis OF_is_compatible(faa->fa_node, "rockchip,rk3399-i2c"));
116d1cecf06Skettenis }
117d1cecf06Skettenis
118d1cecf06Skettenis void
rkiic_attach(struct device * parent,struct device * self,void * aux)119d1cecf06Skettenis rkiic_attach(struct device *parent, struct device *self, void *aux)
120d1cecf06Skettenis {
121d1cecf06Skettenis struct rkiic_softc *sc = (struct rkiic_softc *)self;
122d1cecf06Skettenis struct fdt_attach_args *faa = aux;
123d1cecf06Skettenis struct i2cbus_attach_args iba;
124d1cecf06Skettenis uint32_t clock_speed, bus_speed;
125d1cecf06Skettenis uint32_t div, divl, divh;
126d1cecf06Skettenis uint32_t clkdivl, clkdivh;
127d1cecf06Skettenis
128d1cecf06Skettenis if (faa->fa_nreg < 1) {
129d1cecf06Skettenis printf(": no registers\n");
130d1cecf06Skettenis return;
131d1cecf06Skettenis }
132d1cecf06Skettenis
133d1cecf06Skettenis sc->sc_iot = faa->fa_iot;
134d1cecf06Skettenis sc->sc_node = faa->fa_node;
135d1cecf06Skettenis
136d1cecf06Skettenis if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
137d1cecf06Skettenis faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
138d1cecf06Skettenis printf(": can't map registers\n");
139d1cecf06Skettenis return;
140d1cecf06Skettenis }
141d1cecf06Skettenis
142d1cecf06Skettenis printf("\n");
143d1cecf06Skettenis
144d1cecf06Skettenis pinctrl_byname(sc->sc_node, "default");
145d1cecf06Skettenis
1465aee12e8Skettenis clock_set_assigned(sc->sc_node);
147d1cecf06Skettenis clock_enable(sc->sc_node, "i2c");
148d1cecf06Skettenis clock_enable(sc->sc_node, "pclk");
149d1cecf06Skettenis
150d1cecf06Skettenis clock_speed = clock_get_frequency(sc->sc_node, "i2c");
151d1cecf06Skettenis bus_speed = OF_getpropint(sc->sc_node, "clock-frequency", 100000);
152d1cecf06Skettenis
153d1cecf06Skettenis div = 2;
154d1cecf06Skettenis while (clock_speed > div * bus_speed * 8)
155d1cecf06Skettenis div++;
156d1cecf06Skettenis divl = div / 2;
157d1cecf06Skettenis divh = div - divl;
158d1cecf06Skettenis clkdivl = (divl - 1) & 0xffff;
159d1cecf06Skettenis clkdivh = (divh - 1) & 0xffff;
160d1cecf06Skettenis HWRITE4(sc, RKI2C_CLKDIV, clkdivh << 16 | clkdivl);
161d1cecf06Skettenis
162d1cecf06Skettenis sc->sc_ic.ic_cookie = sc;
163d1cecf06Skettenis sc->sc_ic.ic_acquire_bus = rkiic_acquire_bus;
164d1cecf06Skettenis sc->sc_ic.ic_release_bus = rkiic_release_bus;
165d1cecf06Skettenis sc->sc_ic.ic_exec = rkiic_exec;
166d1cecf06Skettenis
167d1cecf06Skettenis /* Configure its children */
168d1cecf06Skettenis memset(&iba, 0, sizeof(iba));
169d1cecf06Skettenis iba.iba_name = "iic";
170d1cecf06Skettenis iba.iba_tag = &sc->sc_ic;
171d1cecf06Skettenis iba.iba_bus_scan = rkiic_bus_scan;
172d1cecf06Skettenis iba.iba_bus_scan_arg = &sc->sc_node;
173d1cecf06Skettenis
174d1cecf06Skettenis config_found(&sc->sc_dev, &iba, iicbus_print);
175798f1d07Skettenis
176798f1d07Skettenis sc->sc_ib.ib_node = sc->sc_node;
177798f1d07Skettenis sc->sc_ib.ib_ic = &sc->sc_ic;
178798f1d07Skettenis i2c_register(&sc->sc_ib);
179d1cecf06Skettenis }
180d1cecf06Skettenis
181d1cecf06Skettenis int
rkiic_acquire_bus(void * cookie,int flags)182d1cecf06Skettenis rkiic_acquire_bus(void *cookie, int flags)
183d1cecf06Skettenis {
184d1cecf06Skettenis struct rkiic_softc *sc = cookie;
185d1cecf06Skettenis
186d1cecf06Skettenis HSET4(sc, RKI2C_CON, RKI2C_CON_I2C_EN);
187d1cecf06Skettenis return 0;
188d1cecf06Skettenis }
189d1cecf06Skettenis
190d1cecf06Skettenis void
rkiic_release_bus(void * cookie,int flags)191d1cecf06Skettenis rkiic_release_bus(void *cookie, int flags)
192d1cecf06Skettenis {
193d1cecf06Skettenis struct rkiic_softc *sc = cookie;
194d1cecf06Skettenis
195d1cecf06Skettenis HCLR4(sc, RKI2C_CON, RKI2C_CON_I2C_EN);
196d1cecf06Skettenis }
197d1cecf06Skettenis
198d1cecf06Skettenis int
rkiic_send_start(void * cookie,int flags)199d1cecf06Skettenis rkiic_send_start(void *cookie, int flags)
200d1cecf06Skettenis {
201d1cecf06Skettenis struct rkiic_softc *sc = cookie;
202d1cecf06Skettenis int timo;
203d1cecf06Skettenis
204d1cecf06Skettenis HSET4(sc, RKI2C_IPD, RKI2C_IPD_START);
205d1cecf06Skettenis HSET4(sc, RKI2C_CON, RKI2C_CON_START);
206d1cecf06Skettenis for (timo = 1000; timo > 0; timo--) {
207d1cecf06Skettenis if (HREAD4(sc, RKI2C_IPD) & RKI2C_IPD_START)
208d1cecf06Skettenis break;
209d1cecf06Skettenis delay(10);
210d1cecf06Skettenis }
211d1cecf06Skettenis HCLR4(sc, RKI2C_CON, RKI2C_CON_START);
212d1cecf06Skettenis if (timo == 0)
213d1cecf06Skettenis return ETIMEDOUT;
214d1cecf06Skettenis return 0;
215d1cecf06Skettenis }
216d1cecf06Skettenis
217d1cecf06Skettenis int
rkiic_send_stop(void * cookie,int flags)218d1cecf06Skettenis rkiic_send_stop(void *cookie, int flags)
219d1cecf06Skettenis {
220d1cecf06Skettenis struct rkiic_softc *sc = cookie;
221d1cecf06Skettenis int timo;
222d1cecf06Skettenis
223d1cecf06Skettenis HSET4(sc, RKI2C_IPD, RKI2C_IPD_STOP);
224d1cecf06Skettenis HSET4(sc, RKI2C_CON, RKI2C_CON_STOP);
225d1cecf06Skettenis for (timo = 1000; timo > 0; timo--) {
226d1cecf06Skettenis if (HREAD4(sc, RKI2C_IPD) & RKI2C_IPD_STOP)
227d1cecf06Skettenis break;
228d1cecf06Skettenis delay(10);
229d1cecf06Skettenis }
230d1cecf06Skettenis HCLR4(sc, RKI2C_CON, RKI2C_CON_STOP);
231d1cecf06Skettenis if (timo == 0)
232d1cecf06Skettenis return ETIMEDOUT;
233d1cecf06Skettenis return 0;
234d1cecf06Skettenis }
235d1cecf06Skettenis
236d1cecf06Skettenis int
rkiic_write(struct rkiic_softc * sc,i2c_addr_t addr,const void * cmd,size_t cmdlen,void * buf,size_t buflen)237d1cecf06Skettenis rkiic_write(struct rkiic_softc *sc, i2c_addr_t addr, const void *cmd,
238d1cecf06Skettenis size_t cmdlen, void *buf, size_t buflen)
239d1cecf06Skettenis {
240d1cecf06Skettenis uint8_t txbuf[32];
241d1cecf06Skettenis int len = 0;
242d1cecf06Skettenis int timo, i;
243d1cecf06Skettenis
244d1cecf06Skettenis /*
245d1cecf06Skettenis * Lump slave address, command and data into one single buffer
246d1cecf06Skettenis * and transfer it in a single operation.
247d1cecf06Skettenis */
248d1cecf06Skettenis txbuf[len++] = addr << 1;
249d1cecf06Skettenis for (i = 0; i < cmdlen; i++)
250d1cecf06Skettenis txbuf[len++] = ((uint8_t *)cmd)[i];
251d1cecf06Skettenis for (i = 0; i < buflen; i++)
252d1cecf06Skettenis txbuf[len++] = ((uint8_t *)buf)[i];
253d1cecf06Skettenis
254d1cecf06Skettenis for (i = 0; i < len; i += 4) {
255d1cecf06Skettenis HWRITE4(sc, RKI2C_TXDATA0 + i,
256d1cecf06Skettenis *((uint32_t *)&txbuf[i]));
257d1cecf06Skettenis }
258d1cecf06Skettenis
259d1cecf06Skettenis /* Start operation. */
260d1cecf06Skettenis HWRITE4(sc, RKI2C_MTXCNT, len);
261d1cecf06Skettenis
262d1cecf06Skettenis /* Wait for completion. */
263d1cecf06Skettenis for (timo = 1000; timo > 0; timo--) {
264d1cecf06Skettenis if (HREAD4(sc, RKI2C_IPD) & RKI2C_IPD_MBTF)
265d1cecf06Skettenis break;
266d1cecf06Skettenis delay(10);
267d1cecf06Skettenis }
268d1cecf06Skettenis if (timo == 0)
269d1cecf06Skettenis return ETIMEDOUT;
270d1cecf06Skettenis
271d1cecf06Skettenis return 0;
272d1cecf06Skettenis }
273d1cecf06Skettenis
274d1cecf06Skettenis int
rkiic_read(struct rkiic_softc * sc,i2c_addr_t addr,const void * cmd,size_t cmdlen,void * buf,size_t buflen)275d1cecf06Skettenis rkiic_read(struct rkiic_softc *sc, i2c_addr_t addr, const void *cmd,
276d1cecf06Skettenis size_t cmdlen, void *buf, size_t buflen)
277d1cecf06Skettenis {
278d1cecf06Skettenis uint32_t mrxraddr, rxdata;
279798f1d07Skettenis size_t pos = 0;
280798f1d07Skettenis uint32_t con;
281d1cecf06Skettenis int timo, i;
282d1cecf06Skettenis
283d1cecf06Skettenis HWRITE4(sc, RKI2C_MRXADDR, (addr << 1) | RKI2C_MRXADDR_ADDLVLD);
284d1cecf06Skettenis
285d1cecf06Skettenis /* Send the command as "register address". */
286d1cecf06Skettenis mrxraddr = 0;
287d1cecf06Skettenis for (i = 0; i < cmdlen; i++) {
288d1cecf06Skettenis mrxraddr |= ((uint8_t *)cmd)[i] << (i * 8);
289d1cecf06Skettenis mrxraddr |= RKI2C_MRXRADDR_SRADDLVLD << i;
290d1cecf06Skettenis }
291d1cecf06Skettenis HWRITE4(sc, RKI2C_MRXRADDR, mrxraddr);
292d1cecf06Skettenis
293798f1d07Skettenis while (1) {
294d1cecf06Skettenis /* Indicate that we're done after this operation. */
295798f1d07Skettenis if (buflen <= 32)
296d1cecf06Skettenis HSET4(sc, RKI2C_CON, RKI2C_CON_NAK);
297d1cecf06Skettenis
298d1cecf06Skettenis /* Start operation. */
299798f1d07Skettenis HWRITE4(sc, RKI2C_MRXCNT, MIN(buflen, 32));
300d1cecf06Skettenis
301d1cecf06Skettenis /* Wait for completion. */
302d1cecf06Skettenis for (timo = 1000; timo > 0; timo--) {
303d1cecf06Skettenis if (HREAD4(sc, RKI2C_IPD) & RKI2C_IPD_MBRF)
304d1cecf06Skettenis break;
305d1cecf06Skettenis delay(10);
306d1cecf06Skettenis }
307d1cecf06Skettenis if (timo == 0)
308d1cecf06Skettenis return ETIMEDOUT;
309d1cecf06Skettenis
310798f1d07Skettenis /* Ack interrupt. */
311798f1d07Skettenis HWRITE4(sc, RKI2C_IPD, RKI2C_IPD_MBRF);
312798f1d07Skettenis
313798f1d07Skettenis for (i = 0; i < MIN(buflen, 32); i++) {
314d1cecf06Skettenis if (i % 4 == 0)
315d1cecf06Skettenis rxdata = HREAD4(sc, RKI2C_RXDATA0 + i);
316798f1d07Skettenis ((uint8_t *)buf)[pos++] = rxdata;
317d1cecf06Skettenis rxdata >>= 8;
318d1cecf06Skettenis }
319d1cecf06Skettenis
320798f1d07Skettenis if (buflen <= 32)
321d1cecf06Skettenis return 0;
322798f1d07Skettenis
323798f1d07Skettenis /* Switch transfer mode after the first block. */
324798f1d07Skettenis if (pos <= 32) {
325798f1d07Skettenis con = HREAD4(sc, RKI2C_CON);
326798f1d07Skettenis con &= ~RKI2C_CON_I2C_MODE_MASK;
327798f1d07Skettenis con |= RKI2C_CON_I2C_MODE_RX;
328798f1d07Skettenis HWRITE4(sc, RKI2C_CON, con);
329798f1d07Skettenis }
330798f1d07Skettenis buflen -= 32;
331798f1d07Skettenis }
332d1cecf06Skettenis }
333d1cecf06Skettenis
334d1cecf06Skettenis int
rkiic_exec(void * cookie,i2c_op_t op,i2c_addr_t addr,const void * cmd,size_t cmdlen,void * buf,size_t buflen,int flags)335d1cecf06Skettenis rkiic_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmd,
336d1cecf06Skettenis size_t cmdlen, void *buf, size_t buflen, int flags)
337d1cecf06Skettenis {
338d1cecf06Skettenis struct rkiic_softc *sc = cookie;
339d1cecf06Skettenis uint32_t con;
340d1cecf06Skettenis int error;
341d1cecf06Skettenis
342798f1d07Skettenis if (cmdlen > 3 || (I2C_OP_WRITE_P(op) && buflen > 28))
343d1cecf06Skettenis return EINVAL;
344d1cecf06Skettenis
345d1cecf06Skettenis /* Clear interrupts. */
346d1cecf06Skettenis HWRITE4(sc, RKI2C_IPD, RKI2C_IPD_ALL);
347d1cecf06Skettenis
348798f1d07Skettenis /* Configure transfer mode. */
349d1cecf06Skettenis con = HREAD4(sc, RKI2C_CON);
350d1cecf06Skettenis con &= ~RKI2C_CON_I2C_MODE_MASK;
351d1cecf06Skettenis if (I2C_OP_WRITE_P(op))
352d1cecf06Skettenis con |= RKI2C_CON_I2C_MODE_TX;
353d1cecf06Skettenis else
354d1cecf06Skettenis con |= RKI2C_CON_I2C_MODE_RRX;
355d1cecf06Skettenis con &= ~RKI2C_CON_NAK;
356d1cecf06Skettenis con |= RKI2C_CON_ACT2NAK;
357d1cecf06Skettenis HWRITE4(sc, RKI2C_CON, con);
358d1cecf06Skettenis
359d1cecf06Skettenis error = rkiic_send_start(sc, flags);
360d1cecf06Skettenis if (error)
361d1cecf06Skettenis return error;
362d1cecf06Skettenis
363d1cecf06Skettenis if (I2C_OP_WRITE_P(op))
364d1cecf06Skettenis error = rkiic_write(sc, addr, cmd, cmdlen, buf, buflen);
365d1cecf06Skettenis else
366d1cecf06Skettenis error = rkiic_read(sc, addr, cmd, cmdlen, buf, buflen);
367d1cecf06Skettenis
368d1cecf06Skettenis if (I2C_OP_STOP_P(op))
369d1cecf06Skettenis rkiic_send_stop(sc, flags);
370d1cecf06Skettenis
371d1cecf06Skettenis return error;
372d1cecf06Skettenis }
373d1cecf06Skettenis
374d1cecf06Skettenis void
rkiic_bus_scan(struct device * self,struct i2cbus_attach_args * iba,void * arg)375d1cecf06Skettenis rkiic_bus_scan(struct device *self, struct i2cbus_attach_args *iba, void *arg)
376d1cecf06Skettenis {
377d1cecf06Skettenis int iba_node = *(int *)arg;
378d1cecf06Skettenis struct i2c_attach_args ia;
37969575cceSpatrick char name[32], status[32];
380d1cecf06Skettenis uint32_t reg[1];
381d1cecf06Skettenis int node;
382d1cecf06Skettenis
383d1cecf06Skettenis for (node = OF_child(iba_node); node; node = OF_peer(node)) {
384d1cecf06Skettenis memset(name, 0, sizeof(name));
38569575cceSpatrick memset(status, 0, sizeof(status));
386d1cecf06Skettenis memset(reg, 0, sizeof(reg));
387d1cecf06Skettenis
388d1cecf06Skettenis if (OF_getprop(node, "compatible", name, sizeof(name)) == -1)
389d1cecf06Skettenis continue;
390d1cecf06Skettenis if (name[0] == '\0')
391d1cecf06Skettenis continue;
392d1cecf06Skettenis
39369575cceSpatrick if (OF_getprop(node, "status", status, sizeof(status)) > 0 &&
39469575cceSpatrick strcmp(status, "disabled") == 0)
39569575cceSpatrick continue;
39669575cceSpatrick
397d1cecf06Skettenis if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg))
398d1cecf06Skettenis continue;
399d1cecf06Skettenis
400d1cecf06Skettenis memset(&ia, 0, sizeof(ia));
401d1cecf06Skettenis ia.ia_tag = iba->iba_tag;
402d1cecf06Skettenis ia.ia_addr = bemtoh32(®[0]);
403d1cecf06Skettenis ia.ia_name = name;
404d1cecf06Skettenis ia.ia_cookie = &node;
405d1cecf06Skettenis config_found(self, &ia, iic_print);
406d1cecf06Skettenis }
407d1cecf06Skettenis }
408