14e190a62SNicolas Souchu /*- 2*718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*718cf2ccSPedro 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--) { 694e190a62SNicolas Souchu 70e0efc557SJoerg Wunsch if ((pcf_get_S1(sc) & PIN) == 0) 714e190a62SNicolas Souchu return (0); 724e190a62SNicolas Souchu } 734e190a62SNicolas Souchu 744f16b8b1SNicolas Souchu #ifdef PCFDEBUG 754f16b8b1SNicolas Souchu printf("pcf: timeout!\n"); 764f16b8b1SNicolas Souchu #endif 774f16b8b1SNicolas Souchu 784e190a62SNicolas Souchu return (IIC_ETIMEOUT); 794e190a62SNicolas Souchu } 804e190a62SNicolas Souchu 8113e3657bSJohn Baldwin static void 8213e3657bSJohn Baldwin pcf_stop_locked(struct pcf_softc *sc) 834e190a62SNicolas Souchu { 844e190a62SNicolas Souchu 8513e3657bSJohn Baldwin PCF_ASSERT_LOCKED(sc); 86e0efc557SJoerg Wunsch #ifdef PCFDEBUG 87e0efc557SJoerg Wunsch device_printf(dev, " >> stop\n"); 88e0efc557SJoerg Wunsch #endif 89af548787SNicolas Souchu /* 90af548787SNicolas Souchu * Send STOP condition iff the START condition was previously sent. 919d5abbddSJens Schweikhardt * STOP is sent only once even if an iicbus_stop() is called after 92e0efc557SJoerg Wunsch * an iicbus_read()... see pcf_read(): the PCF needs to send the stop 93af548787SNicolas Souchu * before the last char is read. 94af548787SNicolas Souchu */ 95e0efc557SJoerg Wunsch if (sc->pcf_started) { 964e190a62SNicolas Souchu /* set stop condition and enable IT */ 97e0efc557SJoerg Wunsch pcf_set_S1(sc, PIN|ESO|ENI|STO|ACK); 984e190a62SNicolas Souchu 99e0efc557SJoerg Wunsch sc->pcf_started = 0; 100af548787SNicolas Souchu } 1014e190a62SNicolas Souchu } 1024e190a62SNicolas Souchu 10313e3657bSJohn Baldwin static int 104e0efc557SJoerg Wunsch pcf_noack(struct pcf_softc *sc, int timeout) 105af548787SNicolas Souchu { 106af548787SNicolas Souchu int noack; 107af548787SNicolas Souchu int k = timeout/10; 108af548787SNicolas Souchu 10913e3657bSJohn Baldwin PCF_ASSERT_LOCKED(sc); 110af548787SNicolas Souchu do { 111e0efc557SJoerg Wunsch noack = pcf_get_S1(sc) & LRB; 112af548787SNicolas Souchu if (!noack) 113af548787SNicolas Souchu break; 114af548787SNicolas Souchu DELAY(10); /* XXX wait 10 us */ 115af548787SNicolas Souchu } while (k--); 116af548787SNicolas Souchu 117af548787SNicolas Souchu return (noack); 118af548787SNicolas Souchu } 119af548787SNicolas Souchu 120e0efc557SJoerg Wunsch int 121e0efc557SJoerg Wunsch pcf_repeated_start(device_t dev, u_char slave, int timeout) 1224e190a62SNicolas Souchu { 123e0efc557SJoerg Wunsch struct pcf_softc *sc = DEVTOSOFTC(dev); 1244e190a62SNicolas Souchu int error = 0; 1254e190a62SNicolas Souchu 12613e3657bSJohn Baldwin PCF_LOCK(sc); 127e0efc557SJoerg Wunsch #ifdef PCFDEBUG 128e0efc557SJoerg Wunsch device_printf(dev, " >> repeated start for slave %#x\n", 129e0efc557SJoerg Wunsch (unsigned)slave); 130e0efc557SJoerg Wunsch #endif 1314e190a62SNicolas Souchu /* repeated start */ 132e0efc557SJoerg Wunsch pcf_set_S1(sc, ESO|STA|STO|ACK); 1334e190a62SNicolas Souchu 1344e190a62SNicolas Souchu /* set slave address to PCF. Last bit (LSB) must be set correctly 1354e190a62SNicolas Souchu * according to transfer direction */ 136e0efc557SJoerg Wunsch pcf_set_S0(sc, slave); 1374e190a62SNicolas Souchu 1384e190a62SNicolas Souchu /* wait for address sent, polling */ 139e0efc557SJoerg Wunsch if ((error = pcf_wait_byte(sc))) 1404e190a62SNicolas Souchu goto error; 1414e190a62SNicolas Souchu 142af548787SNicolas Souchu /* check for ack */ 143e0efc557SJoerg Wunsch if (pcf_noack(sc, timeout)) { 1444e190a62SNicolas Souchu error = IIC_ENOACK; 1454f16b8b1SNicolas Souchu #ifdef PCFDEBUG 1464f16b8b1SNicolas Souchu printf("pcf: no ack on repeated_start!\n"); 1474f16b8b1SNicolas Souchu #endif 1484e190a62SNicolas Souchu goto error; 1494e190a62SNicolas Souchu } 1504e190a62SNicolas Souchu 15113e3657bSJohn Baldwin PCF_UNLOCK(sc); 1524e190a62SNicolas Souchu return (0); 1534e190a62SNicolas Souchu 1544e190a62SNicolas Souchu error: 15513e3657bSJohn Baldwin pcf_stop_locked(sc); 15613e3657bSJohn Baldwin PCF_UNLOCK(sc); 1574e190a62SNicolas Souchu return (error); 1584e190a62SNicolas Souchu } 1594e190a62SNicolas Souchu 160e0efc557SJoerg Wunsch int 161e0efc557SJoerg Wunsch pcf_start(device_t dev, u_char slave, int timeout) 1624e190a62SNicolas Souchu { 163e0efc557SJoerg Wunsch struct pcf_softc *sc = DEVTOSOFTC(dev); 1644e190a62SNicolas Souchu int error = 0; 1654e190a62SNicolas Souchu 16613e3657bSJohn Baldwin PCF_LOCK(sc); 167e0efc557SJoerg Wunsch #ifdef PCFDEBUG 168e0efc557SJoerg Wunsch device_printf(dev, " >> start for slave %#x\n", (unsigned)slave); 169e0efc557SJoerg Wunsch #endif 1704f16b8b1SNicolas Souchu if ((pcf_get_S1(sc) & nBB) == 0) { 1714f16b8b1SNicolas Souchu #ifdef PCFDEBUG 1724f16b8b1SNicolas Souchu printf("pcf: busy!\n"); 1734f16b8b1SNicolas Souchu #endif 17413e3657bSJohn Baldwin PCF_UNLOCK(sc); 175d1e99670SIan Lepore return (IIC_EBUSERR); 1764f16b8b1SNicolas Souchu } 1774e190a62SNicolas Souchu 1784e190a62SNicolas Souchu /* set slave address to PCF. Last bit (LSB) must be set correctly 1794e190a62SNicolas Souchu * according to transfer direction */ 180e0efc557SJoerg Wunsch pcf_set_S0(sc, slave); 1814e190a62SNicolas Souchu 1824e190a62SNicolas Souchu /* START only */ 183e0efc557SJoerg Wunsch pcf_set_S1(sc, PIN|ESO|STA|ACK); 1844e190a62SNicolas Souchu 185e0efc557SJoerg Wunsch sc->pcf_started = 1; 186af548787SNicolas Souchu 1874e190a62SNicolas Souchu /* wait for address sent, polling */ 188e0efc557SJoerg Wunsch if ((error = pcf_wait_byte(sc))) 1894e190a62SNicolas Souchu goto error; 1904e190a62SNicolas Souchu 191af548787SNicolas Souchu /* check for ACK */ 192e0efc557SJoerg Wunsch if (pcf_noack(sc, timeout)) { 1934e190a62SNicolas Souchu error = IIC_ENOACK; 1944f16b8b1SNicolas Souchu #ifdef PCFDEBUG 1954f16b8b1SNicolas Souchu printf("pcf: no ack on start!\n"); 1964f16b8b1SNicolas Souchu #endif 1974e190a62SNicolas Souchu goto error; 1984e190a62SNicolas Souchu } 1994e190a62SNicolas Souchu 20013e3657bSJohn Baldwin PCF_UNLOCK(sc); 2014e190a62SNicolas Souchu return (0); 2024e190a62SNicolas Souchu 2034e190a62SNicolas Souchu error: 20413e3657bSJohn Baldwin pcf_stop_locked(sc); 20513e3657bSJohn Baldwin PCF_UNLOCK(sc); 2064e190a62SNicolas Souchu return (error); 2074e190a62SNicolas Souchu } 2084e190a62SNicolas Souchu 20913e3657bSJohn Baldwin int 21013e3657bSJohn Baldwin pcf_stop(device_t dev) 21113e3657bSJohn Baldwin { 21213e3657bSJohn Baldwin struct pcf_softc *sc = DEVTOSOFTC(dev); 21313e3657bSJohn Baldwin 21413e3657bSJohn Baldwin #ifdef PCFDEBUG 21513e3657bSJohn Baldwin device_printf(dev, " >> stop\n"); 21613e3657bSJohn Baldwin #endif 21713e3657bSJohn Baldwin PCF_LOCK(sc); 21813e3657bSJohn Baldwin pcf_stop_locked(sc); 21913e3657bSJohn Baldwin PCF_UNLOCK(sc); 22013e3657bSJohn Baldwin 22113e3657bSJohn Baldwin return (0); 22213e3657bSJohn Baldwin } 22313e3657bSJohn Baldwin 224e0efc557SJoerg Wunsch void 225e0efc557SJoerg Wunsch pcf_intr(void *arg) 2264e190a62SNicolas Souchu { 2274f16b8b1SNicolas Souchu struct pcf_softc *sc = arg; 2284e190a62SNicolas Souchu char data, status, addr; 2294e190a62SNicolas Souchu char error = 0; 2304e190a62SNicolas Souchu 23113e3657bSJohn Baldwin PCF_LOCK(sc); 232e0efc557SJoerg Wunsch status = pcf_get_S1(sc); 2334e190a62SNicolas Souchu 2344e190a62SNicolas Souchu if (status & PIN) { 2354f16b8b1SNicolas Souchu printf("pcf: spurious interrupt, status=0x%x\n", 236e0efc557SJoerg Wunsch status & 0xff); 2374e190a62SNicolas Souchu 2384e190a62SNicolas Souchu goto error; 2394e190a62SNicolas Souchu } 2404e190a62SNicolas Souchu 2414e190a62SNicolas Souchu if (status & LAB) 2424f16b8b1SNicolas Souchu printf("pcf: bus arbitration lost!\n"); 2434e190a62SNicolas Souchu 2444e190a62SNicolas Souchu if (status & BER) { 2454e190a62SNicolas Souchu error = IIC_EBUSERR; 246e0efc557SJoerg Wunsch iicbus_intr(sc->iicbus, INTR_ERROR, &error); 2474e190a62SNicolas Souchu 2484e190a62SNicolas Souchu goto error; 2494e190a62SNicolas Souchu } 2504e190a62SNicolas Souchu 2514e190a62SNicolas Souchu do { 252e0efc557SJoerg Wunsch status = pcf_get_S1(sc); 2534e190a62SNicolas Souchu 254e0efc557SJoerg Wunsch switch(sc->pcf_slave_mode) { 2554e190a62SNicolas Souchu 2564e190a62SNicolas Souchu case SLAVE_TRANSMITTER: 2574e190a62SNicolas Souchu if (status & LRB) { 2584e190a62SNicolas Souchu /* ack interrupt line */ 259e0efc557SJoerg Wunsch dummy_write(sc); 2604e190a62SNicolas Souchu 2614e190a62SNicolas Souchu /* no ack, don't send anymore */ 262e0efc557SJoerg Wunsch sc->pcf_slave_mode = SLAVE_RECEIVER; 2634e190a62SNicolas Souchu 264e0efc557SJoerg Wunsch iicbus_intr(sc->iicbus, INTR_NOACK, NULL); 2654e190a62SNicolas Souchu break; 2664e190a62SNicolas Souchu } 2674e190a62SNicolas Souchu 2684e190a62SNicolas Souchu /* get data from upper code */ 269e0efc557SJoerg Wunsch iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data); 2704e190a62SNicolas Souchu 271e0efc557SJoerg Wunsch pcf_set_S0(sc, data); 2724e190a62SNicolas Souchu break; 2734e190a62SNicolas Souchu 2744e190a62SNicolas Souchu case SLAVE_RECEIVER: 2754e190a62SNicolas Souchu if (status & AAS) { 276e0efc557SJoerg Wunsch addr = pcf_get_S0(sc); 2774e190a62SNicolas Souchu 2784e190a62SNicolas Souchu if (status & AD0) 279e0efc557SJoerg Wunsch iicbus_intr(sc->iicbus, INTR_GENERAL, &addr); 2804e190a62SNicolas Souchu else 281e0efc557SJoerg Wunsch iicbus_intr(sc->iicbus, INTR_START, &addr); 2824e190a62SNicolas Souchu 2834e190a62SNicolas Souchu if (addr & LSB) { 284e0efc557SJoerg Wunsch sc->pcf_slave_mode = SLAVE_TRANSMITTER; 2854e190a62SNicolas Souchu 2864e190a62SNicolas Souchu /* get the first char from upper code */ 287e0efc557SJoerg Wunsch iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data); 2884e190a62SNicolas Souchu 2894e190a62SNicolas Souchu /* send first data byte */ 290e0efc557SJoerg Wunsch pcf_set_S0(sc, data); 2914e190a62SNicolas Souchu } 2924e190a62SNicolas Souchu 2934e190a62SNicolas Souchu break; 2944e190a62SNicolas Souchu } 2954e190a62SNicolas Souchu 2964e190a62SNicolas Souchu /* stop condition received? */ 2974e190a62SNicolas Souchu if (status & STS) { 2984e190a62SNicolas Souchu /* ack interrupt line */ 299e0efc557SJoerg Wunsch dummy_read(sc); 3004e190a62SNicolas Souchu 3014e190a62SNicolas Souchu /* emulate intr stop condition */ 302e0efc557SJoerg Wunsch iicbus_intr(sc->iicbus, INTR_STOP, NULL); 3034e190a62SNicolas Souchu 3044e190a62SNicolas Souchu } else { 3054e190a62SNicolas Souchu /* get data, ack interrupt line */ 306e0efc557SJoerg Wunsch data = pcf_get_S0(sc); 3074e190a62SNicolas Souchu 3084e190a62SNicolas Souchu /* deliver the character */ 309e0efc557SJoerg Wunsch iicbus_intr(sc->iicbus, INTR_RECEIVE, &data); 3104e190a62SNicolas Souchu } 3114e190a62SNicolas Souchu break; 3124e190a62SNicolas Souchu 3134e190a62SNicolas Souchu default: 3146e551fb6SDavid E. O'Brien panic("%s: unknown slave mode (%d)!", __func__, 315e0efc557SJoerg Wunsch sc->pcf_slave_mode); 3164e190a62SNicolas Souchu } 3174e190a62SNicolas Souchu 318e0efc557SJoerg Wunsch } while ((pcf_get_S1(sc) & PIN) == 0); 31913e3657bSJohn Baldwin PCF_UNLOCK(sc); 3204e190a62SNicolas Souchu 3214e190a62SNicolas Souchu return; 3224e190a62SNicolas Souchu 3234e190a62SNicolas Souchu error: 3244e190a62SNicolas Souchu /* unknown event on bus...reset PCF */ 325e0efc557SJoerg Wunsch pcf_set_S1(sc, PIN|ESO|ENI|ACK); 3264e190a62SNicolas Souchu 327e0efc557SJoerg Wunsch sc->pcf_slave_mode = SLAVE_RECEIVER; 32813e3657bSJohn Baldwin PCF_UNLOCK(sc); 3294e190a62SNicolas Souchu 3304e190a62SNicolas Souchu return; 3314e190a62SNicolas Souchu } 3324e190a62SNicolas Souchu 333e0efc557SJoerg Wunsch int 334e0efc557SJoerg Wunsch pcf_rst_card(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 3354e190a62SNicolas Souchu { 336e0efc557SJoerg Wunsch struct pcf_softc *sc = DEVTOSOFTC(dev); 337af548787SNicolas Souchu 33813e3657bSJohn Baldwin PCF_LOCK(sc); 339af548787SNicolas Souchu if (oldaddr) 340e0efc557SJoerg Wunsch *oldaddr = sc->pcf_addr; 3414e190a62SNicolas Souchu 3424e190a62SNicolas Souchu /* retrieve own address from bus level */ 343af548787SNicolas Souchu if (!addr) 344e0efc557SJoerg Wunsch sc->pcf_addr = PCF_DEFAULT_ADDR; 345af548787SNicolas Souchu else 346e0efc557SJoerg Wunsch sc->pcf_addr = addr; 3474e190a62SNicolas Souchu 348e0efc557SJoerg Wunsch pcf_set_S1(sc, PIN); /* initialize S1 */ 3494e190a62SNicolas Souchu 3504e190a62SNicolas Souchu /* own address S'O<>0 */ 351e0efc557SJoerg Wunsch pcf_set_S0(sc, sc->pcf_addr >> 1); 3524e190a62SNicolas Souchu 3534e190a62SNicolas Souchu /* select clock register */ 354e0efc557SJoerg Wunsch pcf_set_S1(sc, PIN|ES1); 3554e190a62SNicolas Souchu 3564e190a62SNicolas Souchu /* select bus speed : 18=90kb, 19=45kb, 1A=11kb, 1B=1.5kb */ 3574e190a62SNicolas Souchu switch (speed) { 3584e190a62SNicolas Souchu case IIC_SLOW: 359e0efc557SJoerg Wunsch pcf_set_S0(sc, 0x1b); /* XXX Sun uses 0x1f */ 3604e190a62SNicolas Souchu break; 3614e190a62SNicolas Souchu 3624e190a62SNicolas Souchu case IIC_FAST: 363e0efc557SJoerg Wunsch pcf_set_S0(sc, 0x19); /* XXX Sun: 0x1d */ 3644e190a62SNicolas Souchu break; 3654e190a62SNicolas Souchu 3664e190a62SNicolas Souchu case IIC_UNKNOWN: 3674e190a62SNicolas Souchu case IIC_FASTEST: 3684e190a62SNicolas Souchu default: 369e0efc557SJoerg Wunsch pcf_set_S0(sc, 0x18); /* XXX Sun: 0x1c */ 3704e190a62SNicolas Souchu break; 3714e190a62SNicolas Souchu } 3724e190a62SNicolas Souchu 3734e190a62SNicolas Souchu /* set bus on, ack=yes, INT=yes */ 374e0efc557SJoerg Wunsch pcf_set_S1(sc, PIN|ESO|ENI|ACK); 3754e190a62SNicolas Souchu 376e0efc557SJoerg Wunsch sc->pcf_slave_mode = SLAVE_RECEIVER; 37713e3657bSJohn Baldwin PCF_UNLOCK(sc); 3784e190a62SNicolas Souchu 3794e190a62SNicolas Souchu return (0); 3804e190a62SNicolas Souchu } 3814e190a62SNicolas Souchu 382e0efc557SJoerg Wunsch int 3831c44eb75SAndriy Gapon pcf_write(device_t dev, const char *buf, int len, int *sent, int timeout /* us */) 3844e190a62SNicolas Souchu { 385e0efc557SJoerg Wunsch struct pcf_softc *sc = DEVTOSOFTC(dev); 3864e190a62SNicolas Souchu int bytes, error = 0; 3874e190a62SNicolas Souchu 3884e190a62SNicolas Souchu #ifdef PCFDEBUG 389e0efc557SJoerg Wunsch device_printf(dev, " >> writing %d bytes: %#x%s\n", len, 390e0efc557SJoerg Wunsch (unsigned)buf[0], len > 1? "...": ""); 3914e190a62SNicolas Souchu #endif 3924e190a62SNicolas Souchu 3934e190a62SNicolas Souchu bytes = 0; 39413e3657bSJohn Baldwin PCF_LOCK(sc); 3954e190a62SNicolas Souchu while (len) { 3964e190a62SNicolas Souchu 397e0efc557SJoerg Wunsch pcf_set_S0(sc, *buf++); 3984e190a62SNicolas Souchu 399af548787SNicolas Souchu /* wait for the byte to be send */ 400e0efc557SJoerg Wunsch if ((error = pcf_wait_byte(sc))) 4014e190a62SNicolas Souchu goto error; 4024e190a62SNicolas Souchu 403af548787SNicolas Souchu /* check if ack received */ 404e0efc557SJoerg Wunsch if (pcf_noack(sc, timeout)) { 4054e190a62SNicolas Souchu error = IIC_ENOACK; 4064e190a62SNicolas Souchu goto error; 4074e190a62SNicolas Souchu } 4084e190a62SNicolas Souchu 4094e190a62SNicolas Souchu len --; 4104e190a62SNicolas Souchu bytes ++; 4114e190a62SNicolas Souchu } 4124e190a62SNicolas Souchu 4134e190a62SNicolas Souchu error: 4144e190a62SNicolas Souchu *sent = bytes; 41513e3657bSJohn Baldwin PCF_UNLOCK(sc); 4164e190a62SNicolas Souchu 4174e190a62SNicolas Souchu #ifdef PCFDEBUG 418e0efc557SJoerg Wunsch device_printf(dev, " >> %d bytes written (%d)\n", bytes, error); 4194e190a62SNicolas Souchu #endif 4204e190a62SNicolas Souchu 4214e190a62SNicolas Souchu return (error); 4224e190a62SNicolas Souchu } 4234e190a62SNicolas Souchu 424e0efc557SJoerg Wunsch int 425e0efc557SJoerg Wunsch pcf_read(device_t dev, char *buf, int len, int *read, int last, 426af548787SNicolas Souchu int delay /* us */) 4274e190a62SNicolas Souchu { 428e0efc557SJoerg Wunsch struct pcf_softc *sc = DEVTOSOFTC(dev); 4294e190a62SNicolas Souchu int bytes, error = 0; 4304e190a62SNicolas Souchu #ifdef PCFDEBUG 431e0efc557SJoerg Wunsch char *obuf = buf; 432e0efc557SJoerg Wunsch 433e0efc557SJoerg Wunsch device_printf(dev, " << reading %d bytes\n", len); 4344e190a62SNicolas Souchu #endif 4354e190a62SNicolas Souchu 43613e3657bSJohn Baldwin PCF_LOCK(sc); 4374e190a62SNicolas Souchu /* trig the bus to get the first data byte in S0 */ 4384e190a62SNicolas Souchu if (len) { 439af548787SNicolas Souchu if (len == 1 && last) 4404e190a62SNicolas Souchu /* just one byte to read */ 441e0efc557SJoerg Wunsch pcf_set_S1(sc, ESO); /* no ack */ 4424e190a62SNicolas Souchu 443e0efc557SJoerg Wunsch dummy_read(sc); 4444e190a62SNicolas Souchu } 4454e190a62SNicolas Souchu 4464e190a62SNicolas Souchu bytes = 0; 4474e190a62SNicolas Souchu while (len) { 4484e190a62SNicolas Souchu 449af548787SNicolas Souchu /* XXX delay needed here */ 450af548787SNicolas Souchu 451af548787SNicolas Souchu /* wait for trigged byte */ 452e0efc557SJoerg Wunsch if ((error = pcf_wait_byte(sc))) { 45313e3657bSJohn Baldwin pcf_stop_locked(sc); 4544e190a62SNicolas Souchu goto error; 4554e190a62SNicolas Souchu } 4564e190a62SNicolas Souchu 457af548787SNicolas Souchu if (len == 1 && last) 458af548787SNicolas Souchu /* ok, last data byte already in S0, no I2C activity 459e0efc557SJoerg Wunsch * on next pcf_get_S0() */ 46013e3657bSJohn Baldwin pcf_stop_locked(sc); 4614e190a62SNicolas Souchu 462af548787SNicolas Souchu else if (len == 2 && last) 4634e190a62SNicolas Souchu /* next trigged byte with no ack */ 464e0efc557SJoerg Wunsch pcf_set_S1(sc, ESO); 4654e190a62SNicolas Souchu 466af548787SNicolas Souchu /* receive byte, trig next byte */ 467e0efc557SJoerg Wunsch *buf++ = pcf_get_S0(sc); 4684e190a62SNicolas Souchu 4694e190a62SNicolas Souchu len --; 4704e190a62SNicolas Souchu bytes ++; 47174b8d63dSPedro F. Giffuni } 4724e190a62SNicolas Souchu 4734e190a62SNicolas Souchu error: 4744e190a62SNicolas Souchu *read = bytes; 47513e3657bSJohn Baldwin PCF_UNLOCK(sc); 4764e190a62SNicolas Souchu 4774e190a62SNicolas Souchu #ifdef PCFDEBUG 478e0efc557SJoerg Wunsch device_printf(dev, " << %d bytes read (%d): %#x%s\n", bytes, error, 479e0efc557SJoerg Wunsch (unsigned)obuf[0], bytes > 1? "...": ""); 4804e190a62SNicolas Souchu #endif 4814e190a62SNicolas Souchu 4824e190a62SNicolas Souchu return (error); 4834e190a62SNicolas Souchu } 4849e58d59fSJohn Baldwin 4859e58d59fSJohn Baldwin DRIVER_MODULE(iicbus, pcf, iicbus_driver, iicbus_devclass, 0, 0); 4869e58d59fSJohn Baldwin MODULE_DEPEND(pcf, iicbus, PCF_MINVER, PCF_PREFVER, PCF_MAXVER); 4879e58d59fSJohn Baldwin MODULE_VERSION(pcf, PCF_MODVER); 488