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", ®, 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(®[0]);
615b8746eccSjsg ia.ia_name = name;
616b8746eccSjsg ia.ia_cookie = &node;
617b8746eccSjsg
618b8746eccSjsg config_found(self, &ia, iic_print);
619b8746eccSjsg }
620b8746eccSjsg }
621