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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 1998 Nicolas Souchu, Marc Bouget
    5  * Copyright (c) 2004 Joerg Wunsch
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include <sys/param.h>
   34 #include <sys/bus.h>
   35 #include <sys/lock.h>
   36 #include <sys/kernel.h>
   37 #include <sys/module.h>
   38 #include <sys/mutex.h>
   39 #include <sys/systm.h>
   40 
   41 #include <machine/bus.h>
   42 #include <machine/resource.h>
   43 
   44 #include <sys/rman.h>
   45 
   46 #include <dev/iicbus/iicbus.h>
   47 #include <dev/iicbus/iiconf.h>
   48 #include <dev/pcf/pcfvar.h>
   49 #include "iicbus_if.h"
   50 
   51 /* Not so official debugging option. */
   52 /* #define PCFDEBUG */
   53 
   54 static int pcf_wait_byte(struct pcf_softc *pcf);
   55 static int pcf_noack(struct pcf_softc *pcf, int timeout);
   56 static void pcf_stop_locked(struct pcf_softc *pcf);
   57 
   58 /*
   59  * Polling mode for master operations wait for a new
   60  * byte incoming or outgoing
   61  */
   62 static int
   63 pcf_wait_byte(struct pcf_softc *sc)
   64 {
   65         int counter = TIMEOUT;
   66 
   67         PCF_ASSERT_LOCKED(sc);
   68         while (counter--) {
   69                 if ((pcf_get_S1(sc) & PIN) == 0)
   70                         return (0);
   71         }
   72 
   73 #ifdef PCFDEBUG
   74         printf("pcf: timeout!\n");
   75 #endif
   76 
   77         return (IIC_ETIMEOUT);
   78 }
   79 
   80 static void
   81 pcf_stop_locked(struct pcf_softc *sc)
   82 {
   83 
   84         PCF_ASSERT_LOCKED(sc);
   85 #ifdef PCFDEBUG
   86         device_printf(dev, " >> stop\n");
   87 #endif
   88         /*
   89          * Send STOP condition iff the START condition was previously sent.
   90          * STOP is sent only once even if an iicbus_stop() is called after
   91          * an iicbus_read()... see pcf_read(): the PCF needs to send the stop
   92          * before the last char is read.
   93          */
   94         if (sc->pcf_started) {
   95                 /* set stop condition and enable IT */
   96                 pcf_set_S1(sc, PIN|ESO|ENI|STO|ACK);
   97 
   98                 sc->pcf_started = 0;
   99         }
  100 }
  101 
  102 static int
  103 pcf_noack(struct pcf_softc *sc, int timeout)
  104 {
  105         int noack;
  106         int k = timeout/10;
  107 
  108         PCF_ASSERT_LOCKED(sc);
  109         do {
  110                 noack = pcf_get_S1(sc) & LRB;
  111                 if (!noack)
  112                         break;
  113                 DELAY(10);                              /* XXX wait 10 us */
  114         } while (k--);
  115 
  116         return (noack);
  117 }
  118 
  119 int
  120 pcf_repeated_start(device_t dev, u_char slave, int timeout)
  121 {
  122         struct pcf_softc *sc = DEVTOSOFTC(dev);
  123         int error = 0;
  124 
  125         PCF_LOCK(sc);
  126 #ifdef PCFDEBUG
  127         device_printf(dev, " >> repeated start for slave %#x\n",
  128                       (unsigned)slave);
  129 #endif
  130         /* repeated start */
  131         pcf_set_S1(sc, ESO|STA|STO|ACK);
  132 
  133         /* set slave address to PCF. Last bit (LSB) must be set correctly
  134          * according to transfer direction */
  135         pcf_set_S0(sc, slave);
  136 
  137         /* wait for address sent, polling */
  138         if ((error = pcf_wait_byte(sc)))
  139                 goto error;
  140 
  141         /* check for ack */
  142         if (pcf_noack(sc, timeout)) {
  143                 error = IIC_ENOACK;
  144 #ifdef PCFDEBUG
  145                 printf("pcf: no ack on repeated_start!\n");
  146 #endif
  147                 goto error;
  148         }
  149 
  150         PCF_UNLOCK(sc);
  151         return (0);
  152 
  153 error:
  154         pcf_stop_locked(sc);
  155         PCF_UNLOCK(sc);
  156         return (error);
  157 }
  158 
  159 int
  160 pcf_start(device_t dev, u_char slave, int timeout)
  161 {
  162         struct pcf_softc *sc = DEVTOSOFTC(dev);
  163         int error = 0;
  164 
  165         PCF_LOCK(sc);
  166 #ifdef PCFDEBUG
  167         device_printf(dev, " >> start for slave %#x\n", (unsigned)slave);
  168 #endif
  169         if ((pcf_get_S1(sc) & nBB) == 0) {
  170 #ifdef PCFDEBUG
  171                 printf("pcf: busy!\n");
  172 #endif
  173                 PCF_UNLOCK(sc);
  174                 return (IIC_EBUSERR);
  175         }
  176 
  177         /* set slave address to PCF. Last bit (LSB) must be set correctly
  178          * according to transfer direction */
  179         pcf_set_S0(sc, slave);
  180 
  181         /* START only */
  182         pcf_set_S1(sc, PIN|ESO|STA|ACK);
  183 
  184         sc->pcf_started = 1;
  185 
  186         /* wait for address sent, polling */
  187         if ((error = pcf_wait_byte(sc)))
  188                 goto error;
  189 
  190         /* check for ACK */
  191         if (pcf_noack(sc, timeout)) {
  192                 error = IIC_ENOACK;
  193 #ifdef PCFDEBUG
  194                 printf("pcf: no ack on start!\n");
  195 #endif
  196                 goto error;
  197         }
  198 
  199         PCF_UNLOCK(sc);
  200         return (0);
  201 
  202 error:
  203         pcf_stop_locked(sc);
  204         PCF_UNLOCK(sc);
  205         return (error);
  206 }
  207 
  208 int
  209 pcf_stop(device_t dev)
  210 {
  211         struct pcf_softc *sc = DEVTOSOFTC(dev);
  212 
  213 #ifdef PCFDEBUG
  214         device_printf(dev, " >> stop\n");
  215 #endif
  216         PCF_LOCK(sc);
  217         pcf_stop_locked(sc);
  218         PCF_UNLOCK(sc);
  219 
  220         return (0);
  221 }
  222 
  223 void
  224 pcf_intr(void *arg)
  225 {
  226         struct pcf_softc *sc = arg;
  227         char data, status, addr;
  228         char error = 0;
  229 
  230         PCF_LOCK(sc);
  231         status = pcf_get_S1(sc);
  232 
  233         if (status & PIN) {
  234                 printf("pcf: spurious interrupt, status=0x%x\n",
  235                        status & 0xff);
  236 
  237                 goto error;
  238         }
  239 
  240         if (status & LAB)
  241                 printf("pcf: bus arbitration lost!\n");
  242 
  243         if (status & BER) {
  244                 error = IIC_EBUSERR;
  245                 iicbus_intr(sc->iicbus, INTR_ERROR, &error);
  246 
  247                 goto error;
  248         }
  249 
  250         do {
  251                 status = pcf_get_S1(sc);
  252 
  253                 switch(sc->pcf_slave_mode) {
  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                 pcf_set_S0(sc, *buf++);
  395 
  396                 /* wait for the byte to be send */
  397                 if ((error = pcf_wait_byte(sc)))
  398                         goto error;
  399 
  400                 /* check if ack received */
  401                 if (pcf_noack(sc, timeout)) {
  402                         error = IIC_ENOACK;
  403                         goto error;
  404                 }
  405 
  406                 len --;
  407                 bytes ++;
  408         }
  409 
  410 error:
  411         *sent = bytes;
  412         PCF_UNLOCK(sc);
  413 
  414 #ifdef PCFDEBUG
  415         device_printf(dev, " >> %d bytes written (%d)\n", bytes, error);
  416 #endif
  417 
  418         return (error);
  419 }
  420 
  421 int
  422 pcf_read(device_t dev, char *buf, int len, int *read, int last,
  423          int delay /* us */)
  424 {
  425         struct pcf_softc *sc = DEVTOSOFTC(dev);
  426         int bytes, error = 0;
  427 #ifdef PCFDEBUG
  428         char *obuf = buf;
  429 
  430         device_printf(dev, " << reading %d bytes\n", len);
  431 #endif
  432 
  433         PCF_LOCK(sc);
  434         /* trig the bus to get the first data byte in S0 */
  435         if (len) {
  436                 if (len == 1 && last)
  437                         /* just one byte to read */
  438                         pcf_set_S1(sc, ESO);            /* no ack */
  439 
  440                 dummy_read(sc);
  441         }
  442 
  443         bytes = 0;
  444         while (len) {
  445                 /* XXX delay needed here */
  446 
  447                 /* wait for trigged byte */
  448                 if ((error = pcf_wait_byte(sc))) {
  449                         pcf_stop_locked(sc);
  450                         goto error;
  451                 }
  452 
  453                 if (len == 1 && last)
  454                         /* ok, last data byte already in S0, no I2C activity
  455                          * on next pcf_get_S0() */
  456                         pcf_stop_locked(sc);
  457 
  458                 else if (len == 2 && last)
  459                         /* next trigged byte with no ack */
  460                         pcf_set_S1(sc, ESO);
  461 
  462                 /* receive byte, trig next byte */
  463                 *buf++ = pcf_get_S0(sc);
  464 
  465                 len --;
  466                 bytes ++;
  467         }
  468 
  469 error:
  470         *read = bytes;
  471         PCF_UNLOCK(sc);
  472 
  473 #ifdef PCFDEBUG
  474         device_printf(dev, " << %d bytes read (%d): %#x%s\n", bytes, error,
  475                       (unsigned)obuf[0], bytes > 1? "...": "");
  476 #endif
  477 
  478         return (error);
  479 }
  480 
  481 DRIVER_MODULE(iicbus, pcf, iicbus_driver, 0, 0);
  482 MODULE_DEPEND(pcf, iicbus, PCF_MINVER, PCF_PREFVER, PCF_MAXVER);
  483 MODULE_VERSION(pcf, PCF_MODVER);

Cache object: be1e55fa7cd19ee47ee548a3ed5eca9a


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