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$");
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/kernel.h>
   34 #include <sys/module.h>
   35 #include <sys/bus.h>
   36 
   37 #include <machine/bus.h>
   38 #include <machine/resource.h>
   39 
   40 #include <sys/rman.h>
   41 
   42 #include <dev/iicbus/iiconf.h>
   43 #include <dev/pcf/pcfvar.h>
   44 #include "iicbus_if.h"
   45 
   46 /* Not so official debugging option. */
   47 /* #define PCFDEBUG */
   48 
   49 static int pcf_wait_byte(struct pcf_softc *pcf);
   50 static int pcf_noack(struct pcf_softc *pcf, int timeout);
   51 
   52 /*
   53  * Polling mode for master operations wait for a new
   54  * byte incomming or outgoing
   55  */
   56 int
   57 pcf_wait_byte(struct pcf_softc *sc)
   58 {
   59         int counter = TIMEOUT;
   60 
   61         while (counter--) {
   62 
   63                 if ((pcf_get_S1(sc) & PIN) == 0)
   64                         return (0);
   65         }
   66 
   67 #ifdef PCFDEBUG
   68         printf("pcf: timeout!\n");
   69 #endif
   70 
   71         return (IIC_ETIMEOUT);
   72 }
   73 
   74 int
   75 pcf_stop(device_t dev)
   76 {
   77         struct pcf_softc *sc = DEVTOSOFTC(dev);
   78 
   79 #ifdef PCFDEBUG
   80         device_printf(dev, " >> stop\n");
   81 #endif
   82         /*
   83          * Send STOP condition iff the START condition was previously sent.
   84          * STOP is sent only once even if an iicbus_stop() is called after
   85          * an iicbus_read()... see pcf_read(): the PCF needs to send the stop
   86          * before the last char is read.
   87          */
   88         if (sc->pcf_started) {
   89                 /* set stop condition and enable IT */
   90                 pcf_set_S1(sc, PIN|ESO|ENI|STO|ACK);
   91 
   92                 sc->pcf_started = 0;
   93         }
   94 
   95         return (0);
   96 }
   97 
   98 
   99 int
  100 pcf_noack(struct pcf_softc *sc, int timeout)
  101 {
  102         int noack;
  103         int k = timeout/10;
  104 
  105         do {
  106                 noack = pcf_get_S1(sc) & LRB;
  107                 if (!noack)
  108                         break;
  109                 DELAY(10);                              /* XXX wait 10 us */
  110         } while (k--);
  111 
  112         return (noack);
  113 }
  114 
  115 int
  116 pcf_repeated_start(device_t dev, u_char slave, int timeout)
  117 {
  118         struct pcf_softc *sc = DEVTOSOFTC(dev);
  119         int error = 0;
  120 
  121 #ifdef PCFDEBUG
  122         device_printf(dev, " >> repeated start for slave %#x\n",
  123                       (unsigned)slave);
  124 #endif
  125         /* repeated start */
  126         pcf_set_S1(sc, ESO|STA|STO|ACK);
  127 
  128         /* set slave address to PCF. Last bit (LSB) must be set correctly
  129          * according to transfer direction */
  130         pcf_set_S0(sc, slave);
  131 
  132         /* wait for address sent, polling */
  133         if ((error = pcf_wait_byte(sc)))
  134                 goto error;
  135 
  136         /* check for ack */
  137         if (pcf_noack(sc, timeout)) {
  138                 error = IIC_ENOACK;
  139 #ifdef PCFDEBUG
  140                 printf("pcf: no ack on repeated_start!\n");
  141 #endif
  142                 goto error;
  143         }
  144 
  145         return (0);
  146 
  147 error:
  148         pcf_stop(dev);
  149         return (error);
  150 }
  151 
  152 int
  153 pcf_start(device_t dev, u_char slave, int timeout)
  154 {
  155         struct pcf_softc *sc = DEVTOSOFTC(dev);
  156         int error = 0;
  157 
  158 #ifdef PCFDEBUG
  159         device_printf(dev, " >> start for slave %#x\n", (unsigned)slave);
  160 #endif
  161         if ((pcf_get_S1(sc) & nBB) == 0) {
  162 #ifdef PCFDEBUG
  163                 printf("pcf: busy!\n");
  164 #endif
  165                 return (IIC_EBUSBSY);
  166         }
  167 
  168         /* set slave address to PCF. Last bit (LSB) must be set correctly
  169          * according to transfer direction */
  170         pcf_set_S0(sc, slave);
  171 
  172         /* START only */
  173         pcf_set_S1(sc, PIN|ESO|STA|ACK);
  174 
  175         sc->pcf_started = 1;
  176 
  177         /* wait for address sent, polling */
  178         if ((error = pcf_wait_byte(sc)))
  179                 goto error;
  180 
  181         /* check for ACK */
  182         if (pcf_noack(sc, timeout)) {
  183                 error = IIC_ENOACK;
  184 #ifdef PCFDEBUG
  185                 printf("pcf: no ack on start!\n");
  186 #endif
  187                 goto error;
  188         }
  189 
  190         return (0);
  191 
  192 error:
  193         pcf_stop(dev);
  194         return (error);
  195 }
  196 
  197 void
  198 pcf_intr(void *arg)
  199 {
  200         struct pcf_softc *sc = arg;
  201         char data, status, addr;
  202         char error = 0;
  203 
  204         status = pcf_get_S1(sc);
  205 
  206         if (status & PIN) {
  207                 printf("pcf: spurious interrupt, status=0x%x\n",
  208                        status & 0xff);
  209 
  210                 goto error;
  211         }
  212 
  213         if (status & LAB)
  214                 printf("pcf: bus arbitration lost!\n");
  215 
  216         if (status & BER) {
  217                 error = IIC_EBUSERR;
  218                 iicbus_intr(sc->iicbus, INTR_ERROR, &error);
  219 
  220                 goto error;
  221         }
  222 
  223         do {
  224                 status = pcf_get_S1(sc);
  225 
  226                 switch(sc->pcf_slave_mode) {
  227 
  228                 case SLAVE_TRANSMITTER:
  229                         if (status & LRB) {
  230                                 /* ack interrupt line */
  231                                 dummy_write(sc);
  232 
  233                                 /* no ack, don't send anymore */
  234                                 sc->pcf_slave_mode = SLAVE_RECEIVER;
  235 
  236                                 iicbus_intr(sc->iicbus, INTR_NOACK, NULL);
  237                                 break;
  238                         }
  239 
  240                         /* get data from upper code */
  241                         iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data);
  242 
  243                         pcf_set_S0(sc, data);
  244                         break;
  245 
  246                 case SLAVE_RECEIVER:
  247                         if (status & AAS) {
  248                                 addr = pcf_get_S0(sc);
  249 
  250                                 if (status & AD0)
  251                                         iicbus_intr(sc->iicbus, INTR_GENERAL, &addr);
  252                                 else
  253                                         iicbus_intr(sc->iicbus, INTR_START, &addr);
  254 
  255                                 if (addr & LSB) {
  256                                         sc->pcf_slave_mode = SLAVE_TRANSMITTER;
  257 
  258                                         /* get the first char from upper code */
  259                                         iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data);
  260 
  261                                         /* send first data byte */
  262                                         pcf_set_S0(sc, data);
  263                                 }
  264 
  265                                 break;
  266                         }
  267 
  268                         /* stop condition received? */
  269                         if (status & STS) {
  270                                 /* ack interrupt line */
  271                                 dummy_read(sc);
  272 
  273                                 /* emulate intr stop condition */
  274                                 iicbus_intr(sc->iicbus, INTR_STOP, NULL);
  275 
  276                         } else {
  277                                 /* get data, ack interrupt line */
  278                                 data = pcf_get_S0(sc);
  279 
  280                                 /* deliver the character */
  281                                 iicbus_intr(sc->iicbus, INTR_RECEIVE, &data);
  282                         }
  283                         break;
  284 
  285                     default:
  286                         panic("%s: unknown slave mode (%d)!", __func__,
  287                                 sc->pcf_slave_mode);
  288                     }
  289 
  290         } while ((pcf_get_S1(sc) & PIN) == 0);
  291 
  292         return;
  293 
  294 error:
  295         /* unknown event on bus...reset PCF */
  296         pcf_set_S1(sc, PIN|ESO|ENI|ACK);
  297 
  298         sc->pcf_slave_mode = SLAVE_RECEIVER;
  299 
  300         return;
  301 }
  302 
  303 int
  304 pcf_rst_card(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
  305 {
  306         struct pcf_softc *sc = DEVTOSOFTC(dev);
  307 
  308         if (oldaddr)
  309                 *oldaddr = sc->pcf_addr;
  310 
  311         /* retrieve own address from bus level */
  312         if (!addr)
  313                 sc->pcf_addr = PCF_DEFAULT_ADDR;
  314         else
  315                 sc->pcf_addr = addr;
  316 
  317         pcf_set_S1(sc, PIN);                            /* initialize S1 */
  318 
  319         /* own address S'O<>0 */
  320         pcf_set_S0(sc, sc->pcf_addr >> 1);
  321 
  322         /* select clock register */
  323         pcf_set_S1(sc, PIN|ES1);
  324 
  325         /* select bus speed : 18=90kb, 19=45kb, 1A=11kb, 1B=1.5kb */
  326         switch (speed) {
  327         case IIC_SLOW:
  328                 pcf_set_S0(sc,  0x1b); /* XXX Sun uses 0x1f */
  329                 break;
  330 
  331         case IIC_FAST:
  332                 pcf_set_S0(sc,  0x19); /* XXX Sun: 0x1d */
  333                 break;
  334 
  335         case IIC_UNKNOWN:
  336         case IIC_FASTEST:
  337         default:
  338                 pcf_set_S0(sc,  0x18); /* XXX Sun: 0x1c */
  339                 break;
  340         }
  341 
  342         /* set bus on, ack=yes, INT=yes */
  343         pcf_set_S1(sc, PIN|ESO|ENI|ACK);
  344 
  345         sc->pcf_slave_mode = SLAVE_RECEIVER;
  346 
  347         return (0);
  348 }
  349 
  350 int
  351 pcf_write(device_t dev, char *buf, int len, int *sent, int timeout /* us */)
  352 {
  353         struct pcf_softc *sc = DEVTOSOFTC(dev);
  354         int bytes, error = 0;
  355 
  356 #ifdef PCFDEBUG
  357         device_printf(dev, " >> writing %d bytes: %#x%s\n", len,
  358                       (unsigned)buf[0], len > 1? "...": "");
  359 #endif
  360 
  361         bytes = 0;
  362         while (len) {
  363 
  364                 pcf_set_S0(sc, *buf++);
  365 
  366                 /* wait for the byte to be send */
  367                 if ((error = pcf_wait_byte(sc)))
  368                         goto error;
  369 
  370                 /* check if ack received */
  371                 if (pcf_noack(sc, timeout)) {
  372                         error = IIC_ENOACK;
  373                         goto error;
  374                 }
  375 
  376                 len --;
  377                 bytes ++;
  378         }
  379 
  380 error:
  381         *sent = bytes;
  382 
  383 #ifdef PCFDEBUG
  384         device_printf(dev, " >> %d bytes written (%d)\n", bytes, error);
  385 #endif
  386 
  387         return (error);
  388 }
  389 
  390 int
  391 pcf_read(device_t dev, char *buf, int len, int *read, int last,
  392          int delay /* us */)
  393 {
  394         struct pcf_softc *sc = DEVTOSOFTC(dev);
  395         int bytes, error = 0;
  396 #ifdef PCFDEBUG
  397         char *obuf = buf;
  398 
  399         device_printf(dev, " << reading %d bytes\n", len);
  400 #endif
  401 
  402         /* trig the bus to get the first data byte in S0 */
  403         if (len) {
  404                 if (len == 1 && last)
  405                         /* just one byte to read */
  406                         pcf_set_S1(sc, ESO);            /* no ack */
  407 
  408                 dummy_read(sc);
  409         }
  410 
  411         bytes = 0;
  412         while (len) {
  413 
  414                 /* XXX delay needed here */
  415 
  416                 /* wait for trigged byte */
  417                 if ((error = pcf_wait_byte(sc))) {
  418                         pcf_stop(dev);
  419                         goto error;
  420                 }
  421 
  422                 if (len == 1 && last)
  423                         /* ok, last data byte already in S0, no I2C activity
  424                          * on next pcf_get_S0() */
  425                         pcf_stop(dev);
  426 
  427                 else if (len == 2 && last)
  428                         /* next trigged byte with no ack */
  429                         pcf_set_S1(sc, ESO);
  430 
  431                 /* receive byte, trig next byte */
  432                 *buf++ = pcf_get_S0(sc);
  433 
  434                 len --;
  435                 bytes ++;
  436         };
  437 
  438 error:
  439         *read = bytes;
  440 
  441 #ifdef PCFDEBUG
  442         device_printf(dev, " << %d bytes read (%d): %#x%s\n", bytes, error,
  443                       (unsigned)obuf[0], bytes > 1? "...": "");
  444 #endif
  445 
  446         return (error);
  447 }

Cache object: d880df09c08219982e5ed964e3875ec3


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