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  * $FreeBSD: releng/5.2/sys/dev/iicbus/iicsmb.c 118728 2003-08-10 14:28:24Z ticso $
   27  *
   28  */
   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/kernel.h>
   50 #include <sys/systm.h>
   51 #include <sys/module.h>
   52 #include <sys/bus.h>
   53 #include <sys/uio.h>
   54 
   55 
   56 #include <dev/iicbus/iiconf.h>
   57 #include <dev/iicbus/iicbus.h>
   58 
   59 #include <dev/smbus/smbconf.h>
   60 
   61 #include "iicbus_if.h"
   62 #include "smbus_if.h"
   63 
   64 struct iicsmb_softc {
   65 
   66 #define SMB_WAITING_ADDR        0x0
   67 #define SMB_WAITING_LOW         0x1
   68 #define SMB_WAITING_HIGH        0x2
   69 #define SMB_DONE                0x3
   70         int state;
   71 
   72         u_char devaddr;                 /* slave device address */
   73 
   74         char low;                       /* low byte received first */
   75         char high;                      /* high byte */
   76 
   77         device_t smbus;
   78 };
   79 
   80 static int iicsmb_probe(device_t);
   81 static int iicsmb_attach(device_t);
   82 static int iicsmb_detach(device_t);
   83 static void iicsmb_identify(driver_t *driver, device_t parent);
   84 
   85 static void iicsmb_intr(device_t dev, int event, char *buf);
   86 static int iicsmb_callback(device_t dev, int index, caddr_t data);
   87 static int iicsmb_quick(device_t dev, u_char slave, int how);
   88 static int iicsmb_sendb(device_t dev, u_char slave, char byte);
   89 static int iicsmb_recvb(device_t dev, u_char slave, char *byte);
   90 static int iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
   91 static int iicsmb_writew(device_t dev, u_char slave, char cmd, short word);
   92 static int iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
   93 static int iicsmb_readw(device_t dev, u_char slave, char cmd, short *word);
   94 static int iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
   95 static int iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
   96 static int iicsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf);
   97 
   98 static devclass_t iicsmb_devclass;
   99 
  100 static device_method_t iicsmb_methods[] = {
  101         /* device interface */
  102         DEVMETHOD(device_identify,      iicsmb_identify),
  103         DEVMETHOD(device_probe,         iicsmb_probe),
  104         DEVMETHOD(device_attach,        iicsmb_attach),
  105         DEVMETHOD(device_detach,        iicsmb_detach),
  106 
  107         /* bus interface */
  108         DEVMETHOD(bus_driver_added,     bus_generic_driver_added),
  109         DEVMETHOD(bus_print_child,      bus_generic_print_child),
  110 
  111         /* iicbus interface */
  112         DEVMETHOD(iicbus_intr,          iicsmb_intr),
  113 
  114         /* smbus interface */
  115         DEVMETHOD(smbus_callback,       iicsmb_callback),
  116         DEVMETHOD(smbus_quick,          iicsmb_quick),
  117         DEVMETHOD(smbus_sendb,          iicsmb_sendb),
  118         DEVMETHOD(smbus_recvb,          iicsmb_recvb),
  119         DEVMETHOD(smbus_writeb,         iicsmb_writeb),
  120         DEVMETHOD(smbus_writew,         iicsmb_writew),
  121         DEVMETHOD(smbus_readb,          iicsmb_readb),
  122         DEVMETHOD(smbus_readw,          iicsmb_readw),
  123         DEVMETHOD(smbus_pcall,          iicsmb_pcall),
  124         DEVMETHOD(smbus_bwrite,         iicsmb_bwrite),
  125         DEVMETHOD(smbus_bread,          iicsmb_bread),
  126         
  127         { 0, 0 }
  128 };
  129 
  130 static driver_t iicsmb_driver = {
  131         "iicsmb",
  132         iicsmb_methods,
  133         sizeof(struct iicsmb_softc),
  134 };
  135 
  136 #define IICBUS_TIMEOUT  100     /* us */
  137 
  138 static void
  139 iicsmb_identify(driver_t *driver, device_t parent)
  140 {
  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 (0);
  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         bzero(sc, sizeof(*sc));
  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 
  176         return (0);
  177 }
  178 
  179 /*
  180  * iicsmb_intr()
  181  *
  182  * iicbus interrupt handler
  183  */
  184 static void
  185 iicsmb_intr(device_t dev, int event, char *buf)
  186 {
  187         struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev);
  188 
  189         switch (event) {
  190         case INTR_GENERAL:
  191         case INTR_START:
  192                 sc->state = SMB_WAITING_ADDR;
  193                 break;
  194 
  195         case INTR_STOP:
  196                 /* call smbus intr handler */
  197                 smbus_intr(sc->smbus, sc->devaddr,
  198                                 sc->low, sc->high, SMB_ENOERR);
  199                 break;
  200 
  201         case INTR_RECEIVE:
  202                 switch (sc->state) {
  203                 case SMB_DONE:
  204                         /* XXX too much data, discard */
  205                         printf("%s: too much data from 0x%x\n", __func__,
  206                                 sc->devaddr & 0xff);
  207                         goto end;
  208 
  209                 case SMB_WAITING_ADDR:
  210                         sc->devaddr = (u_char)*buf;
  211                         sc->state = SMB_WAITING_LOW;
  212                         break;
  213 
  214                 case SMB_WAITING_LOW:
  215                         sc->low = *buf;
  216                         sc->state = SMB_WAITING_HIGH;
  217                         break;
  218 
  219                 case SMB_WAITING_HIGH:
  220                         sc->high = *buf;
  221                         sc->state = SMB_DONE;
  222                         break;
  223                 }
  224 end:
  225                 break;
  226 
  227         case INTR_TRANSMIT:
  228         case INTR_NOACK:
  229                 break;
  230 
  231         case INTR_ERROR:
  232                 switch (*buf) {
  233                 case IIC_EBUSERR:
  234                         smbus_intr(sc->smbus, sc->devaddr, 0, 0, SMB_EBUSERR);
  235                         break;
  236 
  237                 default:
  238                         printf("%s unknown error 0x%x!\n", __func__,
  239                                                                 (int)*buf);
  240                         break;
  241                 }
  242                 break;
  243 
  244         default:
  245                 panic("%s: unknown event (%d)!", __func__, event);
  246         }
  247 
  248         return;
  249 }
  250 
  251 static int
  252 iicsmb_callback(device_t dev, int index, caddr_t data)
  253 {
  254         device_t parent = device_get_parent(dev);
  255         int error = 0;
  256         int how;
  257 
  258         switch (index) {
  259         case SMB_REQUEST_BUS:
  260                 /* request underlying iicbus */
  261                 how = *(int *)data;
  262                 error = iicbus_request_bus(parent, dev, how);
  263                 break;
  264 
  265         case SMB_RELEASE_BUS:
  266                 /* release underlying iicbus */
  267                 error = iicbus_release_bus(parent, dev);
  268                 break;
  269 
  270         default:
  271                 error = EINVAL;
  272         }
  273 
  274         return (error);
  275 }
  276 
  277 static int
  278 iicsmb_quick(device_t dev, u_char slave, int how)
  279 {
  280         device_t parent = device_get_parent(dev);
  281         int error;
  282 
  283         switch (how) {
  284         case SMB_QWRITE:
  285                 error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT);
  286                 break;
  287 
  288         case SMB_QREAD:
  289                 error = iicbus_start(parent, slave | LSB, IICBUS_TIMEOUT);
  290                 break;
  291 
  292         default:
  293                 error = EINVAL;
  294                 break;
  295         }
  296 
  297         if (!error)
  298                 error = iicbus_stop(parent);
  299 
  300         return (error);
  301 }
  302 
  303 static int
  304 iicsmb_sendb(device_t dev, u_char slave, char byte)
  305 {
  306         device_t parent = device_get_parent(dev);
  307         int error, sent;
  308 
  309         error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT);
  310 
  311         if (!error) {
  312                 error = iicbus_write(parent, &byte, 1, &sent, IICBUS_TIMEOUT);
  313 
  314                 iicbus_stop(parent);
  315         }
  316 
  317         return (error);
  318 }
  319 
  320 static int
  321 iicsmb_recvb(device_t dev, u_char slave, char *byte)
  322 {
  323         device_t parent = device_get_parent(dev);
  324         int error, read;
  325 
  326         error = iicbus_start(parent, slave | LSB, 0);
  327 
  328         if (!error) {
  329                 error = iicbus_read(parent, byte, 1, &read, IIC_LAST_READ, IICBUS_TIMEOUT);
  330 
  331                 iicbus_stop(parent);
  332         }
  333 
  334         return (error);
  335 }
  336 
  337 static int
  338 iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
  339 {
  340         device_t parent = device_get_parent(dev);
  341         int error, sent;
  342 
  343         error = iicbus_start(parent, slave & ~LSB, 0);
  344 
  345         if (!error) {
  346                 if (!(error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
  347                         error = iicbus_write(parent, &byte, 1, &sent, IICBUS_TIMEOUT);
  348 
  349                 iicbus_stop(parent);
  350         }
  351 
  352         return (error);
  353 }
  354 
  355 static int
  356 iicsmb_writew(device_t dev, u_char slave, char cmd, short word)
  357 {
  358         device_t parent = device_get_parent(dev);
  359         int error, sent;
  360 
  361         char low = (char)(word & 0xff);
  362         char high = (char)((word & 0xff00) >> 8);
  363 
  364         error = iicbus_start(parent, slave & ~LSB, 0);
  365 
  366         if (!error) {
  367                 if (!(error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
  368                   if (!(error = iicbus_write(parent, &low, 1, &sent, IICBUS_TIMEOUT)))
  369                     error = iicbus_write(parent, &high, 1, &sent, IICBUS_TIMEOUT);
  370 
  371                 iicbus_stop(parent);
  372         }
  373 
  374         return (error);
  375 }
  376 
  377 static int
  378 iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
  379 {
  380         device_t parent = device_get_parent(dev);
  381         int error, sent, read;
  382 
  383         if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT)))
  384                 return (error);
  385 
  386         if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
  387                 goto error;
  388 
  389         if ((error = iicbus_repeated_start(parent, slave | LSB, IICBUS_TIMEOUT)))
  390                 goto error;
  391 
  392         if ((error = iicbus_read(parent, byte, 1, &read, IIC_LAST_READ, IICBUS_TIMEOUT)))
  393                 goto error;
  394 
  395 error:
  396         iicbus_stop(parent);
  397         return (error);
  398 }
  399 
  400 #define BUF2SHORT(low,high) \
  401         ((short)(((high) & 0xff) << 8) | (short)((low) & 0xff))
  402 
  403 static int
  404 iicsmb_readw(device_t dev, u_char slave, char cmd, short *word)
  405 {
  406         device_t parent = device_get_parent(dev);
  407         int error, sent, read;
  408         char buf[2];
  409 
  410         if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT)))
  411                 return (error);
  412 
  413         if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
  414                 goto error;
  415 
  416         if ((error = iicbus_repeated_start(parent, slave | LSB, IICBUS_TIMEOUT)))
  417                 goto error;
  418 
  419         if ((error = iicbus_read(parent, buf, 2, &read, IIC_LAST_READ, IICBUS_TIMEOUT)))
  420                 goto error;
  421 
  422         /* first, receive low, then high byte */
  423         *word = BUF2SHORT(buf[0], buf[1]);
  424 
  425 error:
  426         iicbus_stop(parent);
  427         return (error);
  428 }
  429 
  430 static int
  431 iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
  432 {
  433         device_t parent = device_get_parent(dev);
  434         int error, sent, read;
  435         char buf[2];
  436 
  437         if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT)))
  438                 return (error);
  439 
  440         if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
  441                 goto error;
  442 
  443         /* first, send low, then high byte */
  444         buf[0] = (char)(sdata & 0xff);
  445         buf[1] = (char)((sdata & 0xff00) >> 8);
  446 
  447         if ((error = iicbus_write(parent, buf, 2, &sent, IICBUS_TIMEOUT)))
  448                 goto error;
  449 
  450         if ((error = iicbus_repeated_start(parent, slave | LSB, IICBUS_TIMEOUT)))
  451                 goto error;
  452 
  453         if ((error = iicbus_read(parent, buf, 2, &read, IIC_LAST_READ, IICBUS_TIMEOUT)))
  454                 goto error;
  455 
  456         /* first, receive low, then high byte */
  457         *rdata = BUF2SHORT(buf[0], buf[1]);
  458 
  459 error:
  460         iicbus_stop(parent);
  461         return (error);
  462 }
  463 
  464 static int
  465 iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
  466 {
  467         device_t parent = device_get_parent(dev);
  468         int error, sent;
  469 
  470         if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT)))
  471                 goto error;
  472 
  473         if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
  474                 goto error;
  475 
  476         if ((error = iicbus_write(parent, buf, (int)count, &sent, IICBUS_TIMEOUT)))
  477                 goto error;
  478 
  479         if ((error = iicbus_stop(parent)))
  480                 goto error;
  481 
  482 error:
  483         return (error);
  484 }
  485 
  486 static int
  487 iicsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
  488 {
  489         device_t parent = device_get_parent(dev);
  490         int error, sent, read;
  491 
  492         if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT)))
  493                 return (error);
  494 
  495         if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
  496                 goto error;
  497 
  498         if ((error = iicbus_repeated_start(parent, slave | LSB, IICBUS_TIMEOUT)))
  499                 goto error;
  500 
  501         if ((error = iicbus_read(parent, buf, (int)count, &read,
  502                                                 IIC_LAST_READ, IICBUS_TIMEOUT)))
  503                 goto error;
  504 
  505 error:
  506         iicbus_stop(parent);
  507         return (error);
  508 }
  509 
  510 DRIVER_MODULE(iicsmb, iicbus, iicsmb_driver, iicsmb_devclass, 0, 0);
  511 MODULE_DEPEND(iicsmb, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
  512 MODULE_DEPEND(iicsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
  513 MODULE_VERSION(iicsmb, 1);

Cache object: 88633ce34cbbfdf54d60a1b34ba661fb


[ 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.