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 /*      $NetBSD: pcf8584.c,v 1.20 2022/09/25 18:43:32 thorpej Exp $     */
    2 /*      $OpenBSD: pcf8584.c,v 1.9 2007/10/20 18:46:21 kettenis Exp $ */
    3 
    4 /*
    5  * Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
    6  *
    7  * Permission to use, copy, modify, and distribute this software for any
    8  * purpose with or without fee is hereby granted, provided that the above
    9  * copyright notice and this permission notice appear in all copies.
   10  *
   11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   18  */
   19 
   20 #include <sys/param.h>
   21 #include <sys/systm.h>
   22 #include <sys/device.h>
   23 #include <sys/kernel.h>
   24 #include <sys/proc.h>
   25 #include <sys/bus.h>
   26 
   27 #include <dev/i2c/i2cvar.h>
   28 
   29 #include <dev/ic/pcf8584var.h>
   30 #include <dev/ic/pcf8584reg.h>
   31 
   32 /* Internal registers */
   33 #define PCF8584_S0              0x00
   34 #define PCF8584_S1              0x01
   35 #define PCF8584_S2              0x02
   36 #define PCF8584_S3              0x03
   37 
   38 void            pcfiic_init(struct pcfiic_softc *);
   39 int             pcfiic_i2c_acquire_bus(void *, int);
   40 void            pcfiic_i2c_release_bus(void *, int);
   41 int             pcfiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
   42                     size_t, void *, size_t, int);
   43 
   44 int             pcfiic_xmit(struct pcfiic_softc *, u_int8_t, const u_int8_t *,
   45                     size_t, const u_int8_t *, size_t);
   46 int             pcfiic_recv(struct pcfiic_softc *, u_int8_t, u_int8_t *,
   47                     size_t);
   48 
   49 u_int8_t        pcfiic_read(struct pcfiic_softc *, bus_size_t);
   50 void            pcfiic_write(struct pcfiic_softc *, bus_size_t, u_int8_t);
   51 void            pcfiic_choose_bus(struct pcfiic_softc *, u_int8_t);
   52 int             pcfiic_wait_BBN(struct pcfiic_softc *);
   53 int             pcfiic_wait_pin(struct pcfiic_softc *, volatile u_int8_t *);
   54 
   55 void
   56 pcfiic_init(struct pcfiic_softc *sc)
   57 {
   58         /* init S1 */
   59         pcfiic_write(sc, PCF8584_S1, PCF8584_CTRL_PIN);
   60         /* own address */
   61         pcfiic_write(sc, PCF8584_S0, sc->sc_addr);
   62 
   63         /* select clock reg */
   64         pcfiic_write(sc, PCF8584_S1, PCF8584_CTRL_PIN | PCF8584_CTRL_ES1);
   65         pcfiic_write(sc, PCF8584_S0, sc->sc_clock);
   66 
   67         pcfiic_write(sc, PCF8584_S1, PCF8584_CMD_IDLE);
   68 
   69         delay(200000);  /* Multi-Master mode, wait for longest i2c message */
   70 }
   71 
   72 void
   73 pcfiic_attach(struct pcfiic_softc *sc, i2c_addr_t addr, u_int8_t clock,
   74     int swapregs)
   75 {
   76         struct i2cbus_attach_args               iba;
   77 
   78         if (swapregs) {
   79                 sc->sc_regmap[PCF8584_S1] = PCF8584_S0;
   80                 sc->sc_regmap[PCF8584_S0] = PCF8584_S1;
   81         } else {
   82                 sc->sc_regmap[PCF8584_S0] = PCF8584_S0;
   83                 sc->sc_regmap[PCF8584_S1] = PCF8584_S1;
   84         }
   85         sc->sc_clock = clock;
   86         sc->sc_addr = addr;
   87 
   88         pcfiic_init(sc);
   89 
   90         printf("\n");
   91 
   92         if (sc->sc_master)
   93                 pcfiic_choose_bus(sc, 0);
   94 
   95         iic_tag_init(&sc->sc_i2c);
   96         sc->sc_i2c.ic_cookie = sc;
   97         sc->sc_i2c.ic_exec = pcfiic_i2c_exec;
   98 
   99         bzero(&iba, sizeof(iba));
  100         iba.iba_tag = &sc->sc_i2c;
  101         config_found(sc->sc_dev, &iba, iicbus_print, CFARGS_NONE);
  102 }
  103 
  104 int
  105 pcfiic_intr(void *arg)
  106 {
  107         return (0);
  108 }
  109 
  110 int
  111 pcfiic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr,
  112     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
  113 {
  114         struct pcfiic_softc     *sc = arg;
  115         int                     ret = 0;
  116 
  117 #if 0
  118         printf("%s: exec op: %d addr: 0x%x cmdlen: %d len: %d flags 0x%x\n",
  119             device_xname(sc->sc_dev), op, addr, (int)cmdlen, (int)len, flags);
  120 #endif
  121 
  122         if (sc->sc_poll)
  123                 flags |= I2C_F_POLL;
  124 
  125         if (sc->sc_master)
  126                 pcfiic_choose_bus(sc, addr >> 7);
  127 
  128         /*
  129          * If we are writing, write address, cmdbuf, buf.
  130          * If we are reading, write address, cmdbuf, then read address, buf.
  131          */
  132         if (I2C_OP_WRITE_P(op)) {
  133                 ret = pcfiic_xmit(sc, addr & 0x7f, cmdbuf, cmdlen, buf, len);
  134         } else {
  135                 if (pcfiic_xmit(sc, addr & 0x7f, cmdbuf, cmdlen, NULL, 0) != 0)
  136                         return (1);
  137                 ret = pcfiic_recv(sc, addr & 0x7f, buf, len);
  138         }
  139         return (ret);
  140 }
  141 
  142 int
  143 pcfiic_xmit(struct pcfiic_softc *sc, u_int8_t addr, const u_int8_t *cmdbuf,
  144     size_t cmdlen, const u_int8_t *buf, size_t len)
  145 {
  146         int                     i, err = 0;
  147         volatile u_int8_t       r;
  148 
  149         if (pcfiic_wait_BBN(sc) != 0)
  150                 return (1);
  151 
  152         pcfiic_write(sc, PCF8584_S0, addr << 1);
  153         pcfiic_write(sc, PCF8584_S1, PCF8584_CMD_START);
  154 
  155         for (i = 0; i <= cmdlen + len; i++) {
  156                 if (pcfiic_wait_pin(sc, &r) != 0) {
  157                         pcfiic_write(sc, PCF8584_S1, PCF8584_CMD_STOP);
  158                         return (1);
  159                 }
  160 
  161                 if (r & PCF8584_STATUS_LRB) {
  162                         err = 1;
  163                         break;
  164                 }
  165 
  166                 if (i < cmdlen)
  167                         pcfiic_write(sc, PCF8584_S0, cmdbuf[i]);
  168                 else if (i < cmdlen + len)
  169                         pcfiic_write(sc, PCF8584_S0, buf[i - cmdlen]);
  170         }
  171         pcfiic_write(sc, PCF8584_S1, PCF8584_CMD_STOP);
  172         return (err);
  173 }
  174 
  175 int
  176 pcfiic_recv(struct pcfiic_softc *sc, u_int8_t addr, u_int8_t *buf, size_t len)
  177 {
  178         int                     i = 0, err = 0;
  179         volatile u_int8_t       r;
  180 
  181         if (pcfiic_wait_BBN(sc) != 0)
  182                 return (1);
  183 
  184         pcfiic_write(sc, PCF8584_S0, (addr << 1) | 0x01);
  185         pcfiic_write(sc, PCF8584_S1, PCF8584_CMD_START);
  186 
  187         for (i = 0; i <= len; i++) {
  188                 if (pcfiic_wait_pin(sc, &r) != 0) {
  189                         pcfiic_write(sc, PCF8584_S1, PCF8584_CMD_STOP);
  190                         return (1);
  191                 }
  192 
  193                 if ((i != len) && (r & PCF8584_STATUS_LRB)) {
  194                         pcfiic_write(sc, PCF8584_S1, PCF8584_CMD_STOP);
  195                         return (1);
  196                 }
  197 
  198                 if (i == len - 1) {
  199                         pcfiic_write(sc, PCF8584_S1, PCF8584_CMD_NAK);
  200                 } else if (i == len) {
  201                         pcfiic_write(sc, PCF8584_S1, PCF8584_CMD_STOP);
  202                 }
  203 
  204                 r = pcfiic_read(sc, PCF8584_S0);
  205                 if (i > 0)
  206                         buf[i - 1] = r;
  207         }
  208         return (err);
  209 }
  210 
  211 u_int8_t
  212 pcfiic_read(struct pcfiic_softc *sc, bus_size_t r)
  213 {
  214         bus_space_barrier(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r], 1,
  215             BUS_SPACE_BARRIER_READ);
  216         return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r]));
  217 }
  218 
  219 void
  220 pcfiic_write(struct pcfiic_softc *sc, bus_size_t r, u_int8_t v)
  221 {
  222         bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r], v);
  223         (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, PCF8584_S1);
  224 }
  225 
  226 void
  227 pcfiic_choose_bus(struct pcfiic_softc *sc, u_int8_t bus)
  228 {
  229         bus_space_write_1(sc->sc_iot, sc->sc_ioh2, 0, bus);
  230         bus_space_barrier(sc->sc_iot, sc->sc_ioh2, 0, 1,
  231             BUS_SPACE_BARRIER_WRITE);
  232 }
  233 
  234 int
  235 pcfiic_wait_BBN(struct pcfiic_softc *sc)
  236 {
  237         int             i;
  238 
  239         for (i = 0; i < 1000; i++) {
  240                 if (pcfiic_read(sc, PCF8584_S1) & PCF8584_STATUS_BBN)
  241                         return (0);
  242                 delay(1000);
  243         }
  244         return (1);
  245 }
  246 
  247 int
  248 pcfiic_wait_pin(struct pcfiic_softc *sc, volatile u_int8_t *r)
  249 {
  250         int             i;
  251 
  252         for (i = 0; i < 1000; i++) {
  253                 *r = pcfiic_read(sc, PCF8584_S1);
  254                 if ((*r & PCF8584_STATUS_PIN) == 0)
  255                         return (0);
  256                 delay(1000);
  257         }
  258         return (1);
  259 }

Cache object: b1ccd52fa8732485c9b405b3f40374f5


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