1 /* $NetBSD: dwiic.c,v 1.10 2024/02/09 16:56:23 skrll Exp $ */
2 
3 /* $OpenBSD: dwiic.c,v 1.4 2018/05/23 22:08:00 kettenis Exp $ */
4 
5 /*-
6  * Copyright (c) 2017 The NetBSD Foundation, Inc.
7  * All rights reserved.
8  *
9  * This code is derived from software contributed to The NetBSD Foundation
10  * by Manuel Bouyer.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 /*
34  * Synopsys DesignWare I2C controller
35  *
36  * Copyright (c) 2015, 2016 joshua stein <jcs@openbsd.org>
37  *
38  * Permission to use, copy, modify, and/or distribute this software for any
39  * purpose with or without fee is hereby granted, provided that the above
40  * copyright notice and this permission notice appear in all copies.
41  *
42  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
43  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
44  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
45  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
46  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
47  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
48  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
49  */
50 
51 #include <sys/cdefs.h>
52 __KERNEL_RCSID(0, "$NetBSD: dwiic.c,v 1.10 2024/02/09 16:56:23 skrll Exp $");
53 
54 #include <sys/param.h>
55 
56 #include <sys/atomic.h>
57 #include <sys/bus.h>
58 #include <sys/device.h>
59 #include <sys/kernel.h>
60 #include <sys/systm.h>
61 
62 #include <dev/ic/dwiic_var.h>
63 
64 //#define DWIIC_DEBUG
65 
66 #ifdef DWIIC_DEBUG
67 #define DPRINTF(x) printf x
68 #else
69 #define DPRINTF(x)
70 #endif
71 
72 /* register offsets */
73 #define DW_IC_CON             0x0
74 #define DW_IC_TAR             0x4
75 #define DW_IC_DATA_CMD                  0x10
76 #define DW_IC_SS_SCL_HCNT     0x14
77 #define DW_IC_SS_SCL_LCNT     0x18
78 #define DW_IC_FS_SCL_HCNT     0x1c
79 #define DW_IC_FS_SCL_LCNT     0x20
80 #define DW_IC_INTR_STAT                 0x2c
81 #define DW_IC_INTR_MASK                 0x30
82 #define DW_IC_RAW_INTR_STAT   0x34
83 #define DW_IC_RX_TL           0x38
84 #define DW_IC_TX_TL           0x3c
85 #define DW_IC_CLR_INTR                  0x40
86 #define DW_IC_CLR_RX_UNDER    0x44
87 #define DW_IC_CLR_RX_OVER     0x48
88 #define DW_IC_CLR_TX_OVER     0x4c
89 #define DW_IC_CLR_RD_REQ      0x50
90 #define DW_IC_CLR_TX_ABRT     0x54
91 #define DW_IC_CLR_RX_DONE     0x58
92 #define DW_IC_CLR_ACTIVITY    0x5c
93 #define DW_IC_CLR_STOP_DET    0x60
94 #define DW_IC_CLR_START_DET   0x64
95 #define DW_IC_CLR_GEN_CALL    0x68
96 #define DW_IC_ENABLE                    0x6c
97 #define DW_IC_STATUS                    0x70
98 #define DW_IC_TXFLR           0x74
99 #define DW_IC_RXFLR           0x78
100 #define DW_IC_SDA_HOLD                  0x7c
101 #define DW_IC_TX_ABRT_SOURCE  0x80
102 #define DW_IC_ENABLE_STATUS   0x9c
103 #define DW_IC_COMP_PARAM_1    0xf4
104 #define DW_IC_COMP_VERSION    0xf8
105 #define DW_IC_SDA_HOLD_MIN_VERS         0x3131312A
106 #define DW_IC_COMP_TYPE                 0xfc
107 #define DW_IC_COMP_TYPE_VALUE 0x44570140
108 
109 #define DW_IC_CON_MASTER      0x1
110 #define DW_IC_CON_SPEED_STD   0x2
111 #define DW_IC_CON_SPEED_FAST  0x4
112 #define DW_IC_CON_10BITADDR_MASTER 0x10
113 #define DW_IC_CON_RESTART_EN  0x20
114 #define DW_IC_CON_SLAVE_DISABLE         0x40
115 
116 #define DW_IC_DATA_CMD_READ   0x100
117 #define DW_IC_DATA_CMD_STOP   0x200
118 #define DW_IC_DATA_CMD_RESTART          0x400
119 
120 #define DW_IC_INTR_RX_UNDER   0x001
121 #define DW_IC_INTR_RX_OVER    0x002
122 #define DW_IC_INTR_RX_FULL    0x004
123 #define DW_IC_INTR_TX_OVER    0x008
124 #define DW_IC_INTR_TX_EMPTY   0x010
125 #define DW_IC_INTR_RD_REQ     0x020
126 #define DW_IC_INTR_TX_ABRT    0x040
127 #define DW_IC_INTR_RX_DONE    0x080
128 #define DW_IC_INTR_ACTIVITY   0x100
129 #define DW_IC_INTR_STOP_DET   0x200
130 #define DW_IC_INTR_START_DET  0x400
131 #define DW_IC_INTR_GEN_CALL   0x800
132 
133 #define DW_IC_STATUS_ACTIVITY 0x1
134 
135 /* hardware abort codes from the DW_IC_TX_ABRT_SOURCE register */
136 #define ABRT_7B_ADDR_NOACK    0
137 #define ABRT_10ADDR1_NOACK    1
138 #define ABRT_10ADDR2_NOACK    2
139 #define ABRT_TXDATA_NOACK     3
140 #define ABRT_GCALL_NOACK      4
141 #define ABRT_GCALL_READ                 5
142 #define ABRT_SBYTE_ACKDET     7
143 #define ABRT_SBYTE_NORSTRT    9
144 #define ABRT_10B_RD_NORSTRT   10
145 #define ABRT_MASTER_DIS                 11
146 #define ARB_LOST              12
147 
148 static int          dwiic_init(struct dwiic_softc *);
149 static void         dwiic_enable(struct dwiic_softc *, bool);
150 static uint32_t     dwiic_read(struct dwiic_softc *, int);
151 static void         dwiic_write(struct dwiic_softc *, int, uint32_t);
152 static int          dwiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
153                         size_t, void *, size_t, int);
154 
155 bool
dwiic_attach(struct dwiic_softc * sc)156 dwiic_attach(struct dwiic_softc *sc)
157 {
158           if (sc->sc_power != NULL) {
159                     if (!sc->sc_power(sc, 1)) {
160                               aprint_error_dev(sc->sc_dev, "failed to power up\n");
161                               return 0;
162                     }
163           }
164 
165           /* fetch timing parameters */
166           if (sc->ss_hcnt == 0)
167                     sc->ss_hcnt = dwiic_read(sc, DW_IC_SS_SCL_HCNT);
168           if (sc->ss_lcnt == 0)
169                     sc->ss_lcnt = dwiic_read(sc, DW_IC_SS_SCL_LCNT);
170           if (sc->fs_hcnt == 0)
171                     sc->fs_hcnt = dwiic_read(sc, DW_IC_FS_SCL_HCNT);
172           if (sc->fs_lcnt == 0)
173                     sc->fs_lcnt = dwiic_read(sc, DW_IC_FS_SCL_LCNT);
174           if (sc->sda_hold_time == 0)
175                     sc->sda_hold_time = dwiic_read(sc, DW_IC_SDA_HOLD);
176 
177           if (dwiic_init(sc)) {
178                     aprint_error_dev(sc->sc_dev, "failed initializing\n");
179                     return 0;
180           }
181 
182           /* leave the controller disabled */
183           dwiic_write(sc, DW_IC_INTR_MASK, 0);
184           dwiic_enable(sc, 0);
185           dwiic_read(sc, DW_IC_CLR_INTR);
186 
187           mutex_init(&sc->sc_int_lock, MUTEX_DEFAULT, IPL_VM);
188           cv_init(&sc->sc_int_readwait, "dwiicr");
189           cv_init(&sc->sc_int_writewait, "dwiicw");
190           cv_init(&sc->sc_int_stopwait, "dwiics");
191 
192           /* setup and attach iic bus */
193           iic_tag_init(&sc->sc_i2c_tag);
194           sc->sc_i2c_tag.ic_cookie = sc;
195           sc->sc_i2c_tag.ic_exec = dwiic_i2c_exec;
196 
197           sc->sc_iba.iba_tag = &sc->sc_i2c_tag;
198 
199           /* config_found_ia for "i2cbus" is done in the bus-attachment glue */
200 
201           atomic_store_release(&sc->sc_attached, true);
202 
203           return 1;
204 }
205 
206 int
dwiic_detach(device_t self,int flags)207 dwiic_detach(device_t self, int flags)
208 {
209           struct dwiic_softc *sc = device_private(self);
210 
211           dwiic_enable(sc, 0);
212           if (sc->sc_ih != NULL) {
213                     intr_disestablish(sc->sc_ih);
214                     sc->sc_ih = NULL;
215           }
216 
217           return 0;
218 }
219 
220 bool
dwiic_suspend(device_t self,const pmf_qual_t * qual)221 dwiic_suspend(device_t self, const pmf_qual_t *qual)
222 {
223           struct dwiic_softc *sc = device_private(self);
224 
225           /* disable controller */
226           dwiic_enable(sc, 0);
227 
228           /* disable interrupts */
229           dwiic_write(sc, DW_IC_INTR_MASK, 0);
230           dwiic_read(sc, DW_IC_CLR_INTR);
231           if (sc->sc_power != NULL) {
232                     if (!sc->sc_power(sc, 0)) {
233                               device_printf(sc->sc_dev, "failed to power off\n");
234                     }
235           }
236           return true;
237 }
238 
239 bool
dwiic_resume(device_t self,const pmf_qual_t * qual)240 dwiic_resume(device_t self, const pmf_qual_t *qual)
241 {
242           struct dwiic_softc *sc = device_private(self);
243           if (sc->sc_power != NULL) {
244                     if (!sc->sc_power(sc, 1)) {
245                               device_printf(sc->sc_dev, "failed to power up\n");
246                               return false;
247                     }
248           }
249           dwiic_init(sc);
250           return true;
251 }
252 
253 static uint32_t
dwiic_read(struct dwiic_softc * sc,int offset)254 dwiic_read(struct dwiic_softc *sc, int offset)
255 {
256           u_int32_t b = bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset);
257 
258           DPRINTF(("%s: read at 0x%x = 0x%x\n", device_xname(sc->sc_dev), offset, b));
259 
260           return b;
261 }
262 
263 static void
dwiic_write(struct dwiic_softc * sc,int offset,uint32_t val)264 dwiic_write(struct dwiic_softc *sc, int offset, uint32_t val)
265 {
266           bus_space_write_4(sc->sc_iot, sc->sc_ioh, offset, val);
267 
268           DPRINTF(("%s: write at 0x%x: 0x%x\n", device_xname(sc->sc_dev), offset,
269               val));
270 }
271 
272 static int
dwiic_init(struct dwiic_softc * sc)273 dwiic_init(struct dwiic_softc *sc)
274 {
275           uint32_t reg;
276 
277           /* make sure we're talking to a device we know */
278           reg = dwiic_read(sc, DW_IC_COMP_TYPE);
279           if (reg != DW_IC_COMP_TYPE_VALUE) {
280                     DPRINTF(("%s: invalid component type 0x%x\n",
281                         device_xname(sc->sc_dev), reg));
282                     return 1;
283           }
284 
285           /* disable the adapter */
286           dwiic_enable(sc, 0);
287 
288           /* write standard-mode SCL timing parameters */
289           dwiic_write(sc, DW_IC_SS_SCL_HCNT, sc->ss_hcnt);
290           dwiic_write(sc, DW_IC_SS_SCL_LCNT, sc->ss_lcnt);
291 
292           /* and fast-mode SCL timing parameters */
293           dwiic_write(sc, DW_IC_FS_SCL_HCNT, sc->fs_hcnt);
294           dwiic_write(sc, DW_IC_FS_SCL_LCNT, sc->fs_lcnt);
295 
296           /* SDA hold time */
297           reg = dwiic_read(sc, DW_IC_COMP_VERSION);
298           if (reg >= DW_IC_SDA_HOLD_MIN_VERS)
299                     dwiic_write(sc, DW_IC_SDA_HOLD, sc->sda_hold_time);
300 
301           /* FIFO threshold levels */
302           sc->tx_fifo_depth = 32;
303           sc->rx_fifo_depth = 32;
304           dwiic_write(sc, DW_IC_TX_TL, sc->tx_fifo_depth / 2);
305           dwiic_write(sc, DW_IC_RX_TL, 0);
306 
307           /* configure as i2c master with fast speed */
308           sc->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
309               DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
310           dwiic_write(sc, DW_IC_CON, sc->master_cfg);
311 
312           return 0;
313 }
314 
315 static void
dwiic_enable(struct dwiic_softc * sc,bool enable)316 dwiic_enable(struct dwiic_softc *sc, bool enable)
317 {
318           int retries;
319 
320           for (retries = 100; retries > 0; retries--) {
321                     dwiic_write(sc, DW_IC_ENABLE, enable);
322                     if ((dwiic_read(sc, DW_IC_ENABLE_STATUS) & 1) == enable)
323                               return;
324 
325                     DELAY(25);
326           }
327 
328           device_printf(sc->sc_dev, "failed to %sable\n",
329               (enable ? "en" : "dis"));
330 }
331 
332 static int
dwiic_i2c_exec(void * cookie,i2c_op_t op,i2c_addr_t addr,const void * cmdbuf,size_t cmdlen,void * buf,size_t len,int flags)333 dwiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf,
334     size_t cmdlen, void *buf, size_t len, int flags)
335 {
336           struct dwiic_softc *sc = cookie;
337           u_int32_t ic_con, st, cmd, resp;
338           int retries, tx_limit, rx_avail, x, readpos;
339           const uint8_t *bcmd;
340           uint8_t *bdata;
341 
342           if (sc->sc_poll)
343                     flags |= I2C_F_POLL;
344 
345           DPRINTF(("%s: %s: op %d, addr 0x%02x, cmdlen %zu, len %zu, "
346               "flags 0x%02x\n", device_xname(sc->sc_dev), __func__, op, addr, cmdlen,
347               len, flags));
348 
349           /* setup transfer */
350           sc->sc_i2c_xfer.op = op;
351           sc->sc_i2c_xfer.buf = buf;
352           sc->sc_i2c_xfer.len = len;
353           sc->sc_i2c_xfer.flags = flags;
354           sc->sc_i2c_xfer.error = 0;
355 
356           /* wait for bus to be idle */
357           for (retries = 100; retries > 0; retries--) {
358                     st = dwiic_read(sc, DW_IC_STATUS);
359                     if (!(st & DW_IC_STATUS_ACTIVITY))
360                               break;
361                     DELAY(1000);
362           }
363           DPRINTF(("%s: %s: status 0x%x\n", device_xname(sc->sc_dev), __func__, st));
364           if (st & DW_IC_STATUS_ACTIVITY) {
365                     return (1);
366           }
367 
368           /* disable controller */
369           dwiic_enable(sc, 0);
370 
371           /* set slave address */
372           ic_con = dwiic_read(sc, DW_IC_CON);
373           ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
374           dwiic_write(sc, DW_IC_CON, ic_con);
375           dwiic_write(sc, DW_IC_TAR, addr);
376 
377           /* disable interrupts */
378           dwiic_write(sc, DW_IC_INTR_MASK, 0);
379           dwiic_read(sc, DW_IC_CLR_INTR);
380 
381           /* enable controller */
382           dwiic_enable(sc, 1);
383 
384           /* wait until the controller is ready for commands */
385           if (flags & I2C_F_POLL)
386                     DELAY(200);
387           else {
388                     mutex_enter(&sc->sc_int_lock);
389                     dwiic_read(sc, DW_IC_CLR_INTR);
390                     dwiic_write(sc, DW_IC_INTR_MASK, DW_IC_INTR_TX_EMPTY);
391 
392                     if (cv_timedwait(&sc->sc_int_writewait,
393                         &sc->sc_int_lock, hz / 2) != 0)
394                               device_printf(sc->sc_dev,
395                                   "timed out waiting for tx_empty intr\n");
396                     dwiic_write(sc, DW_IC_INTR_MASK, 0);
397                     dwiic_read(sc, DW_IC_CLR_INTR);
398                     mutex_exit(&sc->sc_int_lock);
399           }
400 
401           /* send our command, one byte at a time */
402           if (cmdlen > 0) {
403                     bcmd = (const void *)cmdbuf;
404 
405                     DPRINTF(("%s: %s: sending cmd (len %zu):", device_xname(sc->sc_dev),
406                         __func__, cmdlen));
407                     for (x = 0; x < cmdlen; x++)
408                               DPRINTF((" %02x", bcmd[x]));
409                     DPRINTF(("\n"));
410 
411                     tx_limit = sc->tx_fifo_depth - dwiic_read(sc, DW_IC_TXFLR);
412                     if (cmdlen > tx_limit) {
413                               /* TODO */
414                               device_printf(sc->sc_dev, "can't write %zu (> %d)\n",
415                                   cmdlen, tx_limit);
416                               sc->sc_i2c_xfer.error = 1;
417                               return (1);
418                     }
419 
420                     for (x = 0; x < cmdlen; x++) {
421                               cmd = bcmd[x];
422                               /*
423                                * Generate STOP condition if this is the last
424                                * byte of the transfer.
425                                */
426                               if (x == (cmdlen - 1) && len == 0 && I2C_OP_STOP_P(op))
427                                         cmd |= DW_IC_DATA_CMD_STOP;
428                               dwiic_write(sc, DW_IC_DATA_CMD, cmd);
429                     }
430           }
431 
432           bdata = (void *)buf;
433           x = readpos = 0;
434           tx_limit = sc->tx_fifo_depth - dwiic_read(sc, DW_IC_TXFLR);
435 
436           DPRINTF(("%s: %s: need to read %zu bytes, can send %d read reqs\n",
437                     device_xname(sc->sc_dev), __func__, len, tx_limit));
438 
439           while (x < len) {
440                     if (I2C_OP_WRITE_P(op))
441                               cmd = bdata[x];
442                     else
443                               cmd = DW_IC_DATA_CMD_READ;
444 
445                     /*
446                      * Generate RESTART condition if we're reversing
447                      * direction.
448                      */
449                     if (x == 0 && cmdlen > 0 && I2C_OP_READ_P(op))
450                               cmd |= DW_IC_DATA_CMD_RESTART;
451                     /*
452                      * Generate STOP condition on the last byte of the
453                      * transfer.
454                      */
455                     if (x == (len - 1) && I2C_OP_STOP_P(op))
456                               cmd |= DW_IC_DATA_CMD_STOP;
457 
458                     dwiic_write(sc, DW_IC_DATA_CMD, cmd);
459 
460                     tx_limit--;
461                     x++;
462 
463                     /*
464                      * As TXFLR fills up, we need to clear it out by reading all
465                      * available data.
466                      */
467                     while (I2C_OP_READ_P(op) && (tx_limit == 0 || x == len)) {
468                               DPRINTF(("%s: %s: tx_limit %d, sent %d read reqs\n",
469                                   device_xname(sc->sc_dev), __func__, tx_limit, x));
470 
471                               if (flags & I2C_F_POLL) {
472                                         for (retries = 100; retries > 0; retries--) {
473                                                   rx_avail = dwiic_read(sc, DW_IC_RXFLR);
474                                                   if (rx_avail > 0)
475                                                             break;
476                                                   DELAY(50);
477                                         }
478                               } else {
479                                         mutex_enter(&sc->sc_int_lock);
480                                         dwiic_read(sc, DW_IC_CLR_INTR);
481                                         dwiic_write(sc, DW_IC_INTR_MASK,
482                                             DW_IC_INTR_RX_FULL);
483 
484                                         if (cv_timedwait(&sc->sc_int_readwait,
485                                             &sc->sc_int_lock, hz / 2) != 0)
486                                                   device_printf(sc->sc_dev,
487                                                       "timed out waiting for "
488                                                       "rx_full intr\n");
489 
490                                         dwiic_write(sc, DW_IC_INTR_MASK, 0);
491                                         dwiic_read(sc, DW_IC_CLR_INTR);
492                                         mutex_exit(&sc->sc_int_lock);
493                                         rx_avail = dwiic_read(sc, DW_IC_RXFLR);
494                               }
495 
496                               if (rx_avail == 0) {
497                                         device_printf(sc->sc_dev,
498                                             "timed out reading remaining %d\n",
499                                             (int)(len - 1 - readpos));
500                                         sc->sc_i2c_xfer.error = 1;
501                                         return (1);
502                               }
503 
504                               DPRINTF(("%s: %s: %d avail to read (%zu remaining)\n",
505                                   device_xname(sc->sc_dev), __func__, rx_avail,
506                                   len - readpos));
507 
508                               while (rx_avail > 0) {
509                                         resp = dwiic_read(sc, DW_IC_DATA_CMD);
510                                         if (readpos < len) {
511                                                   bdata[readpos] = resp;
512                                                   readpos++;
513                                         }
514                                         rx_avail--;
515                               }
516 
517                               if (readpos >= len)
518                                         break;
519 
520                               DPRINTF(("%s: still need to read %d bytes\n",
521                                   device_xname(sc->sc_dev), (int)(len - readpos)));
522                               tx_limit = sc->tx_fifo_depth -
523                                   dwiic_read(sc, DW_IC_TXFLR);
524                     }
525           }
526 
527           if (I2C_OP_STOP_P(op) && I2C_OP_WRITE_P(op)) {
528                     if (flags & I2C_F_POLL) {
529                               /* wait for bus to be idle */
530                               for (retries = 100; retries > 0; retries--) {
531                                         st = dwiic_read(sc, DW_IC_STATUS);
532                                         if (!(st & DW_IC_STATUS_ACTIVITY))
533                                                   break;
534                                         DELAY(1000);
535                               }
536                               if (st & DW_IC_STATUS_ACTIVITY)
537                                         device_printf(sc->sc_dev, "timed out waiting "
538                                             "for bus idle\n");
539                     } else {
540                               mutex_enter(&sc->sc_int_lock);
541                               dwiic_read(sc, DW_IC_CLR_INTR);
542                               dwiic_write(sc, DW_IC_INTR_MASK,
543                                   DW_IC_INTR_STOP_DET);
544                               if (cv_timedwait(&sc->sc_int_stopwait,
545                                   &sc->sc_int_lock, hz / 2) != 0)
546                                         device_printf(sc->sc_dev, "timed out waiting "
547                                             "for stop intr\n");
548                               dwiic_write(sc, DW_IC_INTR_MASK, 0);
549                               dwiic_read(sc, DW_IC_CLR_INTR);
550                               mutex_exit(&sc->sc_int_lock);
551                     }
552           }
553 
554           return 0;
555 }
556 
557 static uint32_t
dwiic_read_clear_intrbits(struct dwiic_softc * sc)558 dwiic_read_clear_intrbits(struct dwiic_softc *sc)
559 {
560        uint32_t stat;
561 
562        stat = dwiic_read(sc, DW_IC_INTR_STAT);
563 
564        if (stat & DW_IC_INTR_RX_UNDER)
565                  dwiic_read(sc, DW_IC_CLR_RX_UNDER);
566        if (stat & DW_IC_INTR_RX_OVER)
567                  dwiic_read(sc, DW_IC_CLR_RX_OVER);
568        if (stat & DW_IC_INTR_TX_OVER)
569                  dwiic_read(sc, DW_IC_CLR_TX_OVER);
570        if (stat & DW_IC_INTR_RD_REQ)
571                  dwiic_read(sc, DW_IC_CLR_RD_REQ);
572        if (stat & DW_IC_INTR_TX_ABRT)
573                  dwiic_read(sc, DW_IC_CLR_TX_ABRT);
574        if (stat & DW_IC_INTR_RX_DONE)
575                  dwiic_read(sc, DW_IC_CLR_RX_DONE);
576        if (stat & DW_IC_INTR_ACTIVITY)
577                  dwiic_read(sc, DW_IC_CLR_ACTIVITY);
578        if (stat & DW_IC_INTR_STOP_DET)
579                  dwiic_read(sc, DW_IC_CLR_STOP_DET);
580        if (stat & DW_IC_INTR_START_DET)
581                  dwiic_read(sc, DW_IC_CLR_START_DET);
582        if (stat & DW_IC_INTR_GEN_CALL)
583                  dwiic_read(sc, DW_IC_CLR_GEN_CALL);
584 
585        return stat;
586 }
587 
588 int
dwiic_intr(void * arg)589 dwiic_intr(void *arg)
590 {
591           struct dwiic_softc *sc = arg;
592           uint32_t en, stat;
593 
594           /*
595            * Give up if attach hasn't succeeded.  If it failed, nothing
596            * to do here.  If it is still ongoing and simply hasn't yet
597            * succeeded, interrupts from the device are masked -- so this
598            * interrupt must be shared with another driver -- and any
599            * interrupts applicable to us will be delivered once
600            * interrupts from the device are unmasked in dwiic_i2c_exec.
601            */
602           if (!atomic_load_acquire(&sc->sc_attached))
603                     return 0;
604 
605           en = dwiic_read(sc, DW_IC_ENABLE);
606           /* probably for the other controller */
607           if (!en)
608                     return 0;
609 
610           stat = dwiic_read_clear_intrbits(sc);
611           DPRINTF(("%s: %s: enabled=0x%x stat=0x%x\n", device_xname(sc->sc_dev),
612               __func__, en, stat));
613           if (!(stat & ~DW_IC_INTR_ACTIVITY))
614                     return 1;
615 
616           if (stat & DW_IC_INTR_TX_ABRT)
617                     sc->sc_i2c_xfer.error = 1;
618 
619           if (sc->sc_i2c_xfer.flags & I2C_F_POLL)
620                     DPRINTF(("%s: %s: intr in poll mode?\n", device_xname(sc->sc_dev),
621                         __func__));
622           else {
623                     mutex_enter(&sc->sc_int_lock);
624                     if (stat & DW_IC_INTR_RX_FULL) {
625                               dwiic_write(sc, DW_IC_INTR_MASK, 0);
626                               DPRINTF(("%s: %s: waking up reader\n",
627                                   device_xname(sc->sc_dev), __func__));
628                               cv_signal(&sc->sc_int_readwait);
629                     }
630                     if (stat & DW_IC_INTR_TX_EMPTY) {
631                               dwiic_write(sc, DW_IC_INTR_MASK, 0);
632                               DPRINTF(("%s: %s: waking up writer\n",
633                                   device_xname(sc->sc_dev), __func__));
634                               cv_signal(&sc->sc_int_writewait);
635                     }
636                     if (stat & DW_IC_INTR_STOP_DET) {
637                               dwiic_write(sc, DW_IC_INTR_MASK, 0);
638                               DPRINTF(("%s: %s: waking up stopper\n",
639                                   device_xname(sc->sc_dev), __func__));
640                               cv_signal(&sc->sc_int_stopwait);
641                     }
642                     mutex_exit(&sc->sc_int_lock);
643           }
644 
645           return 1;
646 }
647