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

Cache object: 2b90505946cbaef3ff69946b54414007


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