xref: /openbsd-src/sys/dev/fdt/sxitwi.c (revision 9fdf0c627b1fec102f212f847a6f7676c1829e65)
1*9fdf0c62Smpi /* $OpenBSD: sxitwi.c,v 1.14 2021/10/24 17:52:27 mpi Exp $ */
2b1b56d26Skettenis /*	$NetBSD: gttwsi_core.c,v 1.2 2014/11/23 13:37:27 jmcneill Exp $	*/
3b1b56d26Skettenis /*
4b1b56d26Skettenis  * Copyright (c) 2008 Eiji Kawauchi.
5b1b56d26Skettenis  * All rights reserved.
6b1b56d26Skettenis  *
7b1b56d26Skettenis  * Redistribution and use in source and binary forms, with or without
8b1b56d26Skettenis  * modification, are permitted provided that the following conditions
9b1b56d26Skettenis  * are met:
10b1b56d26Skettenis  * 1. Redistributions of source code must retain the above copyright
11b1b56d26Skettenis  *    notice, this list of conditions and the following disclaimer.
12b1b56d26Skettenis  * 2. Redistributions in binary form must reproduce the above copyright
13b1b56d26Skettenis  *    notice, this list of conditions and the following disclaimer in the
14b1b56d26Skettenis  *    documentation and/or other materials provided with the distribution.
15b1b56d26Skettenis  * 3. All advertising materials mentioning features or use of this software
16b1b56d26Skettenis  *    must display the following acknowledgement:
17b1b56d26Skettenis  *      This product includes software developed for the NetBSD Project by
18b1b56d26Skettenis  *      Eiji Kawauchi.
19b1b56d26Skettenis  * 4. The name of the author may not be used to endorse or promote products
20b1b56d26Skettenis  *    derived from this software without specific prior written permission
21b1b56d26Skettenis  *
22b1b56d26Skettenis  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23b1b56d26Skettenis  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24b1b56d26Skettenis  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25b1b56d26Skettenis  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26b1b56d26Skettenis  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27b1b56d26Skettenis  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28b1b56d26Skettenis  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29b1b56d26Skettenis  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30b1b56d26Skettenis  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31b1b56d26Skettenis  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32b1b56d26Skettenis  */
33b1b56d26Skettenis /*
34b1b56d26Skettenis  * Copyright (c) 2005 Brocade Communcations, inc.
35b1b56d26Skettenis  * All rights reserved.
36b1b56d26Skettenis  *
37b1b56d26Skettenis  * Written by Matt Thomas for Brocade Communcations, Inc.
38b1b56d26Skettenis  *
39b1b56d26Skettenis  * Redistribution and use in source and binary forms, with or without
40b1b56d26Skettenis  * modification, are permitted provided that the following conditions
41b1b56d26Skettenis  * are met:
42b1b56d26Skettenis  * 1. Redistributions of source code must retain the above copyright
43b1b56d26Skettenis  *    notice, this list of conditions and the following disclaimer.
44b1b56d26Skettenis  * 2. Redistributions in binary form must reproduce the above copyright
45b1b56d26Skettenis  *    notice, this list of conditions and the following disclaimer in the
46b1b56d26Skettenis  *    documentation and/or other materials provided with the distribution.
47b1b56d26Skettenis  * 3. The name of Brocade Communications, Inc. may not be used to endorse
48b1b56d26Skettenis  *    or promote products derived from this software without specific prior
49b1b56d26Skettenis  *    written permission.
50b1b56d26Skettenis  *
51b1b56d26Skettenis  * THIS SOFTWARE IS PROVIDED BY BROCADE COMMUNICATIONS, INC. ``AS IS'' AND
52b1b56d26Skettenis  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53b1b56d26Skettenis  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54b1b56d26Skettenis  * ARE DISCLAIMED.  IN NO EVENT SHALL EITHER BROCADE COMMUNICATIONS, INC. BE
55b1b56d26Skettenis  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
56b1b56d26Skettenis  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
57b1b56d26Skettenis  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
58b1b56d26Skettenis  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
59b1b56d26Skettenis  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
60b1b56d26Skettenis  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
61b1b56d26Skettenis  * OF THE POSSIBILITY OF SUCH DAMAGE.
62b1b56d26Skettenis  */
63b1b56d26Skettenis 
64b1b56d26Skettenis /*
65b1b56d26Skettenis  * Marvell Two-Wire Serial Interface (aka I2C) master driver
66b1b56d26Skettenis  */
67b1b56d26Skettenis 
68b1b56d26Skettenis #include <sys/param.h>
69b1b56d26Skettenis #include <sys/systm.h>
70b1b56d26Skettenis #include <sys/device.h>
71b1b56d26Skettenis #include <sys/kernel.h>
72b1b56d26Skettenis #include <sys/rwlock.h>
73b1b56d26Skettenis 
74b1b56d26Skettenis #define	_I2C_PRIVATE
75b1b56d26Skettenis #include <dev/i2c/i2cvar.h>
76b1b56d26Skettenis 
77b1b56d26Skettenis #include <machine/bus.h>
78b1b56d26Skettenis #include <machine/fdt.h>
79b1b56d26Skettenis 
80b1b56d26Skettenis #include <dev/ofw/openfirm.h>
81b1b56d26Skettenis #include <dev/ofw/ofw_clock.h>
82b1b56d26Skettenis #include <dev/ofw/ofw_pinctrl.h>
8373a63b7dSpatrick #include <dev/ofw/ofw_misc.h>
84b1b56d26Skettenis #include <dev/ofw/fdt.h>
85b1b56d26Skettenis 
8647e62276Spatrick #define	TWSI_SLAVEADDR		0
8747e62276Spatrick #define	TWSI_EXTEND_SLAVEADDR	1
8847e62276Spatrick #define	TWSI_DATA		2
8947e62276Spatrick #define	TWSI_CONTROL		3
9047e62276Spatrick #define	TWSI_STATUS		4
9147e62276Spatrick #define	TWSI_CLOCK		5
9247e62276Spatrick #define	TWSI_SOFTRESET		6
9347e62276Spatrick #define	TWSI_NREG		7
94b1b56d26Skettenis 
95b1b56d26Skettenis #define	SLAVEADDR_GCE_MASK	0x01
96b1b56d26Skettenis #define	SLAVEADDR_SADDR_MASK	0xfe
97b1b56d26Skettenis 
98b1b56d26Skettenis #define	EXTEND_SLAVEADDR_MASK	0xff
99b1b56d26Skettenis 
100b1b56d26Skettenis #define	DATA_MASK		0xff
101b1b56d26Skettenis 
102b1b56d26Skettenis #define	CONTROL_ACK		(1 << 2)
103b1b56d26Skettenis #define	CONTROL_IFLG		(1 << 3)
104b1b56d26Skettenis #define	CONTROL_STOP		(1 << 4)
105b1b56d26Skettenis #define	CONTROL_START		(1 << 5)
106b1b56d26Skettenis #define	CONTROL_TWSIEN		(1 << 6)
107b1b56d26Skettenis #define	CONTROL_INTEN		(1 << 7)
108b1b56d26Skettenis 
109b1b56d26Skettenis #define	STAT_BE		0x00	/* Bus Error */
110b1b56d26Skettenis #define	STAT_SCT	0x08	/* Start condition transmitted */
111b1b56d26Skettenis #define	STAT_RSCT	0x10	/* Repeated start condition transmitted */
112b1b56d26Skettenis #define	STAT_AWBT_AR	0x18	/* Address + write bit transd, ack recvd */
113b1b56d26Skettenis #define	STAT_AWBT_ANR	0x20	/* Address + write bit transd, ack not recvd */
114b1b56d26Skettenis #define	STAT_MTDB_AR	0x28	/* Master transd data byte, ack recvd */
115b1b56d26Skettenis #define	STAT_MTDB_ANR	0x30	/* Master transd data byte, ack not recvd */
116b1b56d26Skettenis #define	STAT_MLADADT	0x38	/* Master lost arbitr during addr or data tx */
117b1b56d26Skettenis #define	STAT_ARBT_AR	0x40	/* Address + read bit transd, ack recvd */
118b1b56d26Skettenis #define	STAT_ARBT_ANR	0x48	/* Address + read bit transd, ack not recvd */
119b1b56d26Skettenis #define	STAT_MRRD_AT	0x50	/* Master received read data, ack transd */
120b1b56d26Skettenis #define	STAT_MRRD_ANT	0x58	/* Master received read data, ack not transd */
121b1b56d26Skettenis #define	STAT_SAWBT_AR	0xd0	/* Second addr + write bit transd, ack recvd */
122b1b56d26Skettenis #define	STAT_SAWBT_ANR	0xd8	/* S addr + write bit transd, ack not recvd */
123b1b56d26Skettenis #define	STAT_SARBT_AR	0xe0	/* Second addr + read bit transd, ack recvd */
124b1b56d26Skettenis #define	STAT_SARBT_ANR	0xe8	/* S addr + read bit transd, ack not recvd */
125b1b56d26Skettenis #define	STAT_NRS	0xf8	/* No relevant status */
126b1b56d26Skettenis 
127b1b56d26Skettenis #define	SOFTRESET_VAL		0		/* reset value */
128b1b56d26Skettenis 
129b1b56d26Skettenis struct sxitwi_softc {
130b1b56d26Skettenis 	struct device		 sc_dev;
131b1b56d26Skettenis 	bus_space_tag_t		 sc_iot;
132b1b56d26Skettenis 	bus_space_handle_t	 sc_ioh;
133b1b56d26Skettenis 	int			 sc_node;
134b1b56d26Skettenis 	u_int			 sc_started;
135183a6846Skettenis 	u_int			 sc_twsien_iflg;
136b1b56d26Skettenis 	struct i2c_controller	 sc_ic;
13773a63b7dSpatrick 	struct i2c_bus		 sc_ib;
138b1b56d26Skettenis 	struct rwlock		 sc_buslock;
139b1b56d26Skettenis 	void			*sc_ih;
14047e62276Spatrick 	uint8_t			 sc_regs[TWSI_NREG];
14147e62276Spatrick 	int			 sc_delay;
142b1b56d26Skettenis };
143b1b56d26Skettenis 
144b1b56d26Skettenis void	sxitwi_attach(struct device *, struct device *, void *);
145b1b56d26Skettenis int	sxitwi_match(struct device *, void *, void *);
146b1b56d26Skettenis void	sxitwi_bus_scan(struct device *, struct i2cbus_attach_args *, void *);
147b1b56d26Skettenis 
148b1b56d26Skettenis int	sxitwi_intr(void *);
149b1b56d26Skettenis int	sxitwi_acquire_bus(void *, int);
150b1b56d26Skettenis void	sxitwi_release_bus(void *, int);
151b1b56d26Skettenis int	sxitwi_send_start(void *, int);
152b1b56d26Skettenis int	sxitwi_send_stop(void *, int);
153b1b56d26Skettenis int	sxitwi_initiate_xfer(void *, i2c_addr_t, int);
154b1b56d26Skettenis int	sxitwi_read_byte(void *, uint8_t *, int);
155b1b56d26Skettenis int	sxitwi_write_byte(void *, uint8_t, int);
156b1b56d26Skettenis int	sxitwi_wait(struct sxitwi_softc *, u_int, u_int, int);
157b1b56d26Skettenis static inline u_int sxitwi_read_4(struct sxitwi_softc *, u_int);
158b1b56d26Skettenis static inline void sxitwi_write_4(struct sxitwi_softc *, u_int, u_int);
159b1b56d26Skettenis 
160b1b56d26Skettenis struct cfdriver sxitwi_cd = {
161b1b56d26Skettenis 	NULL, "sxitwi", DV_DULL
162b1b56d26Skettenis };
163b1b56d26Skettenis 
164*9fdf0c62Smpi const struct cfattach sxitwi_ca = {
165b1b56d26Skettenis 	sizeof(struct sxitwi_softc), sxitwi_match, sxitwi_attach
166b1b56d26Skettenis };
167b1b56d26Skettenis 
168b1b56d26Skettenis int
sxitwi_match(struct device * parent,void * match,void * aux)169b1b56d26Skettenis sxitwi_match(struct device *parent, void *match, void *aux)
170b1b56d26Skettenis {
171b1b56d26Skettenis 	struct fdt_attach_args *faa = aux;
172b1b56d26Skettenis 
173c7b07e68Spatrick 	return (OF_is_compatible(faa->fa_node, "allwinner,sun4i-a10-i2c") ||
174183a6846Skettenis 	    OF_is_compatible(faa->fa_node, "allwinner,sun6i-a31-i2c") ||
17547e62276Spatrick 	    OF_is_compatible(faa->fa_node, "allwinner,sun7i-a20-i2c") ||
1766e85977dSkettenis 	    OF_is_compatible(faa->fa_node, "marvell,mv78230-i2c") ||
17747e62276Spatrick 	    OF_is_compatible(faa->fa_node, "marvell,mv78230-a0-i2c"));
178b1b56d26Skettenis }
179b1b56d26Skettenis 
180b1b56d26Skettenis void
sxitwi_attach(struct device * parent,struct device * self,void * aux)181b1b56d26Skettenis sxitwi_attach(struct device *parent, struct device *self, void *aux)
182b1b56d26Skettenis {
183b1b56d26Skettenis 	struct sxitwi_softc *sc = (struct sxitwi_softc *)self;
184b1b56d26Skettenis 	struct fdt_attach_args *faa = aux;
185b1b56d26Skettenis 	struct i2cbus_attach_args iba;
1862284a7beSkettenis 	uint32_t freq, parent_freq;
18747e62276Spatrick 	uint32_t m, n, nbase;
188b1b56d26Skettenis 
189b1b56d26Skettenis 	if (faa->fa_nreg < 1) {
190b1b56d26Skettenis 		printf(": no registers\n");
191b1b56d26Skettenis 		return;
192b1b56d26Skettenis 	}
193b1b56d26Skettenis 
19447e62276Spatrick 	nbase = 1;
19547e62276Spatrick 	sc->sc_regs[TWSI_SLAVEADDR] = 0x00;
19647e62276Spatrick 	sc->sc_regs[TWSI_EXTEND_SLAVEADDR] = 0x04;
19747e62276Spatrick 	sc->sc_regs[TWSI_DATA] = 0x08;
19847e62276Spatrick 	sc->sc_regs[TWSI_CONTROL] = 0x0c;
19947e62276Spatrick 	sc->sc_regs[TWSI_STATUS] = 0x10;
20047e62276Spatrick 	sc->sc_regs[TWSI_CLOCK] = 0x14;
20147e62276Spatrick 	sc->sc_regs[TWSI_SOFTRESET] = 0x18;
20247e62276Spatrick 
2036e85977dSkettenis 	if (OF_is_compatible(faa->fa_node, "marvell,mv78230-i2c") ||
2046e85977dSkettenis 	    OF_is_compatible(faa->fa_node, "marvell,mv78230-a0-i2c")) {
20547e62276Spatrick 		nbase = 2;
20647e62276Spatrick 		sc->sc_delay = 1;
20747e62276Spatrick 		sc->sc_regs[TWSI_SLAVEADDR] = 0x00;
20847e62276Spatrick 		sc->sc_regs[TWSI_EXTEND_SLAVEADDR] = 0x10;
20947e62276Spatrick 		sc->sc_regs[TWSI_DATA] = 0x04;
21047e62276Spatrick 		sc->sc_regs[TWSI_CONTROL] = 0x08;
21147e62276Spatrick 		sc->sc_regs[TWSI_STATUS] = 0x0c;
21247e62276Spatrick 		sc->sc_regs[TWSI_CLOCK] = 0x0c;
21347e62276Spatrick 		sc->sc_regs[TWSI_SOFTRESET] = 0x1c;
21447e62276Spatrick 	}
21547e62276Spatrick 
2162284a7beSkettenis 	/*
2172284a7beSkettenis 	 * Calculate clock dividers up front such that we can bail out
2182284a7beSkettenis 	 * early if the desired clock rate can't be obtained.  Make
2192284a7beSkettenis 	 * sure the bus clock rate is never above the desired rate.
2202284a7beSkettenis 	 */
2212284a7beSkettenis 	parent_freq = clock_get_frequency(faa->fa_node, NULL);
2222284a7beSkettenis 	freq = OF_getpropint(faa->fa_node, "clock-frequency", 100000);
2232284a7beSkettenis 	if (parent_freq == 0) {
2242284a7beSkettenis 		printf(": unknown clock frequency\n");
2252284a7beSkettenis 		return;
2262284a7beSkettenis 	}
2272284a7beSkettenis 	n = 0, m = 0;
22847e62276Spatrick 	while ((freq * (nbase << n) * 16 * 10) < parent_freq)
2292284a7beSkettenis 		n++;
23047e62276Spatrick 	while ((freq * (nbase << n) * (m + 1) * 10) < parent_freq)
2312284a7beSkettenis 		m++;
2322284a7beSkettenis 	if (n > 8 || m > 16) {
2332284a7beSkettenis 		printf(": clock frequency too high\n");
2342284a7beSkettenis 		return;
2352284a7beSkettenis 	}
2362284a7beSkettenis 
237b1b56d26Skettenis 	sc->sc_node = faa->fa_node;
238b1b56d26Skettenis 	sc->sc_iot = faa->fa_iot;
239b1b56d26Skettenis 
240b1b56d26Skettenis 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
241b1b56d26Skettenis 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
242b1b56d26Skettenis 		printf(": can't map registers\n");
243b1b56d26Skettenis 		return;
244b1b56d26Skettenis 	}
245b1b56d26Skettenis 
246b1b56d26Skettenis 	rw_init(&sc->sc_buslock, sc->sc_dev.dv_xname);
247b1b56d26Skettenis 
248183a6846Skettenis 	/*
249183a6846Skettenis 	 * On the Allwinner A31 we need to write 1 to clear a pending
250183a6846Skettenis 	 * interrupt.
251183a6846Skettenis 	 */
252183a6846Skettenis 	sc->sc_twsien_iflg = CONTROL_TWSIEN;
253183a6846Skettenis 	if (OF_is_compatible(sc->sc_node, "allwinner,sun6i-a31-i2c"))
254eba3a077Skettenis 		sc->sc_twsien_iflg |= CONTROL_IFLG;
255183a6846Skettenis 
256b1b56d26Skettenis 	sc->sc_started = 0;
257b1b56d26Skettenis 	sc->sc_ic.ic_cookie = sc;
258b1b56d26Skettenis 	sc->sc_ic.ic_acquire_bus = sxitwi_acquire_bus;
259b1b56d26Skettenis 	sc->sc_ic.ic_release_bus = sxitwi_release_bus;
260b1b56d26Skettenis 	sc->sc_ic.ic_exec = NULL;
261b1b56d26Skettenis 	sc->sc_ic.ic_send_start = sxitwi_send_start;
262b1b56d26Skettenis 	sc->sc_ic.ic_send_stop = sxitwi_send_stop;
263b1b56d26Skettenis 	sc->sc_ic.ic_initiate_xfer = sxitwi_initiate_xfer;
264b1b56d26Skettenis 	sc->sc_ic.ic_read_byte = sxitwi_read_byte;
265b1b56d26Skettenis 	sc->sc_ic.ic_write_byte = sxitwi_write_byte;
266b1b56d26Skettenis 
267b1b56d26Skettenis 	pinctrl_byname(faa->fa_node, "default");
268b1b56d26Skettenis 
269b1b56d26Skettenis 	/* Enable clock */
270b1b56d26Skettenis 	clock_enable(faa->fa_node, NULL);
271183a6846Skettenis 	reset_deassert_all(faa->fa_node);
272b1b56d26Skettenis 
2732284a7beSkettenis 	/* Set clock rate. */
27447e62276Spatrick 	sxitwi_write_4(sc, TWSI_CLOCK, (m << 3) | (n << 0));
275b1b56d26Skettenis 
276b1b56d26Skettenis 	/* Put the controller into Soft Reset. */
277b1b56d26Skettenis 	sxitwi_write_4(sc, TWSI_SOFTRESET, SOFTRESET_VAL);
278b1b56d26Skettenis 
279b1b56d26Skettenis 	/* Establish interrupt */
28070e69ae2Spatrick 	sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_BIO,
281b1b56d26Skettenis 	    sxitwi_intr, sc, sc->sc_dev.dv_xname);
282b1b56d26Skettenis 	if (sc->sc_ih == NULL) {
2836b4e2a6dSkettenis 		printf(": can't establish interrupt\n");
284b1b56d26Skettenis 		return;
285b1b56d26Skettenis 	}
286b1b56d26Skettenis 
287b1b56d26Skettenis 	printf("\n");
288b1b56d26Skettenis 
289b1b56d26Skettenis 	/* Configure its children */
290b1b56d26Skettenis 	memset(&iba, 0, sizeof(iba));
291b1b56d26Skettenis 	iba.iba_name = "iic";
292b1b56d26Skettenis 	iba.iba_tag = &sc->sc_ic;
293b1b56d26Skettenis 	iba.iba_bus_scan = sxitwi_bus_scan;
294b1b56d26Skettenis 	iba.iba_bus_scan_arg = &sc->sc_node;
295b1b56d26Skettenis 	config_found(&sc->sc_dev, &iba, iicbus_print);
29673a63b7dSpatrick 
29773a63b7dSpatrick 	sc->sc_ib.ib_node = sc->sc_node;
29873a63b7dSpatrick 	sc->sc_ib.ib_ic = &sc->sc_ic;
29973a63b7dSpatrick 	i2c_register(&sc->sc_ib);
300b1b56d26Skettenis }
301b1b56d26Skettenis 
302b1b56d26Skettenis void
sxitwi_bus_scan(struct device * self,struct i2cbus_attach_args * iba,void * arg)303b1b56d26Skettenis sxitwi_bus_scan(struct device *self, struct i2cbus_attach_args *iba, void *arg)
304b1b56d26Skettenis {
305b1b56d26Skettenis 	int iba_node = *(int *)arg;
306b1b56d26Skettenis 	struct i2c_attach_args ia;
307c1762c82Spatrick 	char name[32], status[32];
308b1b56d26Skettenis 	uint32_t reg[1];
309b1b56d26Skettenis 	int node;
310b1b56d26Skettenis 
311b1b56d26Skettenis 	for (node = OF_child(iba_node); node; node = OF_peer(node)) {
312b1b56d26Skettenis 		memset(name, 0, sizeof(name));
313c1762c82Spatrick 		memset(status, 0, sizeof(status));
314b1b56d26Skettenis 		memset(reg, 0, sizeof(reg));
315b1b56d26Skettenis 
316b1b56d26Skettenis 		if (OF_getprop(node, "compatible", name, sizeof(name)) == -1)
317b1b56d26Skettenis 			continue;
318b1b56d26Skettenis 		if (name[0] == '\0')
319b1b56d26Skettenis 			continue;
320b1b56d26Skettenis 
321c1762c82Spatrick 		if (OF_getprop(node, "status", status, sizeof(status)) > 0 &&
322c1762c82Spatrick 		    strcmp(status, "disabled") == 0)
323c1762c82Spatrick 			continue;
324c1762c82Spatrick 
325b1b56d26Skettenis 		if (OF_getprop(node, "reg", &reg, sizeof(reg)) != sizeof(reg))
326b1b56d26Skettenis 			continue;
327b1b56d26Skettenis 
328b1b56d26Skettenis 		memset(&ia, 0, sizeof(ia));
329b1b56d26Skettenis 		ia.ia_tag = iba->iba_tag;
330b1b56d26Skettenis 		ia.ia_addr = bemtoh32(&reg[0]);
331b1b56d26Skettenis 		ia.ia_name = name;
332b1b56d26Skettenis 		ia.ia_cookie = &node;
333b1b56d26Skettenis 		config_found(self, &ia, iic_print);
334b1b56d26Skettenis 	}
335b1b56d26Skettenis }
336b1b56d26Skettenis 
337b1b56d26Skettenis u_int
sxitwi_read_4(struct sxitwi_softc * sc,u_int reg)338b1b56d26Skettenis sxitwi_read_4(struct sxitwi_softc *sc, u_int reg)
339b1b56d26Skettenis {
34047e62276Spatrick 	KASSERT(reg < TWSI_NREG);
34147e62276Spatrick 	return bus_space_read_4(sc->sc_iot, sc->sc_ioh, sc->sc_regs[reg]);
342b1b56d26Skettenis }
343b1b56d26Skettenis 
344b1b56d26Skettenis void
sxitwi_write_4(struct sxitwi_softc * sc,u_int reg,u_int val)345b1b56d26Skettenis sxitwi_write_4(struct sxitwi_softc *sc, u_int reg, u_int val)
346b1b56d26Skettenis {
34747e62276Spatrick 	KASSERT(reg < TWSI_NREG);
34847e62276Spatrick 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, sc->sc_regs[reg], val);
349b1b56d26Skettenis }
350b1b56d26Skettenis 
351b1b56d26Skettenis int
sxitwi_intr(void * arg)352b1b56d26Skettenis sxitwi_intr(void *arg)
353b1b56d26Skettenis {
354b1b56d26Skettenis 	struct sxitwi_softc *sc = arg;
355b1b56d26Skettenis 	u_int val;
356b1b56d26Skettenis 
357b1b56d26Skettenis 	val = sxitwi_read_4(sc, TWSI_CONTROL);
358b1b56d26Skettenis 	if (val & CONTROL_IFLG) {
359b1b56d26Skettenis 		sxitwi_write_4(sc, TWSI_CONTROL, val & ~CONTROL_INTEN);
360b1b56d26Skettenis 		return 1;
361b1b56d26Skettenis 	}
362b1b56d26Skettenis 	return 0;
363b1b56d26Skettenis }
364b1b56d26Skettenis 
365b1b56d26Skettenis int
sxitwi_acquire_bus(void * arg,int flags)366b1b56d26Skettenis sxitwi_acquire_bus(void *arg, int flags)
367b1b56d26Skettenis {
368b1b56d26Skettenis 	struct sxitwi_softc *sc = arg;
369b1b56d26Skettenis 
370b1b56d26Skettenis 	if (flags & I2C_F_POLL)
371b1b56d26Skettenis 		return 0;
372b1b56d26Skettenis 
373b1b56d26Skettenis 	return rw_enter(&sc->sc_buslock, RW_WRITE);
374b1b56d26Skettenis }
375b1b56d26Skettenis 
376b1b56d26Skettenis void
sxitwi_release_bus(void * arg,int flags)377b1b56d26Skettenis sxitwi_release_bus(void *arg, int flags)
378b1b56d26Skettenis {
379b1b56d26Skettenis 	struct sxitwi_softc *sc = arg;
380b1b56d26Skettenis 
381b1b56d26Skettenis 	if (flags & I2C_F_POLL)
382b1b56d26Skettenis 		return;
383b1b56d26Skettenis 
384b1b56d26Skettenis 	rw_exit(&sc->sc_buslock);
385b1b56d26Skettenis }
386b1b56d26Skettenis 
387b1b56d26Skettenis int
sxitwi_send_start(void * v,int flags)388b1b56d26Skettenis sxitwi_send_start(void *v, int flags)
389b1b56d26Skettenis {
390b1b56d26Skettenis 	struct sxitwi_softc *sc = v;
391b1b56d26Skettenis 	int expect;
392b1b56d26Skettenis 
393b1b56d26Skettenis 	if (sc->sc_started)
394b1b56d26Skettenis 		expect = STAT_RSCT;
395b1b56d26Skettenis 	else
396b1b56d26Skettenis 		expect = STAT_SCT;
397b1b56d26Skettenis 	sc->sc_started = 1;
398b1b56d26Skettenis 
399b1b56d26Skettenis 	return sxitwi_wait(sc, CONTROL_START, expect, flags);
400b1b56d26Skettenis }
401b1b56d26Skettenis 
402b1b56d26Skettenis int
sxitwi_send_stop(void * v,int flags)403b1b56d26Skettenis sxitwi_send_stop(void *v, int flags)
404b1b56d26Skettenis {
405b1b56d26Skettenis 	struct sxitwi_softc *sc = v;
406b1b56d26Skettenis 
407b1b56d26Skettenis 	sc->sc_started = 0;
408b1b56d26Skettenis 
40915dcc434Skettenis 	/*
41015dcc434Skettenis 	 * No need to wait; the controller doesn't transmit the next
41115dcc434Skettenis 	 * START condition until the bus is free.
41215dcc434Skettenis 	 */
413183a6846Skettenis 	sxitwi_write_4(sc, TWSI_CONTROL, CONTROL_STOP | sc->sc_twsien_iflg);
41447e62276Spatrick 	if (sc->sc_delay)
41547e62276Spatrick 		delay(5);
416b1b56d26Skettenis 	return 0;
417b1b56d26Skettenis }
418b1b56d26Skettenis 
419b1b56d26Skettenis int
sxitwi_initiate_xfer(void * v,i2c_addr_t addr,int flags)420b1b56d26Skettenis sxitwi_initiate_xfer(void *v, i2c_addr_t addr, int flags)
421b1b56d26Skettenis {
422b1b56d26Skettenis 	struct sxitwi_softc *sc = v;
423b1b56d26Skettenis 	u_int data, expect;
424b1b56d26Skettenis 	int error, read;
425b1b56d26Skettenis 
426b1b56d26Skettenis 	sxitwi_send_start(v, flags);
427b1b56d26Skettenis 
428b1b56d26Skettenis 	read = (flags & I2C_F_READ) != 0;
429b1b56d26Skettenis 	if (read)
430b1b56d26Skettenis 		expect = STAT_ARBT_AR;
431b1b56d26Skettenis 	else
432b1b56d26Skettenis 		expect = STAT_AWBT_AR;
433b1b56d26Skettenis 
434b1b56d26Skettenis 	/*
435b1b56d26Skettenis 	 * First byte contains whether this xfer is a read or write.
436b1b56d26Skettenis 	 */
437b1b56d26Skettenis 	data = read;
438b1b56d26Skettenis 	if (addr > 0x7f) {
439b1b56d26Skettenis 		/*
440b1b56d26Skettenis 		 * If this is a 10bit request, the first address byte is
441b1b56d26Skettenis 		 * 0b11110<b9><b8><r/w>.
442b1b56d26Skettenis 		 */
443b1b56d26Skettenis 		data |= 0xf0 | ((addr & 0x300) >> 7);
444b1b56d26Skettenis 		sxitwi_write_4(sc, TWSI_DATA, data);
445b1b56d26Skettenis 		error = sxitwi_wait(sc, 0, expect, flags);
446b1b56d26Skettenis 		if (error)
447b1b56d26Skettenis 			return error;
448b1b56d26Skettenis 		/*
449b1b56d26Skettenis 		 * The first address byte has been sent, now to send
450b1b56d26Skettenis 		 * the second one.
451b1b56d26Skettenis 		 */
452b1b56d26Skettenis 		if (read)
453b1b56d26Skettenis 			expect = STAT_SARBT_AR;
454b1b56d26Skettenis 		else
455b1b56d26Skettenis 			expect = STAT_SAWBT_AR;
456b1b56d26Skettenis 		data = (uint8_t)addr;
457b1b56d26Skettenis 	} else
458b1b56d26Skettenis 		data |= (addr << 1);
459b1b56d26Skettenis 
460b1b56d26Skettenis 	sxitwi_write_4(sc, TWSI_DATA, data);
461b1b56d26Skettenis 	return sxitwi_wait(sc, 0, expect, flags);
462b1b56d26Skettenis }
463b1b56d26Skettenis 
464b1b56d26Skettenis int
sxitwi_read_byte(void * v,uint8_t * valp,int flags)465b1b56d26Skettenis sxitwi_read_byte(void *v, uint8_t *valp, int flags)
466b1b56d26Skettenis {
467b1b56d26Skettenis 	struct sxitwi_softc *sc = v;
468b1b56d26Skettenis 	int error;
469b1b56d26Skettenis 
470b1b56d26Skettenis 	if (flags & I2C_F_LAST)
471b1b56d26Skettenis 		error = sxitwi_wait(sc, 0, STAT_MRRD_ANT, flags);
472b1b56d26Skettenis 	else
473b1b56d26Skettenis 		error = sxitwi_wait(sc, CONTROL_ACK, STAT_MRRD_AT, flags);
474b1b56d26Skettenis 	if (!error)
475b1b56d26Skettenis 		*valp = sxitwi_read_4(sc, TWSI_DATA);
476b1b56d26Skettenis 	if ((flags & (I2C_F_LAST | I2C_F_STOP)) == (I2C_F_LAST | I2C_F_STOP))
477b1b56d26Skettenis 		error = sxitwi_send_stop(sc, flags);
478b1b56d26Skettenis 	return error;
479b1b56d26Skettenis }
480b1b56d26Skettenis 
481b1b56d26Skettenis int
sxitwi_write_byte(void * v,uint8_t val,int flags)482b1b56d26Skettenis sxitwi_write_byte(void *v, uint8_t val, int flags)
483b1b56d26Skettenis {
484b1b56d26Skettenis 	struct sxitwi_softc *sc = v;
485b1b56d26Skettenis 	int error;
486b1b56d26Skettenis 
487b1b56d26Skettenis 	sxitwi_write_4(sc, TWSI_DATA, val);
488b1b56d26Skettenis 	error = sxitwi_wait(sc, 0, STAT_MTDB_AR, flags);
489b1b56d26Skettenis 	if (flags & I2C_F_STOP)
490b1b56d26Skettenis 		sxitwi_send_stop(sc, flags);
491b1b56d26Skettenis 	return error;
492b1b56d26Skettenis }
493b1b56d26Skettenis 
494b1b56d26Skettenis int
sxitwi_wait(struct sxitwi_softc * sc,u_int control,u_int expect,int flags)495b1b56d26Skettenis sxitwi_wait(struct sxitwi_softc *sc, u_int control, u_int expect, int flags)
496b1b56d26Skettenis {
497b1b56d26Skettenis 	u_int status;
49815dcc434Skettenis 	int timo;
499b1b56d26Skettenis 
500183a6846Skettenis 	sxitwi_write_4(sc, TWSI_CONTROL, control | sc->sc_twsien_iflg);
501b1b56d26Skettenis 
50215dcc434Skettenis 	for (timo = 10000; timo > 0; timo--) {
503b1b56d26Skettenis 		control = sxitwi_read_4(sc, TWSI_CONTROL);
504b1b56d26Skettenis 		if (control & CONTROL_IFLG)
505b1b56d26Skettenis 			break;
50615dcc434Skettenis 		delay(1);
507b1b56d26Skettenis 	}
50815dcc434Skettenis 	if (timo == 0)
50915dcc434Skettenis 		return ETIMEDOUT;
510b1b56d26Skettenis 
51147e62276Spatrick 	if (sc->sc_delay)
51247e62276Spatrick 		delay(5);
51347e62276Spatrick 
514b1b56d26Skettenis 	status = sxitwi_read_4(sc, TWSI_STATUS);
515b1b56d26Skettenis 	if (status != expect)
516b1b56d26Skettenis 		return EIO;
51715dcc434Skettenis 	return 0;
518b1b56d26Skettenis }
519