xref: /openbsd-src/sys/dev/fdt/rkiic.c (revision 9fdf0c627b1fec102f212f847a6f7676c1829e65)
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", &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(&reg[0]);
403d1cecf06Skettenis 		ia.ia_name = name;
404d1cecf06Skettenis 		ia.ia_cookie = &node;
405d1cecf06Skettenis 		config_found(self, &ia, iic_print);
406d1cecf06Skettenis 	}
407d1cecf06Skettenis }
408