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

Cache object: b9f6bd534a696291a7f654d6dd391416


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