root/dev/ic/pcf8584.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pcfiic_init
  2. pcfiic_attach
  3. pcfiic_intr
  4. pcfiic_i2c_acquire_bus
  5. pcfiic_i2c_release_bus
  6. pcfiic_i2c_exec
  7. pcfiic_xmit
  8. pcfiic_recv
  9. pcfiic_read
  10. pcfiic_write
  11. pcfiic_choose_bus
  12. pcfiic_wait_nBB
  13. pcfiic_wait_pin

    1 /*      $OpenBSD: pcf8584.c,v 1.8 2007/05/21 03:11:11 jsg 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 #define PCF_FREQ_90             0x00 /* 90 kHz */
   64 #define PCF_FREQ_45             0x01 /* 45 kHz */
   65 #define PCF_FREQ_11             0x02 /* 11 kHz */
   66 #define PCF_FREQ_1_5            0x03 /* 1.5 kHz */
   67 
   68 struct cfdriver pcfiic_cd = {
   69         NULL, "pcfiic", DV_DULL
   70 };
   71 
   72 void            pcfiic_init(struct pcfiic_softc *);
   73 int             pcfiic_i2c_acquire_bus(void *, int);
   74 void            pcfiic_i2c_release_bus(void *, int);
   75 int             pcfiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
   76                     size_t, void *, size_t, int);
   77 
   78 int             pcfiic_xmit(struct pcfiic_softc *, u_int8_t, const u_int8_t *,
   79                     size_t);
   80 int             pcfiic_recv(struct pcfiic_softc *, u_int8_t, u_int8_t *,
   81                     size_t);
   82 
   83 volatile u_int8_t pcfiic_read(struct pcfiic_softc *, bus_size_t);
   84 volatile void   pcfiic_write(struct pcfiic_softc *, bus_size_t, u_int8_t);
   85 void            pcfiic_choose_bus(struct pcfiic_softc *, u_int8_t);
   86 int             pcfiic_wait_nBB(struct pcfiic_softc *);
   87 int             pcfiic_wait_pin(struct pcfiic_softc *, volatile u_int8_t *);
   88 
   89 void
   90 pcfiic_init(struct pcfiic_softc *sc)
   91 {
   92         /* init S1 */
   93         pcfiic_write(sc, PCF_S1, PCF_CTRL_PIN);
   94         /* own address */
   95         pcfiic_write(sc, PCF_S0, sc->sc_addr);
   96 
   97         /* select clock reg */
   98         pcfiic_write(sc, PCF_S1, PCF_CTRL_PIN|PCF_CTRL_ES1);
   99         pcfiic_write(sc, PCF_S0, sc->sc_clock);
  100 
  101         pcfiic_write(sc, PCF_S1, PCF_CTRL_IDLE);
  102 
  103         delay(200000);  /* Multi-Master mode, wait for longest i2c message */
  104 }
  105 
  106 void
  107 pcfiic_attach(struct pcfiic_softc *sc, i2c_addr_t addr, u_int8_t clock,
  108     int swapregs,
  109     void (*scan_func)(struct device *, struct i2cbus_attach_args *, void *),
  110     void *scan_arg)
  111 {
  112         struct i2cbus_attach_args               iba;
  113 
  114         if (swapregs) {
  115                 sc->sc_regmap[PCF_S1] = PCF_S0;
  116                 sc->sc_regmap[PCF_S0] = PCF_S1;
  117         } else {
  118                 sc->sc_regmap[PCF_S0] = PCF_S0;
  119                 sc->sc_regmap[PCF_S1] = PCF_S1;
  120         }
  121         sc->sc_clock = clock;
  122         sc->sc_addr = addr;
  123 
  124         pcfiic_init(sc);
  125 
  126         printf("\n");
  127 
  128         if (sc->sc_master)
  129                 pcfiic_choose_bus(sc, 0);
  130 
  131         rw_init(&sc->sc_lock, "iiclk");
  132         sc->sc_i2c.ic_cookie = sc;
  133         sc->sc_i2c.ic_acquire_bus = pcfiic_i2c_acquire_bus;
  134         sc->sc_i2c.ic_release_bus = pcfiic_i2c_release_bus;
  135         sc->sc_i2c.ic_exec = pcfiic_i2c_exec;
  136 
  137         bzero(&iba, sizeof(iba));
  138         iba.iba_name = "iic";
  139         iba.iba_tag = &sc->sc_i2c;
  140         iba.iba_bus_scan = scan_func;
  141         iba.iba_bus_scan_arg = scan_arg;
  142         config_found(&sc->sc_dev, &iba, iicbus_print);
  143 }
  144 
  145 int
  146 pcfiic_intr(void *arg)
  147 {
  148         return (0);
  149 }
  150 
  151 int
  152 pcfiic_i2c_acquire_bus(void *arg, int flags)
  153 {
  154         struct pcfiic_softc     *sc = arg;
  155 
  156         if (cold || sc->sc_poll || (flags & I2C_F_POLL))
  157                 return (0);
  158 
  159         return (rw_enter(&sc->sc_lock, RW_WRITE | RW_INTR));
  160 }
  161 
  162 void
  163 pcfiic_i2c_release_bus(void *arg, int flags)
  164 {
  165         struct pcfiic_softc     *sc = arg;
  166 
  167         if (cold || sc->sc_poll || (flags & I2C_F_POLL))
  168                 return;
  169 
  170         rw_exit(&sc->sc_lock);
  171 }
  172 
  173 int
  174 pcfiic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr,
  175     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
  176 {
  177         struct pcfiic_softc     *sc = arg;
  178         int                     ret = 0;
  179 
  180 #if 0
  181         printf("%s: exec op: %d addr: 0x%x cmdlen: %d len: %d flags 0x%x\n",
  182             sc->sc_dev.dv_xname, op, addr, cmdlen, len, flags);
  183 #endif
  184 
  185         if (cold || sc->sc_poll)
  186                 flags |= I2C_F_POLL;
  187 
  188         if (sc->sc_master)
  189                 pcfiic_choose_bus(sc, addr >> 7);
  190 
  191         if (cmdlen > 0)
  192                 if (pcfiic_xmit(sc, addr & 0x7f, cmdbuf, cmdlen) != 0)
  193                         return (1);
  194 
  195         if (len > 0) {
  196                 if (I2C_OP_WRITE_P(op))
  197                         ret = pcfiic_xmit(sc, addr & 0x7f, buf, len);
  198                 else
  199                         ret = pcfiic_recv(sc, addr & 0x7f, buf, len);
  200         }
  201         return (ret);
  202 }
  203 
  204 int
  205 pcfiic_xmit(struct pcfiic_softc *sc, u_int8_t addr, const u_int8_t *buf,
  206     size_t len)
  207 {
  208         int                     i, err = 0;
  209         volatile u_int8_t       r;
  210 
  211         if (pcfiic_wait_nBB(sc) != 0)
  212                 return (1);
  213 
  214         pcfiic_write(sc, PCF_S0, addr << 1);
  215         pcfiic_write(sc, PCF_S1, PCF_CTRL_START);
  216 
  217         for (i = 0; i <= len; i++) {
  218                 if (pcfiic_wait_pin(sc, &r) != 0) {
  219                         pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
  220                         return (1);
  221                 }
  222 
  223                 if (r & PCF_STAT_LRB) {
  224                         err = 1;
  225                         break;
  226                 }
  227 
  228                 if (i < len)
  229                         pcfiic_write(sc, PCF_S0, buf[i]);
  230         }
  231         pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
  232         return (err);
  233 }
  234 
  235 int
  236 pcfiic_recv(struct pcfiic_softc *sc, u_int8_t addr, u_int8_t *buf, size_t len)
  237 {
  238         int                     i = 0, err = 0;
  239         volatile u_int8_t       r;
  240 
  241         if (pcfiic_wait_nBB(sc) != 0)
  242                 return (1);
  243 
  244         pcfiic_write(sc, PCF_S0, (addr << 1) | 0x01);
  245         pcfiic_write(sc, PCF_S1, PCF_CTRL_START);
  246 
  247         for (i = 0; i <= len; i++) {
  248                 if (pcfiic_wait_pin(sc, &r) != 0) {
  249                         pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
  250                         return (1);
  251                 }
  252 
  253                 if ((i != len) && (r & PCF_STAT_LRB)) {
  254                         pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
  255                         return (1);
  256                 }
  257 
  258                 if (i == len - 1) {
  259                         pcfiic_write(sc, PCF_S1, PCF_CTRL_ESO);
  260                 } else if (i == len) {
  261                         pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
  262                 }
  263 
  264                 r = pcfiic_read(sc, PCF_S0);
  265                 if (i > 0)
  266                         buf[i - 1] = r;
  267         }
  268         return (err);
  269 }
  270 
  271 volatile u_int8_t
  272 pcfiic_read(struct pcfiic_softc *sc, bus_size_t r)
  273 {
  274         bus_space_barrier(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r], 1,
  275             BUS_SPACE_BARRIER_READ);
  276         return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r]));
  277 }
  278 
  279 volatile void
  280 pcfiic_write(struct pcfiic_softc *sc, bus_size_t r, u_int8_t v)
  281 {
  282         bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r], v);
  283         bus_space_barrier(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r], 1,
  284             BUS_SPACE_BARRIER_WRITE);
  285 }
  286 
  287 void
  288 pcfiic_choose_bus(struct pcfiic_softc *sc, u_int8_t bus)
  289 {
  290         bus_space_write_1(sc->sc_iot, sc->sc_ioh2, 0, bus);
  291         bus_space_barrier(sc->sc_iot, sc->sc_ioh2, 0, 1,
  292             BUS_SPACE_BARRIER_WRITE);
  293 }
  294 
  295 int
  296 pcfiic_wait_nBB(struct pcfiic_softc *sc)
  297 {
  298         int             i;
  299 
  300         for (i = 0; i < 1000; i++) {
  301                 if (pcfiic_read(sc, PCF_S1) & PCF_STAT_nBB)
  302                         return (0);
  303                 delay(1000);
  304         }
  305         return (1);
  306 }
  307 
  308 int
  309 pcfiic_wait_pin(struct pcfiic_softc *sc, volatile u_int8_t *r)
  310 {
  311         int             i;
  312 
  313         for (i = 0; i < 1000; i++) {
  314                 *r = pcfiic_read(sc, PCF_S1);
  315                 if ((*r & PCF_STAT_PIN) == 0)
  316                         return (0);
  317                 delay(1000);
  318         }
  319         return (1);
  320 }

/* [<][>][^][v][top][bottom][index][help] */