14e190a62SNicolas Souchu /*- 24e190a62SNicolas Souchu * Copyright (c) 1998 Nicolas Souchu, Marc Bouget 34e190a62SNicolas Souchu * All rights reserved. 44e190a62SNicolas Souchu * 54e190a62SNicolas Souchu * Redistribution and use in source and binary forms, with or without 64e190a62SNicolas Souchu * modification, are permitted provided that the following conditions 74e190a62SNicolas Souchu * are met: 84e190a62SNicolas Souchu * 1. Redistributions of source code must retain the above copyright 94e190a62SNicolas Souchu * notice, this list of conditions and the following disclaimer. 104e190a62SNicolas Souchu * 2. Redistributions in binary form must reproduce the above copyright 114e190a62SNicolas Souchu * notice, this list of conditions and the following disclaimer in the 124e190a62SNicolas Souchu * documentation and/or other materials provided with the distribution. 134e190a62SNicolas Souchu * 144e190a62SNicolas Souchu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 154e190a62SNicolas Souchu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 164e190a62SNicolas Souchu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 174e190a62SNicolas Souchu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 184e190a62SNicolas Souchu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 194e190a62SNicolas Souchu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 204e190a62SNicolas Souchu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 214e190a62SNicolas Souchu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 224e190a62SNicolas Souchu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 234e190a62SNicolas Souchu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 244e190a62SNicolas Souchu * SUCH DAMAGE. 254e190a62SNicolas Souchu * 26af548787SNicolas Souchu * $Id: pcf.c,v 1.2 1998/10/22 05:58:40 bde Exp $ 274e190a62SNicolas Souchu * 284e190a62SNicolas Souchu */ 294e190a62SNicolas Souchu #include <sys/param.h> 304e190a62SNicolas Souchu #include <sys/systm.h> 314e190a62SNicolas Souchu #include <sys/kernel.h> 324e190a62SNicolas Souchu #include <sys/module.h> 334e190a62SNicolas Souchu #include <sys/bus.h> 344e190a62SNicolas Souchu #include <sys/conf.h> 354e190a62SNicolas Souchu #include <sys/malloc.h> 364e190a62SNicolas Souchu 374e190a62SNicolas Souchu #include <machine/clock.h> 384e190a62SNicolas Souchu 394e190a62SNicolas Souchu #include <i386/isa/isa_device.h> 404e190a62SNicolas Souchu 414e190a62SNicolas Souchu #include <dev/iicbus/iiconf.h> 424e190a62SNicolas Souchu #include "iicbus_if.h" 434e190a62SNicolas Souchu 44af548787SNicolas Souchu #define TIMEOUT 9999 /* XXX */ 454e190a62SNicolas Souchu 464e190a62SNicolas Souchu /* Status bits of S1 register (read only) */ 474e190a62SNicolas Souchu #define nBB 0x01 /* busy when low set/reset by STOP/START*/ 484e190a62SNicolas Souchu #define LAB 0x02 /* lost arbitration bit in multi-master mode */ 494e190a62SNicolas Souchu #define AAS 0x04 /* addressed as slave */ 504e190a62SNicolas Souchu #define LRB 0x08 /* last received byte when not AAS */ 514e190a62SNicolas Souchu #define AD0 0x08 /* general call received when AAS */ 524e190a62SNicolas Souchu #define BER 0x10 /* bus error, misplaced START or STOP */ 534e190a62SNicolas Souchu #define STS 0x20 /* STOP detected in slave receiver mode */ 544e190a62SNicolas Souchu #define PIN 0x80 /* pending interrupt not (r/w) */ 554e190a62SNicolas Souchu 564e190a62SNicolas Souchu /* Control bits of S1 register (write only) */ 574e190a62SNicolas Souchu #define ACK 0x01 584e190a62SNicolas Souchu #define STO 0x02 594e190a62SNicolas Souchu #define STA 0x04 604e190a62SNicolas Souchu #define ENI 0x08 614e190a62SNicolas Souchu #define ES2 0x10 624e190a62SNicolas Souchu #define ES1 0x20 634e190a62SNicolas Souchu #define ES0 0x40 644e190a62SNicolas Souchu 654e190a62SNicolas Souchu #define BUFSIZE 2048 664e190a62SNicolas Souchu 674e190a62SNicolas Souchu #define SLAVE_TRANSMITTER 0x1 684e190a62SNicolas Souchu #define SLAVE_RECEIVER 0x2 694e190a62SNicolas Souchu 70af548787SNicolas Souchu #define PCF_DEFAULT_ADDR 0xaa 71af548787SNicolas Souchu 724e190a62SNicolas Souchu struct pcf_softc { 734e190a62SNicolas Souchu 744e190a62SNicolas Souchu int pcf_base; /* isa port */ 75af548787SNicolas Souchu u_char pcf_addr; /* interface I2C address */ 764e190a62SNicolas Souchu 774e190a62SNicolas Souchu int pcf_slave_mode; /* receiver or transmitter */ 78af548787SNicolas Souchu int pcf_started; /* 1 if start condition sent */ 794e190a62SNicolas Souchu 804e190a62SNicolas Souchu device_t iicbus; /* the corresponding iicbus */ 814e190a62SNicolas Souchu }; 824e190a62SNicolas Souchu 834e190a62SNicolas Souchu struct pcf_isa_softc { 844e190a62SNicolas Souchu 854e190a62SNicolas Souchu int pcf_unit; /* unit of the isa device */ 864e190a62SNicolas Souchu int pcf_base; /* isa port */ 874e190a62SNicolas Souchu int pcf_irq; /* isa irq or null if polled */ 884e190a62SNicolas Souchu 894e190a62SNicolas Souchu unsigned int pcf_flags; /* boot flags */ 904e190a62SNicolas Souchu }; 914e190a62SNicolas Souchu 924e190a62SNicolas Souchu #define MAXPCF 2 934e190a62SNicolas Souchu 944e190a62SNicolas Souchu static struct pcf_isa_softc *pcfdata[MAXPCF]; 954e190a62SNicolas Souchu static npcf = 0; 964e190a62SNicolas Souchu 974e190a62SNicolas Souchu static int pcfprobe_isa(struct isa_device *); 984e190a62SNicolas Souchu static int pcfattach_isa(struct isa_device *); 994e190a62SNicolas Souchu 1004e190a62SNicolas Souchu struct isa_driver pcfdriver = { 1014e190a62SNicolas Souchu pcfprobe_isa, pcfattach_isa, "pcf" 1024e190a62SNicolas Souchu }; 1034e190a62SNicolas Souchu 1044e190a62SNicolas Souchu static int pcf_probe(device_t); 1054e190a62SNicolas Souchu static int pcf_attach(device_t); 1064e190a62SNicolas Souchu static void pcf_print_child(device_t, device_t); 1074e190a62SNicolas Souchu 108af548787SNicolas Souchu static int pcf_repeated_start(device_t, u_char, int); 109af548787SNicolas Souchu static int pcf_start(device_t, u_char, int); 1104e190a62SNicolas Souchu static int pcf_stop(device_t); 1114e190a62SNicolas Souchu static int pcf_write(device_t, char *, int, int *); 1124e190a62SNicolas Souchu static int pcf_read(device_t, char *, int, int *); 113fe310de8SBruce Evans static ointhand2_t pcfintr; 1144e190a62SNicolas Souchu static int pcf_rst_card(device_t, u_char); 1154e190a62SNicolas Souchu 1164e190a62SNicolas Souchu static device_method_t pcf_methods[] = { 1174e190a62SNicolas Souchu /* device interface */ 1184e190a62SNicolas Souchu DEVMETHOD(device_probe, pcf_probe), 1194e190a62SNicolas Souchu DEVMETHOD(device_attach, pcf_attach), 1204e190a62SNicolas Souchu 1214e190a62SNicolas Souchu /* bus interface */ 1224e190a62SNicolas Souchu DEVMETHOD(bus_print_child, pcf_print_child), 1234e190a62SNicolas Souchu 1244e190a62SNicolas Souchu /* iicbus interface */ 125af548787SNicolas Souchu DEVMETHOD(iicbus_callback, iicbus_null_callback), 1264e190a62SNicolas Souchu DEVMETHOD(iicbus_repeated_start, pcf_repeated_start), 1274e190a62SNicolas Souchu DEVMETHOD(iicbus_start, pcf_start), 1284e190a62SNicolas Souchu DEVMETHOD(iicbus_stop, pcf_stop), 1294e190a62SNicolas Souchu DEVMETHOD(iicbus_write, pcf_write), 1304e190a62SNicolas Souchu DEVMETHOD(iicbus_read, pcf_read), 1314e190a62SNicolas Souchu DEVMETHOD(iicbus_reset, pcf_rst_card), 1324e190a62SNicolas Souchu 1334e190a62SNicolas Souchu { 0, 0 } 1344e190a62SNicolas Souchu }; 1354e190a62SNicolas Souchu 1364e190a62SNicolas Souchu static driver_t pcf_driver = { 1374e190a62SNicolas Souchu "pcf", 1384e190a62SNicolas Souchu pcf_methods, 1394e190a62SNicolas Souchu DRIVER_TYPE_MISC, 1404e190a62SNicolas Souchu sizeof(struct pcf_softc), 1414e190a62SNicolas Souchu }; 1424e190a62SNicolas Souchu 1434e190a62SNicolas Souchu static devclass_t pcf_devclass; 1444e190a62SNicolas Souchu 1454e190a62SNicolas Souchu #define DEVTOSOFTC(dev) ((struct pcf_softc *)device_get_softc(dev)) 1464e190a62SNicolas Souchu 1474e190a62SNicolas Souchu static int 1484e190a62SNicolas Souchu pcfprobe_isa(struct isa_device *dvp) 1494e190a62SNicolas Souchu { 1504e190a62SNicolas Souchu device_t pcfdev; 1514e190a62SNicolas Souchu struct pcf_isa_softc *pcf; 1524e190a62SNicolas Souchu int error; 1534e190a62SNicolas Souchu 1544e190a62SNicolas Souchu if (npcf >= MAXPCF) 1554e190a62SNicolas Souchu return (0); 1564e190a62SNicolas Souchu 1574e190a62SNicolas Souchu if ((pcf = (struct pcf_isa_softc *)malloc(sizeof(struct pcf_isa_softc), 1584e190a62SNicolas Souchu M_DEVBUF, M_NOWAIT)) == NULL) 1594e190a62SNicolas Souchu return (0); 1604e190a62SNicolas Souchu 1614e190a62SNicolas Souchu pcf->pcf_base = dvp->id_iobase; /* XXX should be ivars */ 1624e190a62SNicolas Souchu pcf->pcf_unit = dvp->id_unit; 1634e190a62SNicolas Souchu 1644e190a62SNicolas Souchu if (!(dvp->id_flags & IIC_POLLED)) 1654e190a62SNicolas Souchu pcf->pcf_irq = (dvp->id_irq); 1664e190a62SNicolas Souchu 1674e190a62SNicolas Souchu pcfdata[npcf++] = pcf; 1684e190a62SNicolas Souchu 1694e190a62SNicolas Souchu /* XXX add the pcf device to the root_bus until isa bus exists */ 1704e190a62SNicolas Souchu pcfdev = device_add_child(root_bus, "pcf", pcf->pcf_unit, NULL); 171af548787SNicolas Souchu device_probe_and_attach(pcfdev); 1724e190a62SNicolas Souchu 1734e190a62SNicolas Souchu if (!pcfdev) 1744e190a62SNicolas Souchu goto error; 1754e190a62SNicolas Souchu 1764e190a62SNicolas Souchu end_probe: 1774e190a62SNicolas Souchu return (1); 1784e190a62SNicolas Souchu 1794e190a62SNicolas Souchu error: 1804e190a62SNicolas Souchu free(pcf, M_DEVBUF); 1814e190a62SNicolas Souchu return (0); 1824e190a62SNicolas Souchu } 1834e190a62SNicolas Souchu 1844e190a62SNicolas Souchu static int 1854e190a62SNicolas Souchu pcfattach_isa(struct isa_device *isdp) 1864e190a62SNicolas Souchu { 187fe310de8SBruce Evans isdp->id_ointr = pcfintr; 1884e190a62SNicolas Souchu return (1); /* ok */ 1894e190a62SNicolas Souchu } 1904e190a62SNicolas Souchu 1914e190a62SNicolas Souchu static int 1924e190a62SNicolas Souchu pcf_probe(device_t pcfdev) 1934e190a62SNicolas Souchu { 1944e190a62SNicolas Souchu struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(pcfdev); 195af548787SNicolas Souchu int unit = device_get_unit(pcfdev); 196af548787SNicolas Souchu 197af548787SNicolas Souchu /* retrieve base address from isa initialization 198af548787SNicolas Souchu * 199af548787SNicolas Souchu * XXX should use ivars with isabus 200af548787SNicolas Souchu */ 201af548787SNicolas Souchu pcf->pcf_base = pcfdata[unit]->pcf_base; 202af548787SNicolas Souchu 203af548787SNicolas Souchu /* reset the chip */ 204af548787SNicolas Souchu pcf_rst_card(pcfdev, IIC_FASTEST, PCF_DEFAULT_ADDR, NULL); 2054e190a62SNicolas Souchu 2064e190a62SNicolas Souchu /* XXX try do detect chipset */ 2074e190a62SNicolas Souchu 2084e190a62SNicolas Souchu device_set_desc(pcfdev, "PCF8584 I2C bus controller"); 2094e190a62SNicolas Souchu 2104e190a62SNicolas Souchu return (0); 2114e190a62SNicolas Souchu } 2124e190a62SNicolas Souchu 2134e190a62SNicolas Souchu static int 2144e190a62SNicolas Souchu pcf_attach(device_t pcfdev) 2154e190a62SNicolas Souchu { 2164e190a62SNicolas Souchu struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(pcfdev); 2174e190a62SNicolas Souchu 218af548787SNicolas Souchu pcf->iicbus = iicbus_alloc_bus(pcfdev); 219af548787SNicolas Souchu 220af548787SNicolas Souchu if (!pcf->iicbus) 221af548787SNicolas Souchu return (EINVAL); 2224e190a62SNicolas Souchu 2234e190a62SNicolas Souchu /* probe and attach the iicbus */ 2244e190a62SNicolas Souchu device_probe_and_attach(pcf->iicbus); 2254e190a62SNicolas Souchu 2264e190a62SNicolas Souchu return (0); 2274e190a62SNicolas Souchu } 2284e190a62SNicolas Souchu 2294e190a62SNicolas Souchu static void 2304e190a62SNicolas Souchu pcf_print_child(device_t bus, device_t dev) 2314e190a62SNicolas Souchu { 232af548787SNicolas Souchu struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(bus); 233af548787SNicolas Souchu 2344e190a62SNicolas Souchu printf(" on %s%d addr 0x%x", device_get_name(bus), 235af548787SNicolas Souchu device_get_unit(bus), (int)pcf->pcf_addr); 2364e190a62SNicolas Souchu 2374e190a62SNicolas Souchu return; 2384e190a62SNicolas Souchu } 2394e190a62SNicolas Souchu 2404e190a62SNicolas Souchu /* 2414e190a62SNicolas Souchu * PCF8584 datasheet : when operate at 8 MHz or more, a minimun time of 2424e190a62SNicolas Souchu * 6 clocks cycles must be left between two consecutives access 2434e190a62SNicolas Souchu */ 2444e190a62SNicolas Souchu #define pcf_nops() DELAY(10) 2454e190a62SNicolas Souchu 2464e190a62SNicolas Souchu #define dummy_read(pcf) PCF_GET_S0(pcf) 2474e190a62SNicolas Souchu #define dummy_write(pcf) PCF_SET_S0(pcf, 0) 2484e190a62SNicolas Souchu 2494e190a62SNicolas Souchu /* 2504e190a62SNicolas Souchu * Specific register access to PCF8584 2514e190a62SNicolas Souchu */ 2524e190a62SNicolas Souchu static void PCF_SET_S0(struct pcf_softc *pcf, int data) 2534e190a62SNicolas Souchu { 2544e190a62SNicolas Souchu outb(pcf->pcf_base, data); 2554e190a62SNicolas Souchu pcf_nops(); 2564e190a62SNicolas Souchu } 2574e190a62SNicolas Souchu 2584e190a62SNicolas Souchu static void PCF_SET_S1(struct pcf_softc *pcf, int data) 2594e190a62SNicolas Souchu { 2604e190a62SNicolas Souchu outb(pcf->pcf_base+1, data); 2614e190a62SNicolas Souchu pcf_nops(); 2624e190a62SNicolas Souchu } 2634e190a62SNicolas Souchu 2644e190a62SNicolas Souchu static char PCF_GET_S0(struct pcf_softc *pcf) 2654e190a62SNicolas Souchu { 2664e190a62SNicolas Souchu char data; 2674e190a62SNicolas Souchu 2684e190a62SNicolas Souchu data = inb(pcf->pcf_base); 2694e190a62SNicolas Souchu pcf_nops(); 2704e190a62SNicolas Souchu 2714e190a62SNicolas Souchu return (data); 2724e190a62SNicolas Souchu } 2734e190a62SNicolas Souchu 2744e190a62SNicolas Souchu static char PCF_GET_S1(struct pcf_softc *pcf) 2754e190a62SNicolas Souchu { 2764e190a62SNicolas Souchu char data; 2774e190a62SNicolas Souchu 2784e190a62SNicolas Souchu data = inb(pcf->pcf_base+1); 2794e190a62SNicolas Souchu pcf_nops(); 2804e190a62SNicolas Souchu 2814e190a62SNicolas Souchu return (data); 2824e190a62SNicolas Souchu } 2834e190a62SNicolas Souchu 2844e190a62SNicolas Souchu /* 2854e190a62SNicolas Souchu * Polling mode for master operations wait for a new 2864e190a62SNicolas Souchu * byte incomming or outgoing 2874e190a62SNicolas Souchu */ 2884e190a62SNicolas Souchu static int pcf_wait_byte(struct pcf_softc *pcf) 2894e190a62SNicolas Souchu { 2904e190a62SNicolas Souchu int counter = TIMEOUT; 2914e190a62SNicolas Souchu 2924e190a62SNicolas Souchu while (counter--) { 2934e190a62SNicolas Souchu 2944e190a62SNicolas Souchu if ((PCF_GET_S1(pcf) & PIN) == 0) 2954e190a62SNicolas Souchu return (0); 2964e190a62SNicolas Souchu } 2974e190a62SNicolas Souchu 2984e190a62SNicolas Souchu return (IIC_ETIMEOUT); 2994e190a62SNicolas Souchu } 3004e190a62SNicolas Souchu 3014e190a62SNicolas Souchu static int pcf_stop(device_t pcfdev) 3024e190a62SNicolas Souchu { 3034e190a62SNicolas Souchu struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 3044e190a62SNicolas Souchu 305af548787SNicolas Souchu /* 306af548787SNicolas Souchu * Send STOP condition iff the START condition was previously sent. 307af548787SNicolas Souchu * STOP is sent only once even if a iicbus_stop() is called after 308af548787SNicolas Souchu * an iicbus_read()... see pcf_read(): the pcf needs to send the stop 309af548787SNicolas Souchu * before the last char is read. 310af548787SNicolas Souchu */ 311af548787SNicolas Souchu if (pcf->pcf_started) { 3124e190a62SNicolas Souchu /* set stop condition and enable IT */ 3134e190a62SNicolas Souchu PCF_SET_S1(pcf, PIN|ES0|ENI|STO|ACK); 3144e190a62SNicolas Souchu 315af548787SNicolas Souchu pcf->pcf_started = 0; 316af548787SNicolas Souchu } 317af548787SNicolas Souchu 3184e190a62SNicolas Souchu return (0); 3194e190a62SNicolas Souchu } 3204e190a62SNicolas Souchu 321af548787SNicolas Souchu 322af548787SNicolas Souchu static int pcf_noack(struct pcf_softc *pcf, int timeout) 323af548787SNicolas Souchu { 324af548787SNicolas Souchu int noack; 325af548787SNicolas Souchu int k = timeout/10; 326af548787SNicolas Souchu 327af548787SNicolas Souchu do { 328af548787SNicolas Souchu noack = PCF_GET_S1(pcf) & LRB; 329af548787SNicolas Souchu if (!noack) 330af548787SNicolas Souchu break; 331af548787SNicolas Souchu DELAY(10); /* XXX wait 10 us */ 332af548787SNicolas Souchu } while (k--); 333af548787SNicolas Souchu 334af548787SNicolas Souchu return (noack); 335af548787SNicolas Souchu } 336af548787SNicolas Souchu 337af548787SNicolas Souchu static int pcf_repeated_start(device_t pcfdev, u_char slave, int timeout) 3384e190a62SNicolas Souchu { 3394e190a62SNicolas Souchu struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 3404e190a62SNicolas Souchu int error = 0; 3414e190a62SNicolas Souchu 3424e190a62SNicolas Souchu /* repeated start */ 3434e190a62SNicolas Souchu PCF_SET_S1(pcf, ES0|STA|STO|ACK); 3444e190a62SNicolas Souchu 3454e190a62SNicolas Souchu /* set slave address to PCF. Last bit (LSB) must be set correctly 3464e190a62SNicolas Souchu * according to transfer direction */ 3474e190a62SNicolas Souchu PCF_SET_S0(pcf, slave); 3484e190a62SNicolas Souchu 3494e190a62SNicolas Souchu /* wait for address sent, polling */ 3504e190a62SNicolas Souchu if ((error = pcf_wait_byte(pcf))) 3514e190a62SNicolas Souchu goto error; 3524e190a62SNicolas Souchu 353af548787SNicolas Souchu /* check for ack */ 354af548787SNicolas Souchu if (pcf_noack(pcf, timeout)) { 3554e190a62SNicolas Souchu error = IIC_ENOACK; 3564e190a62SNicolas Souchu goto error; 3574e190a62SNicolas Souchu } 3584e190a62SNicolas Souchu 3594e190a62SNicolas Souchu return (0); 3604e190a62SNicolas Souchu 3614e190a62SNicolas Souchu error: 3624e190a62SNicolas Souchu pcf_stop(pcfdev); 3634e190a62SNicolas Souchu return (error); 3644e190a62SNicolas Souchu } 3654e190a62SNicolas Souchu 366af548787SNicolas Souchu static int pcf_start(device_t pcfdev, u_char slave, int timeout) 3674e190a62SNicolas Souchu { 3684e190a62SNicolas Souchu struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 3694e190a62SNicolas Souchu int error = 0; 3704e190a62SNicolas Souchu 3714e190a62SNicolas Souchu if (PCF_GET_S1(pcf) & nBB == 0) 3724e190a62SNicolas Souchu return (IIC_EBUSBSY); 3734e190a62SNicolas Souchu 3744e190a62SNicolas Souchu /* set slave address to PCF. Last bit (LSB) must be set correctly 3754e190a62SNicolas Souchu * according to transfer direction */ 3764e190a62SNicolas Souchu PCF_SET_S0(pcf, slave); 3774e190a62SNicolas Souchu 3784e190a62SNicolas Souchu /* START only */ 3794e190a62SNicolas Souchu PCF_SET_S1(pcf, PIN|ES0|STA|ACK); 3804e190a62SNicolas Souchu 381af548787SNicolas Souchu pcf->pcf_started = 1; 382af548787SNicolas Souchu 3834e190a62SNicolas Souchu /* wait for address sent, polling */ 3844e190a62SNicolas Souchu if ((error = pcf_wait_byte(pcf))) 3854e190a62SNicolas Souchu goto error; 3864e190a62SNicolas Souchu 387af548787SNicolas Souchu /* check for ACK */ 388af548787SNicolas Souchu if (pcf_noack(pcf, timeout)) { 3894e190a62SNicolas Souchu error = IIC_ENOACK; 3904e190a62SNicolas Souchu goto error; 3914e190a62SNicolas Souchu } 3924e190a62SNicolas Souchu 3934e190a62SNicolas Souchu return (0); 3944e190a62SNicolas Souchu 3954e190a62SNicolas Souchu error: 3964e190a62SNicolas Souchu pcf_stop(pcfdev); 3974e190a62SNicolas Souchu return (error); 3984e190a62SNicolas Souchu } 3994e190a62SNicolas Souchu 400fe310de8SBruce Evans static void 4014e190a62SNicolas Souchu pcfintr(unit) 4024e190a62SNicolas Souchu { 4034e190a62SNicolas Souchu struct pcf_softc *pcf = 4044e190a62SNicolas Souchu (struct pcf_softc *)devclass_get_softc(pcf_devclass, unit); 4054e190a62SNicolas Souchu 4064e190a62SNicolas Souchu char data, status, addr; 4074e190a62SNicolas Souchu char error = 0; 4084e190a62SNicolas Souchu 4094e190a62SNicolas Souchu status = PCF_GET_S1(pcf); 4104e190a62SNicolas Souchu 4114e190a62SNicolas Souchu if (status & PIN) { 4124e190a62SNicolas Souchu printf("pcf%d: spurious interrupt, status=0x%x\n", unit, 4134e190a62SNicolas Souchu status & 0xff); 4144e190a62SNicolas Souchu 4154e190a62SNicolas Souchu goto error; 4164e190a62SNicolas Souchu } 4174e190a62SNicolas Souchu 4184e190a62SNicolas Souchu if (status & LAB) 4194e190a62SNicolas Souchu printf("pcf%d: bus arbitration lost!\n", unit); 4204e190a62SNicolas Souchu 4214e190a62SNicolas Souchu if (status & BER) { 4224e190a62SNicolas Souchu error = IIC_EBUSERR; 4234e190a62SNicolas Souchu iicbus_intr(pcf->iicbus, INTR_ERROR, &error); 4244e190a62SNicolas Souchu 4254e190a62SNicolas Souchu goto error; 4264e190a62SNicolas Souchu } 4274e190a62SNicolas Souchu 4284e190a62SNicolas Souchu do { 4294e190a62SNicolas Souchu status = PCF_GET_S1(pcf); 4304e190a62SNicolas Souchu 4314e190a62SNicolas Souchu switch(pcf->pcf_slave_mode) { 4324e190a62SNicolas Souchu 4334e190a62SNicolas Souchu case SLAVE_TRANSMITTER: 4344e190a62SNicolas Souchu if (status & LRB) { 4354e190a62SNicolas Souchu /* ack interrupt line */ 4364e190a62SNicolas Souchu dummy_write(pcf); 4374e190a62SNicolas Souchu 4384e190a62SNicolas Souchu /* no ack, don't send anymore */ 4394e190a62SNicolas Souchu pcf->pcf_slave_mode = SLAVE_RECEIVER; 4404e190a62SNicolas Souchu 4414e190a62SNicolas Souchu iicbus_intr(pcf->iicbus, INTR_NOACK, NULL); 4424e190a62SNicolas Souchu break; 4434e190a62SNicolas Souchu } 4444e190a62SNicolas Souchu 4454e190a62SNicolas Souchu /* get data from upper code */ 4464e190a62SNicolas Souchu iicbus_intr(pcf->iicbus, INTR_TRANSMIT, &data); 4474e190a62SNicolas Souchu 4484e190a62SNicolas Souchu PCF_SET_S0(pcf, data); 4494e190a62SNicolas Souchu break; 4504e190a62SNicolas Souchu 4514e190a62SNicolas Souchu case SLAVE_RECEIVER: 4524e190a62SNicolas Souchu if (status & AAS) { 4534e190a62SNicolas Souchu addr = PCF_GET_S0(pcf); 4544e190a62SNicolas Souchu 4554e190a62SNicolas Souchu if (status & AD0) 4564e190a62SNicolas Souchu iicbus_intr(pcf->iicbus, INTR_GENERAL, &addr); 4574e190a62SNicolas Souchu else 4584e190a62SNicolas Souchu iicbus_intr(pcf->iicbus, INTR_START, &addr); 4594e190a62SNicolas Souchu 4604e190a62SNicolas Souchu if (addr & LSB) { 4614e190a62SNicolas Souchu pcf->pcf_slave_mode = SLAVE_TRANSMITTER; 4624e190a62SNicolas Souchu 4634e190a62SNicolas Souchu /* get the first char from upper code */ 4644e190a62SNicolas Souchu iicbus_intr(pcf->iicbus, INTR_TRANSMIT, &data); 4654e190a62SNicolas Souchu 4664e190a62SNicolas Souchu /* send first data byte */ 4674e190a62SNicolas Souchu PCF_SET_S0(pcf, data); 4684e190a62SNicolas Souchu } 4694e190a62SNicolas Souchu 4704e190a62SNicolas Souchu break; 4714e190a62SNicolas Souchu } 4724e190a62SNicolas Souchu 4734e190a62SNicolas Souchu /* stop condition received? */ 4744e190a62SNicolas Souchu if (status & STS) { 4754e190a62SNicolas Souchu /* ack interrupt line */ 4764e190a62SNicolas Souchu dummy_read(pcf); 4774e190a62SNicolas Souchu 4784e190a62SNicolas Souchu /* emulate intr stop condition */ 4794e190a62SNicolas Souchu iicbus_intr(pcf->iicbus, INTR_STOP, NULL); 4804e190a62SNicolas Souchu 4814e190a62SNicolas Souchu } else { 4824e190a62SNicolas Souchu /* get data, ack interrupt line */ 4834e190a62SNicolas Souchu data = PCF_GET_S0(pcf); 4844e190a62SNicolas Souchu 4854e190a62SNicolas Souchu /* deliver the character */ 4864e190a62SNicolas Souchu iicbus_intr(pcf->iicbus, INTR_RECEIVE, &data); 4874e190a62SNicolas Souchu } 4884e190a62SNicolas Souchu break; 4894e190a62SNicolas Souchu 4904e190a62SNicolas Souchu default: 4914e190a62SNicolas Souchu panic("%s: unknown slave mode (%d)!", __FUNCTION__, 4924e190a62SNicolas Souchu pcf->pcf_slave_mode); 4934e190a62SNicolas Souchu } 4944e190a62SNicolas Souchu 4954e190a62SNicolas Souchu } while ((PCF_GET_S1(pcf) & PIN) == 0); 4964e190a62SNicolas Souchu 4974e190a62SNicolas Souchu return; 4984e190a62SNicolas Souchu 4994e190a62SNicolas Souchu error: 5004e190a62SNicolas Souchu /* unknown event on bus...reset PCF */ 5014e190a62SNicolas Souchu PCF_SET_S1(pcf, PIN|ES0|ENI|ACK); 5024e190a62SNicolas Souchu 5034e190a62SNicolas Souchu pcf->pcf_slave_mode = SLAVE_RECEIVER; 5044e190a62SNicolas Souchu 5054e190a62SNicolas Souchu return; 5064e190a62SNicolas Souchu } 5074e190a62SNicolas Souchu 508af548787SNicolas Souchu static int pcf_rst_card(device_t pcfdev, u_char speed, u_char addr, u_char *oldaddr) 5094e190a62SNicolas Souchu { 5104e190a62SNicolas Souchu struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 511af548787SNicolas Souchu 512af548787SNicolas Souchu if (oldaddr) 513af548787SNicolas Souchu *oldaddr = pcf->pcf_addr; 5144e190a62SNicolas Souchu 5154e190a62SNicolas Souchu /* retrieve own address from bus level */ 516af548787SNicolas Souchu if (!addr) 517af548787SNicolas Souchu pcf->pcf_addr = PCF_DEFAULT_ADDR; 518af548787SNicolas Souchu else 519af548787SNicolas Souchu pcf->pcf_addr = addr; 5204e190a62SNicolas Souchu 5214e190a62SNicolas Souchu PCF_SET_S1(pcf, PIN); /* initialize S1 */ 5224e190a62SNicolas Souchu 5234e190a62SNicolas Souchu /* own address S'O<>0 */ 524af548787SNicolas Souchu PCF_SET_S0(pcf, pcf->pcf_addr >> 1); 5254e190a62SNicolas Souchu 5264e190a62SNicolas Souchu /* select clock register */ 5274e190a62SNicolas Souchu PCF_SET_S1(pcf, PIN|ES1); 5284e190a62SNicolas Souchu 5294e190a62SNicolas Souchu /* select bus speed : 18=90kb, 19=45kb, 1A=11kb, 1B=1.5kb */ 5304e190a62SNicolas Souchu switch (speed) { 5314e190a62SNicolas Souchu case IIC_SLOW: 5324e190a62SNicolas Souchu PCF_SET_S0(pcf, 0x1b); 5334e190a62SNicolas Souchu break; 5344e190a62SNicolas Souchu 5354e190a62SNicolas Souchu case IIC_FAST: 5364e190a62SNicolas Souchu PCF_SET_S0(pcf, 0x19); 5374e190a62SNicolas Souchu break; 5384e190a62SNicolas Souchu 5394e190a62SNicolas Souchu case IIC_UNKNOWN: 5404e190a62SNicolas Souchu case IIC_FASTEST: 5414e190a62SNicolas Souchu default: 5424e190a62SNicolas Souchu PCF_SET_S0(pcf, 0x18); 5434e190a62SNicolas Souchu break; 5444e190a62SNicolas Souchu } 5454e190a62SNicolas Souchu 5464e190a62SNicolas Souchu /* set bus on, ack=yes, INT=yes */ 5474e190a62SNicolas Souchu PCF_SET_S1(pcf, PIN|ES0|ENI|ACK); 5484e190a62SNicolas Souchu 5494e190a62SNicolas Souchu pcf->pcf_slave_mode = SLAVE_RECEIVER; 5504e190a62SNicolas Souchu 5514e190a62SNicolas Souchu return (0); 5524e190a62SNicolas Souchu } 5534e190a62SNicolas Souchu 5544e190a62SNicolas Souchu static int 555af548787SNicolas Souchu pcf_write(device_t pcfdev, char *buf, int len, int *sent, int timeout /* us */) 5564e190a62SNicolas Souchu { 5574e190a62SNicolas Souchu struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 5584e190a62SNicolas Souchu int bytes, error = 0; 5594e190a62SNicolas Souchu 5604e190a62SNicolas Souchu #ifdef PCFDEBUG 5614e190a62SNicolas Souchu printf("pcf%d: >> writing %d bytes\n", device_get_unit(pcfdev), len); 5624e190a62SNicolas Souchu #endif 5634e190a62SNicolas Souchu 5644e190a62SNicolas Souchu bytes = 0; 5654e190a62SNicolas Souchu while (len) { 5664e190a62SNicolas Souchu 5674e190a62SNicolas Souchu PCF_SET_S0(pcf, *buf++); 5684e190a62SNicolas Souchu 569af548787SNicolas Souchu /* wait for the byte to be send */ 5704e190a62SNicolas Souchu if ((error = pcf_wait_byte(pcf))) 5714e190a62SNicolas Souchu goto error; 5724e190a62SNicolas Souchu 573af548787SNicolas Souchu /* check if ack received */ 574af548787SNicolas Souchu if (pcf_noack(pcf, timeout)) { 5754e190a62SNicolas Souchu error = IIC_ENOACK; 5764e190a62SNicolas Souchu goto error; 5774e190a62SNicolas Souchu } 5784e190a62SNicolas Souchu 5794e190a62SNicolas Souchu len --; 5804e190a62SNicolas Souchu bytes ++; 5814e190a62SNicolas Souchu } 5824e190a62SNicolas Souchu 5834e190a62SNicolas Souchu error: 5844e190a62SNicolas Souchu *sent = bytes; 5854e190a62SNicolas Souchu 5864e190a62SNicolas Souchu #ifdef PCFDEBUG 5874e190a62SNicolas Souchu printf("pcf%d: >> %d bytes written (%d)\n", 5884e190a62SNicolas Souchu device_get_unit(pcfdev), bytes, error); 5894e190a62SNicolas Souchu #endif 5904e190a62SNicolas Souchu 5914e190a62SNicolas Souchu return (error); 5924e190a62SNicolas Souchu } 5934e190a62SNicolas Souchu 5944e190a62SNicolas Souchu static int 595af548787SNicolas Souchu pcf_read(device_t pcfdev, char *buf, int len, int *read, int last, 596af548787SNicolas Souchu int delay /* us */) 5974e190a62SNicolas Souchu { 5984e190a62SNicolas Souchu struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 5994e190a62SNicolas Souchu int bytes, error = 0; 6004e190a62SNicolas Souchu 6014e190a62SNicolas Souchu #ifdef PCFDEBUG 6024e190a62SNicolas Souchu printf("pcf%d: << reading %d bytes\n", device_get_unit(pcfdev), len); 6034e190a62SNicolas Souchu #endif 6044e190a62SNicolas Souchu 6054e190a62SNicolas Souchu /* trig the bus to get the first data byte in S0 */ 6064e190a62SNicolas Souchu if (len) { 607af548787SNicolas Souchu if (len == 1 && last) 6084e190a62SNicolas Souchu /* just one byte to read */ 6094e190a62SNicolas Souchu PCF_SET_S1(pcf, ES0); /* no ack */ 6104e190a62SNicolas Souchu 6114e190a62SNicolas Souchu dummy_read(pcf); 6124e190a62SNicolas Souchu } 6134e190a62SNicolas Souchu 6144e190a62SNicolas Souchu bytes = 0; 6154e190a62SNicolas Souchu while (len) { 6164e190a62SNicolas Souchu 617af548787SNicolas Souchu /* XXX delay needed here */ 618af548787SNicolas Souchu 619af548787SNicolas Souchu /* wait for trigged byte */ 6204e190a62SNicolas Souchu if ((error = pcf_wait_byte(pcf))) { 6214e190a62SNicolas Souchu pcf_stop(pcfdev); 6224e190a62SNicolas Souchu goto error; 6234e190a62SNicolas Souchu } 6244e190a62SNicolas Souchu 625af548787SNicolas Souchu if (len == 1 && last) 626af548787SNicolas Souchu /* ok, last data byte already in S0, no I2C activity 627af548787SNicolas Souchu * on next PCF_GET_S0() */ 6284e190a62SNicolas Souchu pcf_stop(pcfdev); 6294e190a62SNicolas Souchu 630af548787SNicolas Souchu else if (len == 2 && last) 6314e190a62SNicolas Souchu /* next trigged byte with no ack */ 6324e190a62SNicolas Souchu PCF_SET_S1(pcf, ES0); 6334e190a62SNicolas Souchu 634af548787SNicolas Souchu /* receive byte, trig next byte */ 6354e190a62SNicolas Souchu *buf++ = PCF_GET_S0(pcf); 6364e190a62SNicolas Souchu 6374e190a62SNicolas Souchu len --; 6384e190a62SNicolas Souchu bytes ++; 6394e190a62SNicolas Souchu }; 6404e190a62SNicolas Souchu 6414e190a62SNicolas Souchu error: 6424e190a62SNicolas Souchu *read = bytes; 6434e190a62SNicolas Souchu 6444e190a62SNicolas Souchu #ifdef PCFDEBUG 6454e190a62SNicolas Souchu printf("pcf%d: << %d bytes read (%d)\n", 6464e190a62SNicolas Souchu device_get_unit(pcfdev), bytes, error); 6474e190a62SNicolas Souchu #endif 6484e190a62SNicolas Souchu 6494e190a62SNicolas Souchu return (error); 6504e190a62SNicolas Souchu } 6514e190a62SNicolas Souchu 6524e190a62SNicolas Souchu DRIVER_MODULE(pcf, root, pcf_driver, pcf_devclass, 0, 0); 653