Annotation of src/sys/dev/usb/auvitek_i2c.c, Revision 1.6.8.1
1.6.8.1 ! thorpej 1: /* $NetBSD: auvitek_i2c.c,v 1.6 2021/04/24 23:36:59 thorpej Exp $ */
1.1 jmcneill 2:
3: /*-
4: * Copyright (c) 2010 Jared D. McNeill <jmcneill@invisible.ca>
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: *
16: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26: * POSSIBILITY OF SUCH DAMAGE.
27: */
28:
29: /*
30: * Auvitek AU0828 USB controller - I2C access ops
31: */
32:
33: #include <sys/cdefs.h>
1.6.8.1 ! thorpej 34: __KERNEL_RCSID(0, "$NetBSD: auvitek_i2c.c,v 1.6 2021/04/24 23:36:59 thorpej Exp $");
1.4 skrll 35:
36: #ifdef _KERNEL_OPT
37: #include "opt_usb.h"
38: #endif
1.1 jmcneill 39:
40: #include <sys/param.h>
41: #include <sys/systm.h>
42: #include <sys/device.h>
43: #include <sys/conf.h>
44: #include <sys/bus.h>
45: #include <sys/module.h>
46:
47: #include <dev/usb/usb.h>
48: #include <dev/usb/usbdi.h>
49: #include <dev/usb/usbdi_util.h>
50: #include <dev/usb/usbdevs.h>
51:
52: #include <dev/i2c/i2cvar.h>
53:
54: #include <dev/usb/auvitekreg.h>
55: #include <dev/usb/auvitekvar.h>
56:
1.3 jmcneill 57: /* #define AUVITEK_I2C_DEBUG */
58:
1.1 jmcneill 59: static int auvitek_i2c_exec(void *, i2c_op_t, i2c_addr_t,
60: const void *, size_t, void *, size_t, int);
61:
62: static int auvitek_i2c_read(struct auvitek_softc *, i2c_addr_t,
63: uint8_t *, size_t);
64: static int auvitek_i2c_write(struct auvitek_softc *, i2c_addr_t,
65: const uint8_t *, size_t);
66: static bool auvitek_i2c_wait(struct auvitek_softc *);
67: static bool auvitek_i2c_wait_rdack(struct auvitek_softc *);
68: static bool auvitek_i2c_wait_rddone(struct auvitek_softc *);
69: static bool auvitek_i2c_wait_wrdone(struct auvitek_softc *);
70:
71: int
72: auvitek_i2c_attach(struct auvitek_softc *sc)
73: {
1.5 thorpej 74: iic_tag_init(&sc->sc_i2c);
1.1 jmcneill 75: sc->sc_i2c.ic_cookie = sc;
76: sc->sc_i2c.ic_exec = auvitek_i2c_exec;
77:
1.3 jmcneill 78: auvitek_i2c_rescan(sc, NULL, NULL);
79:
1.1 jmcneill 80: return 0;
81: }
82:
83: int
84: auvitek_i2c_detach(struct auvitek_softc *sc, int flags)
85: {
1.5 thorpej 86: iic_tag_fini(&sc->sc_i2c);
1.1 jmcneill 87:
1.3 jmcneill 88: if (sc->sc_i2cdev)
89: config_detach(sc->sc_i2cdev, flags);
90:
1.1 jmcneill 91: return 0;
92: }
93:
1.3 jmcneill 94: void
95: auvitek_i2c_rescan(struct auvitek_softc *sc, const char *ifattr,
96: const int *locs)
97: {
98: #ifdef AUVITEK_I2C_DEBUG
99: struct i2cbus_attach_args iba;
100:
101: if (ifattr_match(ifattr, "i2cbus") && sc->sc_i2cdev == NULL) {
102: memset(&iba, 0, sizeof(iba));
103: iba.iba_tag = &sc->sc_i2c;
1.6 thorpej 104: sc->sc_i2cdev = config_found(sc->sc_dev, &iba, iicbus_print,
1.6.8.1 ! thorpej 105: CFARGS(.iattr = "i2cbus"));
1.3 jmcneill 106: }
107: #endif
108: }
109:
110: void
111: auvitek_i2c_childdet(struct auvitek_softc *sc, device_t child)
112: {
113: if (sc->sc_i2cdev == child)
114: sc->sc_i2cdev = NULL;
115: }
116:
1.1 jmcneill 117: static int
118: auvitek_i2c_exec(void *opaque, i2c_op_t op, i2c_addr_t addr,
119: const void *cmd, size_t cmdlen, void *vbuf, size_t buflen, int flags)
120: {
121: struct auvitek_softc *sc = opaque;
122:
123: if (I2C_OP_READ_P(op))
124: return auvitek_i2c_read(sc, addr, vbuf, buflen);
125: else
126: return auvitek_i2c_write(sc, addr, cmd, cmdlen);
127: }
128:
129: static int
130: auvitek_i2c_read(struct auvitek_softc *sc, i2c_addr_t addr,
131: uint8_t *buf, size_t buflen)
132: {
133: uint8_t v;
134: unsigned int i;
135:
136: auvitek_write_1(sc, AU0828_REG_I2C_MBMODE, 1);
137: auvitek_write_1(sc, AU0828_REG_I2C_CLKDIV, sc->sc_i2c_clkdiv);
138: auvitek_write_1(sc, AU0828_REG_I2C_DSTADDR, addr << 1);
139:
140: if (buflen == 0) {
141: auvitek_write_1(sc, AU0828_REG_I2C_TRIGGER,
142: AU0828_I2C_TRIGGER_RD);
143: if (auvitek_i2c_wait_rdack(sc) == false)
144: return EBUSY;
145: return 0;
146: }
147:
148: for (i = 0; i < buflen; i++) {
149: v = AU0828_I2C_TRIGGER_RD;
150: if (i < (buflen - 1))
151: v |= AU0828_I2C_TRIGGER_HOLD;
152: auvitek_write_1(sc, AU0828_REG_I2C_TRIGGER, v);
153:
154: if (auvitek_i2c_wait_rddone(sc) == false)
155: return EBUSY;
156:
157: buf[i] = auvitek_read_1(sc, AU0828_REG_I2C_FIFORD);
158: }
159:
160: if (auvitek_i2c_wait(sc) == false)
161: return EBUSY;
162:
163: return 0;
164: }
165:
166: static int
167: auvitek_i2c_write(struct auvitek_softc *sc, i2c_addr_t addr,
168: const uint8_t *buf, size_t buflen)
169: {
170: uint8_t v;
171: unsigned int i, fifolen;
172:
173: auvitek_write_1(sc, AU0828_REG_I2C_MBMODE, 1);
174: auvitek_write_1(sc, AU0828_REG_I2C_CLKDIV, sc->sc_i2c_clkdiv);
175: auvitek_write_1(sc, AU0828_REG_I2C_DSTADDR, addr << 1);
176:
177: if (buflen == 0) {
178: auvitek_write_1(sc, AU0828_REG_I2C_TRIGGER,
179: AU0828_I2C_TRIGGER_RD);
180: if (auvitek_i2c_wait(sc) == false)
181: return EBUSY;
182: if (auvitek_i2c_wait_rdack(sc) == false)
183: return EBUSY;
184: return 0;
185: }
186:
187: fifolen = 0;
188: for (i = 0; i < buflen; i++) {
189: v = AU0828_I2C_TRIGGER_WR;
190: if (i < (buflen - 1))
191: v |= AU0828_I2C_TRIGGER_HOLD;
192:
193: auvitek_write_1(sc, AU0828_REG_I2C_FIFOWR, buf[i]);
194: ++fifolen;
195:
196: if (fifolen == 4 || i == (buflen - 1)) {
197: auvitek_write_1(sc, AU0828_REG_I2C_TRIGGER, v);
198: fifolen = 0;
199:
200: if (auvitek_i2c_wait_wrdone(sc) == false)
201: return EBUSY;
202: }
203: }
204:
205: if (auvitek_i2c_wait(sc) == false)
206: return EBUSY;
207:
208: return 0;
209: }
210:
211: static bool
212: auvitek_i2c_wait(struct auvitek_softc *sc)
213: {
214: uint8_t status;
215: int retry = 1000;
216:
217: while (--retry > 0) {
218: status = auvitek_read_1(sc, AU0828_REG_I2C_STATUS);
219: if (!(status & AU0828_I2C_STATUS_BUSY))
220: break;
221: delay(10);
222: }
223: if (retry == 0)
224: return false;
225:
226: return true;
227: }
228:
229: static bool
230: auvitek_i2c_wait_rdack(struct auvitek_softc *sc)
231: {
232: uint8_t status;
233: int retry = 1000;
234:
235: while (--retry > 0) {
236: status = auvitek_read_1(sc, AU0828_REG_I2C_STATUS);
237: if (!(status & AU0828_I2C_STATUS_NO_RD_ACK))
238: break;
239: delay(10);
240: }
241: if (retry == 0)
242: return false;
243:
244: return true;
245: }
246:
247: static bool
248: auvitek_i2c_wait_rddone(struct auvitek_softc *sc)
249: {
250: uint8_t status;
251: int retry = 1000;
252:
253: while (--retry > 0) {
254: status = auvitek_read_1(sc, AU0828_REG_I2C_STATUS);
255: if (status & AU0828_I2C_STATUS_RD_DONE)
256: break;
257: delay(10);
258: }
259: if (retry == 0)
260: return false;
261:
262: return true;
263: }
264:
265: static bool
266: auvitek_i2c_wait_wrdone(struct auvitek_softc *sc)
267: {
268: uint8_t status;
269: int retry = 1000;
270:
271: while (--retry > 0) {
272: status = auvitek_read_1(sc, AU0828_REG_I2C_STATUS);
273: if (status & AU0828_I2C_STATUS_WR_DONE)
274: break;
275: delay(10);
276: }
277: if (retry == 0)
278: return false;
279:
280: return true;
281: }
CVSweb <webmaster@jp.NetBSD.org>