The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/pcf8584.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 /*      $OpenBSD: pcf8584.c,v 1.11 2010/08/01 18:48:41 kettenis Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
    5  *
    6  * Permission to use, copy, modify, and distribute this software for any
    7  * purpose with or without fee is hereby granted, provided that the above
    8  * copyright notice and this permission notice appear in all copies.
    9  *
   10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17  */
   18 
   19 #include <sys/param.h>
   20 #include <sys/systm.h>
   21 #include <sys/device.h>
   22 #include <sys/malloc.h>
   23 #include <sys/kernel.h>
   24 #include <sys/rwlock.h>
   25 #include <sys/proc.h>
   26 
   27 #include <machine/bus.h>
   28 
   29 #include <dev/i2c/i2cvar.h>
   30 
   31 #include <dev/ic/pcf8584var.h>
   32 
   33 #define PCF_S0                  0x00
   34 #define PCF_S1                  0x01
   35 #define PCF_S2                  0x02
   36 #define PCF_S3                  0x03
   37 
   38 #define PCF_CTRL_ACK            (1<<0)
   39 #define PCF_CTRL_STO            (1<<1)
   40 #define PCF_CTRL_STA            (1<<2)
   41 #define PCF_CTRL_ENI            (1<<3)
   42 #define PCF_CTRL_ES2            (1<<4)
   43 #define PCF_CTRL_ES1            (1<<5)
   44 #define PCF_CTRL_ESO            (1<<6)
   45 #define PCF_CTRL_PIN            (1<<7)
   46 
   47 #define PCF_CTRL_START          (PCF_CTRL_PIN | PCF_CTRL_ESO | \
   48     PCF_CTRL_STA | PCF_CTRL_ACK)
   49 #define PCF_CTRL_STOP           (PCF_CTRL_PIN | PCF_CTRL_ESO | \
   50     PCF_CTRL_STO | PCF_CTRL_ACK)
   51 #define PCF_CTRL_REPSTART       (PCF_CTRL_ESO | PCF_CTRL_STA | PCF_CTRL_ACK)
   52 #define PCF_CTRL_IDLE           (PCF_CTRL_PIN | PCF_CTRL_ESO | PCF_CTRL_ACK)
   53 
   54 #define PCF_STAT_nBB            (1<<0)
   55 #define PCF_STAT_LAB            (1<<1)
   56 #define PCF_STAT_AAS            (1<<2)
   57 #define PCF_STAT_AD0            (1<<3)
   58 #define PCF_STAT_LRB            (1<<3)
   59 #define PCF_STAT_BER            (1<<4)
   60 #define PCF_STAT_STS            (1<<5)
   61 #define PCF_STAT_PIN            (1<<7)
   62 
   63 struct cfdriver pcfiic_cd = {
   64         NULL, "pcfiic", DV_DULL
   65 };
   66 
   67 void            pcfiic_init(struct pcfiic_softc *);
   68 int             pcfiic_i2c_acquire_bus(void *, int);
   69 void            pcfiic_i2c_release_bus(void *, int);
   70 int             pcfiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
   71                     size_t, void *, size_t, int);
   72 
   73 int             pcfiic_xmit(struct pcfiic_softc *, u_int8_t, const u_int8_t *,
   74                     size_t);
   75 int             pcfiic_recv(struct pcfiic_softc *, u_int8_t, u_int8_t *,
   76                     size_t);
   77 
   78 u_int8_t        pcfiic_read(struct pcfiic_softc *, bus_size_t);
   79 void            pcfiic_write(struct pcfiic_softc *, bus_size_t, u_int8_t);
   80 void            pcfiic_choose_bus(struct pcfiic_softc *, u_int8_t);
   81 int             pcfiic_wait_nBB(struct pcfiic_softc *);
   82 int             pcfiic_wait_pin(struct pcfiic_softc *, volatile u_int8_t *);
   83 
   84 void
   85 pcfiic_init(struct pcfiic_softc *sc)
   86 {
   87         /* init S1 */
   88         pcfiic_write(sc, PCF_S1, PCF_CTRL_PIN);
   89         /* own address */
   90         pcfiic_write(sc, PCF_S0, sc->sc_addr);
   91 
   92         /* select clock reg */
   93         pcfiic_write(sc, PCF_S1, PCF_CTRL_PIN|PCF_CTRL_ES1);
   94         pcfiic_write(sc, PCF_S0, sc->sc_clock);
   95 
   96         pcfiic_write(sc, PCF_S1, PCF_CTRL_IDLE);
   97 
   98         delay(200000);  /* Multi-Master mode, wait for longest i2c message */
   99 }
  100 
  101 void
  102 pcfiic_attach(struct pcfiic_softc *sc, i2c_addr_t addr, u_int8_t clock,
  103     int swapregs,
  104     void (*scan_func)(struct device *, struct i2cbus_attach_args *, void *),
  105     void *scan_arg)
  106 {
  107         struct i2cbus_attach_args               iba;
  108 
  109         if (swapregs) {
  110                 sc->sc_regmap[PCF_S1] = PCF_S0;
  111                 sc->sc_regmap[PCF_S0] = PCF_S1;
  112         } else {
  113                 sc->sc_regmap[PCF_S0] = PCF_S0;
  114                 sc->sc_regmap[PCF_S1] = PCF_S1;
  115         }
  116         sc->sc_clock = clock;
  117         sc->sc_addr = addr;
  118 
  119         pcfiic_init(sc);
  120 
  121         printf("\n");
  122 
  123         if (sc->sc_master)
  124                 pcfiic_choose_bus(sc, 0);
  125 
  126         rw_init(&sc->sc_lock, "iiclk");
  127         sc->sc_i2c.ic_cookie = sc;
  128         sc->sc_i2c.ic_acquire_bus = pcfiic_i2c_acquire_bus;
  129         sc->sc_i2c.ic_release_bus = pcfiic_i2c_release_bus;
  130         sc->sc_i2c.ic_exec = pcfiic_i2c_exec;
  131 
  132         bzero(&iba, sizeof(iba));
  133         iba.iba_name = "iic";
  134         iba.iba_tag = &sc->sc_i2c;
  135         iba.iba_bus_scan = scan_func;
  136         iba.iba_bus_scan_arg = scan_arg;
  137         config_found(&sc->sc_dev, &iba, iicbus_print);
  138 }
  139 
  140 int
  141 pcfiic_intr(void *arg)
  142 {
  143         return (0);
  144 }
  145 
  146 int
  147 pcfiic_i2c_acquire_bus(void *arg, int flags)
  148 {
  149         struct pcfiic_softc     *sc = arg;
  150 
  151         if (cold || sc->sc_poll || (flags & I2C_F_POLL))
  152                 return (0);
  153 
  154         return (rw_enter(&sc->sc_lock, RW_WRITE | RW_INTR));
  155 }
  156 
  157 void
  158 pcfiic_i2c_release_bus(void *arg, int flags)
  159 {
  160         struct pcfiic_softc     *sc = arg;
  161 
  162         if (cold || sc->sc_poll || (flags & I2C_F_POLL))
  163                 return;
  164 
  165         rw_exit(&sc->sc_lock);
  166 }
  167 
  168 int
  169 pcfiic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr,
  170     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
  171 {
  172         struct pcfiic_softc     *sc = arg;
  173         int                     ret = 0;
  174 
  175 #if 0
  176         printf("%s: exec op: %d addr: 0x%x cmdlen: %d len: %d flags 0x%x\n",
  177             sc->sc_dev.dv_xname, op, addr, cmdlen, len, flags);
  178 #endif
  179 
  180         if (cold || sc->sc_poll)
  181                 flags |= I2C_F_POLL;
  182 
  183         if (sc->sc_master)
  184                 pcfiic_choose_bus(sc, addr >> 7);
  185 
  186         if (cmdlen > 0)
  187                 if (pcfiic_xmit(sc, addr & 0x7f, cmdbuf, cmdlen) != 0)
  188                         return (1);
  189 
  190         if (len > 0) {
  191                 if (I2C_OP_WRITE_P(op))
  192                         ret = pcfiic_xmit(sc, addr & 0x7f, buf, len);
  193                 else
  194                         ret = pcfiic_recv(sc, addr & 0x7f, buf, len);
  195         }
  196         return (ret);
  197 }
  198 
  199 int
  200 pcfiic_xmit(struct pcfiic_softc *sc, u_int8_t addr, const u_int8_t *buf,
  201     size_t len)
  202 {
  203         int                     i, err = 0;
  204         volatile u_int8_t       r;
  205 
  206         if (pcfiic_wait_nBB(sc) != 0)
  207                 return (1);
  208 
  209         pcfiic_write(sc, PCF_S0, addr << 1);
  210         pcfiic_write(sc, PCF_S1, PCF_CTRL_START);
  211 
  212         for (i = 0; i <= len; i++) {
  213                 if (pcfiic_wait_pin(sc, &r) != 0) {
  214                         pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
  215                         return (1);
  216                 }
  217 
  218                 if (r & PCF_STAT_LRB) {
  219                         err = 1;
  220                         break;
  221                 }
  222 
  223                 if (i < len)
  224                         pcfiic_write(sc, PCF_S0, buf[i]);
  225         }
  226         pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
  227         return (err);
  228 }
  229 
  230 int
  231 pcfiic_recv(struct pcfiic_softc *sc, u_int8_t addr, u_int8_t *buf, size_t len)
  232 {
  233         int                     i = 0, err = 0;
  234         volatile u_int8_t       r;
  235 
  236         if (pcfiic_wait_nBB(sc) != 0)
  237                 return (1);
  238 
  239         pcfiic_write(sc, PCF_S0, (addr << 1) | 0x01);
  240         pcfiic_write(sc, PCF_S1, PCF_CTRL_START);
  241 
  242         for (i = 0; i <= len; i++) {
  243                 if (pcfiic_wait_pin(sc, &r) != 0) {
  244                         pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
  245                         return (1);
  246                 }
  247 
  248                 if ((i != len) && (r & PCF_STAT_LRB)) {
  249                         pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
  250                         return (1);
  251                 }
  252 
  253                 if (i == len - 1) {
  254                         pcfiic_write(sc, PCF_S1, PCF_CTRL_ESO);
  255                 } else if (i == len) {
  256                         pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
  257                 }
  258 
  259                 r = pcfiic_read(sc, PCF_S0);
  260                 if (i > 0)
  261                         buf[i - 1] = r;
  262         }
  263         return (err);
  264 }
  265 
  266 u_int8_t
  267 pcfiic_read(struct pcfiic_softc *sc, bus_size_t r)
  268 {
  269         bus_space_barrier(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r], 1,
  270             BUS_SPACE_BARRIER_READ);
  271         return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r]));
  272 }
  273 
  274 void
  275 pcfiic_write(struct pcfiic_softc *sc, bus_size_t r, u_int8_t v)
  276 {
  277         bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r], v);
  278         bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, 4,
  279             BUS_SPACE_BARRIER_WRITE | BUS_SPACE_BARRIER_READ);
  280         bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[PCF_S1]);
  281 }
  282 
  283 void
  284 pcfiic_choose_bus(struct pcfiic_softc *sc, u_int8_t bus)
  285 {
  286         bus_space_write_1(sc->sc_iot, sc->sc_ioh2, 0, bus);
  287         bus_space_barrier(sc->sc_iot, sc->sc_ioh2, 0, 1,
  288             BUS_SPACE_BARRIER_WRITE);
  289 }
  290 
  291 int
  292 pcfiic_wait_nBB(struct pcfiic_softc *sc)
  293 {
  294         int             i;
  295 
  296         for (i = 0; i < 1000; i++) {
  297                 if (pcfiic_read(sc, PCF_S1) & PCF_STAT_nBB)
  298                         return (0);
  299                 delay(1000);
  300         }
  301         return (1);
  302 }
  303 
  304 int
  305 pcfiic_wait_pin(struct pcfiic_softc *sc, volatile u_int8_t *r)
  306 {
  307         int             i;
  308 
  309         for (i = 0; i < 1000; i++) {
  310                 *r = pcfiic_read(sc, PCF_S1);
  311                 if ((*r & PCF_STAT_PIN) == 0)
  312                         return (0);
  313                 delay(1000);
  314         }
  315         return (1);
  316 }

Cache object: 9134e754e833d23cc75e344f06775905


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