xref: /openbsd-src/sys/arch/armv7/omap/ti_iic.c (revision 9fdf0c627b1fec102f212f847a6f7676c1829e65)
1*9fdf0c62Smpi /*	$OpenBSD: ti_iic.c,v 1.15 2021/10/24 17:52:28 mpi Exp $	*/
2f7dd3a19Srapha /* $NetBSD: ti_iic.c,v 1.4 2013/04/25 13:04:27 rkujawa Exp $ */
3f7dd3a19Srapha 
4f7dd3a19Srapha /*
5f7dd3a19Srapha  * Copyright (c) 2013 Manuel Bouyer.  All rights reserved.
6f7dd3a19Srapha  *
7f7dd3a19Srapha  * Redistribution and use in source and binary forms, with or without
8f7dd3a19Srapha  * modification, are permitted provided that the following conditions
9f7dd3a19Srapha  * are met:
10f7dd3a19Srapha  * 1. Redistributions of source code must retain the above copyright
11f7dd3a19Srapha  *    notice, this list of conditions and the following disclaimer.
12f7dd3a19Srapha  * 2. Redistributions in binary form must reproduce the above copyright
13f7dd3a19Srapha  *    notice, this list of conditions and the following disclaimer in the
14f7dd3a19Srapha  *    documentation and/or other materials provided with the distribution.
15f7dd3a19Srapha  *
16f7dd3a19Srapha  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17f7dd3a19Srapha  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18f7dd3a19Srapha  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19f7dd3a19Srapha  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20f7dd3a19Srapha  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21f7dd3a19Srapha  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22f7dd3a19Srapha  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23f7dd3a19Srapha  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24f7dd3a19Srapha  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25f7dd3a19Srapha  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26f7dd3a19Srapha  */
27f7dd3a19Srapha 
28f7dd3a19Srapha /*-
29f7dd3a19Srapha  * Copyright (c) 2012 Jared D. McNeill <jmcneill@invisible.ca>
30f7dd3a19Srapha  * All rights reserved.
31f7dd3a19Srapha  *
32f7dd3a19Srapha  * Redistribution and use in source and binary forms, with or without
33f7dd3a19Srapha  * modification, are permitted provided that the following conditions
34f7dd3a19Srapha  * are met:
35f7dd3a19Srapha  * 1. Redistributions of source code must retain the above copyright
36f7dd3a19Srapha  *    notice, this list of conditions and the following disclaimer.
37f7dd3a19Srapha  * 2. The name of the author may not be used to endorse or promote products
38f7dd3a19Srapha  *    derived from this software without specific prior written permission.
39f7dd3a19Srapha  *
40f7dd3a19Srapha  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
41f7dd3a19Srapha  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
42f7dd3a19Srapha  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
43f7dd3a19Srapha  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
44f7dd3a19Srapha  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
45f7dd3a19Srapha  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46f7dd3a19Srapha  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
47f7dd3a19Srapha  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
48f7dd3a19Srapha  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49f7dd3a19Srapha  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50f7dd3a19Srapha  * SUCH DAMAGE.
51f7dd3a19Srapha  */
52f7dd3a19Srapha 
53f7dd3a19Srapha #include <sys/param.h>
54f7dd3a19Srapha #include <sys/systm.h>
55f7dd3a19Srapha #include <sys/device.h>
56f7dd3a19Srapha #include <sys/rwlock.h>
57f7dd3a19Srapha 
58f7dd3a19Srapha #include <machine/bus.h>
59f7dd3a19Srapha #include <machine/intr.h>
60b8746eccSjsg #include <machine/fdt.h>
61f7dd3a19Srapha 
62f7dd3a19Srapha #include <dev/i2c/i2cvar.h>
63f7dd3a19Srapha 
64f7dd3a19Srapha #include <armv7/omap/prcmvar.h>
65f7dd3a19Srapha #include <armv7/omap/ti_iicreg.h>
66f7dd3a19Srapha 
67b8746eccSjsg #include <dev/ofw/openfirm.h>
6816f6b372Sjsg #include <dev/ofw/ofw_pinctrl.h>
69ac7c670eSpatrick #include <dev/ofw/fdt.h>
70b8746eccSjsg 
71f7dd3a19Srapha #ifndef AM335X_I2C_SLAVE_ADDR
72f7dd3a19Srapha #define AM335X_I2C_SLAVE_ADDR	0x01
73f7dd3a19Srapha #endif
74f7dd3a19Srapha 
75f7dd3a19Srapha #ifdef I2CDEBUG
76f7dd3a19Srapha #define DPRINTF(args)	printf args
77f7dd3a19Srapha #else
78f7dd3a19Srapha #define DPRINTF(args)
79f7dd3a19Srapha #endif
80f7dd3a19Srapha 
81f7dd3a19Srapha /* operation in progress */
82f7dd3a19Srapha typedef enum {
83f7dd3a19Srapha 	TI_I2CREAD,
84f7dd3a19Srapha 	TI_I2CWRITE,
85f7dd3a19Srapha 	TI_I2CDONE,
86f7dd3a19Srapha 	TI_I2CERROR
87f7dd3a19Srapha } ti_i2cop_t;
88f7dd3a19Srapha 
89f7dd3a19Srapha struct ti_iic_softc {
90f7dd3a19Srapha 	struct device		sc_dev;
91f7dd3a19Srapha 	struct i2c_controller	sc_ic;
92f7dd3a19Srapha 	struct rwlock		sc_buslock;
93f7dd3a19Srapha 	struct device		*sc_i2cdev;
94f7dd3a19Srapha 
95f7dd3a19Srapha 	bus_space_tag_t		sc_iot;
96f7dd3a19Srapha 	bus_space_handle_t	sc_ioh;
97f7dd3a19Srapha 
98f7dd3a19Srapha 	void			*sc_ih;
99b8746eccSjsg 	int			sc_node;
100f7dd3a19Srapha 	ti_i2cop_t		sc_op;
101f7dd3a19Srapha 	int			sc_buflen;
102f7dd3a19Srapha 	int			sc_bufidx;
103f7dd3a19Srapha 	char			*sc_buf;
104f7dd3a19Srapha 
105f7dd3a19Srapha 	int			sc_rxthres;
106f7dd3a19Srapha 	int			sc_txthres;
107f7dd3a19Srapha };
108f7dd3a19Srapha 
109f7dd3a19Srapha 
110f7dd3a19Srapha #define I2C_READ_REG(sc, reg)		\
111f7dd3a19Srapha 	bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, (reg))
112f7dd3a19Srapha #define I2C_READ_DATA(sc)		\
113f7dd3a19Srapha 	bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, AM335X_I2C_DATA);
114f7dd3a19Srapha #define I2C_WRITE_REG(sc, reg, val)	\
115f7dd3a19Srapha 	bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
116f7dd3a19Srapha #define I2C_WRITE_DATA(sc, val)		\
117f7dd3a19Srapha 	bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, AM335X_I2C_DATA, (val))
118f7dd3a19Srapha 
119f7dd3a19Srapha #define DEVNAME(sc)	((sc)->sc_dev.dv_xname)
120f7dd3a19Srapha 
121b8746eccSjsg int	ti_iic_match(struct device *, void *, void *);
122016c75deSjsg void	ti_iic_attach(struct device *, struct device *, void *);
123016c75deSjsg int	ti_iic_intr(void *);
124f7dd3a19Srapha 
125016c75deSjsg int	ti_iic_acquire_bus(void *, int);
126016c75deSjsg void	ti_iic_release_bus(void *, int);
127016c75deSjsg int	ti_iic_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t, void *,
128016c75deSjsg 	    size_t, int);
129b8746eccSjsg void	ti_iic_scan(struct device *, struct i2cbus_attach_args *, void *);
130f7dd3a19Srapha 
131016c75deSjsg int	ti_iic_reset(struct ti_iic_softc *);
132016c75deSjsg int	ti_iic_op(struct ti_iic_softc *, i2c_addr_t, ti_i2cop_t, uint8_t *,
133016c75deSjsg 	    size_t, int);
134016c75deSjsg void	ti_iic_handle_intr(struct ti_iic_softc *, uint32_t);
135016c75deSjsg void	ti_iic_do_read(struct ti_iic_softc *, uint32_t);
136016c75deSjsg void	ti_iic_do_write(struct ti_iic_softc *, uint32_t);
137f7dd3a19Srapha 
138016c75deSjsg int	ti_iic_wait(struct ti_iic_softc *, uint16_t, uint16_t, int);
139016c75deSjsg uint32_t	ti_iic_stat(struct ti_iic_softc *, uint32_t);
140016c75deSjsg int	ti_iic_flush(struct ti_iic_softc *);
141f7dd3a19Srapha 
142*9fdf0c62Smpi const struct cfattach tiiic_ca = {
143b8746eccSjsg 	sizeof (struct ti_iic_softc), ti_iic_match, ti_iic_attach
144f7dd3a19Srapha };
145f7dd3a19Srapha 
146f7dd3a19Srapha struct cfdriver tiiic_cd = {
147f7dd3a19Srapha 	NULL, "tiiic", DV_DULL
148f7dd3a19Srapha };
149f7dd3a19Srapha 
150b8746eccSjsg int
ti_iic_match(struct device * parent,void * match,void * aux)151b8746eccSjsg ti_iic_match(struct device *parent, void *match, void *aux)
152b8746eccSjsg {
153b8746eccSjsg 	struct fdt_attach_args *faa = aux;
154b8746eccSjsg 
155b8746eccSjsg 	return OF_is_compatible(faa->fa_node, "ti,omap4-i2c");
156b8746eccSjsg }
157b8746eccSjsg 
158016c75deSjsg void
ti_iic_attach(struct device * parent,struct device * self,void * aux)159b8746eccSjsg ti_iic_attach(struct device *parent, struct device *self, void *aux)
160f7dd3a19Srapha {
161f7dd3a19Srapha 	struct ti_iic_softc *sc = (struct ti_iic_softc *)self;
162b8746eccSjsg 	struct fdt_attach_args *faa = aux;
163f7dd3a19Srapha 	struct i2cbus_attach_args iba;
164f7dd3a19Srapha 	uint16_t rev;
1657d7522cbSjsg 	int unit, len;
166b8746eccSjsg 	char hwmods[128];
167f7dd3a19Srapha 
1687d7522cbSjsg 	if (faa->fa_nreg < 1)
169b8746eccSjsg 		return;
170b8746eccSjsg 
171b8746eccSjsg 	sc->sc_iot = faa->fa_iot;
172b8746eccSjsg 	sc->sc_node = faa->fa_node;
173b8746eccSjsg 
1744d149eb4Skettenis 	unit = -1;
175b8746eccSjsg 	if ((len = OF_getprop(faa->fa_node, "ti,hwmods", hwmods,
176b8746eccSjsg 	    sizeof(hwmods))) == 5) {
177b8746eccSjsg 		if (!strncmp(hwmods, "i2c", 3) &&
178b8746eccSjsg 		    (hwmods[3] > '0') && (hwmods[3] <= '9'))
179b8746eccSjsg 			unit = hwmods[3] - '1';
180b8746eccSjsg 	}
181b8746eccSjsg 
182f7dd3a19Srapha 	rw_init(&sc->sc_buslock, "tiiilk");
183f7dd3a19Srapha 
184f7dd3a19Srapha 	sc->sc_rxthres = sc->sc_txthres = 4;
185f7dd3a19Srapha 
186ac7c670eSpatrick 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
187ac7c670eSpatrick 	    faa->fa_reg[0].size, 0, &sc->sc_ioh))
188b115af84Sjsg 		panic("%s: bus_space_map failed!", DEVNAME(sc));
189f7dd3a19Srapha 
19016f6b372Sjsg 	pinctrl_byname(faa->fa_node, "default");
1911558a2f3Sjsg 
1927d7522cbSjsg 	sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_NET,
193f7dd3a19Srapha 	    ti_iic_intr, sc, DEVNAME(sc));
194f7dd3a19Srapha 
1954d149eb4Skettenis 	if (unit != -1)
196b8746eccSjsg 		prcm_enablemodule(PRCM_I2C0 + unit);
197f7dd3a19Srapha 
198f7dd3a19Srapha 	rev = I2C_READ_REG(sc, AM335X_I2C_REVNB_LO);
199f7dd3a19Srapha 	printf(" rev %d.%d\n",
200f7dd3a19Srapha 	    (int)I2C_REVNB_LO_MAJOR(rev),
201f7dd3a19Srapha 	    (int)I2C_REVNB_LO_MINOR(rev));
202f7dd3a19Srapha 
203f7dd3a19Srapha 	ti_iic_reset(sc);
204f7dd3a19Srapha 	ti_iic_flush(sc);
205f7dd3a19Srapha 
206f7dd3a19Srapha 	sc->sc_ic.ic_cookie = sc;
207f7dd3a19Srapha 	sc->sc_ic.ic_acquire_bus = ti_iic_acquire_bus;
208f7dd3a19Srapha 	sc->sc_ic.ic_release_bus = ti_iic_release_bus;
209f7dd3a19Srapha 	sc->sc_ic.ic_exec = ti_iic_exec;
210f7dd3a19Srapha 
211f7dd3a19Srapha 	bzero(&iba, sizeof iba);
212f7dd3a19Srapha 	iba.iba_name = "iic";
213f7dd3a19Srapha 	iba.iba_tag = &sc->sc_ic;
214b8746eccSjsg 	iba.iba_bus_scan = ti_iic_scan;
215b8746eccSjsg 	iba.iba_bus_scan_arg = &sc->sc_node;
216f7dd3a19Srapha 	(void) config_found(&sc->sc_dev, &iba, iicbus_print);
217f7dd3a19Srapha }
218f7dd3a19Srapha 
219016c75deSjsg int
ti_iic_intr(void * arg)220f7dd3a19Srapha ti_iic_intr(void *arg)
221f7dd3a19Srapha {
222f7dd3a19Srapha 	struct ti_iic_softc *sc = arg;
223f7dd3a19Srapha 	uint32_t stat;
224f7dd3a19Srapha 
225f7dd3a19Srapha 	DPRINTF(("ti_iic_intr\n"));
226f7dd3a19Srapha 	stat = I2C_READ_REG(sc, AM335X_I2C_IRQSTATUS);
227f7dd3a19Srapha 	I2C_WRITE_REG(sc, AM335X_I2C_IRQSTATUS, stat);
228f7dd3a19Srapha 	DPRINTF(("ti_iic_intr pre handle sc->sc_op eq %#x\n", sc->sc_op));
229f7dd3a19Srapha 
230f7dd3a19Srapha 	ti_iic_handle_intr(sc, stat);
231f7dd3a19Srapha 
232f7dd3a19Srapha 	if (sc->sc_op == TI_I2CERROR || sc->sc_op == TI_I2CDONE) {
233f7dd3a19Srapha 		DPRINTF(("ti_iic_intr post handle sc->sc_op %#x\n", sc->sc_op));
234f7dd3a19Srapha 		wakeup(&sc->sc_dev);
235f7dd3a19Srapha 	}
236f7dd3a19Srapha 
237f7dd3a19Srapha 	DPRINTF(("ti_iic_intr status 0x%x\n", stat));
238f7dd3a19Srapha 
239f7dd3a19Srapha 	return 1;
240f7dd3a19Srapha }
241f7dd3a19Srapha 
242016c75deSjsg int
ti_iic_acquire_bus(void * opaque,int flags)243f7dd3a19Srapha ti_iic_acquire_bus(void *opaque, int flags)
244f7dd3a19Srapha {
245f7dd3a19Srapha 	struct ti_iic_softc *sc = opaque;
246f7dd3a19Srapha 
247f7dd3a19Srapha 	if (flags & I2C_F_POLL)
248f7dd3a19Srapha 		return 0;
249f7dd3a19Srapha 
250f7dd3a19Srapha 	return (rw_enter(&sc->sc_buslock, RW_WRITE));
251f7dd3a19Srapha }
252f7dd3a19Srapha 
253016c75deSjsg void
ti_iic_release_bus(void * opaque,int flags)254f7dd3a19Srapha ti_iic_release_bus(void *opaque, int flags)
255f7dd3a19Srapha {
256f7dd3a19Srapha 	struct ti_iic_softc *sc = opaque;
257f7dd3a19Srapha 
258f7dd3a19Srapha 	if (flags & I2C_F_POLL)
259f7dd3a19Srapha 		return;
260f7dd3a19Srapha 
261f7dd3a19Srapha 	rw_exit(&sc->sc_buslock);
262f7dd3a19Srapha }
263f7dd3a19Srapha 
264016c75deSjsg int
ti_iic_exec(void * opaque,i2c_op_t op,i2c_addr_t addr,const void * cmdbuf,size_t cmdlen,void * buf,size_t len,int flags)265f7dd3a19Srapha ti_iic_exec(void *opaque, i2c_op_t op, i2c_addr_t addr,
266f7dd3a19Srapha     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
267f7dd3a19Srapha {
268f7dd3a19Srapha 	struct ti_iic_softc *sc = opaque;
2696f3f6514Sjsg 	int err = 0;
270f7dd3a19Srapha 
271f7dd3a19Srapha 	DPRINTF(("ti_iic_exec: op 0x%x cmdlen %zd len %zd flags 0x%x\n",
272f7dd3a19Srapha 	    op, cmdlen, len, flags));
273f7dd3a19Srapha 
274f7dd3a19Srapha #define __UNCONST(a)  ((void *)(unsigned long)(const void *)(a))
275f7dd3a19Srapha 	if (cmdlen > 0) {
276f7dd3a19Srapha 		err = ti_iic_op(sc, addr, TI_I2CWRITE, __UNCONST(cmdbuf),
277f7dd3a19Srapha 		    cmdlen, (I2C_OP_READ_P(op) ? 0 : I2C_F_STOP) | flags);
278f7dd3a19Srapha 		if (err)
279f7dd3a19Srapha 			goto done;
280f7dd3a19Srapha 	}
281f7dd3a19Srapha 	if (I2C_OP_STOP_P(op))
282f7dd3a19Srapha 		flags |= I2C_F_STOP;
283f7dd3a19Srapha 
284f7dd3a19Srapha 	/*
285f7dd3a19Srapha 	 * I2C controller doesn't allow for zero-byte transfers.
286f7dd3a19Srapha 	 */
287f7dd3a19Srapha 	if (len == 0)
288f7dd3a19Srapha 		goto done;
289f7dd3a19Srapha 
290f7dd3a19Srapha 	if (I2C_OP_READ_P(op))
291f7dd3a19Srapha 		err = ti_iic_op(sc, addr, TI_I2CREAD, buf, len, flags);
292f7dd3a19Srapha 	else
293f7dd3a19Srapha 		err = ti_iic_op(sc, addr, TI_I2CWRITE, buf, len, flags);
294f7dd3a19Srapha 
295f7dd3a19Srapha done:
296f7dd3a19Srapha 	if (err)
297f7dd3a19Srapha 		ti_iic_reset(sc);
298f7dd3a19Srapha 
299f7dd3a19Srapha 	ti_iic_flush(sc);
300f7dd3a19Srapha 
301f7dd3a19Srapha 	DPRINTF(("ti_iic_exec: done %d\n", err));
302f7dd3a19Srapha 	return err;
303f7dd3a19Srapha }
304f7dd3a19Srapha 
305016c75deSjsg int
ti_iic_reset(struct ti_iic_softc * sc)306f7dd3a19Srapha ti_iic_reset(struct ti_iic_softc *sc)
307f7dd3a19Srapha {
308f7dd3a19Srapha 	uint32_t psc, scll, sclh;
309f7dd3a19Srapha 	int i;
310f7dd3a19Srapha 
311f7dd3a19Srapha 	DPRINTF(("ti_iic_reset\n"));
312f7dd3a19Srapha 
313f7dd3a19Srapha 	/* Disable */
314f7dd3a19Srapha 	I2C_WRITE_REG(sc, AM335X_I2C_CON, 0);
315f7dd3a19Srapha 	/* Soft reset */
316f7dd3a19Srapha 	I2C_WRITE_REG(sc, AM335X_I2C_SYSC, I2C_SYSC_SRST);
317f7dd3a19Srapha 	delay(1000);
318f7dd3a19Srapha 	/* enable so that we can check for reset complete */
319f7dd3a19Srapha 	I2C_WRITE_REG(sc, AM335X_I2C_CON, I2C_CON_EN);
320f7dd3a19Srapha 	delay(1000);
321f7dd3a19Srapha 	for (i = 0; i < 1000; i++) { /* 1s delay for reset */
322f7dd3a19Srapha 		if (I2C_READ_REG(sc, AM335X_I2C_SYSS) & I2C_SYSS_RDONE)
323f7dd3a19Srapha 			break;
324f7dd3a19Srapha 	}
325f7dd3a19Srapha 	/* Disable again */
326f7dd3a19Srapha 	I2C_WRITE_REG(sc, AM335X_I2C_CON, 0);
327f7dd3a19Srapha 	delay(50000);
328f7dd3a19Srapha 
329f7dd3a19Srapha 	if (i >= 1000) {
330f7dd3a19Srapha 		printf("%s: couldn't reset module\n", DEVNAME(sc));
331f7dd3a19Srapha 		return 1;
332f7dd3a19Srapha 	}
333f7dd3a19Srapha 
334f7dd3a19Srapha 	/* XXX standard speed only */
335f7dd3a19Srapha 	psc = 3;
336f7dd3a19Srapha 	scll = 53;
337f7dd3a19Srapha 	sclh = 55;
338f7dd3a19Srapha 
339f7dd3a19Srapha 	/* Clocks */
340f7dd3a19Srapha 	I2C_WRITE_REG(sc, AM335X_I2C_PSC, psc);
341f7dd3a19Srapha 	I2C_WRITE_REG(sc, AM335X_I2C_SCLL, scll);
342f7dd3a19Srapha 	I2C_WRITE_REG(sc, AM335X_I2C_SCLH, sclh);
343f7dd3a19Srapha 
344f7dd3a19Srapha 	/* Own I2C address */
345f7dd3a19Srapha 	I2C_WRITE_REG(sc, AM335X_I2C_OA, AM335X_I2C_SLAVE_ADDR);
346f7dd3a19Srapha 
347f7dd3a19Srapha 	/* 5 bytes fifo */
348f7dd3a19Srapha 	I2C_WRITE_REG(sc, AM335X_I2C_BUF,
349f7dd3a19Srapha 	    I2C_BUF_RXTRSH(sc->sc_rxthres) | I2C_BUF_TXTRSH(sc->sc_txthres));
350f7dd3a19Srapha 
351f7dd3a19Srapha 	/* Enable */
352f7dd3a19Srapha 	I2C_WRITE_REG(sc, AM335X_I2C_CON, I2C_CON_EN);
353f7dd3a19Srapha 
354f7dd3a19Srapha 	return 0;
355f7dd3a19Srapha }
356f7dd3a19Srapha 
357016c75deSjsg int
ti_iic_op(struct ti_iic_softc * sc,i2c_addr_t addr,ti_i2cop_t op,uint8_t * buf,size_t buflen,int flags)358f7dd3a19Srapha ti_iic_op(struct ti_iic_softc *sc, i2c_addr_t addr, ti_i2cop_t op,
359f7dd3a19Srapha     uint8_t *buf, size_t buflen, int flags)
360f7dd3a19Srapha {
361f7dd3a19Srapha 	uint16_t con, stat, mask;
362f7dd3a19Srapha 	int err, retry;
363f7dd3a19Srapha 
364f7dd3a19Srapha 	KASSERT(op == TI_I2CREAD || op == TI_I2CWRITE);
365f7dd3a19Srapha 	DPRINTF(("ti_iic_op: addr %#x op %#x buf %p buflen %#x flags %#x\n",
366f7dd3a19Srapha 	    addr, op, buf, (unsigned int) buflen, flags));
367f7dd3a19Srapha 
368f7dd3a19Srapha 	mask = I2C_IRQSTATUS_ARDY | I2C_IRQSTATUS_NACK | I2C_IRQSTATUS_AL;
369f7dd3a19Srapha 	if (op == TI_I2CREAD)
370f7dd3a19Srapha 		mask |= I2C_IRQSTATUS_RDR | I2C_IRQSTATUS_RRDY;
371f7dd3a19Srapha 	else
372f7dd3a19Srapha 		mask |= I2C_IRQSTATUS_XDR | I2C_IRQSTATUS_XRDY;
373f7dd3a19Srapha 
374f7dd3a19Srapha 	err = ti_iic_wait(sc, I2C_IRQSTATUS_BB, 0, flags);
375f7dd3a19Srapha 	if (err) {
376f7dd3a19Srapha 		DPRINTF(("ti_iic_op: wait error %d\n", err));
377f7dd3a19Srapha 		return err;
378f7dd3a19Srapha 	}
379f7dd3a19Srapha 
380f7dd3a19Srapha 	con = I2C_CON_EN;
381f7dd3a19Srapha 	con |= I2C_CON_MST;
382f7dd3a19Srapha 	con |= I2C_CON_STT;
383f7dd3a19Srapha 	if (flags & I2C_F_STOP)
384f7dd3a19Srapha 		con |= I2C_CON_STP;
385f7dd3a19Srapha 	if (addr & ~0x7f)
386f7dd3a19Srapha 		con |= I2C_CON_XSA;
387f7dd3a19Srapha 	if (op == TI_I2CWRITE)
388f7dd3a19Srapha 		con |= I2C_CON_TRX;
389f7dd3a19Srapha 
390f7dd3a19Srapha 	sc->sc_op = op;
391f7dd3a19Srapha 	sc->sc_buf = buf;
392f7dd3a19Srapha 	sc->sc_buflen = buflen;
393f7dd3a19Srapha 	sc->sc_bufidx = 0;
394f7dd3a19Srapha 
395f7dd3a19Srapha 	I2C_WRITE_REG(sc,
396f7dd3a19Srapha 	    AM335X_I2C_CON, I2C_CON_EN | I2C_CON_MST | I2C_CON_STP);
397f7dd3a19Srapha 	DPRINTF(("ti_iic_op: op %d con 0x%x ", op, con));
398f7dd3a19Srapha 	I2C_WRITE_REG(sc, AM335X_I2C_CNT, buflen);
399f7dd3a19Srapha 	I2C_WRITE_REG(sc, AM335X_I2C_SA, (addr & I2C_SA_MASK));
400f7dd3a19Srapha 	DPRINTF(("SA 0x%x len %d\n",
401f7dd3a19Srapha 	    I2C_READ_REG(sc, AM335X_I2C_SA), I2C_READ_REG(sc, AM335X_I2C_CNT)));
402f7dd3a19Srapha 
403f7dd3a19Srapha 	if ((flags & I2C_F_POLL) == 0) {
404f7dd3a19Srapha 		/* clear any pending interrupt */
405f7dd3a19Srapha 		I2C_WRITE_REG(sc, AM335X_I2C_IRQSTATUS,
406f7dd3a19Srapha 		    I2C_READ_REG(sc, AM335X_I2C_IRQSTATUS));
407f7dd3a19Srapha 		/* and enable */
408f7dd3a19Srapha 		I2C_WRITE_REG(sc, AM335X_I2C_IRQENABLE_SET, mask);
409f7dd3a19Srapha 	}
410f7dd3a19Srapha 	/* start transfer */
411f7dd3a19Srapha 	I2C_WRITE_REG(sc, AM335X_I2C_CON, con);
412f7dd3a19Srapha 
413f7dd3a19Srapha 	if ((flags & I2C_F_POLL) == 0) {
414f7dd3a19Srapha 		/* and wait for completion */
415f7dd3a19Srapha 		DPRINTF(("ti_iic_op waiting, op %#x\n", sc->sc_op));
416f7dd3a19Srapha 		while (sc->sc_op == op) {
4176ac86807Smpi 			if (tsleep_nsec(&sc->sc_dev, PWAIT, "tiiic",
4186ac86807Smpi 			    SEC_TO_NSEC(5)) == EWOULDBLOCK) {
419f7dd3a19Srapha 				/* timeout */
420f7dd3a19Srapha 				op = TI_I2CERROR;
421f7dd3a19Srapha 			}
422f7dd3a19Srapha 		}
423f7dd3a19Srapha 		DPRINTF(("ti_iic_op waiting done, op %#x\n", sc->sc_op));
424f7dd3a19Srapha 
425f7dd3a19Srapha 		/* disable interrupts */
426f7dd3a19Srapha 		I2C_WRITE_REG(sc, AM335X_I2C_IRQENABLE_CLR, 0xffff);
427f7dd3a19Srapha 	} else {
428f7dd3a19Srapha 		/* poll for completion */
429f7dd3a19Srapha 		DPRINTF(("ti_iic_op polling, op %x\n", sc->sc_op));
430f7dd3a19Srapha 		while (sc->sc_op == op) {
431f7dd3a19Srapha 			stat = ti_iic_stat(sc, mask);
432f7dd3a19Srapha 			DPRINTF(("ti_iic_op stat 0x%x\n", stat));
433f7dd3a19Srapha 			if (stat == 0) /* timeout */
434f7dd3a19Srapha 				sc->sc_op = TI_I2CERROR;
435f7dd3a19Srapha 			else
436f7dd3a19Srapha 				ti_iic_handle_intr(sc, stat);
437f7dd3a19Srapha 			I2C_WRITE_REG(sc, AM335X_I2C_IRQSTATUS, stat);
438f7dd3a19Srapha 		}
439f7dd3a19Srapha 		DPRINTF(("ti_iic_op polling done, op now %x\n", sc->sc_op));
440f7dd3a19Srapha 	}
441f7dd3a19Srapha 	retry = 10000;
442f7dd3a19Srapha 	I2C_WRITE_REG(sc, AM335X_I2C_CON, 0);
443f7dd3a19Srapha 	while (I2C_READ_REG(sc, AM335X_I2C_CON) & I2C_CON_MST) {
444f7dd3a19Srapha 		delay(100);
445f7dd3a19Srapha 		if (--retry == 0)
446f7dd3a19Srapha 			break;
447f7dd3a19Srapha 	}
448f7dd3a19Srapha 
449f7dd3a19Srapha 	return (sc->sc_op == TI_I2CDONE) ? 0 : EIO;
450f7dd3a19Srapha }
451f7dd3a19Srapha 
452016c75deSjsg void
ti_iic_handle_intr(struct ti_iic_softc * sc,uint32_t stat)453f7dd3a19Srapha ti_iic_handle_intr(struct ti_iic_softc *sc, uint32_t stat)
454f7dd3a19Srapha {
455f7dd3a19Srapha 	KASSERT(stat != 0);
456f7dd3a19Srapha 	DPRINTF(("ti_iic_handle_intr stat %#x\n", stat));
457f7dd3a19Srapha 
458f7dd3a19Srapha 	if (stat & (I2C_IRQSTATUS_NACK|I2C_IRQSTATUS_AL)) {
459f7dd3a19Srapha 		sc->sc_op = TI_I2CERROR;
460f7dd3a19Srapha 		return;
461f7dd3a19Srapha 	}
462f7dd3a19Srapha 	if (stat & I2C_IRQSTATUS_ARDY) {
463f7dd3a19Srapha 		sc->sc_op = TI_I2CDONE;
464f7dd3a19Srapha 		return;
465f7dd3a19Srapha 	}
466f7dd3a19Srapha 	if (sc->sc_op == TI_I2CREAD)
467f7dd3a19Srapha 		ti_iic_do_read(sc, stat);
468f7dd3a19Srapha 	else if (sc->sc_op == TI_I2CWRITE)
469f7dd3a19Srapha 		ti_iic_do_write(sc, stat);
470f7dd3a19Srapha 	else
471f7dd3a19Srapha 		return;
472f7dd3a19Srapha }
473f7dd3a19Srapha void
ti_iic_do_read(struct ti_iic_softc * sc,uint32_t stat)474f7dd3a19Srapha ti_iic_do_read(struct ti_iic_softc *sc, uint32_t stat)
475f7dd3a19Srapha {
476dd46c2aeSrapha 	int len = 0;
477f7dd3a19Srapha 
478f7dd3a19Srapha 	DPRINTF(("ti_iic_do_read stat %#x\n", stat));
479f7dd3a19Srapha 	if (stat & I2C_IRQSTATUS_RDR) {
480f7dd3a19Srapha 		len = I2C_READ_REG(sc, AM335X_I2C_BUFSTAT);
481f7dd3a19Srapha 		len = I2C_BUFSTAT_RXSTAT(len);
482f7dd3a19Srapha 		DPRINTF(("ti_iic_do_read receive drain len %d left %d\n",
483f7dd3a19Srapha 		    len, I2C_READ_REG(sc, AM335X_I2C_CNT)));
484f7dd3a19Srapha 	} else if (stat & I2C_IRQSTATUS_RRDY) {
485f7dd3a19Srapha 		len = sc->sc_rxthres + 1;
486f7dd3a19Srapha 		DPRINTF(("ti_iic_do_read receive len %d left %d\n",
487f7dd3a19Srapha 		    len, I2C_READ_REG(sc, AM335X_I2C_CNT)));
488f7dd3a19Srapha 	}
489f7dd3a19Srapha 	for (;
490f7dd3a19Srapha 	    sc->sc_bufidx < sc->sc_buflen && len > 0;
491f7dd3a19Srapha 	    sc->sc_bufidx++, len--) {
492f7dd3a19Srapha 		sc->sc_buf[sc->sc_bufidx] = I2C_READ_DATA(sc);
493f7dd3a19Srapha 		DPRINTF(("ti_iic_do_read got b[%d]=0x%x\n", sc->sc_bufidx,
494f7dd3a19Srapha 		    sc->sc_buf[sc->sc_bufidx]));
495f7dd3a19Srapha 	}
496f7dd3a19Srapha 	DPRINTF(("ti_iic_do_read done\n"));
497f7dd3a19Srapha }
498f7dd3a19Srapha 
499f7dd3a19Srapha void
ti_iic_do_write(struct ti_iic_softc * sc,uint32_t stat)500f7dd3a19Srapha ti_iic_do_write(struct ti_iic_softc *sc, uint32_t stat)
501f7dd3a19Srapha {
502dd46c2aeSrapha 	int len = 0;
503f7dd3a19Srapha 
504f7dd3a19Srapha 	DPRINTF(("ti_iic_do_write stat %#x\n", stat));
505f7dd3a19Srapha 
506f7dd3a19Srapha 	if (stat & I2C_IRQSTATUS_XDR) {
507f7dd3a19Srapha 		len = I2C_READ_REG(sc, AM335X_I2C_BUFSTAT);
508f7dd3a19Srapha 		len = I2C_BUFSTAT_TXSTAT(len);
509f7dd3a19Srapha 		DPRINTF(("ti_iic_do_write xmit drain len %d left %d\n",
510f7dd3a19Srapha 		    len, I2C_READ_REG(sc, AM335X_I2C_CNT)));
511f7dd3a19Srapha 	} else if (stat & I2C_IRQSTATUS_XRDY) {
512f7dd3a19Srapha 		len = sc->sc_txthres + 1;
513f7dd3a19Srapha 		DPRINTF(("ti_iic_do_write xmit len %d left %d\n",
514f7dd3a19Srapha 		    len, I2C_READ_REG(sc, AM335X_I2C_CNT)));
515f7dd3a19Srapha 	}
516f7dd3a19Srapha 	for (;
517f7dd3a19Srapha 	    sc->sc_bufidx < sc->sc_buflen && len > 0;
518f7dd3a19Srapha 	    sc->sc_bufidx++, len--) {
519f7dd3a19Srapha 		DPRINTF(("ti_iic_do_write send b[%d]=0x%x\n",
520f7dd3a19Srapha 		    sc->sc_bufidx, sc->sc_buf[sc->sc_bufidx]));
521f7dd3a19Srapha 		I2C_WRITE_DATA(sc, sc->sc_buf[sc->sc_bufidx]);
522f7dd3a19Srapha 	}
523f7dd3a19Srapha 	DPRINTF(("ti_iic_do_write done\n"));
524f7dd3a19Srapha }
525f7dd3a19Srapha 
526016c75deSjsg int
ti_iic_wait(struct ti_iic_softc * sc,uint16_t mask,uint16_t val,int flags)527f7dd3a19Srapha ti_iic_wait(struct ti_iic_softc *sc, uint16_t mask, uint16_t val, int flags)
528f7dd3a19Srapha {
529f7dd3a19Srapha 	int retry = 10;
530f7dd3a19Srapha 	uint16_t v;
531f7dd3a19Srapha 	DPRINTF(("ti_iic_wait mask %#x val %#x flags %#x\n", mask, val, flags));
532f7dd3a19Srapha 
533f7dd3a19Srapha 	while (((v = I2C_READ_REG(sc, AM335X_I2C_IRQSTATUS_RAW)) & mask) != val) {
534f7dd3a19Srapha 		--retry;
535f7dd3a19Srapha 		if (retry == 0) {
536f7dd3a19Srapha 			printf("%s: wait timeout, mask=%#x val=%#x stat=%#x\n",
537f7dd3a19Srapha 			    DEVNAME(sc), mask, val, v);
538f7dd3a19Srapha 			return EBUSY;
539f7dd3a19Srapha 		}
540f7dd3a19Srapha 		if (flags & I2C_F_POLL)
541f7dd3a19Srapha 			delay(50000);
542f7dd3a19Srapha 		else
5436ac86807Smpi 			tsleep_nsec(&sc->sc_dev, PWAIT, "tiiic",
5446ac86807Smpi 			    MSEC_TO_NSEC(50));
545f7dd3a19Srapha 	}
546f7dd3a19Srapha 	DPRINTF(("ti_iic_wait done retry %#x\n", retry));
547f7dd3a19Srapha 
548f7dd3a19Srapha 	return 0;
549f7dd3a19Srapha }
550f7dd3a19Srapha 
551016c75deSjsg uint32_t
ti_iic_stat(struct ti_iic_softc * sc,uint32_t mask)552f7dd3a19Srapha ti_iic_stat(struct ti_iic_softc *sc, uint32_t mask)
553f7dd3a19Srapha {
554f7dd3a19Srapha 	uint32_t v;
555f7dd3a19Srapha 	int retry = 500;
556f7dd3a19Srapha 	DPRINTF(("ti_iic_wait mask %#x\n", mask));
557f7dd3a19Srapha 	while (--retry > 0) {
558f7dd3a19Srapha 		v = I2C_READ_REG(sc, AM335X_I2C_IRQSTATUS_RAW) & mask;
559f7dd3a19Srapha 		if (v != 0)
560f7dd3a19Srapha 			break;
561f7dd3a19Srapha 		delay(100);
562f7dd3a19Srapha 	}
563f7dd3a19Srapha 	DPRINTF(("ti_iic_wait done retry %#x\n", retry));
564f7dd3a19Srapha 	return v;
565f7dd3a19Srapha }
566f7dd3a19Srapha 
567016c75deSjsg int
ti_iic_flush(struct ti_iic_softc * sc)568f7dd3a19Srapha ti_iic_flush(struct ti_iic_softc *sc)
569f7dd3a19Srapha {
570f7dd3a19Srapha 	DPRINTF(("ti_iic_flush\n"));
571f7dd3a19Srapha #if 0
572f7dd3a19Srapha 	int retry = 1000;
573f7dd3a19Srapha 	uint16_t v;
574f7dd3a19Srapha 
575f7dd3a19Srapha 	while ((v =
576f7dd3a19Srapha 	    I2C_READ_REG(sc, AM335X_I2C_IRQSTATUS_RAW)) & I2C_IRQSTATUS_RRDY) {
577f7dd3a19Srapha 		if (--retry == 0) {
578f7dd3a19Srapha 			printf("%s: flush timeout, stat = %#x\n", DEVNAME(sc), v);
579f7dd3a19Srapha 			return EBUSY;
580f7dd3a19Srapha 		}
581f7dd3a19Srapha 		(void)I2C_READ_DATA(sc);
582f7dd3a19Srapha 		delay(1000);
583f7dd3a19Srapha 	}
584f7dd3a19Srapha #endif
585f7dd3a19Srapha 
586f7dd3a19Srapha 	I2C_WRITE_REG(sc, AM335X_I2C_CNT, 0);
587f7dd3a19Srapha 	return 0;
588f7dd3a19Srapha }
589b8746eccSjsg 
590b8746eccSjsg void
ti_iic_scan(struct device * self,struct i2cbus_attach_args * iba,void * aux)591b8746eccSjsg ti_iic_scan(struct device *self, struct i2cbus_attach_args *iba, void *aux)
592b8746eccSjsg {
593b8746eccSjsg 	int iba_node = *(int *)aux;
594b8746eccSjsg 	extern int iic_print(void *, const char *);
595b8746eccSjsg 	struct i2c_attach_args ia;
596b8746eccSjsg 	char name[32];
597b8746eccSjsg 	uint32_t reg[1];
598b8746eccSjsg 	int node;
599b8746eccSjsg 
600b8746eccSjsg 	for (node = OF_child(iba_node); node; node = OF_peer(node)) {
601b8746eccSjsg 		memset(name, 0, sizeof(name));
602b8746eccSjsg 		memset(reg, 0, sizeof(reg));
603b8746eccSjsg 
604b8746eccSjsg 		if (OF_getprop(node, "compatible", name, sizeof(name)) == -1)
605b8746eccSjsg 			continue;
606b8746eccSjsg 		if (name[0] == '\0')
607b8746eccSjsg 			continue;
608b8746eccSjsg 
609b8746eccSjsg 		if (OF_getprop(node, "reg", &reg, sizeof(reg)) != sizeof(reg))
610b8746eccSjsg 			continue;
611b8746eccSjsg 
612b8746eccSjsg 		memset(&ia, 0, sizeof(ia));
613b8746eccSjsg 		ia.ia_tag = iba->iba_tag;
614b8746eccSjsg 		ia.ia_addr = bemtoh32(&reg[0]);
615b8746eccSjsg 		ia.ia_name = name;
616b8746eccSjsg 		ia.ia_cookie = &node;
617b8746eccSjsg 
618b8746eccSjsg 		config_found(self, &ia, iic_print);
619b8746eccSjsg 	}
620b8746eccSjsg }
621