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", ®, 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(®[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