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/iicbb.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  * Generic I2C bit-banging code
   32  *
   33  * Example:
   34  *
   35  *      iicbus
   36  *       /  \ 
   37  *    iicbb pcf
   38  *     |  \
   39  *   bti2c lpbb
   40  *
   41  * From Linux I2C generic interface
   42  * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
   43  *
   44  */
   45 
   46 #include <sys/param.h>
   47 #include <sys/kernel.h>
   48 #include <sys/systm.h>
   49 #include <sys/module.h>
   50 #include <sys/bus.h>
   51 #include <sys/uio.h>
   52 
   53 
   54 #include <dev/iicbus/iiconf.h>
   55 #include <dev/iicbus/iicbus.h>
   56 
   57 #include <dev/smbus/smbconf.h>
   58 
   59 #include "iicbus_if.h"
   60 #include "iicbb_if.h"
   61 
   62 struct iicbb_softc {
   63         device_t iicbus;
   64 };
   65 
   66 static int iicbb_attach(device_t);
   67 static void iicbb_child_detached(device_t, device_t);
   68 static int iicbb_detach(device_t);
   69 static int iicbb_print_child(device_t, device_t);
   70 static int iicbb_probe(device_t);
   71 
   72 static int iicbb_callback(device_t, int, caddr_t);
   73 static int iicbb_start(device_t, u_char, int);
   74 static int iicbb_stop(device_t);
   75 static int iicbb_write(device_t, const char *, int, int *, int);
   76 static int iicbb_read(device_t, char *, int, int *, int, int);
   77 static int iicbb_reset(device_t, u_char, u_char, u_char *);
   78 static int iicbb_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs);
   79 
   80 static device_method_t iicbb_methods[] = {
   81         /* device interface */
   82         DEVMETHOD(device_probe,         iicbb_probe),
   83         DEVMETHOD(device_attach,        iicbb_attach),
   84         DEVMETHOD(device_detach,        iicbb_detach),
   85 
   86         /* bus interface */
   87         DEVMETHOD(bus_child_detached,   iicbb_child_detached),
   88         DEVMETHOD(bus_print_child,      iicbb_print_child),
   89 
   90         /* iicbus interface */
   91         DEVMETHOD(iicbus_callback,      iicbb_callback),
   92         DEVMETHOD(iicbus_start,         iicbb_start),
   93         DEVMETHOD(iicbus_repeated_start, iicbb_start),
   94         DEVMETHOD(iicbus_stop,          iicbb_stop),
   95         DEVMETHOD(iicbus_write,         iicbb_write),
   96         DEVMETHOD(iicbus_read,          iicbb_read),
   97         DEVMETHOD(iicbus_reset,         iicbb_reset),
   98         DEVMETHOD(iicbus_transfer,      iicbb_transfer),
   99 
  100         { 0, 0 }
  101 };
  102 
  103 driver_t iicbb_driver = {
  104         "iicbb",
  105         iicbb_methods,
  106         sizeof(struct iicbb_softc),
  107 };
  108 
  109 devclass_t iicbb_devclass;
  110 
  111 static int
  112 iicbb_probe(device_t dev)
  113 {
  114         device_set_desc(dev, "I2C bit-banging driver");
  115 
  116         return (0);
  117 }
  118 
  119 static int
  120 iicbb_attach(device_t dev)
  121 {
  122         struct iicbb_softc *sc = (struct iicbb_softc *)device_get_softc(dev);
  123 
  124         sc->iicbus = device_add_child(dev, "iicbus", -1);
  125         if (!sc->iicbus)
  126                 return (ENXIO);
  127         bus_generic_attach(dev);
  128 
  129         return (0);
  130 }
  131 
  132 static int
  133 iicbb_detach(device_t dev)
  134 {
  135         struct iicbb_softc *sc = (struct iicbb_softc *)device_get_softc(dev);
  136         device_t child;
  137 
  138         /*
  139          * We need to save child because the detach indirectly causes
  140          * sc->iicbus to be zeroed.  Since we added the device
  141          * unconditionally in iicbb_attach, we need to make sure we
  142          * delete it here.  See iicbb_child_detached.  We need that
  143          * callback in case newbus detached our children w/o detaching
  144          * us (say iicbus is a module and unloaded w/o iicbb being
  145          * unloaded).
  146          */
  147         child = sc->iicbus;
  148         bus_generic_detach(dev);
  149         if (child)
  150                 device_delete_child(dev, child);
  151 
  152         return (0);
  153 }
  154 
  155 static void
  156 iicbb_child_detached( device_t dev, device_t child )
  157 {
  158         struct iicbb_softc *sc = (struct iicbb_softc *)device_get_softc(dev);
  159 
  160         if (child == sc->iicbus)
  161                 sc->iicbus = NULL;
  162 }
  163 
  164 static int
  165 iicbb_print_child(device_t bus, device_t dev)
  166 {
  167         int error;
  168         int retval = 0;
  169         u_char oldaddr;
  170 
  171         retval += bus_print_child_header(bus, dev);
  172         /* retrieve the interface I2C address */
  173         error = IICBB_RESET(device_get_parent(bus), IIC_FASTEST, 0, &oldaddr);
  174         if (error == IIC_ENOADDR) {
  175                 retval += printf(" on %s master-only\n",
  176                                  device_get_nameunit(bus));
  177         } else {
  178                 /* restore the address */
  179                 IICBB_RESET(device_get_parent(bus), IIC_FASTEST, oldaddr, NULL);
  180 
  181                 retval += printf(" on %s addr 0x%x\n",
  182                                  device_get_nameunit(bus), oldaddr & 0xff);
  183         }
  184 
  185         return (retval);
  186 }
  187 
  188 #define IIC_DELAY       10
  189 
  190 #define I2C_SETSDA(dev,val) do {                        \
  191         IICBB_SETSDA(device_get_parent(dev), val);      \
  192         DELAY(IIC_DELAY);                               \
  193         } while (0)
  194 
  195 #define I2C_SETSCL(dev,val) do {                        \
  196         iicbb_setscl(dev, val, 100);                    \
  197         } while (0)
  198 
  199 #define I2C_SET(dev,ctrl,data) do {                     \
  200         I2C_SETSCL(dev, ctrl);                          \
  201         I2C_SETSDA(dev, data);                          \
  202         } while (0)
  203 
  204 #define I2C_GETSDA(dev) (IICBB_GETSDA(device_get_parent(dev)))
  205 
  206 #define I2C_GETSCL(dev) (IICBB_GETSCL(device_get_parent(dev)))
  207 
  208 static int i2c_debug = 0;
  209 #define I2C_DEBUG(x)    do {                                    \
  210                                 if (i2c_debug) (x);             \
  211                         } while (0)
  212 
  213 #define I2C_LOG(format,args...) do {                            \
  214                                         printf(format, args);   \
  215                                 } while (0)
  216 
  217 static void
  218 iicbb_setscl(device_t dev, int val, int timeout)
  219 {
  220         int k = 0;
  221 
  222         IICBB_SETSCL(device_get_parent(dev), val);
  223         DELAY(IIC_DELAY);
  224 
  225         while (val && !I2C_GETSCL(dev) && k++ < timeout) {
  226                 IICBB_SETSCL(device_get_parent(dev), val);
  227                 DELAY(IIC_DELAY);
  228         }
  229                 
  230         return;
  231 }
  232 
  233 static void
  234 iicbb_one(device_t dev, int timeout)
  235 {
  236         I2C_SET(dev,0,1);
  237         I2C_SET(dev,1,1);
  238         I2C_SET(dev,0,1);
  239         return;
  240 }
  241 
  242 static void
  243 iicbb_zero(device_t dev, int timeout)
  244 {
  245         I2C_SET(dev,0,0);
  246         I2C_SET(dev,1,0);
  247         I2C_SET(dev,0,0);
  248         return;
  249 }
  250 
  251 /*
  252  * Waiting for ACKNOWLEDGE.
  253  *
  254  * When a chip is being addressed or has received data it will issue an
  255  * ACKNOWLEDGE pulse. Therefore the MASTER must release the DATA line
  256  * (set it to high level) and then release the CLOCK line.
  257  * Now it must wait for the SLAVE to pull the DATA line low.
  258  * Actually on the bus this looks like a START condition so nothing happens
  259  * because of the fact that the IC's that have not been addressed are doing
  260  * nothing.
  261  *
  262  * When the SLAVE has pulled this line low the MASTER will take the CLOCK
  263  * line low and then the SLAVE will release the SDA (data) line.
  264  */
  265 static int
  266 iicbb_ack(device_t dev, int timeout)
  267 {
  268         int noack;
  269         int k = 0;
  270     
  271         I2C_SET(dev,0,1);
  272         I2C_SET(dev,1,1);
  273         do {
  274                 noack = I2C_GETSDA(dev);
  275                 if (!noack)
  276                         break;
  277                 DELAY(10);
  278                 k += 10;
  279         } while (k < timeout);
  280 
  281         I2C_SET(dev,0,1);
  282         I2C_DEBUG(printf("%c ",noack?'-':'+'));
  283 
  284         return (noack);
  285 }
  286 
  287 static void
  288 iicbb_sendbyte(device_t dev, u_char data, int timeout)
  289 {
  290         int i;
  291     
  292         for (i=7; i>=0; i--) {
  293                 if (data&(1<<i)) {
  294                         iicbb_one(dev, timeout);
  295                 } else {
  296                         iicbb_zero(dev, timeout);
  297                 }
  298         }
  299         I2C_DEBUG(printf("w%02x",(int)data));
  300         return;
  301 }
  302 
  303 static u_char
  304 iicbb_readbyte(device_t dev, int last, int timeout)
  305 {
  306         int i;
  307         unsigned char data=0;
  308     
  309         I2C_SET(dev,0,1);
  310         for (i=7; i>=0; i--) 
  311         {
  312                 I2C_SET(dev,1,1);
  313                 if (I2C_GETSDA(dev))
  314                         data |= (1<<i);
  315                 I2C_SET(dev,0,1);
  316         }
  317         if (last) {
  318                 iicbb_one(dev, timeout);
  319         } else {
  320                 iicbb_zero(dev, timeout);
  321         }
  322         I2C_DEBUG(printf("r%02x%c ",(int)data,last?'-':'+'));
  323         return data;
  324 }
  325 
  326 static int
  327 iicbb_callback(device_t dev, int index, caddr_t data)
  328 {
  329         return (IICBB_CALLBACK(device_get_parent(dev), index, data));
  330 }
  331 
  332 static int
  333 iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
  334 {
  335         return (IICBB_RESET(device_get_parent(dev), speed, addr, oldaddr));
  336 }
  337 
  338 static int
  339 iicbb_start(device_t dev, u_char slave, int timeout)
  340 {
  341         int error;
  342 
  343         I2C_DEBUG(printf("<"));
  344 
  345         I2C_SET(dev,1,1);
  346         I2C_SET(dev,1,0);
  347         I2C_SET(dev,0,0);
  348 
  349         /* send address */
  350         iicbb_sendbyte(dev, slave, timeout);
  351 
  352         /* check for ack */
  353         if (iicbb_ack(dev, timeout)) {
  354                 error = IIC_ENOACK;
  355                 goto error;
  356         }
  357 
  358         return(0);
  359 
  360 error:
  361         iicbb_stop(dev);
  362         return (error);
  363 }
  364 
  365 static int
  366 iicbb_stop(device_t dev)
  367 {
  368         I2C_SET(dev,0,0);
  369         I2C_SET(dev,1,0);
  370         I2C_SET(dev,1,1);
  371         I2C_DEBUG(printf(">"));
  372         return (0);
  373 }
  374 
  375 static int
  376 iicbb_write(device_t dev, const char *buf, int len, int *sent, int timeout)
  377 {
  378         int bytes, error = 0;
  379 
  380         bytes = 0;
  381         while (len) {
  382                 /* send byte */
  383                 iicbb_sendbyte(dev,(u_char)*buf++, timeout);
  384 
  385                 /* check for ack */
  386                 if (iicbb_ack(dev, timeout)) {
  387                         error = IIC_ENOACK;
  388                         goto error;
  389                 }
  390                 bytes ++;
  391                 len --;
  392         }
  393 
  394 error:
  395         *sent = bytes;
  396         return (error);
  397 }
  398 
  399 static int
  400 iicbb_read(device_t dev, char * buf, int len, int *read, int last, int delay)
  401 {
  402         int bytes;
  403 
  404         bytes = 0;
  405         while (len) {
  406                 /* XXX should insert delay here */
  407                 *buf++ = (char)iicbb_readbyte(dev, (len == 1) ? last : 0, delay);
  408 
  409                 bytes ++;
  410                 len --;
  411         }
  412 
  413         *read = bytes;
  414         return (0);
  415 }
  416 
  417 static int
  418 iicbb_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
  419 {
  420         int error;
  421 
  422         error = IICBB_PRE_XFER(device_get_parent(dev));
  423         if (error)
  424                 return (error);
  425 
  426         error = iicbus_transfer_gen(dev, msgs, nmsgs);
  427 
  428         IICBB_POST_XFER(device_get_parent(dev));
  429         return (error);
  430 }
  431 
  432 DRIVER_MODULE(iicbus, iicbb, iicbus_driver, iicbus_devclass, 0, 0);
  433 
  434 MODULE_DEPEND(iicbb, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
  435 MODULE_VERSION(iicbb, IICBB_MODVER);

Cache object: 56420d423d1da5ccfd06d90491a90309


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