root/dev/pci/ichiic.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ichiic_match
  2. ichiic_attach
  3. ichiic_i2c_acquire_bus
  4. ichiic_i2c_release_bus
  5. ichiic_i2c_exec
  6. ichiic_intr

    1 /*      $OpenBSD: ichiic.c,v 1.18 2007/05/03 09:36:26 dlg Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2005, 2006 Alexander Yurchenko <grange@openbsd.org>
    5  *
    6  * Permission to use, copy, modify, and distribute this software for any
    7  * purpose with or without fee is hereby granted, provided that the above
    8  * copyright notice and this permission notice appear in all copies.
    9  *
   10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17  */
   18 
   19 /*
   20  * Intel ICH SMBus controller driver.
   21  */
   22 
   23 #include <sys/param.h>
   24 #include <sys/systm.h>
   25 #include <sys/device.h>
   26 #include <sys/kernel.h>
   27 #include <sys/rwlock.h>
   28 #include <sys/proc.h>
   29 
   30 #include <machine/bus.h>
   31 
   32 #include <dev/pci/pcidevs.h>
   33 #include <dev/pci/pcireg.h>
   34 #include <dev/pci/pcivar.h>
   35 
   36 #include <dev/pci/ichreg.h>
   37 
   38 #include <dev/i2c/i2cvar.h>
   39 
   40 #ifdef ICHIIC_DEBUG
   41 #define DPRINTF(x) printf x
   42 #else
   43 #define DPRINTF(x)
   44 #endif
   45 
   46 #define ICHIIC_DELAY    100
   47 #define ICHIIC_TIMEOUT  1
   48 
   49 struct ichiic_softc {
   50         struct device           sc_dev;
   51 
   52         bus_space_tag_t         sc_iot;
   53         bus_space_handle_t      sc_ioh;
   54         void *                  sc_ih;
   55         int                     sc_poll;
   56 
   57         struct i2c_controller   sc_i2c_tag;
   58         struct rwlock           sc_i2c_lock;
   59         struct {
   60                 i2c_op_t     op;
   61                 void *       buf;
   62                 size_t       len;
   63                 int          flags;
   64                 volatile int error;
   65         }                       sc_i2c_xfer;
   66 };
   67 
   68 int     ichiic_match(struct device *, void *, void *);
   69 void    ichiic_attach(struct device *, struct device *, void *);
   70 
   71 int     ichiic_i2c_acquire_bus(void *, int);
   72 void    ichiic_i2c_release_bus(void *, int);
   73 int     ichiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
   74             void *, size_t, int);
   75 
   76 int     ichiic_intr(void *);
   77 
   78 struct cfattach ichiic_ca = {
   79         sizeof(struct ichiic_softc),
   80         ichiic_match,
   81         ichiic_attach
   82 };
   83 
   84 struct cfdriver ichiic_cd = {
   85         NULL, "ichiic", DV_DULL
   86 };
   87 
   88 const struct pci_matchid ichiic_ids[] = {
   89         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6300ESB_SMB },
   90         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6321ESB_SMB },
   91         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AA_SMB },
   92         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AB_SMB },
   93         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_SMB },
   94         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801CA_SMB },
   95         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801DB_SMB },
   96         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801E_SMB },
   97         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801EB_SMB },
   98         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801FB_SMB },
   99         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GB_SMB },
  100         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801H_SMB }
  101 };
  102 
  103 int
  104 ichiic_match(struct device *parent, void *match, void *aux)
  105 {
  106         return (pci_matchbyid(aux, ichiic_ids,
  107             sizeof(ichiic_ids) / sizeof(ichiic_ids[0])));
  108 }
  109 
  110 void
  111 ichiic_attach(struct device *parent, struct device *self, void *aux)
  112 {
  113         struct ichiic_softc *sc = (struct ichiic_softc *)self;
  114         struct pci_attach_args *pa = aux;
  115         struct i2cbus_attach_args iba;
  116         pcireg_t conf;
  117         bus_size_t iosize;
  118         pci_intr_handle_t ih;
  119         const char *intrstr = NULL;
  120 
  121         /* Read configuration */
  122         conf = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_SMB_HOSTC);
  123         DPRINTF((": conf 0x%08x", conf));
  124 
  125         if ((conf & ICH_SMB_HOSTC_HSTEN) == 0) {
  126                 printf(": SMBus disabled\n");
  127                 return;
  128         }
  129 
  130         /* Map I/O space */
  131         if (pci_mapreg_map(pa, ICH_SMB_BASE, PCI_MAPREG_TYPE_IO, 0,
  132             &sc->sc_iot, &sc->sc_ioh, NULL, &iosize, 0)) {
  133                 printf(": can't map I/O space\n");
  134                 return;
  135         }
  136 
  137         sc->sc_poll = 1;
  138         if (conf & ICH_SMB_HOSTC_SMIEN) {
  139                 /* No PCI IRQ */
  140                 printf(": SMI");
  141         } else {
  142                 /* Install interrupt handler */
  143                 if (pci_intr_map(pa, &ih) == 0) {
  144                         intrstr = pci_intr_string(pa->pa_pc, ih);
  145                         sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
  146                             ichiic_intr, sc, sc->sc_dev.dv_xname);
  147                         if (sc->sc_ih != NULL) {
  148                                 printf(": %s", intrstr);
  149                                 sc->sc_poll = 0;
  150                         }
  151                 }
  152                 if (sc->sc_poll)
  153                         printf(": polling");
  154         }
  155 
  156         printf("\n");
  157 
  158         /* Attach I2C bus */
  159         rw_init(&sc->sc_i2c_lock, "iiclk");
  160         sc->sc_i2c_tag.ic_cookie = sc;
  161         sc->sc_i2c_tag.ic_acquire_bus = ichiic_i2c_acquire_bus;
  162         sc->sc_i2c_tag.ic_release_bus = ichiic_i2c_release_bus;
  163         sc->sc_i2c_tag.ic_exec = ichiic_i2c_exec;
  164 
  165         bzero(&iba, sizeof(iba));
  166         iba.iba_name = "iic";
  167         iba.iba_tag = &sc->sc_i2c_tag;
  168         config_found(self, &iba, iicbus_print);
  169 
  170         return;
  171 }
  172 
  173 int
  174 ichiic_i2c_acquire_bus(void *cookie, int flags)
  175 {
  176         struct ichiic_softc *sc = cookie;
  177 
  178         if (cold || sc->sc_poll || (flags & I2C_F_POLL))
  179                 return (0);
  180 
  181         return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
  182 }
  183 
  184 void
  185 ichiic_i2c_release_bus(void *cookie, int flags)
  186 {
  187         struct ichiic_softc *sc = cookie;
  188 
  189         if (cold || sc->sc_poll || (flags & I2C_F_POLL))
  190                 return;
  191 
  192         rw_exit(&sc->sc_i2c_lock);
  193 }
  194 
  195 int
  196 ichiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
  197     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
  198 {
  199         struct ichiic_softc *sc = cookie;
  200         u_int8_t *b;
  201         u_int8_t ctl, st;
  202         int retries;
  203 
  204         DPRINTF(("%s: exec: op %d, addr 0x%02x, cmdlen %d, len %d, "
  205             "flags 0x%02x\n", sc->sc_dev.dv_xname, op, addr, cmdlen,
  206             len, flags));
  207 
  208         /* Wait for bus to be idle */
  209         for (retries = 100; retries > 0; retries--) {
  210                 st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
  211                 if (!(st & ICH_SMB_HS_BUSY))
  212                         break;
  213                 DELAY(ICHIIC_DELAY);
  214         }
  215         DPRINTF(("%s: exec: st 0x%b\n", sc->sc_dev.dv_xname, st,
  216             ICH_SMB_HS_BITS));
  217         if (st & ICH_SMB_HS_BUSY)
  218                 return (1);
  219 
  220         if (cold || sc->sc_poll)
  221                 flags |= I2C_F_POLL;
  222 
  223         if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
  224                 return (1);
  225 
  226         /* Setup transfer */
  227         sc->sc_i2c_xfer.op = op;
  228         sc->sc_i2c_xfer.buf = buf;
  229         sc->sc_i2c_xfer.len = len;
  230         sc->sc_i2c_xfer.flags = flags;
  231         sc->sc_i2c_xfer.error = 0;
  232 
  233         /* Set slave address and transfer direction */
  234         bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_TXSLVA,
  235             ICH_SMB_TXSLVA_ADDR(addr) |
  236             (I2C_OP_READ_P(op) ? ICH_SMB_TXSLVA_READ : 0));
  237 
  238         b = (void *)cmdbuf;
  239         if (cmdlen > 0)
  240                 /* Set command byte */
  241                 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HCMD, b[0]);
  242 
  243         if (I2C_OP_WRITE_P(op)) {
  244                 /* Write data */
  245                 b = buf;
  246                 if (len > 0)
  247                         bus_space_write_1(sc->sc_iot, sc->sc_ioh,
  248                             ICH_SMB_HD0, b[0]);
  249                 if (len > 1)
  250                         bus_space_write_1(sc->sc_iot, sc->sc_ioh,
  251                             ICH_SMB_HD1, b[1]);
  252         }
  253 
  254         /* Set SMBus command */
  255         if (len == 0)
  256                 ctl = ICH_SMB_HC_CMD_BYTE;
  257         else if (len == 1)
  258                 ctl = ICH_SMB_HC_CMD_BDATA;
  259         else if (len == 2)
  260                 ctl = ICH_SMB_HC_CMD_WDATA;
  261 
  262         if ((flags & I2C_F_POLL) == 0)
  263                 ctl |= ICH_SMB_HC_INTREN;
  264 
  265         /* Start transaction */
  266         ctl |= ICH_SMB_HC_START;
  267         bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HC, ctl);
  268 
  269         if (flags & I2C_F_POLL) {
  270                 /* Poll for completion */
  271                 DELAY(ICHIIC_DELAY);
  272                 for (retries = 1000; retries > 0; retries--) {
  273                         st = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
  274                             ICH_SMB_HS);
  275                         if ((st & ICH_SMB_HS_BUSY) == 0)
  276                                 break;
  277                         DELAY(ICHIIC_DELAY);
  278                 }
  279                 if (st & ICH_SMB_HS_BUSY)
  280                         goto timeout;
  281                 ichiic_intr(sc);
  282         } else {
  283                 /* Wait for interrupt */
  284                 if (tsleep(sc, PRIBIO, "iicexec", ICHIIC_TIMEOUT * hz))
  285                         goto timeout;
  286         }
  287 
  288         if (sc->sc_i2c_xfer.error)
  289                 return (1);
  290 
  291         return (0);
  292 
  293 timeout:
  294         /*
  295          * Transfer timeout. Kill the transaction and clear status bits.
  296          */
  297         printf("%s: exec: op %d, addr 0x%02x, cmdlen %d, len %d, "
  298             "flags 0x%02x: timeout, status 0x%b\n",
  299             sc->sc_dev.dv_xname, op, addr, cmdlen, len, flags,
  300             st, ICH_SMB_HS_BITS);
  301         bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HC,
  302             ICH_SMB_HC_KILL);
  303         DELAY(ICHIIC_DELAY);
  304         st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
  305         if ((st & ICH_SMB_HS_FAILED) == 0)
  306                 printf("%s: abort failed, status 0x%b\n",
  307                     sc->sc_dev.dv_xname, st, ICH_SMB_HS_BITS);
  308         bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS, st);
  309         return (1);
  310 }
  311 
  312 int
  313 ichiic_intr(void *arg)
  314 {
  315         struct ichiic_softc *sc = arg;
  316         u_int8_t st;
  317         u_int8_t *b;
  318         size_t len;
  319 
  320         /* Read status */
  321         st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
  322         if ((st & ICH_SMB_HS_BUSY) != 0 || (st & (ICH_SMB_HS_INTR |
  323             ICH_SMB_HS_DEVERR | ICH_SMB_HS_BUSERR | ICH_SMB_HS_FAILED |
  324             ICH_SMB_HS_SMBAL | ICH_SMB_HS_BDONE)) == 0)
  325                 /* Interrupt was not for us */
  326                 return (0);
  327 
  328         DPRINTF(("%s: intr st 0x%b\n", sc->sc_dev.dv_xname, st,
  329             ICH_SMB_HS_BITS));
  330 
  331         /* Clear status bits */
  332         bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS, st);
  333 
  334         /* Check for errors */
  335         if (st & (ICH_SMB_HS_DEVERR | ICH_SMB_HS_BUSERR | ICH_SMB_HS_FAILED)) {
  336                 sc->sc_i2c_xfer.error = 1;
  337                 goto done;
  338         }
  339 
  340         if (st & ICH_SMB_HS_INTR) {
  341                 if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
  342                         goto done;
  343 
  344                 /* Read data */
  345                 b = sc->sc_i2c_xfer.buf;
  346                 len = sc->sc_i2c_xfer.len;
  347                 if (len > 0)
  348                         b[0] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
  349                             ICH_SMB_HD0);
  350                 if (len > 1)
  351                         b[1] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
  352                             ICH_SMB_HD1);
  353         }
  354 
  355 done:
  356         if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
  357                 wakeup(sc);
  358         return (1);
  359 }

/* [<][>][^][v][top][bottom][index][help] */