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/i386/isa/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  * 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$
   27  *
   28  */
   29 #include <sys/param.h>
   30 #include <sys/systm.h>
   31 #include <sys/kernel.h>
   32 #include <sys/module.h>
   33 #include <sys/bus.h>
   34 #include <sys/malloc.h>
   35 
   36 #include <machine/clock.h>
   37 #include <machine/bus.h>
   38 #include <machine/resource.h>
   39 #include <sys/rman.h>
   40 
   41 #include <isa/isareg.h>
   42 #include <isa/isavar.h>
   43 
   44 #include <i386/isa/isa_device.h>
   45 
   46 #include <dev/iicbus/iiconf.h>
   47 #include "iicbus_if.h"
   48 
   49 #define IO_PCFSIZE      2
   50 
   51 #define TIMEOUT 9999                                    /* XXX */
   52 
   53 /* Status bits of S1 register (read only) */
   54 #define nBB     0x01            /* busy when low set/reset by STOP/START*/
   55 #define LAB     0x02            /* lost arbitration bit in multi-master mode */
   56 #define AAS     0x04            /* addressed as slave */
   57 #define LRB     0x08            /* last received byte when not AAS */
   58 #define AD0     0x08            /* general call received when AAS */
   59 #define BER     0x10            /* bus error, misplaced START or STOP */
   60 #define STS     0x20            /* STOP detected in slave receiver mode */
   61 #define PIN     0x80            /* pending interrupt not (r/w) */
   62 
   63 /* Control bits of S1 register (write only) */
   64 #define ACK     0x01
   65 #define STO     0x02
   66 #define STA     0x04
   67 #define ENI     0x08
   68 #define ES2     0x10
   69 #define ES1     0x20
   70 #define ES0     0x40
   71 
   72 #define BUFSIZE 2048
   73 
   74 #define SLAVE_TRANSMITTER       0x1
   75 #define SLAVE_RECEIVER          0x2
   76 
   77 #define PCF_DEFAULT_ADDR        0xaa
   78 
   79 struct pcf_softc {
   80 
   81         int pcf_base;                   /* isa port */
   82         int pcf_flags;
   83         u_char pcf_addr;                /* interface I2C address */
   84 
   85         int pcf_slave_mode;             /* receiver or transmitter */
   86         int pcf_started;                /* 1 if start condition sent */
   87 
   88         device_t iicbus;                /* the corresponding iicbus */
   89 
   90         int rid_irq, rid_ioport;
   91         struct resource *res_irq, *res_ioport;
   92         void *intr_cookie;
   93 };
   94 
   95 static int pcf_probe(device_t);
   96 static int pcf_attach(device_t);
   97 static void pcfintr(void *arg);
   98 
   99 static int pcf_print_child(device_t, device_t);
  100 
  101 static int pcf_repeated_start(device_t, u_char, int);
  102 static int pcf_start(device_t, u_char, int);
  103 static int pcf_stop(device_t);
  104 static int pcf_write(device_t, char *, int, int *, int);
  105 static int pcf_read(device_t, char *, int, int *, int, int);
  106 static int pcf_rst_card(device_t, u_char, u_char, u_char *);
  107 
  108 static device_method_t pcf_methods[] = {
  109         /* device interface */
  110         DEVMETHOD(device_probe,         pcf_probe),
  111         DEVMETHOD(device_attach,        pcf_attach),
  112 
  113         /* bus interface */
  114         DEVMETHOD(bus_print_child,      pcf_print_child),
  115 
  116         /* iicbus interface */
  117         DEVMETHOD(iicbus_callback,      iicbus_null_callback),
  118         DEVMETHOD(iicbus_repeated_start, pcf_repeated_start),
  119         DEVMETHOD(iicbus_start,         pcf_start),
  120         DEVMETHOD(iicbus_stop,          pcf_stop),
  121         DEVMETHOD(iicbus_write,         pcf_write),
  122         DEVMETHOD(iicbus_read,          pcf_read),
  123         DEVMETHOD(iicbus_reset,         pcf_rst_card),
  124 
  125         { 0, 0 }
  126 };
  127 
  128 static driver_t pcf_driver = {
  129         "pcf",
  130         pcf_methods,
  131         sizeof(struct pcf_softc),
  132 };
  133 
  134 static devclass_t pcf_devclass;
  135 
  136 #define DEVTOSOFTC(dev) ((struct pcf_softc *)device_get_softc(dev))
  137 
  138 static int
  139 pcf_probe(device_t pcfdev)
  140 {
  141         struct pcf_softc *pcf = DEVTOSOFTC(pcfdev);
  142         device_t parent = device_get_parent(pcfdev);
  143 
  144         device_set_desc(pcfdev, "PCF8584 I2C bus controller");
  145 
  146         pcf = DEVTOSOFTC(pcfdev);
  147         bzero(pcf, sizeof(struct pcf_softc));
  148 
  149         pcf->rid_irq = pcf->rid_ioport = 0;
  150         pcf->res_irq = pcf->res_ioport = 0;
  151 
  152         /* IO port is mandatory */
  153         pcf->res_ioport = bus_alloc_resource(pcfdev, SYS_RES_IOPORT,
  154                                              &pcf->rid_ioport, 0ul, ~0ul, 
  155                                              IO_PCFSIZE, RF_ACTIVE);
  156         if (pcf->res_ioport == 0) {
  157                 device_printf(pcfdev, "cannot reserve I/O port range\n");
  158                 goto error;
  159         }
  160         BUS_READ_IVAR(parent, pcfdev, ISA_IVAR_PORT, &pcf->pcf_base);
  161 
  162         pcf->pcf_flags = device_get_flags(pcfdev);
  163 
  164         if (!(pcf->pcf_flags & IIC_POLLED)) {
  165                 pcf->res_irq = bus_alloc_resource(pcfdev, SYS_RES_IRQ, &pcf->rid_irq,
  166                                                   0ul, ~0ul, 1, RF_ACTIVE);
  167                 if (pcf->res_irq == 0) {
  168                         device_printf(pcfdev, "can't reserve irq, polled mode.\n");
  169                         pcf->pcf_flags |= IIC_POLLED;
  170                 }
  171         }
  172 
  173         /* reset the chip */
  174         pcf_rst_card(pcfdev, IIC_FASTEST, PCF_DEFAULT_ADDR, NULL);
  175 
  176         return (0);
  177 error:
  178         if (pcf->res_ioport != 0) {
  179                 bus_deactivate_resource(pcfdev, SYS_RES_IOPORT, pcf->rid_ioport,
  180                                         pcf->res_ioport);
  181                 bus_release_resource(pcfdev, SYS_RES_IOPORT, pcf->rid_ioport,
  182                                      pcf->res_ioport);
  183         }
  184         return (ENXIO);
  185 }
  186 
  187 static int
  188 pcf_attach(device_t pcfdev)
  189 {
  190         struct pcf_softc *pcf = DEVTOSOFTC(pcfdev);
  191         device_t parent = device_get_parent(pcfdev);
  192         int error = 0;
  193 
  194         if (pcf->res_irq) {
  195                 /* default to the tty mask for registration */  /* XXX */
  196                 error = BUS_SETUP_INTR(parent, pcfdev, pcf->res_irq, INTR_TYPE_NET,
  197                                             pcfintr, pcfdev, &pcf->intr_cookie);
  198                 if (error)
  199                         return (error);
  200         }
  201 
  202         pcf->iicbus = iicbus_alloc_bus(pcfdev);
  203 
  204         /* probe and attach the iicbus */
  205         device_probe_and_attach(pcf->iicbus);
  206 
  207         return (0);
  208 }
  209 
  210 static int
  211 pcf_print_child(device_t bus, device_t dev)
  212 {
  213         struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(bus);
  214         int retval = 0;
  215 
  216         retval += bus_print_child_header(bus, dev);
  217         retval += printf(" on %s addr 0x%x\n", device_get_nameunit(bus),
  218                          (int)pcf->pcf_addr);
  219 
  220         return (retval);
  221 }
  222 
  223 /*
  224  * PCF8584 datasheet : when operate at 8 MHz or more, a minimun time of
  225  * 6 clocks cycles must be left between two consecutives access
  226  */
  227 #define pcf_nops()      DELAY(10)
  228 
  229 #define dummy_read(pcf)         PCF_GET_S0(pcf)
  230 #define dummy_write(pcf)        PCF_SET_S0(pcf, 0)
  231 
  232 /*
  233  * Specific register access to PCF8584
  234  */
  235 static void PCF_SET_S0(struct pcf_softc *pcf, int data)
  236 {
  237         outb(pcf->pcf_base, data);
  238         pcf_nops();
  239 }
  240 
  241 static void PCF_SET_S1(struct pcf_softc *pcf, int data)
  242 {
  243         outb(pcf->pcf_base+1, data);
  244         pcf_nops();
  245 }
  246 
  247 static char PCF_GET_S0(struct pcf_softc *pcf)
  248 {
  249         char data;
  250 
  251         data = inb(pcf->pcf_base);
  252         pcf_nops();
  253 
  254         return (data);
  255 }
  256 
  257 static char PCF_GET_S1(struct pcf_softc *pcf)
  258 {
  259         char data;
  260 
  261         data = inb(pcf->pcf_base+1);
  262         pcf_nops();
  263 
  264         return (data);
  265 }
  266 
  267 /*
  268  * Polling mode for master operations wait for a new
  269  * byte incomming or outgoing
  270  */
  271 static int pcf_wait_byte(struct pcf_softc *pcf)
  272 {
  273         int counter = TIMEOUT;
  274 
  275         while (counter--) {
  276 
  277                 if ((PCF_GET_S1(pcf) & PIN) == 0)
  278                         return (0);
  279         }
  280 
  281         return (IIC_ETIMEOUT);
  282 }
  283 
  284 static int pcf_stop(device_t pcfdev)
  285 {
  286         struct pcf_softc *pcf = DEVTOSOFTC(pcfdev);
  287 
  288         /*
  289          * Send STOP condition iff the START condition was previously sent.
  290          * STOP is sent only once even if a iicbus_stop() is called after
  291          * an iicbus_read()... see pcf_read(): the pcf needs to send the stop
  292          * before the last char is read.
  293          */
  294         if (pcf->pcf_started) {
  295                 /* set stop condition and enable IT */
  296                 PCF_SET_S1(pcf, PIN|ES0|ENI|STO|ACK);
  297 
  298                 pcf->pcf_started = 0;
  299         }
  300 
  301         return (0);
  302 }
  303 
  304 
  305 static int pcf_noack(struct pcf_softc *pcf, int timeout)
  306 {
  307         int noack;
  308         int k = timeout/10;
  309 
  310         do {
  311                 noack = PCF_GET_S1(pcf) & LRB;
  312                 if (!noack)
  313                         break;
  314                 DELAY(10);                              /* XXX wait 10 us */
  315         } while (k--);
  316 
  317         return (noack);
  318 }
  319 
  320 static int pcf_repeated_start(device_t pcfdev, u_char slave, int timeout)
  321 {
  322         struct pcf_softc *pcf = DEVTOSOFTC(pcfdev);
  323         int error = 0;
  324 
  325         /* repeated start */
  326         PCF_SET_S1(pcf, ES0|STA|STO|ACK);
  327 
  328         /* set slave address to PCF. Last bit (LSB) must be set correctly
  329          * according to transfer direction */
  330         PCF_SET_S0(pcf, slave);
  331 
  332         /* wait for address sent, polling */
  333         if ((error = pcf_wait_byte(pcf)))
  334                 goto error;
  335 
  336         /* check for ack */
  337         if (pcf_noack(pcf, timeout)) {
  338                 error = IIC_ENOACK;
  339                 goto error;
  340         }
  341 
  342         return (0);
  343 
  344 error:
  345         pcf_stop(pcfdev);
  346         return (error);
  347 }
  348 
  349 static int pcf_start(device_t pcfdev, u_char slave, int timeout)
  350 {
  351         struct pcf_softc *pcf = DEVTOSOFTC(pcfdev);
  352         int error = 0;
  353 
  354         if ((PCF_GET_S1(pcf) & nBB) == 0)
  355                 return (IIC_EBUSBSY);
  356 
  357         /* set slave address to PCF. Last bit (LSB) must be set correctly
  358          * according to transfer direction */
  359         PCF_SET_S0(pcf, slave);
  360 
  361         /* START only */
  362         PCF_SET_S1(pcf, PIN|ES0|STA|ACK);
  363 
  364         pcf->pcf_started = 1;
  365 
  366         /* wait for address sent, polling */
  367         if ((error = pcf_wait_byte(pcf)))
  368                 goto error;
  369 
  370         /* check for ACK */
  371         if (pcf_noack(pcf, timeout)) {
  372                 error = IIC_ENOACK;
  373                 goto error;
  374         }
  375 
  376         return (0);
  377 
  378 error:
  379         pcf_stop(pcfdev);
  380         return (error);
  381 }
  382 
  383 static void
  384 pcfintr(void *arg)
  385 {
  386         device_t pcfdev = (device_t)arg;
  387         struct pcf_softc *pcf = DEVTOSOFTC(pcfdev);
  388 
  389         char data, status, addr;
  390         char error = 0;
  391 
  392         status = PCF_GET_S1(pcf);
  393 
  394         if (status & PIN) {
  395                 device_printf(pcfdev, "spurious interrupt, status=0x%x\n", status & 0xff);
  396 
  397                 goto error;
  398         }       
  399 
  400         if (status & LAB)
  401                 device_printf(pcfdev, "bus arbitration lost!\n");
  402 
  403         if (status & BER) {
  404                 error = IIC_EBUSERR;
  405                 iicbus_intr(pcf->iicbus, INTR_ERROR, &error);
  406 
  407                 goto error;
  408         }
  409 
  410         do {
  411                 status = PCF_GET_S1(pcf);
  412 
  413                 switch(pcf->pcf_slave_mode) {
  414 
  415                 case SLAVE_TRANSMITTER:
  416                         if (status & LRB) {
  417                                 /* ack interrupt line */
  418                                 dummy_write(pcf);
  419 
  420                                 /* no ack, don't send anymore */
  421                                 pcf->pcf_slave_mode = SLAVE_RECEIVER;
  422 
  423                                 iicbus_intr(pcf->iicbus, INTR_NOACK, NULL);
  424                                 break;
  425                         }
  426 
  427                         /* get data from upper code */
  428                         iicbus_intr(pcf->iicbus, INTR_TRANSMIT, &data);
  429 
  430                         PCF_SET_S0(pcf, data);  
  431                         break;  
  432                 
  433                 case SLAVE_RECEIVER:
  434                         if (status & AAS) {
  435                                 addr = PCF_GET_S0(pcf);
  436 
  437                                 if (status & AD0)
  438                                         iicbus_intr(pcf->iicbus, INTR_GENERAL, &addr);
  439                                 else
  440                                         iicbus_intr(pcf->iicbus, INTR_START, &addr);
  441 
  442                                 if (addr & LSB) {
  443                                         pcf->pcf_slave_mode = SLAVE_TRANSMITTER;
  444 
  445                                         /* get the first char from upper code */
  446                                         iicbus_intr(pcf->iicbus, INTR_TRANSMIT, &data);
  447 
  448                                         /* send first data byte */
  449                                         PCF_SET_S0(pcf, data);
  450                                 }
  451 
  452                                 break;
  453                         }
  454 
  455                         /* stop condition received? */
  456                         if (status & STS) {
  457                                 /* ack interrupt line */
  458                                 dummy_read(pcf);
  459 
  460                                 /* emulate intr stop condition */
  461                                 iicbus_intr(pcf->iicbus, INTR_STOP, NULL);
  462 
  463                         } else {
  464                                 /* get data, ack interrupt line */
  465                                 data = PCF_GET_S0(pcf);
  466 
  467                                 /* deliver the character */
  468                                 iicbus_intr(pcf->iicbus, INTR_RECEIVE, &data);
  469                         }
  470                         break;
  471 
  472                     default:
  473                         panic("%s: unknown slave mode (%d)!", __FUNCTION__,
  474                                 pcf->pcf_slave_mode);
  475                     }
  476 
  477         } while ((PCF_GET_S1(pcf) & PIN) == 0);
  478 
  479         return;
  480 
  481 error:
  482         /* unknown event on bus...reset PCF */
  483         PCF_SET_S1(pcf, PIN|ES0|ENI|ACK);
  484 
  485         pcf->pcf_slave_mode = SLAVE_RECEIVER;
  486 
  487         return;
  488 }
  489 
  490 static int pcf_rst_card(device_t pcfdev, u_char speed, u_char addr, u_char *oldaddr)
  491 {
  492         struct pcf_softc *pcf = DEVTOSOFTC(pcfdev);
  493 
  494         if (oldaddr)
  495                 *oldaddr = pcf->pcf_addr;
  496 
  497         /* retrieve own address from bus level */
  498         if (!addr)
  499                 pcf->pcf_addr = PCF_DEFAULT_ADDR;
  500         else
  501                 pcf->pcf_addr = addr;
  502         
  503         PCF_SET_S1(pcf, PIN);                           /* initialize S1 */
  504 
  505         /* own address S'O<>0 */
  506         PCF_SET_S0(pcf, pcf->pcf_addr >> 1);
  507 
  508         /* select clock register */
  509         PCF_SET_S1(pcf, PIN|ES1);
  510 
  511         /* select bus speed : 18=90kb, 19=45kb, 1A=11kb, 1B=1.5kb */
  512         switch (speed) {
  513         case IIC_SLOW:
  514                 PCF_SET_S0(pcf,  0x1b);
  515                 break;
  516 
  517         case IIC_FAST:
  518                 PCF_SET_S0(pcf,  0x19);
  519                 break;
  520 
  521         case IIC_UNKNOWN:
  522         case IIC_FASTEST:
  523         default:
  524                 PCF_SET_S0(pcf,  0x18);
  525                 break;
  526         }
  527 
  528         /* set bus on, ack=yes, INT=yes */
  529         PCF_SET_S1(pcf, PIN|ES0|ENI|ACK);
  530 
  531         pcf->pcf_slave_mode = SLAVE_RECEIVER;
  532 
  533         return (0);
  534 }
  535 
  536 static int
  537 pcf_write(device_t pcfdev, char *buf, int len, int *sent, int timeout /* us */)
  538 {
  539         struct pcf_softc *pcf = DEVTOSOFTC(pcfdev);
  540         int bytes, error = 0;
  541 
  542 #ifdef PCFDEBUG
  543         printf("pcf%d: >> writing %d bytes\n", device_get_unit(pcfdev), len);
  544 #endif
  545 
  546         bytes = 0;
  547         while (len) {
  548 
  549                 PCF_SET_S0(pcf, *buf++);
  550 
  551                 /* wait for the byte to be send */
  552                 if ((error = pcf_wait_byte(pcf)))
  553                         goto error;
  554 
  555                 /* check if ack received */
  556                 if (pcf_noack(pcf, timeout)) {
  557                         error = IIC_ENOACK;
  558                         goto error;
  559                 }
  560 
  561                 len --;
  562                 bytes ++;
  563         }
  564 
  565 error:
  566         *sent = bytes;
  567 
  568 #ifdef PCFDEBUG
  569         printf("pcf%d: >> %d bytes written (%d)\n",
  570                 device_get_unit(pcfdev), bytes, error);
  571 #endif
  572 
  573         return (error);
  574 }
  575 
  576 static int
  577 pcf_read(device_t pcfdev, char *buf, int len, int *read, int last,
  578                                                         int delay /* us */)
  579 {
  580         struct pcf_softc *pcf = DEVTOSOFTC(pcfdev);
  581         int bytes, error = 0;
  582 
  583 #ifdef PCFDEBUG
  584         printf("pcf%d: << reading %d bytes\n", device_get_unit(pcfdev), len);
  585 #endif
  586 
  587         /* trig the bus to get the first data byte in S0 */
  588         if (len) {
  589                 if (len == 1 && last)
  590                         /* just one byte to read */
  591                         PCF_SET_S1(pcf, ES0);           /* no ack */
  592 
  593                 dummy_read(pcf);
  594         }
  595 
  596         bytes = 0;
  597         while (len) {
  598 
  599                 /* XXX delay needed here */
  600 
  601                 /* wait for trigged byte */
  602                 if ((error = pcf_wait_byte(pcf))) {
  603                         pcf_stop(pcfdev);
  604                         goto error;
  605                 }
  606 
  607                 if (len == 1 && last)
  608                         /* ok, last data byte already in S0, no I2C activity
  609                          * on next PCF_GET_S0() */
  610                         pcf_stop(pcfdev);
  611 
  612                 else if (len == 2 && last)
  613                         /* next trigged byte with no ack */
  614                         PCF_SET_S1(pcf, ES0);
  615 
  616                 /* receive byte, trig next byte */
  617                 *buf++ = PCF_GET_S0(pcf);
  618 
  619                 len --;
  620                 bytes ++;
  621         };
  622 
  623 error:
  624         *read = bytes;
  625 
  626 #ifdef PCFDEBUG
  627         printf("pcf%d: << %d bytes read (%d)\n",
  628                 device_get_unit(pcfdev), bytes, error);
  629 #endif
  630 
  631         return (error);
  632 }
  633 
  634 DRIVER_MODULE(pcf, isa, pcf_driver, pcf_devclass, 0, 0);

Cache object: bab18347257a0aa477f700cad6272372


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