The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/iicbus/iicsmb.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1998, 2001 Nicolas Souchu
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 /*
   31  * I2C to SMB bridge
   32  *
   33  * Example:
   34  *
   35  *     smb bttv
   36  *       \ /
   37  *      smbus
   38  *       /  \
   39  *    iicsmb bti2c
   40  *       |
   41  *     iicbus
   42  *     /  |  \
   43  *  iicbb pcf ...
   44  *    |
   45  *  lpbb
   46  */
   47 
   48 #include <sys/param.h>
   49 #include <sys/bus.h>
   50 #include <sys/kernel.h>
   51 #include <sys/lock.h>
   52 #include <sys/module.h>
   53 #include <sys/mutex.h>
   54 #include <sys/systm.h>
   55 #include <sys/uio.h>
   56 
   57 #include <dev/iicbus/iiconf.h>
   58 #include <dev/iicbus/iicbus.h>
   59 
   60 #include <dev/smbus/smbconf.h>
   61 
   62 #include "iicbus_if.h"
   63 #include "smbus_if.h"
   64 
   65 struct iicsmb_softc {
   66 
   67 #define SMB_WAITING_ADDR        0x0
   68 #define SMB_WAITING_LOW         0x1
   69 #define SMB_WAITING_HIGH        0x2
   70 #define SMB_DONE                0x3
   71         int state;
   72 
   73         u_char devaddr;                 /* slave device address */
   74 
   75         char low;                       /* low byte received first */
   76         char high;                      /* high byte */
   77 
   78         struct mtx lock;
   79         device_t smbus;
   80 };
   81 
   82 static int iicsmb_probe(device_t);
   83 static int iicsmb_attach(device_t);
   84 static int iicsmb_detach(device_t);
   85 static void iicsmb_identify(driver_t *driver, device_t parent);
   86 
   87 static int iicsmb_intr(device_t dev, int event, char *buf);
   88 static int iicsmb_callback(device_t dev, int index, void *data);
   89 static int iicsmb_quick(device_t dev, u_char slave, int how);
   90 static int iicsmb_sendb(device_t dev, u_char slave, char byte);
   91 static int iicsmb_recvb(device_t dev, u_char slave, char *byte);
   92 static int iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
   93 static int iicsmb_writew(device_t dev, u_char slave, char cmd, short word);
   94 static int iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
   95 static int iicsmb_readw(device_t dev, u_char slave, char cmd, short *word);
   96 static int iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
   97 static int iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
   98 static int iicsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf);
   99 
  100 static devclass_t iicsmb_devclass;
  101 
  102 static device_method_t iicsmb_methods[] = {
  103         /* device interface */
  104         DEVMETHOD(device_identify,      iicsmb_identify),
  105         DEVMETHOD(device_probe,         iicsmb_probe),
  106         DEVMETHOD(device_attach,        iicsmb_attach),
  107         DEVMETHOD(device_detach,        iicsmb_detach),
  108 
  109         /* iicbus interface */
  110         DEVMETHOD(iicbus_intr,          iicsmb_intr),
  111 
  112         /* smbus interface */
  113         DEVMETHOD(smbus_callback,       iicsmb_callback),
  114         DEVMETHOD(smbus_quick,          iicsmb_quick),
  115         DEVMETHOD(smbus_sendb,          iicsmb_sendb),
  116         DEVMETHOD(smbus_recvb,          iicsmb_recvb),
  117         DEVMETHOD(smbus_writeb,         iicsmb_writeb),
  118         DEVMETHOD(smbus_writew,         iicsmb_writew),
  119         DEVMETHOD(smbus_readb,          iicsmb_readb),
  120         DEVMETHOD(smbus_readw,          iicsmb_readw),
  121         DEVMETHOD(smbus_pcall,          iicsmb_pcall),
  122         DEVMETHOD(smbus_bwrite,         iicsmb_bwrite),
  123         DEVMETHOD(smbus_bread,          iicsmb_bread),
  124 
  125         DEVMETHOD_END
  126 };
  127 
  128 static driver_t iicsmb_driver = {
  129         "iicsmb",
  130         iicsmb_methods,
  131         sizeof(struct iicsmb_softc),
  132 };
  133 
  134 #define IICBUS_TIMEOUT  100     /* us */
  135 
  136 static void
  137 iicsmb_identify(driver_t *driver, device_t parent)
  138 {
  139 
  140         if (device_find_child(parent, "iicsmb", -1) == NULL)
  141                 BUS_ADD_CHILD(parent, 0, "iicsmb", -1);
  142 }
  143 
  144 static int
  145 iicsmb_probe(device_t dev)
  146 {
  147         device_set_desc(dev, "SMBus over I2C bridge");
  148         return (BUS_PROBE_NOWILDCARD);
  149 }
  150 
  151 static int
  152 iicsmb_attach(device_t dev)
  153 {
  154         struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev);
  155 
  156         mtx_init(&sc->lock, "iicsmb", NULL, MTX_DEF);
  157 
  158         sc->smbus = device_add_child(dev, "smbus", -1);
  159 
  160         /* probe and attach the smbus */
  161         bus_generic_attach(dev);
  162 
  163         return (0);
  164 }
  165 
  166 static int
  167 iicsmb_detach(device_t dev)
  168 {
  169         struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev);
  170         
  171         bus_generic_detach(dev);
  172         if (sc->smbus) {
  173                 device_delete_child(dev, sc->smbus);
  174         }
  175         mtx_destroy(&sc->lock);
  176 
  177         return (0);
  178 }
  179 
  180 /*
  181  * iicsmb_intr()
  182  *
  183  * iicbus interrupt handler
  184  */
  185 static int
  186 iicsmb_intr(device_t dev, int event, char *buf)
  187 {
  188         struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev);
  189 
  190         mtx_lock(&sc->lock);
  191         switch (event) {
  192         case INTR_GENERAL:
  193         case INTR_START:
  194                 sc->state = SMB_WAITING_ADDR;
  195                 break;
  196 
  197         case INTR_STOP:
  198                 /* call smbus intr handler */
  199                 smbus_intr(sc->smbus, sc->devaddr,
  200                                 sc->low, sc->high, SMB_ENOERR);
  201                 break;
  202 
  203         case INTR_RECEIVE:
  204                 switch (sc->state) {
  205                 case SMB_DONE:
  206                         /* XXX too much data, discard */
  207                         printf("%s: too much data from 0x%x\n", __func__,
  208                                 sc->devaddr & 0xff);
  209                         goto end;
  210 
  211                 case SMB_WAITING_ADDR:
  212                         sc->devaddr = (u_char)*buf;
  213                         sc->state = SMB_WAITING_LOW;
  214                         break;
  215 
  216                 case SMB_WAITING_LOW:
  217                         sc->low = *buf;
  218                         sc->state = SMB_WAITING_HIGH;
  219                         break;
  220 
  221                 case SMB_WAITING_HIGH:
  222                         sc->high = *buf;
  223                         sc->state = SMB_DONE;
  224                         break;
  225                 }
  226 end:
  227                 break;
  228 
  229         case INTR_TRANSMIT:
  230         case INTR_NOACK:
  231                 break;
  232 
  233         case INTR_ERROR:
  234                 switch (*buf) {
  235                 case IIC_EBUSERR:
  236                         smbus_intr(sc->smbus, sc->devaddr, 0, 0, SMB_EBUSERR);
  237                         break;
  238 
  239                 default:
  240                         printf("%s unknown error 0x%x!\n", __func__,
  241                                                                 (int)*buf);
  242                         break;
  243                 }
  244                 break;
  245 
  246         default:
  247                 panic("%s: unknown event (%d)!", __func__, event);
  248         }
  249         mtx_unlock(&sc->lock);
  250 
  251         return (0);
  252 }
  253 
  254 static int
  255 iicsmb_callback(device_t dev, int index, void *data)
  256 {
  257         device_t parent = device_get_parent(dev);
  258         int error = 0;
  259         int how;
  260 
  261         switch (index) {
  262         case SMB_REQUEST_BUS:
  263                 /* request underlying iicbus */
  264                 how = *(int *)data;
  265                 error = iicbus_request_bus(parent, dev, how);
  266                 break;
  267 
  268         case SMB_RELEASE_BUS:
  269                 /* release underlying iicbus */
  270                 error = iicbus_release_bus(parent, dev);
  271                 break;
  272 
  273         default:
  274                 error = EINVAL;
  275         }
  276 
  277         return (error);
  278 }
  279 
  280 static int
  281 iicsmb_quick(device_t dev, u_char slave, int how)
  282 {
  283         device_t parent = device_get_parent(dev);
  284         int error;
  285 
  286         switch (how) {
  287         case SMB_QWRITE:
  288                 error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT);
  289                 break;
  290 
  291         case SMB_QREAD:
  292                 error = iicbus_start(parent, slave | LSB, IICBUS_TIMEOUT);
  293                 break;
  294 
  295         default:
  296                 error = EINVAL;
  297                 break;
  298         }
  299 
  300         if (!error)
  301                 error = iicbus_stop(parent);
  302                 
  303         return (error);
  304 }
  305 
  306 static int
  307 iicsmb_sendb(device_t dev, u_char slave, char byte)
  308 {
  309         device_t parent = device_get_parent(dev);
  310         int error, sent;
  311 
  312         error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT);
  313 
  314         if (!error) {
  315                 error = iicbus_write(parent, &byte, 1, &sent, IICBUS_TIMEOUT);
  316 
  317                 iicbus_stop(parent);
  318         }
  319 
  320         return (error);
  321 }
  322 
  323 static int
  324 iicsmb_recvb(device_t dev, u_char slave, char *byte)
  325 {
  326         device_t parent = device_get_parent(dev);
  327         int error, read;
  328 
  329         error = iicbus_start(parent, slave | LSB, 0);
  330 
  331         if (!error) {
  332                 error = iicbus_read(parent, byte, 1, &read, IIC_LAST_READ, IICBUS_TIMEOUT);
  333 
  334                 iicbus_stop(parent);
  335         }
  336 
  337         return (error);
  338 }
  339 
  340 static int
  341 iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
  342 {
  343         device_t parent = device_get_parent(dev);
  344         int error, sent;
  345 
  346         error = iicbus_start(parent, slave & ~LSB, 0);
  347 
  348         if (!error) {
  349                 if (!(error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
  350                         error = iicbus_write(parent, &byte, 1, &sent, IICBUS_TIMEOUT);
  351 
  352                 iicbus_stop(parent);
  353         }
  354 
  355         return (error);
  356 }
  357 
  358 static int
  359 iicsmb_writew(device_t dev, u_char slave, char cmd, short word)
  360 {
  361         device_t parent = device_get_parent(dev);
  362         int error, sent;
  363 
  364         char low = (char)(word & 0xff);
  365         char high = (char)((word & 0xff00) >> 8);
  366 
  367         error = iicbus_start(parent, slave & ~LSB, 0);
  368 
  369         if (!error) {
  370                 if (!(error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
  371                   if (!(error = iicbus_write(parent, &low, 1, &sent, IICBUS_TIMEOUT)))
  372                     error = iicbus_write(parent, &high, 1, &sent, IICBUS_TIMEOUT);
  373 
  374                 iicbus_stop(parent);
  375         }
  376 
  377         return (error);
  378 }
  379 
  380 static int
  381 iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
  382 {
  383         device_t parent = device_get_parent(dev);
  384         int error, sent, read;
  385 
  386         if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT)))
  387                 return (error);
  388 
  389         if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
  390                 goto error;
  391 
  392         if ((error = iicbus_repeated_start(parent, slave | LSB, IICBUS_TIMEOUT)))
  393                 goto error;
  394 
  395         if ((error = iicbus_read(parent, byte, 1, &read, IIC_LAST_READ, IICBUS_TIMEOUT)))
  396                 goto error;
  397 
  398 error:
  399         iicbus_stop(parent);
  400         return (error);
  401 }
  402 
  403 #define BUF2SHORT(low,high) \
  404         ((short)(((high) & 0xff) << 8) | (short)((low) & 0xff))
  405 
  406 static int
  407 iicsmb_readw(device_t dev, u_char slave, char cmd, short *word)
  408 {
  409         device_t parent = device_get_parent(dev);
  410         int error, sent, read;
  411         char buf[2];
  412 
  413         if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT)))
  414                 return (error);
  415 
  416         if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
  417                 goto error;
  418 
  419         if ((error = iicbus_repeated_start(parent, slave | LSB, IICBUS_TIMEOUT)))
  420                 goto error;
  421 
  422         if ((error = iicbus_read(parent, buf, 2, &read, IIC_LAST_READ, IICBUS_TIMEOUT)))
  423                 goto error;
  424 
  425         /* first, receive low, then high byte */
  426         *word = BUF2SHORT(buf[0], buf[1]);
  427 
  428 error:
  429         iicbus_stop(parent);
  430         return (error);
  431 }
  432 
  433 static int
  434 iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
  435 {
  436         device_t parent = device_get_parent(dev);
  437         int error, sent, read;
  438         char buf[2];
  439 
  440         if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT)))
  441                 return (error);
  442 
  443         if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
  444                 goto error;
  445 
  446         /* first, send low, then high byte */
  447         buf[0] = (char)(sdata & 0xff);
  448         buf[1] = (char)((sdata & 0xff00) >> 8);
  449 
  450         if ((error = iicbus_write(parent, buf, 2, &sent, IICBUS_TIMEOUT)))
  451                 goto error;
  452 
  453         if ((error = iicbus_repeated_start(parent, slave | LSB, IICBUS_TIMEOUT)))
  454                 goto error;
  455 
  456         if ((error = iicbus_read(parent, buf, 2, &read, IIC_LAST_READ, IICBUS_TIMEOUT)))
  457                 goto error;
  458 
  459         /* first, receive low, then high byte */
  460         *rdata = BUF2SHORT(buf[0], buf[1]);
  461 
  462 error:
  463         iicbus_stop(parent);
  464         return (error);
  465 }
  466 
  467 static int
  468 iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
  469 {
  470         device_t parent = device_get_parent(dev);
  471         int error, sent;
  472 
  473         if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT)))
  474                 goto error;
  475 
  476         if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
  477                 goto error;
  478 
  479         if ((error = iicbus_write(parent, buf, (int)count, &sent, IICBUS_TIMEOUT)))
  480                 goto error;
  481 
  482         if ((error = iicbus_stop(parent)))
  483                 goto error;
  484 
  485 error:
  486         return (error);
  487 }
  488 
  489 static int
  490 iicsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
  491 {
  492         device_t parent = device_get_parent(dev);
  493         int error, sent, read;
  494 
  495         if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT)))
  496                 return (error);
  497 
  498         if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
  499                 goto error;
  500 
  501         if ((error = iicbus_repeated_start(parent, slave | LSB, IICBUS_TIMEOUT)))
  502                 goto error;
  503 
  504         if ((error = iicbus_read(parent, buf, (int)*count, &read,
  505                                                 IIC_LAST_READ, IICBUS_TIMEOUT)))
  506                 goto error;
  507         *count = read;
  508 
  509 error:
  510         iicbus_stop(parent);
  511         return (error);
  512 }
  513 
  514 DRIVER_MODULE(iicsmb, iicbus, iicsmb_driver, iicsmb_devclass, 0, 0);
  515 DRIVER_MODULE(smbus, iicsmb, smbus_driver, smbus_devclass, 0, 0);
  516 MODULE_DEPEND(iicsmb, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
  517 MODULE_DEPEND(iicsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
  518 MODULE_VERSION(iicsmb, 1);

Cache object: 7a1ea24fe0f4764d3411c9bd9152a5cc


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.