LCOV - code coverage report
Current view: top level - dev/ic - dwiic.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 226 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 11 0.0 %
Legend: Lines: hit not hit

          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 : }

Generated by: LCOV version 1.13