14e190a62SNicolas Souchu /*- 24e190a62SNicolas Souchu * Copyright (c) 1998 Nicolas Souchu, Marc Bouget 3e0efc557SJoerg Wunsch * Copyright (c) 2004 Joerg Wunsch 44e190a62SNicolas Souchu * All rights reserved. 54e190a62SNicolas Souchu * 64e190a62SNicolas Souchu * Redistribution and use in source and binary forms, with or without 74e190a62SNicolas Souchu * modification, are permitted provided that the following conditions 84e190a62SNicolas Souchu * are met: 94e190a62SNicolas Souchu * 1. Redistributions of source code must retain the above copyright 104e190a62SNicolas Souchu * notice, this list of conditions and the following disclaimer. 114e190a62SNicolas Souchu * 2. Redistributions in binary form must reproduce the above copyright 124e190a62SNicolas Souchu * notice, this list of conditions and the following disclaimer in the 134e190a62SNicolas Souchu * documentation and/or other materials provided with the distribution. 144e190a62SNicolas Souchu * 154e190a62SNicolas Souchu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 164e190a62SNicolas Souchu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 174e190a62SNicolas Souchu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 184e190a62SNicolas Souchu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 194e190a62SNicolas Souchu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 204e190a62SNicolas Souchu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 214e190a62SNicolas Souchu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 224e190a62SNicolas Souchu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 234e190a62SNicolas Souchu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 244e190a62SNicolas Souchu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 254e190a62SNicolas Souchu * SUCH DAMAGE. 264e190a62SNicolas Souchu */ 27006124d8SDavid E. O'Brien 28006124d8SDavid E. O'Brien #include <sys/cdefs.h> 29006124d8SDavid E. O'Brien __FBSDID("$FreeBSD$"); 30006124d8SDavid E. O'Brien 314e190a62SNicolas Souchu #include <sys/param.h> 3213e3657bSJohn Baldwin #include <sys/bus.h> 3313e3657bSJohn Baldwin #include <sys/lock.h> 344e190a62SNicolas Souchu #include <sys/kernel.h> 354e190a62SNicolas Souchu #include <sys/module.h> 3613e3657bSJohn Baldwin #include <sys/mutex.h> 3713e3657bSJohn Baldwin #include <sys/systm.h> 384e190a62SNicolas Souchu 390f210c92SNicolas Souchu #include <machine/bus.h> 400f210c92SNicolas Souchu #include <machine/resource.h> 41e0efc557SJoerg Wunsch 420f210c92SNicolas Souchu #include <sys/rman.h> 430f210c92SNicolas Souchu 449e58d59fSJohn Baldwin #include <dev/iicbus/iicbus.h> 454e190a62SNicolas Souchu #include <dev/iicbus/iiconf.h> 46e0efc557SJoerg Wunsch #include <dev/pcf/pcfvar.h> 474e190a62SNicolas Souchu #include "iicbus_if.h" 484e190a62SNicolas Souchu 49e0efc557SJoerg Wunsch /* Not so official debugging option. */ 50e0efc557SJoerg Wunsch /* #define PCFDEBUG */ 510f210c92SNicolas Souchu 52e0efc557SJoerg Wunsch static int pcf_wait_byte(struct pcf_softc *pcf); 53e0efc557SJoerg Wunsch static int pcf_noack(struct pcf_softc *pcf, int timeout); 5413e3657bSJohn Baldwin static void pcf_stop_locked(struct pcf_softc *pcf); 554e190a62SNicolas Souchu 564e190a62SNicolas Souchu /* 574e190a62SNicolas Souchu * Polling mode for master operations wait for a new 5813e3657bSJohn Baldwin * byte incoming or outgoing 594e190a62SNicolas Souchu */ 6013e3657bSJohn Baldwin static int 61e0efc557SJoerg Wunsch pcf_wait_byte(struct pcf_softc *sc) 624e190a62SNicolas Souchu { 634e190a62SNicolas Souchu int counter = TIMEOUT; 644e190a62SNicolas Souchu 6513e3657bSJohn Baldwin PCF_ASSERT_LOCKED(sc); 664e190a62SNicolas Souchu while (counter--) { 674e190a62SNicolas Souchu 68e0efc557SJoerg Wunsch if ((pcf_get_S1(sc) & PIN) == 0) 694e190a62SNicolas Souchu return (0); 704e190a62SNicolas Souchu } 714e190a62SNicolas Souchu 724f16b8b1SNicolas Souchu #ifdef PCFDEBUG 734f16b8b1SNicolas Souchu printf("pcf: timeout!\n"); 744f16b8b1SNicolas Souchu #endif 754f16b8b1SNicolas Souchu 764e190a62SNicolas Souchu return (IIC_ETIMEOUT); 774e190a62SNicolas Souchu } 784e190a62SNicolas Souchu 7913e3657bSJohn Baldwin static void 8013e3657bSJohn Baldwin pcf_stop_locked(struct pcf_softc *sc) 814e190a62SNicolas Souchu { 824e190a62SNicolas Souchu 8313e3657bSJohn Baldwin PCF_ASSERT_LOCKED(sc); 84e0efc557SJoerg Wunsch #ifdef PCFDEBUG 85e0efc557SJoerg Wunsch device_printf(dev, " >> stop\n"); 86e0efc557SJoerg Wunsch #endif 87af548787SNicolas Souchu /* 88af548787SNicolas Souchu * Send STOP condition iff the START condition was previously sent. 899d5abbddSJens Schweikhardt * STOP is sent only once even if an iicbus_stop() is called after 90e0efc557SJoerg Wunsch * an iicbus_read()... see pcf_read(): the PCF needs to send the stop 91af548787SNicolas Souchu * before the last char is read. 92af548787SNicolas Souchu */ 93e0efc557SJoerg Wunsch if (sc->pcf_started) { 944e190a62SNicolas Souchu /* set stop condition and enable IT */ 95e0efc557SJoerg Wunsch pcf_set_S1(sc, PIN|ESO|ENI|STO|ACK); 964e190a62SNicolas Souchu 97e0efc557SJoerg Wunsch sc->pcf_started = 0; 98af548787SNicolas Souchu } 994e190a62SNicolas Souchu } 1004e190a62SNicolas Souchu 10113e3657bSJohn Baldwin static int 102e0efc557SJoerg Wunsch pcf_noack(struct pcf_softc *sc, int timeout) 103af548787SNicolas Souchu { 104af548787SNicolas Souchu int noack; 105af548787SNicolas Souchu int k = timeout/10; 106af548787SNicolas Souchu 10713e3657bSJohn Baldwin PCF_ASSERT_LOCKED(sc); 108af548787SNicolas Souchu do { 109e0efc557SJoerg Wunsch noack = pcf_get_S1(sc) & LRB; 110af548787SNicolas Souchu if (!noack) 111af548787SNicolas Souchu break; 112af548787SNicolas Souchu DELAY(10); /* XXX wait 10 us */ 113af548787SNicolas Souchu } while (k--); 114af548787SNicolas Souchu 115af548787SNicolas Souchu return (noack); 116af548787SNicolas Souchu } 117af548787SNicolas Souchu 118e0efc557SJoerg Wunsch int 119e0efc557SJoerg Wunsch pcf_repeated_start(device_t dev, u_char slave, int timeout) 1204e190a62SNicolas Souchu { 121e0efc557SJoerg Wunsch struct pcf_softc *sc = DEVTOSOFTC(dev); 1224e190a62SNicolas Souchu int error = 0; 1234e190a62SNicolas Souchu 12413e3657bSJohn Baldwin PCF_LOCK(sc); 125e0efc557SJoerg Wunsch #ifdef PCFDEBUG 126e0efc557SJoerg Wunsch device_printf(dev, " >> repeated start for slave %#x\n", 127e0efc557SJoerg Wunsch (unsigned)slave); 128e0efc557SJoerg Wunsch #endif 1294e190a62SNicolas Souchu /* repeated start */ 130e0efc557SJoerg Wunsch pcf_set_S1(sc, ESO|STA|STO|ACK); 1314e190a62SNicolas Souchu 1324e190a62SNicolas Souchu /* set slave address to PCF. Last bit (LSB) must be set correctly 1334e190a62SNicolas Souchu * according to transfer direction */ 134e0efc557SJoerg Wunsch pcf_set_S0(sc, slave); 1354e190a62SNicolas Souchu 1364e190a62SNicolas Souchu /* wait for address sent, polling */ 137e0efc557SJoerg Wunsch if ((error = pcf_wait_byte(sc))) 1384e190a62SNicolas Souchu goto error; 1394e190a62SNicolas Souchu 140af548787SNicolas Souchu /* check for ack */ 141e0efc557SJoerg Wunsch if (pcf_noack(sc, timeout)) { 1424e190a62SNicolas Souchu error = IIC_ENOACK; 1434f16b8b1SNicolas Souchu #ifdef PCFDEBUG 1444f16b8b1SNicolas Souchu printf("pcf: no ack on repeated_start!\n"); 1454f16b8b1SNicolas Souchu #endif 1464e190a62SNicolas Souchu goto error; 1474e190a62SNicolas Souchu } 1484e190a62SNicolas Souchu 14913e3657bSJohn Baldwin PCF_UNLOCK(sc); 1504e190a62SNicolas Souchu return (0); 1514e190a62SNicolas Souchu 1524e190a62SNicolas Souchu error: 15313e3657bSJohn Baldwin pcf_stop_locked(sc); 15413e3657bSJohn Baldwin PCF_UNLOCK(sc); 1554e190a62SNicolas Souchu return (error); 1564e190a62SNicolas Souchu } 1574e190a62SNicolas Souchu 158e0efc557SJoerg Wunsch int 159e0efc557SJoerg Wunsch pcf_start(device_t dev, u_char slave, int timeout) 1604e190a62SNicolas Souchu { 161e0efc557SJoerg Wunsch struct pcf_softc *sc = DEVTOSOFTC(dev); 1624e190a62SNicolas Souchu int error = 0; 1634e190a62SNicolas Souchu 16413e3657bSJohn Baldwin PCF_LOCK(sc); 165e0efc557SJoerg Wunsch #ifdef PCFDEBUG 166e0efc557SJoerg Wunsch device_printf(dev, " >> start for slave %#x\n", (unsigned)slave); 167e0efc557SJoerg Wunsch #endif 1684f16b8b1SNicolas Souchu if ((pcf_get_S1(sc) & nBB) == 0) { 1694f16b8b1SNicolas Souchu #ifdef PCFDEBUG 1704f16b8b1SNicolas Souchu printf("pcf: busy!\n"); 1714f16b8b1SNicolas Souchu #endif 17213e3657bSJohn Baldwin PCF_UNLOCK(sc); 1734e190a62SNicolas Souchu return (IIC_EBUSBSY); 1744f16b8b1SNicolas Souchu } 1754e190a62SNicolas Souchu 1764e190a62SNicolas Souchu /* set slave address to PCF. Last bit (LSB) must be set correctly 1774e190a62SNicolas Souchu * according to transfer direction */ 178e0efc557SJoerg Wunsch pcf_set_S0(sc, slave); 1794e190a62SNicolas Souchu 1804e190a62SNicolas Souchu /* START only */ 181e0efc557SJoerg Wunsch pcf_set_S1(sc, PIN|ESO|STA|ACK); 1824e190a62SNicolas Souchu 183e0efc557SJoerg Wunsch sc->pcf_started = 1; 184af548787SNicolas Souchu 1854e190a62SNicolas Souchu /* wait for address sent, polling */ 186e0efc557SJoerg Wunsch if ((error = pcf_wait_byte(sc))) 1874e190a62SNicolas Souchu goto error; 1884e190a62SNicolas Souchu 189af548787SNicolas Souchu /* check for ACK */ 190e0efc557SJoerg Wunsch if (pcf_noack(sc, timeout)) { 1914e190a62SNicolas Souchu error = IIC_ENOACK; 1924f16b8b1SNicolas Souchu #ifdef PCFDEBUG 1934f16b8b1SNicolas Souchu printf("pcf: no ack on start!\n"); 1944f16b8b1SNicolas Souchu #endif 1954e190a62SNicolas Souchu goto error; 1964e190a62SNicolas Souchu } 1974e190a62SNicolas Souchu 19813e3657bSJohn Baldwin PCF_UNLOCK(sc); 1994e190a62SNicolas Souchu return (0); 2004e190a62SNicolas Souchu 2014e190a62SNicolas Souchu error: 20213e3657bSJohn Baldwin pcf_stop_locked(sc); 20313e3657bSJohn Baldwin PCF_UNLOCK(sc); 2044e190a62SNicolas Souchu return (error); 2054e190a62SNicolas Souchu } 2064e190a62SNicolas Souchu 20713e3657bSJohn Baldwin int 20813e3657bSJohn Baldwin pcf_stop(device_t dev) 20913e3657bSJohn Baldwin { 21013e3657bSJohn Baldwin struct pcf_softc *sc = DEVTOSOFTC(dev); 21113e3657bSJohn Baldwin 21213e3657bSJohn Baldwin #ifdef PCFDEBUG 21313e3657bSJohn Baldwin device_printf(dev, " >> stop\n"); 21413e3657bSJohn Baldwin #endif 21513e3657bSJohn Baldwin PCF_LOCK(sc); 21613e3657bSJohn Baldwin pcf_stop_locked(sc); 21713e3657bSJohn Baldwin PCF_UNLOCK(sc); 21813e3657bSJohn Baldwin 21913e3657bSJohn Baldwin return (0); 22013e3657bSJohn Baldwin } 22113e3657bSJohn Baldwin 222e0efc557SJoerg Wunsch void 223e0efc557SJoerg Wunsch pcf_intr(void *arg) 2244e190a62SNicolas Souchu { 2254f16b8b1SNicolas Souchu struct pcf_softc *sc = arg; 2264e190a62SNicolas Souchu char data, status, addr; 2274e190a62SNicolas Souchu char error = 0; 2284e190a62SNicolas Souchu 22913e3657bSJohn Baldwin PCF_LOCK(sc); 230e0efc557SJoerg Wunsch status = pcf_get_S1(sc); 2314e190a62SNicolas Souchu 2324e190a62SNicolas Souchu if (status & PIN) { 2334f16b8b1SNicolas Souchu printf("pcf: spurious interrupt, status=0x%x\n", 234e0efc557SJoerg Wunsch status & 0xff); 2354e190a62SNicolas Souchu 2364e190a62SNicolas Souchu goto error; 2374e190a62SNicolas Souchu } 2384e190a62SNicolas Souchu 2394e190a62SNicolas Souchu if (status & LAB) 2404f16b8b1SNicolas Souchu printf("pcf: bus arbitration lost!\n"); 2414e190a62SNicolas Souchu 2424e190a62SNicolas Souchu if (status & BER) { 2434e190a62SNicolas Souchu error = IIC_EBUSERR; 244e0efc557SJoerg Wunsch iicbus_intr(sc->iicbus, INTR_ERROR, &error); 2454e190a62SNicolas Souchu 2464e190a62SNicolas Souchu goto error; 2474e190a62SNicolas Souchu } 2484e190a62SNicolas Souchu 2494e190a62SNicolas Souchu do { 250e0efc557SJoerg Wunsch status = pcf_get_S1(sc); 2514e190a62SNicolas Souchu 252e0efc557SJoerg Wunsch switch(sc->pcf_slave_mode) { 2534e190a62SNicolas Souchu 2544e190a62SNicolas Souchu case SLAVE_TRANSMITTER: 2554e190a62SNicolas Souchu if (status & LRB) { 2564e190a62SNicolas Souchu /* ack interrupt line */ 257e0efc557SJoerg Wunsch dummy_write(sc); 2584e190a62SNicolas Souchu 2594e190a62SNicolas Souchu /* no ack, don't send anymore */ 260e0efc557SJoerg Wunsch sc->pcf_slave_mode = SLAVE_RECEIVER; 2614e190a62SNicolas Souchu 262e0efc557SJoerg Wunsch iicbus_intr(sc->iicbus, INTR_NOACK, NULL); 2634e190a62SNicolas Souchu break; 2644e190a62SNicolas Souchu } 2654e190a62SNicolas Souchu 2664e190a62SNicolas Souchu /* get data from upper code */ 267e0efc557SJoerg Wunsch iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data); 2684e190a62SNicolas Souchu 269e0efc557SJoerg Wunsch pcf_set_S0(sc, data); 2704e190a62SNicolas Souchu break; 2714e190a62SNicolas Souchu 2724e190a62SNicolas Souchu case SLAVE_RECEIVER: 2734e190a62SNicolas Souchu if (status & AAS) { 274e0efc557SJoerg Wunsch addr = pcf_get_S0(sc); 2754e190a62SNicolas Souchu 2764e190a62SNicolas Souchu if (status & AD0) 277e0efc557SJoerg Wunsch iicbus_intr(sc->iicbus, INTR_GENERAL, &addr); 2784e190a62SNicolas Souchu else 279e0efc557SJoerg Wunsch iicbus_intr(sc->iicbus, INTR_START, &addr); 2804e190a62SNicolas Souchu 2814e190a62SNicolas Souchu if (addr & LSB) { 282e0efc557SJoerg Wunsch sc->pcf_slave_mode = SLAVE_TRANSMITTER; 2834e190a62SNicolas Souchu 2844e190a62SNicolas Souchu /* get the first char from upper code */ 285e0efc557SJoerg Wunsch iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data); 2864e190a62SNicolas Souchu 2874e190a62SNicolas Souchu /* send first data byte */ 288e0efc557SJoerg Wunsch pcf_set_S0(sc, data); 2894e190a62SNicolas Souchu } 2904e190a62SNicolas Souchu 2914e190a62SNicolas Souchu break; 2924e190a62SNicolas Souchu } 2934e190a62SNicolas Souchu 2944e190a62SNicolas Souchu /* stop condition received? */ 2954e190a62SNicolas Souchu if (status & STS) { 2964e190a62SNicolas Souchu /* ack interrupt line */ 297e0efc557SJoerg Wunsch dummy_read(sc); 2984e190a62SNicolas Souchu 2994e190a62SNicolas Souchu /* emulate intr stop condition */ 300e0efc557SJoerg Wunsch iicbus_intr(sc->iicbus, INTR_STOP, NULL); 3014e190a62SNicolas Souchu 3024e190a62SNicolas Souchu } else { 3034e190a62SNicolas Souchu /* get data, ack interrupt line */ 304e0efc557SJoerg Wunsch data = pcf_get_S0(sc); 3054e190a62SNicolas Souchu 3064e190a62SNicolas Souchu /* deliver the character */ 307e0efc557SJoerg Wunsch iicbus_intr(sc->iicbus, INTR_RECEIVE, &data); 3084e190a62SNicolas Souchu } 3094e190a62SNicolas Souchu break; 3104e190a62SNicolas Souchu 3114e190a62SNicolas Souchu default: 3126e551fb6SDavid E. O'Brien panic("%s: unknown slave mode (%d)!", __func__, 313e0efc557SJoerg Wunsch sc->pcf_slave_mode); 3144e190a62SNicolas Souchu } 3154e190a62SNicolas Souchu 316e0efc557SJoerg Wunsch } while ((pcf_get_S1(sc) & PIN) == 0); 31713e3657bSJohn Baldwin PCF_UNLOCK(sc); 3184e190a62SNicolas Souchu 3194e190a62SNicolas Souchu return; 3204e190a62SNicolas Souchu 3214e190a62SNicolas Souchu error: 3224e190a62SNicolas Souchu /* unknown event on bus...reset PCF */ 323e0efc557SJoerg Wunsch pcf_set_S1(sc, PIN|ESO|ENI|ACK); 3244e190a62SNicolas Souchu 325e0efc557SJoerg Wunsch sc->pcf_slave_mode = SLAVE_RECEIVER; 32613e3657bSJohn Baldwin PCF_UNLOCK(sc); 3274e190a62SNicolas Souchu 3284e190a62SNicolas Souchu return; 3294e190a62SNicolas Souchu } 3304e190a62SNicolas Souchu 331e0efc557SJoerg Wunsch int 332e0efc557SJoerg Wunsch pcf_rst_card(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 3334e190a62SNicolas Souchu { 334e0efc557SJoerg Wunsch struct pcf_softc *sc = DEVTOSOFTC(dev); 335af548787SNicolas Souchu 33613e3657bSJohn Baldwin PCF_LOCK(sc); 337af548787SNicolas Souchu if (oldaddr) 338e0efc557SJoerg Wunsch *oldaddr = sc->pcf_addr; 3394e190a62SNicolas Souchu 3404e190a62SNicolas Souchu /* retrieve own address from bus level */ 341af548787SNicolas Souchu if (!addr) 342e0efc557SJoerg Wunsch sc->pcf_addr = PCF_DEFAULT_ADDR; 343af548787SNicolas Souchu else 344e0efc557SJoerg Wunsch sc->pcf_addr = addr; 3454e190a62SNicolas Souchu 346e0efc557SJoerg Wunsch pcf_set_S1(sc, PIN); /* initialize S1 */ 3474e190a62SNicolas Souchu 3484e190a62SNicolas Souchu /* own address S'O<>0 */ 349e0efc557SJoerg Wunsch pcf_set_S0(sc, sc->pcf_addr >> 1); 3504e190a62SNicolas Souchu 3514e190a62SNicolas Souchu /* select clock register */ 352e0efc557SJoerg Wunsch pcf_set_S1(sc, PIN|ES1); 3534e190a62SNicolas Souchu 3544e190a62SNicolas Souchu /* select bus speed : 18=90kb, 19=45kb, 1A=11kb, 1B=1.5kb */ 3554e190a62SNicolas Souchu switch (speed) { 3564e190a62SNicolas Souchu case IIC_SLOW: 357e0efc557SJoerg Wunsch pcf_set_S0(sc, 0x1b); /* XXX Sun uses 0x1f */ 3584e190a62SNicolas Souchu break; 3594e190a62SNicolas Souchu 3604e190a62SNicolas Souchu case IIC_FAST: 361e0efc557SJoerg Wunsch pcf_set_S0(sc, 0x19); /* XXX Sun: 0x1d */ 3624e190a62SNicolas Souchu break; 3634e190a62SNicolas Souchu 3644e190a62SNicolas Souchu case IIC_UNKNOWN: 3654e190a62SNicolas Souchu case IIC_FASTEST: 3664e190a62SNicolas Souchu default: 367e0efc557SJoerg Wunsch pcf_set_S0(sc, 0x18); /* XXX Sun: 0x1c */ 3684e190a62SNicolas Souchu break; 3694e190a62SNicolas Souchu } 3704e190a62SNicolas Souchu 3714e190a62SNicolas Souchu /* set bus on, ack=yes, INT=yes */ 372e0efc557SJoerg Wunsch pcf_set_S1(sc, PIN|ESO|ENI|ACK); 3734e190a62SNicolas Souchu 374e0efc557SJoerg Wunsch sc->pcf_slave_mode = SLAVE_RECEIVER; 37513e3657bSJohn Baldwin PCF_UNLOCK(sc); 3764e190a62SNicolas Souchu 3774e190a62SNicolas Souchu return (0); 3784e190a62SNicolas Souchu } 3794e190a62SNicolas Souchu 380e0efc557SJoerg Wunsch int 381e0efc557SJoerg Wunsch pcf_write(device_t dev, char *buf, int len, int *sent, int timeout /* us */) 3824e190a62SNicolas Souchu { 383e0efc557SJoerg Wunsch struct pcf_softc *sc = DEVTOSOFTC(dev); 3844e190a62SNicolas Souchu int bytes, error = 0; 3854e190a62SNicolas Souchu 3864e190a62SNicolas Souchu #ifdef PCFDEBUG 387e0efc557SJoerg Wunsch device_printf(dev, " >> writing %d bytes: %#x%s\n", len, 388e0efc557SJoerg Wunsch (unsigned)buf[0], len > 1? "...": ""); 3894e190a62SNicolas Souchu #endif 3904e190a62SNicolas Souchu 3914e190a62SNicolas Souchu bytes = 0; 39213e3657bSJohn Baldwin PCF_LOCK(sc); 3934e190a62SNicolas Souchu while (len) { 3944e190a62SNicolas Souchu 395e0efc557SJoerg Wunsch pcf_set_S0(sc, *buf++); 3964e190a62SNicolas Souchu 397af548787SNicolas Souchu /* wait for the byte to be send */ 398e0efc557SJoerg Wunsch if ((error = pcf_wait_byte(sc))) 3994e190a62SNicolas Souchu goto error; 4004e190a62SNicolas Souchu 401af548787SNicolas Souchu /* check if ack received */ 402e0efc557SJoerg Wunsch if (pcf_noack(sc, timeout)) { 4034e190a62SNicolas Souchu error = IIC_ENOACK; 4044e190a62SNicolas Souchu goto error; 4054e190a62SNicolas Souchu } 4064e190a62SNicolas Souchu 4074e190a62SNicolas Souchu len --; 4084e190a62SNicolas Souchu bytes ++; 4094e190a62SNicolas Souchu } 4104e190a62SNicolas Souchu 4114e190a62SNicolas Souchu error: 4124e190a62SNicolas Souchu *sent = bytes; 41313e3657bSJohn Baldwin PCF_UNLOCK(sc); 4144e190a62SNicolas Souchu 4154e190a62SNicolas Souchu #ifdef PCFDEBUG 416e0efc557SJoerg Wunsch device_printf(dev, " >> %d bytes written (%d)\n", bytes, error); 4174e190a62SNicolas Souchu #endif 4184e190a62SNicolas Souchu 4194e190a62SNicolas Souchu return (error); 4204e190a62SNicolas Souchu } 4214e190a62SNicolas Souchu 422e0efc557SJoerg Wunsch int 423e0efc557SJoerg Wunsch pcf_read(device_t dev, char *buf, int len, int *read, int last, 424af548787SNicolas Souchu int delay /* us */) 4254e190a62SNicolas Souchu { 426e0efc557SJoerg Wunsch struct pcf_softc *sc = DEVTOSOFTC(dev); 4274e190a62SNicolas Souchu int bytes, error = 0; 4284e190a62SNicolas Souchu #ifdef PCFDEBUG 429e0efc557SJoerg Wunsch char *obuf = buf; 430e0efc557SJoerg Wunsch 431e0efc557SJoerg Wunsch device_printf(dev, " << reading %d bytes\n", len); 4324e190a62SNicolas Souchu #endif 4334e190a62SNicolas Souchu 43413e3657bSJohn Baldwin PCF_LOCK(sc); 4354e190a62SNicolas Souchu /* trig the bus to get the first data byte in S0 */ 4364e190a62SNicolas Souchu if (len) { 437af548787SNicolas Souchu if (len == 1 && last) 4384e190a62SNicolas Souchu /* just one byte to read */ 439e0efc557SJoerg Wunsch pcf_set_S1(sc, ESO); /* no ack */ 4404e190a62SNicolas Souchu 441e0efc557SJoerg Wunsch dummy_read(sc); 4424e190a62SNicolas Souchu } 4434e190a62SNicolas Souchu 4444e190a62SNicolas Souchu bytes = 0; 4454e190a62SNicolas Souchu while (len) { 4464e190a62SNicolas Souchu 447af548787SNicolas Souchu /* XXX delay needed here */ 448af548787SNicolas Souchu 449af548787SNicolas Souchu /* wait for trigged byte */ 450e0efc557SJoerg Wunsch if ((error = pcf_wait_byte(sc))) { 45113e3657bSJohn Baldwin pcf_stop_locked(sc); 4524e190a62SNicolas Souchu goto error; 4534e190a62SNicolas Souchu } 4544e190a62SNicolas Souchu 455af548787SNicolas Souchu if (len == 1 && last) 456af548787SNicolas Souchu /* ok, last data byte already in S0, no I2C activity 457e0efc557SJoerg Wunsch * on next pcf_get_S0() */ 45813e3657bSJohn Baldwin pcf_stop_locked(sc); 4594e190a62SNicolas Souchu 460af548787SNicolas Souchu else if (len == 2 && last) 4614e190a62SNicolas Souchu /* next trigged byte with no ack */ 462e0efc557SJoerg Wunsch pcf_set_S1(sc, ESO); 4634e190a62SNicolas Souchu 464af548787SNicolas Souchu /* receive byte, trig next byte */ 465e0efc557SJoerg Wunsch *buf++ = pcf_get_S0(sc); 4664e190a62SNicolas Souchu 4674e190a62SNicolas Souchu len --; 4684e190a62SNicolas Souchu bytes ++; 4694e190a62SNicolas Souchu }; 4704e190a62SNicolas Souchu 4714e190a62SNicolas Souchu error: 4724e190a62SNicolas Souchu *read = bytes; 47313e3657bSJohn Baldwin PCF_UNLOCK(sc); 4744e190a62SNicolas Souchu 4754e190a62SNicolas Souchu #ifdef PCFDEBUG 476e0efc557SJoerg Wunsch device_printf(dev, " << %d bytes read (%d): %#x%s\n", bytes, error, 477e0efc557SJoerg Wunsch (unsigned)obuf[0], bytes > 1? "...": ""); 4784e190a62SNicolas Souchu #endif 4794e190a62SNicolas Souchu 4804e190a62SNicolas Souchu return (error); 4814e190a62SNicolas Souchu } 4829e58d59fSJohn Baldwin 4839e58d59fSJohn Baldwin DRIVER_MODULE(iicbus, pcf, iicbus_driver, iicbus_devclass, 0, 0); 4849e58d59fSJohn Baldwin MODULE_DEPEND(pcf, iicbus, PCF_MINVER, PCF_PREFVER, PCF_MAXVER); 4859e58d59fSJohn Baldwin MODULE_VERSION(pcf, PCF_MODVER); 486