Line data Source code
1 : /* $OpenBSD: dwiic.c,v 1.4 2018/05/23 22:08:00 kettenis Exp $ */
2 : /*
3 : * Synopsys DesignWare I2C controller
4 : *
5 : * Copyright (c) 2015-2017 joshua stein <jcs@openbsd.org>
6 : *
7 : * Permission to use, copy, modify, and/or distribute this software for any
8 : * purpose with or without fee is hereby granted, provided that the above
9 : * copyright notice and this permission notice appear in all copies.
10 : *
11 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 : */
19 :
20 : #include <sys/param.h>
21 : #include <sys/systm.h>
22 : #include <sys/kernel.h>
23 : #include <sys/kthread.h>
24 :
25 : #include <dev/acpi/acpireg.h>
26 : #include <dev/acpi/acpivar.h>
27 : #include <dev/acpi/acpidev.h>
28 : #include <dev/acpi/amltypes.h>
29 : #include <dev/acpi/dsdt.h>
30 :
31 : #include <dev/i2c/i2cvar.h>
32 :
33 : #include <dev/ic/dwiicvar.h>
34 :
35 : struct cfdriver dwiic_cd = {
36 : NULL, "dwiic", DV_DULL
37 : };
38 :
39 : int
40 0 : dwiic_activate(struct device *self, int act)
41 : {
42 0 : struct dwiic_softc *sc = (struct dwiic_softc *)self;
43 :
44 0 : switch (act) {
45 : case DVACT_SUSPEND:
46 : /* disable controller */
47 0 : dwiic_enable(sc, 0);
48 :
49 : /* disable interrupts */
50 0 : dwiic_write(sc, DW_IC_INTR_MASK, 0);
51 0 : dwiic_read(sc, DW_IC_CLR_INTR);
52 :
53 : #if notyet
54 : /* power down the controller */
55 : dwiic_acpi_power(sc, 0);
56 : #endif
57 0 : break;
58 : case DVACT_WAKEUP:
59 : #if notyet
60 : /* power up the controller */
61 : dwiic_acpi_power(sc, 1);
62 : #endif
63 0 : dwiic_init(sc);
64 :
65 0 : break;
66 : }
67 :
68 0 : config_activate_children(self, act);
69 :
70 0 : return 0;
71 : }
72 :
73 : int
74 0 : dwiic_i2c_print(void *aux, const char *pnp)
75 : {
76 0 : struct i2c_attach_args *ia = aux;
77 :
78 0 : if (pnp != NULL)
79 0 : printf("\"%s\" at %s", ia->ia_name, pnp);
80 :
81 0 : printf(" addr 0x%x", ia->ia_addr);
82 :
83 0 : return UNCONF;
84 : }
85 :
86 : uint32_t
87 0 : dwiic_read(struct dwiic_softc *sc, int offset)
88 : {
89 0 : u_int32_t b = bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset);
90 :
91 : DPRINTF(("%s: read at 0x%x = 0x%x\n", sc->sc_dev.dv_xname, offset, b));
92 :
93 0 : return b;
94 : }
95 :
96 : void
97 0 : dwiic_write(struct dwiic_softc *sc, int offset, uint32_t val)
98 : {
99 : DPRINTF(("%s: write at 0x%x: 0x%x\n", sc->sc_dev.dv_xname, offset,
100 : val));
101 :
102 0 : bus_space_write_4(sc->sc_iot, sc->sc_ioh, offset, val);
103 0 : }
104 :
105 : int
106 0 : dwiic_i2c_acquire_bus(void *cookie, int flags)
107 : {
108 0 : struct dwiic_softc *sc = cookie;
109 :
110 0 : if (cold || sc->sc_poll || (flags & I2C_F_POLL))
111 0 : return (0);
112 :
113 0 : return rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR);
114 0 : }
115 :
116 : void
117 0 : dwiic_i2c_release_bus(void *cookie, int flags)
118 : {
119 0 : struct dwiic_softc *sc = cookie;
120 :
121 0 : if (cold || sc->sc_poll || (flags & I2C_F_POLL))
122 0 : return;
123 :
124 0 : rw_exit(&sc->sc_i2c_lock);
125 0 : }
126 :
127 : int
128 0 : dwiic_init(struct dwiic_softc *sc)
129 : {
130 : uint32_t reg;
131 :
132 : /* make sure we're talking to a device we know */
133 0 : reg = dwiic_read(sc, DW_IC_COMP_TYPE);
134 0 : if (reg != DW_IC_COMP_TYPE_VALUE) {
135 : DPRINTF(("%s: invalid component type 0x%x\n",
136 : sc->sc_dev.dv_xname, reg));
137 0 : return 1;
138 : }
139 :
140 : /* disable the adapter */
141 0 : dwiic_enable(sc, 0);
142 :
143 : /* write standard-mode SCL timing parameters */
144 0 : dwiic_write(sc, DW_IC_SS_SCL_HCNT, sc->ss_hcnt);
145 0 : dwiic_write(sc, DW_IC_SS_SCL_LCNT, sc->ss_lcnt);
146 :
147 : /* and fast-mode SCL timing parameters */
148 0 : dwiic_write(sc, DW_IC_FS_SCL_HCNT, sc->fs_hcnt);
149 0 : dwiic_write(sc, DW_IC_FS_SCL_LCNT, sc->fs_lcnt);
150 :
151 : /* SDA hold time */
152 0 : reg = dwiic_read(sc, DW_IC_COMP_VERSION);
153 0 : if (reg >= DW_IC_SDA_HOLD_MIN_VERS)
154 0 : dwiic_write(sc, DW_IC_SDA_HOLD, sc->sda_hold_time);
155 :
156 : /* FIFO threshold levels */
157 0 : sc->tx_fifo_depth = 32;
158 0 : sc->rx_fifo_depth = 32;
159 0 : dwiic_write(sc, DW_IC_TX_TL, sc->tx_fifo_depth / 2);
160 0 : dwiic_write(sc, DW_IC_RX_TL, 0);
161 :
162 : /* configure as i2c master with fast speed */
163 0 : sc->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
164 : DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
165 0 : dwiic_write(sc, DW_IC_CON, sc->master_cfg);
166 :
167 0 : return 0;
168 0 : }
169 :
170 : void
171 0 : dwiic_enable(struct dwiic_softc *sc, int enable)
172 : {
173 : int retries;
174 :
175 0 : for (retries = 100; retries > 0; retries--) {
176 0 : dwiic_write(sc, DW_IC_ENABLE, enable);
177 0 : if ((dwiic_read(sc, DW_IC_ENABLE_STATUS) & 1) == enable)
178 0 : return;
179 :
180 0 : DELAY(25);
181 : }
182 :
183 0 : printf("%s: failed to %sable\n", sc->sc_dev.dv_xname,
184 0 : (enable ? "en" : "dis"));
185 0 : }
186 :
187 : int
188 0 : dwiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf,
189 : size_t cmdlen, void *buf, size_t len, int flags)
190 : {
191 0 : struct dwiic_softc *sc = cookie;
192 : u_int32_t ic_con, st, cmd, resp;
193 : int retries, tx_limit, rx_avail, x, readpos;
194 : uint8_t *b;
195 : int s;
196 :
197 0 : if (sc->sc_busy)
198 0 : return 1;
199 :
200 0 : sc->sc_busy++;
201 :
202 : DPRINTF(("%s: %s: op %d, addr 0x%02x, cmdlen %zu, len %zu, "
203 : "flags 0x%02x\n", sc->sc_dev.dv_xname, __func__, op, addr, cmdlen,
204 : len, flags));
205 :
206 : /* setup transfer */
207 0 : sc->sc_i2c_xfer.op = op;
208 0 : sc->sc_i2c_xfer.buf = buf;
209 0 : sc->sc_i2c_xfer.len = len;
210 0 : sc->sc_i2c_xfer.flags = flags;
211 0 : sc->sc_i2c_xfer.error = 0;
212 :
213 : /* wait for bus to be idle */
214 0 : for (retries = 100; retries > 0; retries--) {
215 0 : st = dwiic_read(sc, DW_IC_STATUS);
216 0 : if (!(st & DW_IC_STATUS_ACTIVITY))
217 : break;
218 0 : DELAY(1000);
219 : }
220 : DPRINTF(("%s: %s: status 0x%x\n", sc->sc_dev.dv_xname, __func__, st));
221 0 : if (st & DW_IC_STATUS_ACTIVITY) {
222 0 : sc->sc_busy = 0;
223 0 : return (1);
224 : }
225 :
226 0 : if (cold || sc->sc_poll)
227 0 : flags |= I2C_F_POLL;
228 :
229 : /* disable controller */
230 0 : dwiic_enable(sc, 0);
231 :
232 : /* set slave address */
233 0 : ic_con = dwiic_read(sc, DW_IC_CON);
234 0 : ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
235 0 : dwiic_write(sc, DW_IC_CON, ic_con);
236 0 : dwiic_write(sc, DW_IC_TAR, addr);
237 :
238 : /* disable interrupts */
239 0 : dwiic_write(sc, DW_IC_INTR_MASK, 0);
240 0 : dwiic_read(sc, DW_IC_CLR_INTR);
241 :
242 : /* enable controller */
243 0 : dwiic_enable(sc, 1);
244 :
245 : /* wait until the controller is ready for commands */
246 0 : if (flags & I2C_F_POLL)
247 0 : DELAY(200);
248 : else {
249 0 : s = splbio();
250 0 : dwiic_read(sc, DW_IC_CLR_INTR);
251 0 : dwiic_write(sc, DW_IC_INTR_MASK, DW_IC_INTR_TX_EMPTY);
252 :
253 0 : if (tsleep(&sc->sc_writewait, PRIBIO, "dwiic", hz / 2) != 0)
254 0 : printf("%s: timed out waiting for tx_empty intr\n",
255 0 : sc->sc_dev.dv_xname);
256 0 : splx(s);
257 : }
258 :
259 : /* send our command, one byte at a time */
260 0 : if (cmdlen > 0) {
261 : b = (void *)cmdbuf;
262 :
263 : DPRINTF(("%s: %s: sending cmd (len %zu):", sc->sc_dev.dv_xname,
264 : __func__, cmdlen));
265 0 : for (x = 0; x < cmdlen; x++)
266 : DPRINTF((" %02x", b[x]));
267 : DPRINTF(("\n"));
268 :
269 0 : tx_limit = sc->tx_fifo_depth - dwiic_read(sc, DW_IC_TXFLR);
270 0 : if (cmdlen > tx_limit) {
271 : /* TODO */
272 0 : printf("%s: can't write %zu (> %d)\n",
273 0 : sc->sc_dev.dv_xname, cmdlen, tx_limit);
274 0 : sc->sc_i2c_xfer.error = 1;
275 0 : sc->sc_busy = 0;
276 0 : return (1);
277 : }
278 :
279 0 : for (x = 0; x < cmdlen; x++) {
280 0 : cmd = b[x];
281 : /*
282 : * Generate STOP condition if this is the last
283 : * byte of the transfer.
284 : */
285 0 : if (x == (cmdlen - 1) && len == 0 && I2C_OP_STOP_P(op))
286 0 : cmd |= DW_IC_DATA_CMD_STOP;
287 0 : dwiic_write(sc, DW_IC_DATA_CMD, cmd);
288 : }
289 : }
290 :
291 : b = (void *)buf;
292 : x = readpos = 0;
293 0 : tx_limit = sc->tx_fifo_depth - dwiic_read(sc, DW_IC_TXFLR);
294 :
295 : DPRINTF(("%s: %s: need to read %zu bytes, can send %d read reqs\n",
296 : sc->sc_dev.dv_xname, __func__, len, tx_limit));
297 :
298 0 : while (x < len) {
299 0 : if (I2C_OP_WRITE_P(op))
300 0 : cmd = b[x];
301 : else
302 : cmd = DW_IC_DATA_CMD_READ;
303 :
304 : /*
305 : * Generate RESTART condition if we're reversing
306 : * direction.
307 : */
308 0 : if (x == 0 && cmdlen > 0 && I2C_OP_READ_P(op))
309 0 : cmd |= DW_IC_DATA_CMD_RESTART;
310 : /*
311 : * Generate STOP conditon on the last byte of the
312 : * transfer.
313 : */
314 0 : if (x == (len - 1) && I2C_OP_STOP_P(op))
315 0 : cmd |= DW_IC_DATA_CMD_STOP;
316 :
317 0 : dwiic_write(sc, DW_IC_DATA_CMD, cmd);
318 :
319 0 : tx_limit--;
320 0 : x++;
321 :
322 : /*
323 : * As TXFLR fills up, we need to clear it out by reading all
324 : * available data.
325 : */
326 0 : while (I2C_OP_READ_P(op) && (tx_limit == 0 || x == len)) {
327 : DPRINTF(("%s: %s: tx_limit %d, sent %d read reqs\n",
328 : sc->sc_dev.dv_xname, __func__, tx_limit, x));
329 :
330 0 : if (flags & I2C_F_POLL) {
331 0 : for (retries = 100; retries > 0; retries--) {
332 0 : rx_avail = dwiic_read(sc, DW_IC_RXFLR);
333 0 : if (rx_avail > 0)
334 : break;
335 0 : DELAY(50);
336 : }
337 : } else {
338 0 : s = splbio();
339 0 : dwiic_read(sc, DW_IC_CLR_INTR);
340 0 : dwiic_write(sc, DW_IC_INTR_MASK,
341 : DW_IC_INTR_RX_FULL);
342 :
343 0 : if (tsleep(&sc->sc_readwait, PRIBIO, "dwiic",
344 0 : hz / 2) != 0)
345 0 : printf("%s: timed out waiting for "
346 : "rx_full intr\n",
347 0 : sc->sc_dev.dv_xname);
348 0 : splx(s);
349 :
350 0 : rx_avail = dwiic_read(sc, DW_IC_RXFLR);
351 : }
352 :
353 0 : if (rx_avail == 0) {
354 0 : printf("%s: timed out reading remaining %d\n",
355 0 : sc->sc_dev.dv_xname,
356 0 : (int)(len - 1 - readpos));
357 0 : sc->sc_i2c_xfer.error = 1;
358 0 : sc->sc_busy = 0;
359 :
360 0 : return (1);
361 : }
362 :
363 : DPRINTF(("%s: %s: %d avail to read (%zu remaining)\n",
364 : sc->sc_dev.dv_xname, __func__, rx_avail,
365 : len - readpos));
366 :
367 0 : while (rx_avail > 0) {
368 0 : resp = dwiic_read(sc, DW_IC_DATA_CMD);
369 0 : if (readpos < len) {
370 0 : b[readpos] = resp;
371 0 : readpos++;
372 0 : }
373 0 : rx_avail--;
374 : }
375 :
376 0 : if (readpos >= len)
377 : break;
378 :
379 : DPRINTF(("%s: still need to read %d bytes\n",
380 : sc->sc_dev.dv_xname, (int)(len - readpos)));
381 0 : tx_limit = sc->tx_fifo_depth -
382 0 : dwiic_read(sc, DW_IC_TXFLR);
383 : }
384 : }
385 :
386 0 : if (I2C_OP_STOP_P(op) && I2C_OP_WRITE_P(op)) {
387 0 : if (flags & I2C_F_POLL) {
388 : /* wait for bus to be idle */
389 0 : for (retries = 100; retries > 0; retries--) {
390 0 : st = dwiic_read(sc, DW_IC_STATUS);
391 0 : if (!(st & DW_IC_STATUS_ACTIVITY))
392 : break;
393 0 : DELAY(1000);
394 : }
395 0 : if (st & DW_IC_STATUS_ACTIVITY)
396 0 : printf("%s: timed out waiting for bus idle\n",
397 0 : sc->sc_dev.dv_xname);
398 : } else {
399 0 : s = splbio();
400 0 : while (sc->sc_busy) {
401 0 : dwiic_write(sc, DW_IC_INTR_MASK,
402 : DW_IC_INTR_STOP_DET);
403 0 : if (tsleep(&sc->sc_busy, PRIBIO, "dwiic",
404 0 : hz / 2) != 0)
405 0 : printf("%s: timed out waiting for "
406 : "stop intr\n",
407 0 : sc->sc_dev.dv_xname);
408 : }
409 0 : splx(s);
410 : }
411 : }
412 0 : sc->sc_busy = 0;
413 :
414 0 : return 0;
415 0 : }
416 :
417 : uint32_t
418 0 : dwiic_read_clear_intrbits(struct dwiic_softc *sc)
419 : {
420 : uint32_t stat;
421 :
422 0 : stat = dwiic_read(sc, DW_IC_INTR_STAT);
423 :
424 0 : if (stat & DW_IC_INTR_RX_UNDER)
425 0 : dwiic_read(sc, DW_IC_CLR_RX_UNDER);
426 0 : if (stat & DW_IC_INTR_RX_OVER)
427 0 : dwiic_read(sc, DW_IC_CLR_RX_OVER);
428 0 : if (stat & DW_IC_INTR_TX_OVER)
429 0 : dwiic_read(sc, DW_IC_CLR_TX_OVER);
430 0 : if (stat & DW_IC_INTR_RD_REQ)
431 0 : dwiic_read(sc, DW_IC_CLR_RD_REQ);
432 0 : if (stat & DW_IC_INTR_TX_ABRT)
433 0 : dwiic_read(sc, DW_IC_CLR_TX_ABRT);
434 0 : if (stat & DW_IC_INTR_RX_DONE)
435 0 : dwiic_read(sc, DW_IC_CLR_RX_DONE);
436 0 : if (stat & DW_IC_INTR_ACTIVITY)
437 0 : dwiic_read(sc, DW_IC_CLR_ACTIVITY);
438 0 : if (stat & DW_IC_INTR_STOP_DET)
439 0 : dwiic_read(sc, DW_IC_CLR_STOP_DET);
440 0 : if (stat & DW_IC_INTR_START_DET)
441 0 : dwiic_read(sc, DW_IC_CLR_START_DET);
442 0 : if (stat & DW_IC_INTR_GEN_CALL)
443 0 : dwiic_read(sc, DW_IC_CLR_GEN_CALL);
444 :
445 0 : return stat;
446 : }
447 :
448 : int
449 0 : dwiic_intr(void *arg)
450 : {
451 0 : struct dwiic_softc *sc = arg;
452 : uint32_t en, stat;
453 :
454 0 : en = dwiic_read(sc, DW_IC_ENABLE);
455 : /* probably for the other controller */
456 0 : if (!en)
457 0 : return 0;
458 :
459 0 : stat = dwiic_read_clear_intrbits(sc);
460 : DPRINTF(("%s: %s: enabled=0x%x stat=0x%x\n", sc->sc_dev.dv_xname,
461 : __func__, en, stat));
462 0 : if (!(stat & ~DW_IC_INTR_ACTIVITY))
463 0 : return 1;
464 :
465 0 : if (stat & DW_IC_INTR_TX_ABRT)
466 0 : sc->sc_i2c_xfer.error = 1;
467 :
468 0 : if (sc->sc_i2c_xfer.flags & I2C_F_POLL)
469 : DPRINTF(("%s: %s: intr in poll mode?\n", sc->sc_dev.dv_xname,
470 : __func__));
471 : else {
472 0 : if (stat & DW_IC_INTR_RX_FULL) {
473 0 : dwiic_write(sc, DW_IC_INTR_MASK, 0);
474 : DPRINTF(("%s: %s: waking up reader\n",
475 : sc->sc_dev.dv_xname, __func__));
476 0 : wakeup(&sc->sc_readwait);
477 0 : }
478 0 : if (stat & DW_IC_INTR_TX_EMPTY) {
479 0 : dwiic_write(sc, DW_IC_INTR_MASK, 0);
480 : DPRINTF(("%s: %s: waking up writer\n",
481 : sc->sc_dev.dv_xname, __func__));
482 0 : wakeup(&sc->sc_writewait);
483 0 : }
484 0 : if (stat & DW_IC_INTR_STOP_DET) {
485 0 : dwiic_write(sc, DW_IC_INTR_MASK, 0);
486 0 : sc->sc_busy = 0;
487 0 : wakeup(&sc->sc_busy);
488 0 : }
489 : }
490 :
491 0 : return 1;
492 0 : }
|