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/pcf/pcf.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 Nicolas Souchu, Marc Bouget
    3  * Copyright (c) 2004 Joerg Wunsch
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD: releng/9.0/sys/dev/pcf/pcf.c 194026 2009-06-11 17:15:44Z avg $");
   30 
   31 #include <sys/param.h>
   32 #include <sys/bus.h>
   33 #include <sys/lock.h>
   34 #include <sys/kernel.h>
   35 #include <sys/module.h>
   36 #include <sys/mutex.h>
   37 #include <sys/systm.h>
   38 
   39 #include <machine/bus.h>
   40 #include <machine/resource.h>
   41 
   42 #include <sys/rman.h>
   43 
   44 #include <dev/iicbus/iicbus.h>
   45 #include <dev/iicbus/iiconf.h>
   46 #include <dev/pcf/pcfvar.h>
   47 #include "iicbus_if.h"
   48 
   49 /* Not so official debugging option. */
   50 /* #define PCFDEBUG */
   51 
   52 static int pcf_wait_byte(struct pcf_softc *pcf);
   53 static int pcf_noack(struct pcf_softc *pcf, int timeout);
   54 static void pcf_stop_locked(struct pcf_softc *pcf);
   55 
   56 /*
   57  * Polling mode for master operations wait for a new
   58  * byte incoming or outgoing
   59  */
   60 static int
   61 pcf_wait_byte(struct pcf_softc *sc)
   62 {
   63         int counter = TIMEOUT;
   64 
   65         PCF_ASSERT_LOCKED(sc);
   66         while (counter--) {
   67 
   68                 if ((pcf_get_S1(sc) & PIN) == 0)
   69                         return (0);
   70         }
   71 
   72 #ifdef PCFDEBUG
   73         printf("pcf: timeout!\n");
   74 #endif
   75 
   76         return (IIC_ETIMEOUT);
   77 }
   78 
   79 static void
   80 pcf_stop_locked(struct pcf_softc *sc)
   81 {
   82 
   83         PCF_ASSERT_LOCKED(sc);
   84 #ifdef PCFDEBUG
   85         device_printf(dev, " >> stop\n");
   86 #endif
   87         /*
   88          * Send STOP condition iff the START condition was previously sent.
   89          * STOP is sent only once even if an iicbus_stop() is called after
   90          * an iicbus_read()... see pcf_read(): the PCF needs to send the stop
   91          * before the last char is read.
   92          */
   93         if (sc->pcf_started) {
   94                 /* set stop condition and enable IT */
   95                 pcf_set_S1(sc, PIN|ESO|ENI|STO|ACK);
   96 
   97                 sc->pcf_started = 0;
   98         }
   99 }
  100 
  101 static int
  102 pcf_noack(struct pcf_softc *sc, int timeout)
  103 {
  104         int noack;
  105         int k = timeout/10;
  106 
  107         PCF_ASSERT_LOCKED(sc);
  108         do {
  109                 noack = pcf_get_S1(sc) & LRB;
  110                 if (!noack)
  111                         break;
  112                 DELAY(10);                              /* XXX wait 10 us */
  113         } while (k--);
  114 
  115         return (noack);
  116 }
  117 
  118 int
  119 pcf_repeated_start(device_t dev, u_char slave, int timeout)
  120 {
  121         struct pcf_softc *sc = DEVTOSOFTC(dev);
  122         int error = 0;
  123 
  124         PCF_LOCK(sc);
  125 #ifdef PCFDEBUG
  126         device_printf(dev, " >> repeated start for slave %#x\n",
  127                       (unsigned)slave);
  128 #endif
  129         /* repeated start */
  130         pcf_set_S1(sc, ESO|STA|STO|ACK);
  131 
  132         /* set slave address to PCF. Last bit (LSB) must be set correctly
  133          * according to transfer direction */
  134         pcf_set_S0(sc, slave);
  135 
  136         /* wait for address sent, polling */
  137         if ((error = pcf_wait_byte(sc)))
  138                 goto error;
  139 
  140         /* check for ack */
  141         if (pcf_noack(sc, timeout)) {
  142                 error = IIC_ENOACK;
  143 #ifdef PCFDEBUG
  144                 printf("pcf: no ack on repeated_start!\n");
  145 #endif
  146                 goto error;
  147         }
  148 
  149         PCF_UNLOCK(sc);
  150         return (0);
  151 
  152 error:
  153         pcf_stop_locked(sc);
  154         PCF_UNLOCK(sc);
  155         return (error);
  156 }
  157 
  158 int
  159 pcf_start(device_t dev, u_char slave, int timeout)
  160 {
  161         struct pcf_softc *sc = DEVTOSOFTC(dev);
  162         int error = 0;
  163 
  164         PCF_LOCK(sc);
  165 #ifdef PCFDEBUG
  166         device_printf(dev, " >> start for slave %#x\n", (unsigned)slave);
  167 #endif
  168         if ((pcf_get_S1(sc) & nBB) == 0) {
  169 #ifdef PCFDEBUG
  170                 printf("pcf: busy!\n");
  171 #endif
  172                 PCF_UNLOCK(sc);
  173                 return (IIC_EBUSBSY);
  174         }
  175 
  176         /* set slave address to PCF. Last bit (LSB) must be set correctly
  177          * according to transfer direction */
  178         pcf_set_S0(sc, slave);
  179 
  180         /* START only */
  181         pcf_set_S1(sc, PIN|ESO|STA|ACK);
  182 
  183         sc->pcf_started = 1;
  184 
  185         /* wait for address sent, polling */
  186         if ((error = pcf_wait_byte(sc)))
  187                 goto error;
  188 
  189         /* check for ACK */
  190         if (pcf_noack(sc, timeout)) {
  191                 error = IIC_ENOACK;
  192 #ifdef PCFDEBUG
  193                 printf("pcf: no ack on start!\n");
  194 #endif
  195                 goto error;
  196         }
  197 
  198         PCF_UNLOCK(sc);
  199         return (0);
  200 
  201 error:
  202         pcf_stop_locked(sc);
  203         PCF_UNLOCK(sc);
  204         return (error);
  205 }
  206 
  207 int
  208 pcf_stop(device_t dev)
  209 {
  210         struct pcf_softc *sc = DEVTOSOFTC(dev);
  211 
  212 #ifdef PCFDEBUG
  213         device_printf(dev, " >> stop\n");
  214 #endif
  215         PCF_LOCK(sc);
  216         pcf_stop_locked(sc);
  217         PCF_UNLOCK(sc);
  218 
  219         return (0);
  220 }
  221 
  222 void
  223 pcf_intr(void *arg)
  224 {
  225         struct pcf_softc *sc = arg;
  226         char data, status, addr;
  227         char error = 0;
  228 
  229         PCF_LOCK(sc);
  230         status = pcf_get_S1(sc);
  231 
  232         if (status & PIN) {
  233                 printf("pcf: spurious interrupt, status=0x%x\n",
  234                        status & 0xff);
  235 
  236                 goto error;
  237         }
  238 
  239         if (status & LAB)
  240                 printf("pcf: bus arbitration lost!\n");
  241 
  242         if (status & BER) {
  243                 error = IIC_EBUSERR;
  244                 iicbus_intr(sc->iicbus, INTR_ERROR, &error);
  245 
  246                 goto error;
  247         }
  248 
  249         do {
  250                 status = pcf_get_S1(sc);
  251 
  252                 switch(sc->pcf_slave_mode) {
  253 
  254                 case SLAVE_TRANSMITTER:
  255                         if (status & LRB) {
  256                                 /* ack interrupt line */
  257                                 dummy_write(sc);
  258 
  259                                 /* no ack, don't send anymore */
  260                                 sc->pcf_slave_mode = SLAVE_RECEIVER;
  261 
  262                                 iicbus_intr(sc->iicbus, INTR_NOACK, NULL);
  263                                 break;
  264                         }
  265 
  266                         /* get data from upper code */
  267                         iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data);
  268 
  269                         pcf_set_S0(sc, data);
  270                         break;
  271 
  272                 case SLAVE_RECEIVER:
  273                         if (status & AAS) {
  274                                 addr = pcf_get_S0(sc);
  275 
  276                                 if (status & AD0)
  277                                         iicbus_intr(sc->iicbus, INTR_GENERAL, &addr);
  278                                 else
  279                                         iicbus_intr(sc->iicbus, INTR_START, &addr);
  280 
  281                                 if (addr & LSB) {
  282                                         sc->pcf_slave_mode = SLAVE_TRANSMITTER;
  283 
  284                                         /* get the first char from upper code */
  285                                         iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data);
  286 
  287                                         /* send first data byte */
  288                                         pcf_set_S0(sc, data);
  289                                 }
  290 
  291                                 break;
  292                         }
  293 
  294                         /* stop condition received? */
  295                         if (status & STS) {
  296                                 /* ack interrupt line */
  297                                 dummy_read(sc);
  298 
  299                                 /* emulate intr stop condition */
  300                                 iicbus_intr(sc->iicbus, INTR_STOP, NULL);
  301 
  302                         } else {
  303                                 /* get data, ack interrupt line */
  304                                 data = pcf_get_S0(sc);
  305 
  306                                 /* deliver the character */
  307                                 iicbus_intr(sc->iicbus, INTR_RECEIVE, &data);
  308                         }
  309                         break;
  310 
  311                     default:
  312                         panic("%s: unknown slave mode (%d)!", __func__,
  313                                 sc->pcf_slave_mode);
  314                     }
  315 
  316         } while ((pcf_get_S1(sc) & PIN) == 0);
  317         PCF_UNLOCK(sc);
  318 
  319         return;
  320 
  321 error:
  322         /* unknown event on bus...reset PCF */
  323         pcf_set_S1(sc, PIN|ESO|ENI|ACK);
  324 
  325         sc->pcf_slave_mode = SLAVE_RECEIVER;
  326         PCF_UNLOCK(sc);
  327 
  328         return;
  329 }
  330 
  331 int
  332 pcf_rst_card(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
  333 {
  334         struct pcf_softc *sc = DEVTOSOFTC(dev);
  335 
  336         PCF_LOCK(sc);
  337         if (oldaddr)
  338                 *oldaddr = sc->pcf_addr;
  339 
  340         /* retrieve own address from bus level */
  341         if (!addr)
  342                 sc->pcf_addr = PCF_DEFAULT_ADDR;
  343         else
  344                 sc->pcf_addr = addr;
  345 
  346         pcf_set_S1(sc, PIN);                            /* initialize S1 */
  347 
  348         /* own address S'O<>0 */
  349         pcf_set_S0(sc, sc->pcf_addr >> 1);
  350 
  351         /* select clock register */
  352         pcf_set_S1(sc, PIN|ES1);
  353 
  354         /* select bus speed : 18=90kb, 19=45kb, 1A=11kb, 1B=1.5kb */
  355         switch (speed) {
  356         case IIC_SLOW:
  357                 pcf_set_S0(sc,  0x1b); /* XXX Sun uses 0x1f */
  358                 break;
  359 
  360         case IIC_FAST:
  361                 pcf_set_S0(sc,  0x19); /* XXX Sun: 0x1d */
  362                 break;
  363 
  364         case IIC_UNKNOWN:
  365         case IIC_FASTEST:
  366         default:
  367                 pcf_set_S0(sc,  0x18); /* XXX Sun: 0x1c */
  368                 break;
  369         }
  370 
  371         /* set bus on, ack=yes, INT=yes */
  372         pcf_set_S1(sc, PIN|ESO|ENI|ACK);
  373 
  374         sc->pcf_slave_mode = SLAVE_RECEIVER;
  375         PCF_UNLOCK(sc);
  376 
  377         return (0);
  378 }
  379 
  380 int
  381 pcf_write(device_t dev, const char *buf, int len, int *sent, int timeout /* us */)
  382 {
  383         struct pcf_softc *sc = DEVTOSOFTC(dev);
  384         int bytes, error = 0;
  385 
  386 #ifdef PCFDEBUG
  387         device_printf(dev, " >> writing %d bytes: %#x%s\n", len,
  388                       (unsigned)buf[0], len > 1? "...": "");
  389 #endif
  390 
  391         bytes = 0;
  392         PCF_LOCK(sc);
  393         while (len) {
  394 
  395                 pcf_set_S0(sc, *buf++);
  396 
  397                 /* wait for the byte to be send */
  398                 if ((error = pcf_wait_byte(sc)))
  399                         goto error;
  400 
  401                 /* check if ack received */
  402                 if (pcf_noack(sc, timeout)) {
  403                         error = IIC_ENOACK;
  404                         goto error;
  405                 }
  406 
  407                 len --;
  408                 bytes ++;
  409         }
  410 
  411 error:
  412         *sent = bytes;
  413         PCF_UNLOCK(sc);
  414 
  415 #ifdef PCFDEBUG
  416         device_printf(dev, " >> %d bytes written (%d)\n", bytes, error);
  417 #endif
  418 
  419         return (error);
  420 }
  421 
  422 int
  423 pcf_read(device_t dev, char *buf, int len, int *read, int last,
  424          int delay /* us */)
  425 {
  426         struct pcf_softc *sc = DEVTOSOFTC(dev);
  427         int bytes, error = 0;
  428 #ifdef PCFDEBUG
  429         char *obuf = buf;
  430 
  431         device_printf(dev, " << reading %d bytes\n", len);
  432 #endif
  433 
  434         PCF_LOCK(sc);
  435         /* trig the bus to get the first data byte in S0 */
  436         if (len) {
  437                 if (len == 1 && last)
  438                         /* just one byte to read */
  439                         pcf_set_S1(sc, ESO);            /* no ack */
  440 
  441                 dummy_read(sc);
  442         }
  443 
  444         bytes = 0;
  445         while (len) {
  446 
  447                 /* XXX delay needed here */
  448 
  449                 /* wait for trigged byte */
  450                 if ((error = pcf_wait_byte(sc))) {
  451                         pcf_stop_locked(sc);
  452                         goto error;
  453                 }
  454 
  455                 if (len == 1 && last)
  456                         /* ok, last data byte already in S0, no I2C activity
  457                          * on next pcf_get_S0() */
  458                         pcf_stop_locked(sc);
  459 
  460                 else if (len == 2 && last)
  461                         /* next trigged byte with no ack */
  462                         pcf_set_S1(sc, ESO);
  463 
  464                 /* receive byte, trig next byte */
  465                 *buf++ = pcf_get_S0(sc);
  466 
  467                 len --;
  468                 bytes ++;
  469         };
  470 
  471 error:
  472         *read = bytes;
  473         PCF_UNLOCK(sc);
  474 
  475 #ifdef PCFDEBUG
  476         device_printf(dev, " << %d bytes read (%d): %#x%s\n", bytes, error,
  477                       (unsigned)obuf[0], bytes > 1? "...": "");
  478 #endif
  479 
  480         return (error);
  481 }
  482 
  483 DRIVER_MODULE(iicbus, pcf, iicbus_driver, iicbus_devclass, 0, 0);
  484 MODULE_DEPEND(pcf, iicbus, PCF_MINVER, PCF_PREFVER, PCF_MAXVER);
  485 MODULE_VERSION(pcf, PCF_MODVER);

Cache object: 2de7786e8549f6e48e5bc45906d5d50f


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