14e190a62SNicolas Souchu /*- 2718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3718cf2ccSPedro F. Giffuni * 44e190a62SNicolas Souchu * Copyright (c) 1998 Nicolas Souchu, Marc Bouget 5e0efc557SJoerg Wunsch * Copyright (c) 2004 Joerg Wunsch 64e190a62SNicolas Souchu * All rights reserved. 74e190a62SNicolas Souchu * 84e190a62SNicolas Souchu * Redistribution and use in source and binary forms, with or without 94e190a62SNicolas Souchu * modification, are permitted provided that the following conditions 104e190a62SNicolas Souchu * are met: 114e190a62SNicolas Souchu * 1. Redistributions of source code must retain the above copyright 124e190a62SNicolas Souchu * notice, this list of conditions and the following disclaimer. 134e190a62SNicolas Souchu * 2. Redistributions in binary form must reproduce the above copyright 144e190a62SNicolas Souchu * notice, this list of conditions and the following disclaimer in the 154e190a62SNicolas Souchu * documentation and/or other materials provided with the distribution. 164e190a62SNicolas Souchu * 174e190a62SNicolas Souchu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 184e190a62SNicolas Souchu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 194e190a62SNicolas Souchu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 204e190a62SNicolas Souchu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 214e190a62SNicolas Souchu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 224e190a62SNicolas Souchu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 234e190a62SNicolas Souchu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 244e190a62SNicolas Souchu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 254e190a62SNicolas Souchu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 264e190a62SNicolas Souchu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 274e190a62SNicolas Souchu * SUCH DAMAGE. 284e190a62SNicolas Souchu */ 29006124d8SDavid E. O'Brien 30006124d8SDavid E. O'Brien #include <sys/cdefs.h> 31006124d8SDavid E. O'Brien __FBSDID("$FreeBSD$"); 32006124d8SDavid E. O'Brien 334e190a62SNicolas Souchu #include <sys/param.h> 3413e3657bSJohn Baldwin #include <sys/bus.h> 3513e3657bSJohn Baldwin #include <sys/lock.h> 364e190a62SNicolas Souchu #include <sys/kernel.h> 374e190a62SNicolas Souchu #include <sys/module.h> 3813e3657bSJohn Baldwin #include <sys/mutex.h> 3913e3657bSJohn Baldwin #include <sys/systm.h> 404e190a62SNicolas Souchu 410f210c92SNicolas Souchu #include <machine/bus.h> 420f210c92SNicolas Souchu #include <machine/resource.h> 43e0efc557SJoerg Wunsch 440f210c92SNicolas Souchu #include <sys/rman.h> 450f210c92SNicolas Souchu 469e58d59fSJohn Baldwin #include <dev/iicbus/iicbus.h> 474e190a62SNicolas Souchu #include <dev/iicbus/iiconf.h> 48e0efc557SJoerg Wunsch #include <dev/pcf/pcfvar.h> 494e190a62SNicolas Souchu #include "iicbus_if.h" 504e190a62SNicolas Souchu 51e0efc557SJoerg Wunsch /* Not so official debugging option. */ 52e0efc557SJoerg Wunsch /* #define PCFDEBUG */ 530f210c92SNicolas Souchu 54e0efc557SJoerg Wunsch static int pcf_wait_byte(struct pcf_softc *pcf); 55e0efc557SJoerg Wunsch static int pcf_noack(struct pcf_softc *pcf, int timeout); 5613e3657bSJohn Baldwin static void pcf_stop_locked(struct pcf_softc *pcf); 574e190a62SNicolas Souchu 584e190a62SNicolas Souchu /* 594e190a62SNicolas Souchu * Polling mode for master operations wait for a new 6013e3657bSJohn Baldwin * byte incoming or outgoing 614e190a62SNicolas Souchu */ 6213e3657bSJohn Baldwin static int 63e0efc557SJoerg Wunsch pcf_wait_byte(struct pcf_softc *sc) 644e190a62SNicolas Souchu { 654e190a62SNicolas Souchu int counter = TIMEOUT; 664e190a62SNicolas Souchu 6713e3657bSJohn Baldwin PCF_ASSERT_LOCKED(sc); 684e190a62SNicolas Souchu while (counter--) { 69e0efc557SJoerg Wunsch if ((pcf_get_S1(sc) & PIN) == 0) 704e190a62SNicolas Souchu return (0); 714e190a62SNicolas Souchu } 724e190a62SNicolas Souchu 734f16b8b1SNicolas Souchu #ifdef PCFDEBUG 744f16b8b1SNicolas Souchu printf("pcf: timeout!\n"); 754f16b8b1SNicolas Souchu #endif 764f16b8b1SNicolas Souchu 774e190a62SNicolas Souchu return (IIC_ETIMEOUT); 784e190a62SNicolas Souchu } 794e190a62SNicolas Souchu 8013e3657bSJohn Baldwin static void 8113e3657bSJohn Baldwin pcf_stop_locked(struct pcf_softc *sc) 824e190a62SNicolas Souchu { 834e190a62SNicolas Souchu 8413e3657bSJohn Baldwin PCF_ASSERT_LOCKED(sc); 85e0efc557SJoerg Wunsch #ifdef PCFDEBUG 86e0efc557SJoerg Wunsch device_printf(dev, " >> stop\n"); 87e0efc557SJoerg Wunsch #endif 88af548787SNicolas Souchu /* 89af548787SNicolas Souchu * Send STOP condition iff the START condition was previously sent. 909d5abbddSJens Schweikhardt * STOP is sent only once even if an iicbus_stop() is called after 91e0efc557SJoerg Wunsch * an iicbus_read()... see pcf_read(): the PCF needs to send the stop 92af548787SNicolas Souchu * before the last char is read. 93af548787SNicolas Souchu */ 94e0efc557SJoerg Wunsch if (sc->pcf_started) { 954e190a62SNicolas Souchu /* set stop condition and enable IT */ 96e0efc557SJoerg Wunsch pcf_set_S1(sc, PIN|ESO|ENI|STO|ACK); 974e190a62SNicolas Souchu 98e0efc557SJoerg Wunsch sc->pcf_started = 0; 99af548787SNicolas Souchu } 1004e190a62SNicolas Souchu } 1014e190a62SNicolas Souchu 10213e3657bSJohn Baldwin static int 103e0efc557SJoerg Wunsch pcf_noack(struct pcf_softc *sc, int timeout) 104af548787SNicolas Souchu { 105af548787SNicolas Souchu int noack; 106af548787SNicolas Souchu int k = timeout/10; 107af548787SNicolas Souchu 10813e3657bSJohn Baldwin PCF_ASSERT_LOCKED(sc); 109af548787SNicolas Souchu do { 110e0efc557SJoerg Wunsch noack = pcf_get_S1(sc) & LRB; 111af548787SNicolas Souchu if (!noack) 112af548787SNicolas Souchu break; 113af548787SNicolas Souchu DELAY(10); /* XXX wait 10 us */ 114af548787SNicolas Souchu } while (k--); 115af548787SNicolas Souchu 116af548787SNicolas Souchu return (noack); 117af548787SNicolas Souchu } 118af548787SNicolas Souchu 119e0efc557SJoerg Wunsch int 120e0efc557SJoerg Wunsch pcf_repeated_start(device_t dev, u_char slave, int timeout) 1214e190a62SNicolas Souchu { 122e0efc557SJoerg Wunsch struct pcf_softc *sc = DEVTOSOFTC(dev); 1234e190a62SNicolas Souchu int error = 0; 1244e190a62SNicolas Souchu 12513e3657bSJohn Baldwin PCF_LOCK(sc); 126e0efc557SJoerg Wunsch #ifdef PCFDEBUG 127e0efc557SJoerg Wunsch device_printf(dev, " >> repeated start for slave %#x\n", 128e0efc557SJoerg Wunsch (unsigned)slave); 129e0efc557SJoerg Wunsch #endif 1304e190a62SNicolas Souchu /* repeated start */ 131e0efc557SJoerg Wunsch pcf_set_S1(sc, ESO|STA|STO|ACK); 1324e190a62SNicolas Souchu 1334e190a62SNicolas Souchu /* set slave address to PCF. Last bit (LSB) must be set correctly 1344e190a62SNicolas Souchu * according to transfer direction */ 135e0efc557SJoerg Wunsch pcf_set_S0(sc, slave); 1364e190a62SNicolas Souchu 1374e190a62SNicolas Souchu /* wait for address sent, polling */ 138e0efc557SJoerg Wunsch if ((error = pcf_wait_byte(sc))) 1394e190a62SNicolas Souchu goto error; 1404e190a62SNicolas Souchu 141af548787SNicolas Souchu /* check for ack */ 142e0efc557SJoerg Wunsch if (pcf_noack(sc, timeout)) { 1434e190a62SNicolas Souchu error = IIC_ENOACK; 1444f16b8b1SNicolas Souchu #ifdef PCFDEBUG 1454f16b8b1SNicolas Souchu printf("pcf: no ack on repeated_start!\n"); 1464f16b8b1SNicolas Souchu #endif 1474e190a62SNicolas Souchu goto error; 1484e190a62SNicolas Souchu } 1494e190a62SNicolas Souchu 15013e3657bSJohn Baldwin PCF_UNLOCK(sc); 1514e190a62SNicolas Souchu return (0); 1524e190a62SNicolas Souchu 1534e190a62SNicolas Souchu error: 15413e3657bSJohn Baldwin pcf_stop_locked(sc); 15513e3657bSJohn Baldwin PCF_UNLOCK(sc); 1564e190a62SNicolas Souchu return (error); 1574e190a62SNicolas Souchu } 1584e190a62SNicolas Souchu 159e0efc557SJoerg Wunsch int 160e0efc557SJoerg Wunsch pcf_start(device_t dev, u_char slave, int timeout) 1614e190a62SNicolas Souchu { 162e0efc557SJoerg Wunsch struct pcf_softc *sc = DEVTOSOFTC(dev); 1634e190a62SNicolas Souchu int error = 0; 1644e190a62SNicolas Souchu 16513e3657bSJohn Baldwin PCF_LOCK(sc); 166e0efc557SJoerg Wunsch #ifdef PCFDEBUG 167e0efc557SJoerg Wunsch device_printf(dev, " >> start for slave %#x\n", (unsigned)slave); 168e0efc557SJoerg Wunsch #endif 1694f16b8b1SNicolas Souchu if ((pcf_get_S1(sc) & nBB) == 0) { 1704f16b8b1SNicolas Souchu #ifdef PCFDEBUG 1714f16b8b1SNicolas Souchu printf("pcf: busy!\n"); 1724f16b8b1SNicolas Souchu #endif 17313e3657bSJohn Baldwin PCF_UNLOCK(sc); 174d1e99670SIan Lepore return (IIC_EBUSERR); 1754f16b8b1SNicolas Souchu } 1764e190a62SNicolas Souchu 1774e190a62SNicolas Souchu /* set slave address to PCF. Last bit (LSB) must be set correctly 1784e190a62SNicolas Souchu * according to transfer direction */ 179e0efc557SJoerg Wunsch pcf_set_S0(sc, slave); 1804e190a62SNicolas Souchu 1814e190a62SNicolas Souchu /* START only */ 182e0efc557SJoerg Wunsch pcf_set_S1(sc, PIN|ESO|STA|ACK); 1834e190a62SNicolas Souchu 184e0efc557SJoerg Wunsch sc->pcf_started = 1; 185af548787SNicolas Souchu 1864e190a62SNicolas Souchu /* wait for address sent, polling */ 187e0efc557SJoerg Wunsch if ((error = pcf_wait_byte(sc))) 1884e190a62SNicolas Souchu goto error; 1894e190a62SNicolas Souchu 190af548787SNicolas Souchu /* check for ACK */ 191e0efc557SJoerg Wunsch if (pcf_noack(sc, timeout)) { 1924e190a62SNicolas Souchu error = IIC_ENOACK; 1934f16b8b1SNicolas Souchu #ifdef PCFDEBUG 1944f16b8b1SNicolas Souchu printf("pcf: no ack on start!\n"); 1954f16b8b1SNicolas Souchu #endif 1964e190a62SNicolas Souchu goto error; 1974e190a62SNicolas Souchu } 1984e190a62SNicolas Souchu 19913e3657bSJohn Baldwin PCF_UNLOCK(sc); 2004e190a62SNicolas Souchu return (0); 2014e190a62SNicolas Souchu 2024e190a62SNicolas Souchu error: 20313e3657bSJohn Baldwin pcf_stop_locked(sc); 20413e3657bSJohn Baldwin PCF_UNLOCK(sc); 2054e190a62SNicolas Souchu return (error); 2064e190a62SNicolas Souchu } 2074e190a62SNicolas Souchu 20813e3657bSJohn Baldwin int 20913e3657bSJohn Baldwin pcf_stop(device_t dev) 21013e3657bSJohn Baldwin { 21113e3657bSJohn Baldwin struct pcf_softc *sc = DEVTOSOFTC(dev); 21213e3657bSJohn Baldwin 21313e3657bSJohn Baldwin #ifdef PCFDEBUG 21413e3657bSJohn Baldwin device_printf(dev, " >> stop\n"); 21513e3657bSJohn Baldwin #endif 21613e3657bSJohn Baldwin PCF_LOCK(sc); 21713e3657bSJohn Baldwin pcf_stop_locked(sc); 21813e3657bSJohn Baldwin PCF_UNLOCK(sc); 21913e3657bSJohn Baldwin 22013e3657bSJohn Baldwin return (0); 22113e3657bSJohn Baldwin } 22213e3657bSJohn Baldwin 223e0efc557SJoerg Wunsch void 224e0efc557SJoerg Wunsch pcf_intr(void *arg) 2254e190a62SNicolas Souchu { 2264f16b8b1SNicolas Souchu struct pcf_softc *sc = arg; 2274e190a62SNicolas Souchu char data, status, addr; 2284e190a62SNicolas Souchu char error = 0; 2294e190a62SNicolas Souchu 23013e3657bSJohn Baldwin PCF_LOCK(sc); 231e0efc557SJoerg Wunsch status = pcf_get_S1(sc); 2324e190a62SNicolas Souchu 2334e190a62SNicolas Souchu if (status & PIN) { 2344f16b8b1SNicolas Souchu printf("pcf: spurious interrupt, status=0x%x\n", 235e0efc557SJoerg Wunsch status & 0xff); 2364e190a62SNicolas Souchu 2374e190a62SNicolas Souchu goto error; 2384e190a62SNicolas Souchu } 2394e190a62SNicolas Souchu 2404e190a62SNicolas Souchu if (status & LAB) 2414f16b8b1SNicolas Souchu printf("pcf: bus arbitration lost!\n"); 2424e190a62SNicolas Souchu 2434e190a62SNicolas Souchu if (status & BER) { 2444e190a62SNicolas Souchu error = IIC_EBUSERR; 245e0efc557SJoerg Wunsch iicbus_intr(sc->iicbus, INTR_ERROR, &error); 2464e190a62SNicolas Souchu 2474e190a62SNicolas Souchu goto error; 2484e190a62SNicolas Souchu } 2494e190a62SNicolas Souchu 2504e190a62SNicolas Souchu do { 251e0efc557SJoerg Wunsch status = pcf_get_S1(sc); 2524e190a62SNicolas Souchu 253e0efc557SJoerg Wunsch switch(sc->pcf_slave_mode) { 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 3811c44eb75SAndriy Gapon pcf_write(device_t dev, const 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) { 394e0efc557SJoerg Wunsch pcf_set_S0(sc, *buf++); 3954e190a62SNicolas Souchu 396af548787SNicolas Souchu /* wait for the byte to be send */ 397e0efc557SJoerg Wunsch if ((error = pcf_wait_byte(sc))) 3984e190a62SNicolas Souchu goto error; 3994e190a62SNicolas Souchu 400af548787SNicolas Souchu /* check if ack received */ 401e0efc557SJoerg Wunsch if (pcf_noack(sc, timeout)) { 4024e190a62SNicolas Souchu error = IIC_ENOACK; 4034e190a62SNicolas Souchu goto error; 4044e190a62SNicolas Souchu } 4054e190a62SNicolas Souchu 4064e190a62SNicolas Souchu len --; 4074e190a62SNicolas Souchu bytes ++; 4084e190a62SNicolas Souchu } 4094e190a62SNicolas Souchu 4104e190a62SNicolas Souchu error: 4114e190a62SNicolas Souchu *sent = bytes; 41213e3657bSJohn Baldwin PCF_UNLOCK(sc); 4134e190a62SNicolas Souchu 4144e190a62SNicolas Souchu #ifdef PCFDEBUG 415e0efc557SJoerg Wunsch device_printf(dev, " >> %d bytes written (%d)\n", bytes, error); 4164e190a62SNicolas Souchu #endif 4174e190a62SNicolas Souchu 4184e190a62SNicolas Souchu return (error); 4194e190a62SNicolas Souchu } 4204e190a62SNicolas Souchu 421e0efc557SJoerg Wunsch int 422e0efc557SJoerg Wunsch pcf_read(device_t dev, char *buf, int len, int *read, int last, 423af548787SNicolas Souchu int delay /* us */) 4244e190a62SNicolas Souchu { 425e0efc557SJoerg Wunsch struct pcf_softc *sc = DEVTOSOFTC(dev); 4264e190a62SNicolas Souchu int bytes, error = 0; 4274e190a62SNicolas Souchu #ifdef PCFDEBUG 428e0efc557SJoerg Wunsch char *obuf = buf; 429e0efc557SJoerg Wunsch 430e0efc557SJoerg Wunsch device_printf(dev, " << reading %d bytes\n", len); 4314e190a62SNicolas Souchu #endif 4324e190a62SNicolas Souchu 43313e3657bSJohn Baldwin PCF_LOCK(sc); 4344e190a62SNicolas Souchu /* trig the bus to get the first data byte in S0 */ 4354e190a62SNicolas Souchu if (len) { 436af548787SNicolas Souchu if (len == 1 && last) 4374e190a62SNicolas Souchu /* just one byte to read */ 438e0efc557SJoerg Wunsch pcf_set_S1(sc, ESO); /* no ack */ 4394e190a62SNicolas Souchu 440e0efc557SJoerg Wunsch dummy_read(sc); 4414e190a62SNicolas Souchu } 4424e190a62SNicolas Souchu 4434e190a62SNicolas Souchu bytes = 0; 4444e190a62SNicolas Souchu while (len) { 445af548787SNicolas Souchu /* XXX delay needed here */ 446af548787SNicolas Souchu 447af548787SNicolas Souchu /* wait for trigged byte */ 448e0efc557SJoerg Wunsch if ((error = pcf_wait_byte(sc))) { 44913e3657bSJohn Baldwin pcf_stop_locked(sc); 4504e190a62SNicolas Souchu goto error; 4514e190a62SNicolas Souchu } 4524e190a62SNicolas Souchu 453af548787SNicolas Souchu if (len == 1 && last) 454af548787SNicolas Souchu /* ok, last data byte already in S0, no I2C activity 455e0efc557SJoerg Wunsch * on next pcf_get_S0() */ 45613e3657bSJohn Baldwin pcf_stop_locked(sc); 4574e190a62SNicolas Souchu 458af548787SNicolas Souchu else if (len == 2 && last) 4594e190a62SNicolas Souchu /* next trigged byte with no ack */ 460e0efc557SJoerg Wunsch pcf_set_S1(sc, ESO); 4614e190a62SNicolas Souchu 462af548787SNicolas Souchu /* receive byte, trig next byte */ 463e0efc557SJoerg Wunsch *buf++ = pcf_get_S0(sc); 4644e190a62SNicolas Souchu 4654e190a62SNicolas Souchu len --; 4664e190a62SNicolas Souchu bytes ++; 46774b8d63dSPedro F. Giffuni } 4684e190a62SNicolas Souchu 4694e190a62SNicolas Souchu error: 4704e190a62SNicolas Souchu *read = bytes; 47113e3657bSJohn Baldwin PCF_UNLOCK(sc); 4724e190a62SNicolas Souchu 4734e190a62SNicolas Souchu #ifdef PCFDEBUG 474e0efc557SJoerg Wunsch device_printf(dev, " << %d bytes read (%d): %#x%s\n", bytes, error, 475e0efc557SJoerg Wunsch (unsigned)obuf[0], bytes > 1? "...": ""); 4764e190a62SNicolas Souchu #endif 4774e190a62SNicolas Souchu 4784e190a62SNicolas Souchu return (error); 4794e190a62SNicolas Souchu } 4809e58d59fSJohn Baldwin 481*676ea8e1SJohn Baldwin DRIVER_MODULE(iicbus, pcf, iicbus_driver, 0, 0); 4829e58d59fSJohn Baldwin MODULE_DEPEND(pcf, iicbus, PCF_MINVER, PCF_PREFVER, PCF_MAXVER); 4839e58d59fSJohn Baldwin MODULE_VERSION(pcf, PCF_MODVER); 484