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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: pcf8584.c,v 1.5 2008/04/28 20:23:51 martin Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 2007 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Tobias Nygren.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * Philips PCF8584 I2C Bus Controller
   34  *
   35  * This driver does not yet support multi-master arbitration, concurrent access
   36  * or interrupts, but it should be usable for single-master applications.
   37  * It is currently used by the envctrl(4) driver on sparc64.
   38  */
   39 
   40 #include <sys/cdefs.h>
   41 __KERNEL_RCSID(0, "$NetBSD: pcf8584.c,v 1.5 2008/04/28 20:23:51 martin Exp $");
   42 
   43 #include <sys/param.h>
   44 #include <sys/device.h>
   45 #include <sys/kernel.h>
   46 #include <sys/systm.h>
   47 #include <sys/condvar.h>
   48 #include <sys/mutex.h>
   49 #include <sys/bus.h>
   50 #include <machine/param.h>
   51 #include <dev/i2c/i2cvar.h>
   52 #include <dev/ic/pcf8584reg.h>
   53 #include <dev/ic/pcf8584var.h>
   54 
   55 static void pcf8584_bus_reset(struct pcf8584_handle *, int);
   56 static int pcf8584_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
   57                         void *, size_t, int);
   58 static int pcf8584_acquire_bus(void *, int);
   59 static void pcf8584_release_bus(void *, int);
   60 static void pcf8584_wait(struct pcf8584_handle *, int);
   61 
   62 /*  Must delay for 500 ns between bus accesses according to manual. */
   63 #define DATA_W(x) (DELAY(1), bus_space_write_1(ha->ha_iot, ha->ha_ioh, 0, x))
   64 #define DATA_R() (DELAY(1), bus_space_read_1(ha->ha_iot, ha->ha_ioh, 0))
   65 #define CSR_W(x) (DELAY(1), bus_space_write_1(ha->ha_iot, ha->ha_ioh, 1, x))
   66 #define STATUS_R() (DELAY(1), bus_space_read_1(ha->ha_iot, ha->ha_ioh, 1))
   67 #define BUSY() ((STATUS_R() & PCF8584_STATUS_BBN) == 0)
   68 #define PENDING() ((STATUS_R() & PCF8584_STATUS_PIN) == 0)
   69 #define NAK() ((STATUS_R() & PCF8584_STATUS_LRB) != 0)
   70 
   71 /*
   72  * Wait for an interrupt.
   73  */
   74 static void
   75 pcf8584_wait(struct pcf8584_handle *ha, int flags)
   76 {
   77         int timeo;
   78 
   79         if (flags & I2C_F_POLL) {
   80                 timeo = 20;
   81                 while (timeo && !PENDING()) {
   82                         DELAY(1000);
   83                         timeo--;
   84                 }
   85         } else {
   86                 mutex_enter(&ha->ha_intrmtx);
   87                 cv_timedwait(&ha->ha_intrcond, &ha->ha_intrmtx, mstohz(20));
   88                 mutex_exit(&ha->ha_intrmtx);
   89         }
   90 }
   91 
   92 #ifdef notyet
   93 static void
   94 pcf8584_intr(struct pcf8584_handle *ha) {
   95 
   96         cv_wakeup(&ha->ha_intrcond);
   97 }
   98 #endif
   99 
  100 int
  101 pcf8584_init(struct pcf8584_handle *ha)
  102 {
  103 
  104         ha->ha_i2c.ic_cookie = ha;
  105         ha->ha_i2c.ic_acquire_bus = pcf8584_acquire_bus;
  106         ha->ha_i2c.ic_release_bus = pcf8584_release_bus;
  107         ha->ha_i2c.ic_exec = pcf8584_exec;
  108 
  109         mutex_init(&ha->ha_intrmtx, MUTEX_DEFAULT, IPL_NONE);
  110         cv_init(&ha->ha_intrcond, "pcf8584");
  111 
  112         pcf8584_bus_reset(ha, I2C_F_POLL);
  113 
  114         return 0;
  115 }
  116 
  117 /*
  118  * Reset i2c bus.
  119  */
  120 static void
  121 pcf8584_bus_reset(struct pcf8584_handle *ha, int flags)
  122 {
  123 
  124         /* initialize PCF8584 */
  125         CSR_W(PCF8584_CTRL_PIN);
  126         DATA_W(0x55);
  127         CSR_W(PCF8584_CTRL_PIN | PCF8584_REG_S2);
  128         DATA_W(PCF8584_CLK_12 | PCF8584_SCL_90);
  129         CSR_W(PCF8584_CTRL_PIN | PCF8584_CTRL_ESO | PCF8584_CTRL_ACK);
  130 
  131         /* XXX needs multi-master synchronization delay here */
  132 
  133         /*
  134          * Blindly attempt a write at a nonexistent i2c address (0x7F).
  135          * This allows hung i2c devices to pick up the stop condition.
  136          */
  137         DATA_W(0x7F << 1);
  138         CSR_W(PCF8584_CMD_START);
  139         pcf8584_wait(ha, flags);
  140         CSR_W(PCF8584_CMD_STOP);
  141         pcf8584_wait(ha, flags);
  142 }
  143 
  144 static int
  145 pcf8584_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, 
  146     const void *cmdbuf, size_t cmdlen, void *buf,
  147     size_t len, int flags)
  148 {
  149         int i;
  150         struct pcf8584_handle *ha = cookie;
  151         uint8_t *p = buf;
  152 
  153         KASSERT(cmdlen == 0);
  154         KASSERT(op == I2C_OP_READ_WITH_STOP || op == I2C_OP_WRITE_WITH_STOP);
  155 
  156         if (BUSY()) {
  157                 /* We're the only master on the bus, something is wrong. */
  158                 printf("*%s: i2c bus busy!\n", device_xname(ha->ha_parent));
  159                 pcf8584_bus_reset(ha, flags);
  160         }
  161         if (op == I2C_OP_READ_WITH_STOP)
  162                 DATA_W((addr << 1) | 1);
  163         else
  164                 DATA_W(addr << 1);
  165 
  166         CSR_W(PCF8584_CMD_START);
  167         pcf8584_wait(ha, flags);
  168         if (!PENDING()) {
  169                 printf("%s: no intr after i2c sla\n", device_xname(ha->ha_parent));
  170         }
  171         if (NAK())
  172                 goto fail;
  173 
  174         if (op == I2C_OP_READ_WITH_STOP) {
  175                 (void) DATA_R();/* dummy read */
  176                 for (i = 0; i < len; i++) {
  177                         /* wait for a byte to arrive */
  178                         pcf8584_wait(ha, flags);
  179                         if (!PENDING()) {
  180                                 printf("%s: lost intr during i2c read\n",
  181                                     device_xname(ha->ha_parent));
  182                                 goto fail;
  183                         }
  184                         if (NAK())
  185                                 goto fail;
  186                         if (i == len - 1) {
  187                                 /*
  188                                  * we're about to read the final byte, so we
  189                                  * set the controller to NAK the following
  190                                  * byte, if any.
  191                                  */
  192                                 CSR_W(PCF8584_CMD_NAK);
  193                         }
  194                         *p++ = DATA_R();
  195                 }
  196                 pcf8584_wait(ha, flags);
  197                 if (!PENDING()) {
  198                         printf("%s: no intr on final i2c nak\n",
  199                             device_xname(ha->ha_parent));
  200                         goto fail;
  201                 }
  202                 CSR_W(PCF8584_CMD_STOP);
  203                 (void) DATA_R();/* dummy read */
  204         } else {
  205                 for (i = 0; i < len; i++) {
  206                         DATA_W(*p++);
  207                         pcf8584_wait(ha, flags);
  208                         if (!PENDING()) {
  209                                 printf("%s: no intr during i2c write\n",
  210                                     device_xname(ha->ha_parent));
  211                                 goto fail;
  212                         }
  213                         if (NAK())
  214                                 goto fail;
  215                 }
  216                 CSR_W(PCF8584_CMD_STOP);
  217         }
  218         pcf8584_wait(ha, flags);
  219         return 0;
  220 fail:
  221         CSR_W(PCF8584_CMD_STOP);
  222         pcf8584_wait(ha, flags);
  223 
  224         return 1;
  225 }
  226 
  227 static int
  228 pcf8584_acquire_bus(void *cookie, int flags)
  229 {
  230 
  231         /* XXX concurrent access not yet implemented */
  232         return 0;
  233 }
  234 
  235 static void
  236 pcf8584_release_bus(void *cookie, int flags)
  237 {
  238 
  239 }

Cache object: 33de7cd231b5e359dfeaafc92690a285


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