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

Cache object: 58403dc3cc8650effe6e16751399fb85


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