pcf.c revision 108533
138781Snsouch/*- 238781Snsouch * Copyright (c) 1998 Nicolas Souchu, Marc Bouget 338781Snsouch * All rights reserved. 438781Snsouch * 538781Snsouch * Redistribution and use in source and binary forms, with or without 638781Snsouch * modification, are permitted provided that the following conditions 738781Snsouch * are met: 838781Snsouch * 1. Redistributions of source code must retain the above copyright 938781Snsouch * notice, this list of conditions and the following disclaimer. 1038781Snsouch * 2. Redistributions in binary form must reproduce the above copyright 1138781Snsouch * notice, this list of conditions and the following disclaimer in the 1238781Snsouch * documentation and/or other materials provided with the distribution. 1338781Snsouch * 1438781Snsouch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1538781Snsouch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1638781Snsouch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1738781Snsouch * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1838781Snsouch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1938781Snsouch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2038781Snsouch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2138781Snsouch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2238781Snsouch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2338781Snsouch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2438781Snsouch * SUCH DAMAGE. 2538781Snsouch * 2650477Speter * $FreeBSD: head/sys/dev/pcf/pcf.c 108533 2003-01-01 18:49:04Z schweikh $ 2738781Snsouch * 2838781Snsouch */ 2938781Snsouch#include <sys/param.h> 3038781Snsouch#include <sys/systm.h> 3138781Snsouch#include <sys/kernel.h> 3238781Snsouch#include <sys/module.h> 3338781Snsouch#include <sys/bus.h> 3438781Snsouch 3555939Snsouch#include <machine/bus.h> 3655939Snsouch#include <machine/resource.h> 3755939Snsouch#include <sys/rman.h> 3838781Snsouch 3955939Snsouch#include <isa/isareg.h> 4055939Snsouch#include <isa/isavar.h> 4155939Snsouch 4238781Snsouch#include <i386/isa/isa_device.h> 4338781Snsouch 4438781Snsouch#include <dev/iicbus/iiconf.h> 4538781Snsouch#include "iicbus_if.h" 4638781Snsouch 4755939Snsouch#define IO_PCFSIZE 2 4855939Snsouch 4940784Snsouch#define TIMEOUT 9999 /* XXX */ 5038781Snsouch 5138781Snsouch/* Status bits of S1 register (read only) */ 5238781Snsouch#define nBB 0x01 /* busy when low set/reset by STOP/START*/ 5338781Snsouch#define LAB 0x02 /* lost arbitration bit in multi-master mode */ 5438781Snsouch#define AAS 0x04 /* addressed as slave */ 5538781Snsouch#define LRB 0x08 /* last received byte when not AAS */ 5638781Snsouch#define AD0 0x08 /* general call received when AAS */ 5738781Snsouch#define BER 0x10 /* bus error, misplaced START or STOP */ 5838781Snsouch#define STS 0x20 /* STOP detected in slave receiver mode */ 5938781Snsouch#define PIN 0x80 /* pending interrupt not (r/w) */ 6038781Snsouch 6138781Snsouch/* Control bits of S1 register (write only) */ 6238781Snsouch#define ACK 0x01 6338781Snsouch#define STO 0x02 6438781Snsouch#define STA 0x04 6538781Snsouch#define ENI 0x08 6638781Snsouch#define ES2 0x10 6738781Snsouch#define ES1 0x20 6838781Snsouch#define ES0 0x40 6938781Snsouch 7038781Snsouch#define BUFSIZE 2048 7138781Snsouch 7238781Snsouch#define SLAVE_TRANSMITTER 0x1 7338781Snsouch#define SLAVE_RECEIVER 0x2 7438781Snsouch 7540784Snsouch#define PCF_DEFAULT_ADDR 0xaa 7640784Snsouch 7738781Snsouchstruct pcf_softc { 7838781Snsouch 7938781Snsouch int pcf_base; /* isa port */ 8055939Snsouch int pcf_flags; 8140784Snsouch u_char pcf_addr; /* interface I2C address */ 8238781Snsouch 8338781Snsouch int pcf_slave_mode; /* receiver or transmitter */ 8440784Snsouch int pcf_started; /* 1 if start condition sent */ 8538781Snsouch 8638781Snsouch device_t iicbus; /* the corresponding iicbus */ 8738781Snsouch 8855939Snsouch int rid_irq, rid_ioport; 8955939Snsouch struct resource *res_irq, *res_ioport; 9055939Snsouch void *intr_cookie; 9138781Snsouch}; 9238781Snsouch 9338781Snsouchstatic int pcf_probe(device_t); 9438781Snsouchstatic int pcf_attach(device_t); 9555939Snsouchstatic void pcfintr(void *arg); 9655939Snsouch 9749195Smdoddstatic int pcf_print_child(device_t, device_t); 9838781Snsouch 9940784Snsouchstatic int pcf_repeated_start(device_t, u_char, int); 10040784Snsouchstatic int pcf_start(device_t, u_char, int); 10138781Snsouchstatic int pcf_stop(device_t); 10240788Speterstatic int pcf_write(device_t, char *, int, int *, int); 10340788Speterstatic int pcf_read(device_t, char *, int, int *, int, int); 10440788Speterstatic int pcf_rst_card(device_t, u_char, u_char, u_char *); 10538781Snsouch 10638781Snsouchstatic device_method_t pcf_methods[] = { 10738781Snsouch /* device interface */ 10838781Snsouch DEVMETHOD(device_probe, pcf_probe), 10938781Snsouch DEVMETHOD(device_attach, pcf_attach), 11038781Snsouch 11138781Snsouch /* bus interface */ 11238781Snsouch DEVMETHOD(bus_print_child, pcf_print_child), 11338781Snsouch 11438781Snsouch /* iicbus interface */ 11540784Snsouch DEVMETHOD(iicbus_callback, iicbus_null_callback), 11638781Snsouch DEVMETHOD(iicbus_repeated_start, pcf_repeated_start), 11738781Snsouch DEVMETHOD(iicbus_start, pcf_start), 11838781Snsouch DEVMETHOD(iicbus_stop, pcf_stop), 11938781Snsouch DEVMETHOD(iicbus_write, pcf_write), 12038781Snsouch DEVMETHOD(iicbus_read, pcf_read), 12138781Snsouch DEVMETHOD(iicbus_reset, pcf_rst_card), 12238781Snsouch 12338781Snsouch { 0, 0 } 12438781Snsouch}; 12538781Snsouch 12638781Snsouchstatic driver_t pcf_driver = { 12738781Snsouch "pcf", 12838781Snsouch pcf_methods, 12938781Snsouch sizeof(struct pcf_softc), 13038781Snsouch}; 13138781Snsouch 13238781Snsouchstatic devclass_t pcf_devclass; 13338781Snsouch 13438781Snsouch#define DEVTOSOFTC(dev) ((struct pcf_softc *)device_get_softc(dev)) 13538781Snsouch 13638781Snsouchstatic int 13755939Snsouchpcf_probe(device_t pcfdev) 13838781Snsouch{ 13955939Snsouch struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 14055939Snsouch device_t parent = device_get_parent(pcfdev); 14138781Snsouch 14255939Snsouch device_set_desc(pcfdev, "PCF8584 I2C bus controller"); 14338781Snsouch 14455939Snsouch pcf = DEVTOSOFTC(pcfdev); 14555939Snsouch bzero(pcf, sizeof(struct pcf_softc)); 14638781Snsouch 14755939Snsouch pcf->rid_irq = pcf->rid_ioport = 0; 14855939Snsouch pcf->res_irq = pcf->res_ioport = 0; 14938781Snsouch 15055939Snsouch /* IO port is mandatory */ 15155939Snsouch pcf->res_ioport = bus_alloc_resource(pcfdev, SYS_RES_IOPORT, 15255939Snsouch &pcf->rid_ioport, 0ul, ~0ul, 15355939Snsouch IO_PCFSIZE, RF_ACTIVE); 15455939Snsouch if (pcf->res_ioport == 0) { 15555939Snsouch device_printf(pcfdev, "cannot reserve I/O port range\n"); 15638781Snsouch goto error; 15755939Snsouch } 15855939Snsouch BUS_READ_IVAR(parent, pcfdev, ISA_IVAR_PORT, &pcf->pcf_base); 15938781Snsouch 16055939Snsouch pcf->pcf_flags = device_get_flags(pcfdev); 16138781Snsouch 16255939Snsouch if (!(pcf->pcf_flags & IIC_POLLED)) { 16355939Snsouch pcf->res_irq = bus_alloc_resource(pcfdev, SYS_RES_IRQ, &pcf->rid_irq, 16455939Snsouch 0ul, ~0ul, 1, RF_ACTIVE); 16555939Snsouch if (pcf->res_irq == 0) { 16655939Snsouch device_printf(pcfdev, "can't reserve irq, polled mode.\n"); 16755939Snsouch pcf->pcf_flags |= IIC_POLLED; 16855939Snsouch } 16955939Snsouch } 17038781Snsouch 17140784Snsouch /* reset the chip */ 17240784Snsouch pcf_rst_card(pcfdev, IIC_FASTEST, PCF_DEFAULT_ADDR, NULL); 17340784Snsouch 17438781Snsouch return (0); 17555939Snsoucherror: 17655939Snsouch if (pcf->res_ioport != 0) { 17755939Snsouch bus_deactivate_resource(pcfdev, SYS_RES_IOPORT, pcf->rid_ioport, 17855939Snsouch pcf->res_ioport); 17955939Snsouch bus_release_resource(pcfdev, SYS_RES_IOPORT, pcf->rid_ioport, 18055939Snsouch pcf->res_ioport); 18155939Snsouch } 18255939Snsouch return (ENXIO); 18338781Snsouch} 18438781Snsouch 18538781Snsouchstatic int 18638781Snsouchpcf_attach(device_t pcfdev) 18738781Snsouch{ 18855939Snsouch struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 18955939Snsouch device_t parent = device_get_parent(pcfdev); 19055939Snsouch int error = 0; 19138781Snsouch 19255939Snsouch if (pcf->res_irq) { 19355939Snsouch /* default to the tty mask for registration */ /* XXX */ 19455939Snsouch error = BUS_SETUP_INTR(parent, pcfdev, pcf->res_irq, INTR_TYPE_NET, 19555939Snsouch pcfintr, pcfdev, &pcf->intr_cookie); 19655939Snsouch if (error) 19755939Snsouch return (error); 19855939Snsouch } 19955939Snsouch 20093165Snsouch pcf->iicbus = device_add_child(pcfdev, "iicbus", -1); 20138781Snsouch 20238781Snsouch /* probe and attach the iicbus */ 20393165Snsouch bus_generic_attach(pcfdev); 20438781Snsouch 20538781Snsouch return (0); 20638781Snsouch} 20738781Snsouch 20849195Smdoddstatic int 20938781Snsouchpcf_print_child(device_t bus, device_t dev) 21038781Snsouch{ 21140784Snsouch struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(bus); 21249195Smdodd int retval = 0; 21340784Snsouch 21449195Smdodd retval += bus_print_child_header(bus, dev); 21549195Smdodd retval += printf(" on %s addr 0x%x\n", device_get_nameunit(bus), 21649195Smdodd (int)pcf->pcf_addr); 21738781Snsouch 21849195Smdodd return (retval); 21938781Snsouch} 22038781Snsouch 22138781Snsouch/* 22238781Snsouch * PCF8584 datasheet : when operate at 8 MHz or more, a minimun time of 22338781Snsouch * 6 clocks cycles must be left between two consecutives access 22438781Snsouch */ 22538781Snsouch#define pcf_nops() DELAY(10) 22638781Snsouch 22738781Snsouch#define dummy_read(pcf) PCF_GET_S0(pcf) 22838781Snsouch#define dummy_write(pcf) PCF_SET_S0(pcf, 0) 22938781Snsouch 23038781Snsouch/* 23138781Snsouch * Specific register access to PCF8584 23238781Snsouch */ 23338781Snsouchstatic void PCF_SET_S0(struct pcf_softc *pcf, int data) 23438781Snsouch{ 23538781Snsouch outb(pcf->pcf_base, data); 23638781Snsouch pcf_nops(); 23738781Snsouch} 23838781Snsouch 23938781Snsouchstatic void PCF_SET_S1(struct pcf_softc *pcf, int data) 24038781Snsouch{ 24138781Snsouch outb(pcf->pcf_base+1, data); 24238781Snsouch pcf_nops(); 24338781Snsouch} 24438781Snsouch 24538781Snsouchstatic char PCF_GET_S0(struct pcf_softc *pcf) 24638781Snsouch{ 24738781Snsouch char data; 24838781Snsouch 24938781Snsouch data = inb(pcf->pcf_base); 25038781Snsouch pcf_nops(); 25138781Snsouch 25238781Snsouch return (data); 25338781Snsouch} 25438781Snsouch 25538781Snsouchstatic char PCF_GET_S1(struct pcf_softc *pcf) 25638781Snsouch{ 25738781Snsouch char data; 25838781Snsouch 25938781Snsouch data = inb(pcf->pcf_base+1); 26038781Snsouch pcf_nops(); 26138781Snsouch 26238781Snsouch return (data); 26338781Snsouch} 26438781Snsouch 26538781Snsouch/* 26638781Snsouch * Polling mode for master operations wait for a new 26738781Snsouch * byte incomming or outgoing 26838781Snsouch */ 26938781Snsouchstatic int pcf_wait_byte(struct pcf_softc *pcf) 27038781Snsouch{ 27138781Snsouch int counter = TIMEOUT; 27238781Snsouch 27338781Snsouch while (counter--) { 27438781Snsouch 27538781Snsouch if ((PCF_GET_S1(pcf) & PIN) == 0) 27638781Snsouch return (0); 27738781Snsouch } 27838781Snsouch 27938781Snsouch return (IIC_ETIMEOUT); 28038781Snsouch} 28138781Snsouch 28238781Snsouchstatic int pcf_stop(device_t pcfdev) 28338781Snsouch{ 28438781Snsouch struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 28538781Snsouch 28640784Snsouch /* 28740784Snsouch * Send STOP condition iff the START condition was previously sent. 288108533Sschweikh * STOP is sent only once even if an iicbus_stop() is called after 28940784Snsouch * an iicbus_read()... see pcf_read(): the pcf needs to send the stop 29040784Snsouch * before the last char is read. 29140784Snsouch */ 29240784Snsouch if (pcf->pcf_started) { 29340784Snsouch /* set stop condition and enable IT */ 29440784Snsouch PCF_SET_S1(pcf, PIN|ES0|ENI|STO|ACK); 29538781Snsouch 29640784Snsouch pcf->pcf_started = 0; 29740784Snsouch } 29840784Snsouch 29938781Snsouch return (0); 30038781Snsouch} 30138781Snsouch 30240784Snsouch 30340784Snsouchstatic int pcf_noack(struct pcf_softc *pcf, int timeout) 30438781Snsouch{ 30540784Snsouch int noack; 30640784Snsouch int k = timeout/10; 30740784Snsouch 30840784Snsouch do { 30940784Snsouch noack = PCF_GET_S1(pcf) & LRB; 31040784Snsouch if (!noack) 31140784Snsouch break; 31240784Snsouch DELAY(10); /* XXX wait 10 us */ 31340784Snsouch } while (k--); 31440784Snsouch 31540784Snsouch return (noack); 31640784Snsouch} 31740784Snsouch 31840784Snsouchstatic int pcf_repeated_start(device_t pcfdev, u_char slave, int timeout) 31940784Snsouch{ 32038781Snsouch struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 32138781Snsouch int error = 0; 32238781Snsouch 32338781Snsouch /* repeated start */ 32438781Snsouch PCF_SET_S1(pcf, ES0|STA|STO|ACK); 32538781Snsouch 32638781Snsouch /* set slave address to PCF. Last bit (LSB) must be set correctly 32738781Snsouch * according to transfer direction */ 32838781Snsouch PCF_SET_S0(pcf, slave); 32938781Snsouch 33038781Snsouch /* wait for address sent, polling */ 33138781Snsouch if ((error = pcf_wait_byte(pcf))) 33238781Snsouch goto error; 33338781Snsouch 33440784Snsouch /* check for ack */ 33540784Snsouch if (pcf_noack(pcf, timeout)) { 33638781Snsouch error = IIC_ENOACK; 33738781Snsouch goto error; 33838781Snsouch } 33938781Snsouch 34038781Snsouch return (0); 34138781Snsouch 34238781Snsoucherror: 34338781Snsouch pcf_stop(pcfdev); 34438781Snsouch return (error); 34538781Snsouch} 34638781Snsouch 34740784Snsouchstatic int pcf_start(device_t pcfdev, u_char slave, int timeout) 34838781Snsouch{ 34938781Snsouch struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 35038781Snsouch int error = 0; 35138781Snsouch 35246343Speter if ((PCF_GET_S1(pcf) & nBB) == 0) 35338781Snsouch return (IIC_EBUSBSY); 35438781Snsouch 35538781Snsouch /* set slave address to PCF. Last bit (LSB) must be set correctly 35638781Snsouch * according to transfer direction */ 35738781Snsouch PCF_SET_S0(pcf, slave); 35838781Snsouch 35938781Snsouch /* START only */ 36038781Snsouch PCF_SET_S1(pcf, PIN|ES0|STA|ACK); 36138781Snsouch 36240784Snsouch pcf->pcf_started = 1; 36340784Snsouch 36438781Snsouch /* wait for address sent, polling */ 36538781Snsouch if ((error = pcf_wait_byte(pcf))) 36638781Snsouch goto error; 36738781Snsouch 36840784Snsouch /* check for ACK */ 36940784Snsouch if (pcf_noack(pcf, timeout)) { 37038781Snsouch error = IIC_ENOACK; 37138781Snsouch goto error; 37238781Snsouch } 37338781Snsouch 37438781Snsouch return (0); 37538781Snsouch 37638781Snsoucherror: 37738781Snsouch pcf_stop(pcfdev); 37838781Snsouch return (error); 37938781Snsouch} 38038781Snsouch 38140565Sbdestatic void 38255939Snsouchpcfintr(void *arg) 38338781Snsouch{ 38455939Snsouch device_t pcfdev = (device_t)arg; 38555939Snsouch struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 38638781Snsouch 38738781Snsouch char data, status, addr; 38838781Snsouch char error = 0; 38938781Snsouch 39038781Snsouch status = PCF_GET_S1(pcf); 39138781Snsouch 39238781Snsouch if (status & PIN) { 39355939Snsouch device_printf(pcfdev, "spurious interrupt, status=0x%x\n", status & 0xff); 39438781Snsouch 39538781Snsouch goto error; 39638781Snsouch } 39738781Snsouch 39838781Snsouch if (status & LAB) 39955939Snsouch device_printf(pcfdev, "bus arbitration lost!\n"); 40038781Snsouch 40138781Snsouch if (status & BER) { 40238781Snsouch error = IIC_EBUSERR; 40338781Snsouch iicbus_intr(pcf->iicbus, INTR_ERROR, &error); 40438781Snsouch 40538781Snsouch goto error; 40638781Snsouch } 40738781Snsouch 40838781Snsouch do { 40938781Snsouch status = PCF_GET_S1(pcf); 41038781Snsouch 41138781Snsouch switch(pcf->pcf_slave_mode) { 41238781Snsouch 41338781Snsouch case SLAVE_TRANSMITTER: 41438781Snsouch if (status & LRB) { 41538781Snsouch /* ack interrupt line */ 41638781Snsouch dummy_write(pcf); 41738781Snsouch 41838781Snsouch /* no ack, don't send anymore */ 41938781Snsouch pcf->pcf_slave_mode = SLAVE_RECEIVER; 42038781Snsouch 42138781Snsouch iicbus_intr(pcf->iicbus, INTR_NOACK, NULL); 42238781Snsouch break; 42338781Snsouch } 42438781Snsouch 42538781Snsouch /* get data from upper code */ 42638781Snsouch iicbus_intr(pcf->iicbus, INTR_TRANSMIT, &data); 42738781Snsouch 42838781Snsouch PCF_SET_S0(pcf, data); 42938781Snsouch break; 43038781Snsouch 43138781Snsouch case SLAVE_RECEIVER: 43238781Snsouch if (status & AAS) { 43338781Snsouch addr = PCF_GET_S0(pcf); 43438781Snsouch 43538781Snsouch if (status & AD0) 43638781Snsouch iicbus_intr(pcf->iicbus, INTR_GENERAL, &addr); 43738781Snsouch else 43838781Snsouch iicbus_intr(pcf->iicbus, INTR_START, &addr); 43938781Snsouch 44038781Snsouch if (addr & LSB) { 44138781Snsouch pcf->pcf_slave_mode = SLAVE_TRANSMITTER; 44238781Snsouch 44338781Snsouch /* get the first char from upper code */ 44438781Snsouch iicbus_intr(pcf->iicbus, INTR_TRANSMIT, &data); 44538781Snsouch 44638781Snsouch /* send first data byte */ 44738781Snsouch PCF_SET_S0(pcf, data); 44838781Snsouch } 44938781Snsouch 45038781Snsouch break; 45138781Snsouch } 45238781Snsouch 45338781Snsouch /* stop condition received? */ 45438781Snsouch if (status & STS) { 45538781Snsouch /* ack interrupt line */ 45638781Snsouch dummy_read(pcf); 45738781Snsouch 45838781Snsouch /* emulate intr stop condition */ 45938781Snsouch iicbus_intr(pcf->iicbus, INTR_STOP, NULL); 46038781Snsouch 46138781Snsouch } else { 46238781Snsouch /* get data, ack interrupt line */ 46338781Snsouch data = PCF_GET_S0(pcf); 46438781Snsouch 46538781Snsouch /* deliver the character */ 46638781Snsouch iicbus_intr(pcf->iicbus, INTR_RECEIVE, &data); 46738781Snsouch } 46838781Snsouch break; 46938781Snsouch 47038781Snsouch default: 47187599Sobrien panic("%s: unknown slave mode (%d)!", __func__, 47238781Snsouch pcf->pcf_slave_mode); 47338781Snsouch } 47438781Snsouch 47538781Snsouch } while ((PCF_GET_S1(pcf) & PIN) == 0); 47638781Snsouch 47738781Snsouch return; 47838781Snsouch 47938781Snsoucherror: 48038781Snsouch /* unknown event on bus...reset PCF */ 48138781Snsouch PCF_SET_S1(pcf, PIN|ES0|ENI|ACK); 48238781Snsouch 48338781Snsouch pcf->pcf_slave_mode = SLAVE_RECEIVER; 48438781Snsouch 48538781Snsouch return; 48638781Snsouch} 48738781Snsouch 48840784Snsouchstatic int pcf_rst_card(device_t pcfdev, u_char speed, u_char addr, u_char *oldaddr) 48938781Snsouch{ 49038781Snsouch struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 49138781Snsouch 49240784Snsouch if (oldaddr) 49340784Snsouch *oldaddr = pcf->pcf_addr; 49440784Snsouch 49538781Snsouch /* retrieve own address from bus level */ 49640784Snsouch if (!addr) 49740784Snsouch pcf->pcf_addr = PCF_DEFAULT_ADDR; 49840784Snsouch else 49940784Snsouch pcf->pcf_addr = addr; 50038781Snsouch 50138781Snsouch PCF_SET_S1(pcf, PIN); /* initialize S1 */ 50238781Snsouch 50338781Snsouch /* own address S'O<>0 */ 50440784Snsouch PCF_SET_S0(pcf, pcf->pcf_addr >> 1); 50538781Snsouch 50638781Snsouch /* select clock register */ 50738781Snsouch PCF_SET_S1(pcf, PIN|ES1); 50838781Snsouch 50938781Snsouch /* select bus speed : 18=90kb, 19=45kb, 1A=11kb, 1B=1.5kb */ 51038781Snsouch switch (speed) { 51138781Snsouch case IIC_SLOW: 51238781Snsouch PCF_SET_S0(pcf, 0x1b); 51338781Snsouch break; 51438781Snsouch 51538781Snsouch case IIC_FAST: 51638781Snsouch PCF_SET_S0(pcf, 0x19); 51738781Snsouch break; 51838781Snsouch 51938781Snsouch case IIC_UNKNOWN: 52038781Snsouch case IIC_FASTEST: 52138781Snsouch default: 52238781Snsouch PCF_SET_S0(pcf, 0x18); 52338781Snsouch break; 52438781Snsouch } 52538781Snsouch 52638781Snsouch /* set bus on, ack=yes, INT=yes */ 52738781Snsouch PCF_SET_S1(pcf, PIN|ES0|ENI|ACK); 52838781Snsouch 52938781Snsouch pcf->pcf_slave_mode = SLAVE_RECEIVER; 53038781Snsouch 53138781Snsouch return (0); 53238781Snsouch} 53338781Snsouch 53438781Snsouchstatic int 53540784Snsouchpcf_write(device_t pcfdev, char *buf, int len, int *sent, int timeout /* us */) 53638781Snsouch{ 53738781Snsouch struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 53838781Snsouch int bytes, error = 0; 53938781Snsouch 54038781Snsouch#ifdef PCFDEBUG 54138781Snsouch printf("pcf%d: >> writing %d bytes\n", device_get_unit(pcfdev), len); 54238781Snsouch#endif 54338781Snsouch 54438781Snsouch bytes = 0; 54538781Snsouch while (len) { 54638781Snsouch 54738781Snsouch PCF_SET_S0(pcf, *buf++); 54838781Snsouch 54940784Snsouch /* wait for the byte to be send */ 55038781Snsouch if ((error = pcf_wait_byte(pcf))) 55138781Snsouch goto error; 55238781Snsouch 55340784Snsouch /* check if ack received */ 55440784Snsouch if (pcf_noack(pcf, timeout)) { 55538781Snsouch error = IIC_ENOACK; 55638781Snsouch goto error; 55738781Snsouch } 55838781Snsouch 55938781Snsouch len --; 56038781Snsouch bytes ++; 56138781Snsouch } 56238781Snsouch 56338781Snsoucherror: 56438781Snsouch *sent = bytes; 56538781Snsouch 56638781Snsouch#ifdef PCFDEBUG 56738781Snsouch printf("pcf%d: >> %d bytes written (%d)\n", 56838781Snsouch device_get_unit(pcfdev), bytes, error); 56938781Snsouch#endif 57038781Snsouch 57138781Snsouch return (error); 57238781Snsouch} 57338781Snsouch 57438781Snsouchstatic int 57540784Snsouchpcf_read(device_t pcfdev, char *buf, int len, int *read, int last, 57640784Snsouch int delay /* us */) 57738781Snsouch{ 57838781Snsouch struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 57938781Snsouch int bytes, error = 0; 58038781Snsouch 58138781Snsouch#ifdef PCFDEBUG 58238781Snsouch printf("pcf%d: << reading %d bytes\n", device_get_unit(pcfdev), len); 58338781Snsouch#endif 58438781Snsouch 58538781Snsouch /* trig the bus to get the first data byte in S0 */ 58638781Snsouch if (len) { 58740784Snsouch if (len == 1 && last) 58838781Snsouch /* just one byte to read */ 58938781Snsouch PCF_SET_S1(pcf, ES0); /* no ack */ 59038781Snsouch 59138781Snsouch dummy_read(pcf); 59238781Snsouch } 59338781Snsouch 59438781Snsouch bytes = 0; 59538781Snsouch while (len) { 59638781Snsouch 59740784Snsouch /* XXX delay needed here */ 59840784Snsouch 59940784Snsouch /* wait for trigged byte */ 60038781Snsouch if ((error = pcf_wait_byte(pcf))) { 60138781Snsouch pcf_stop(pcfdev); 60238781Snsouch goto error; 60338781Snsouch } 60438781Snsouch 60540784Snsouch if (len == 1 && last) 60640784Snsouch /* ok, last data byte already in S0, no I2C activity 60740784Snsouch * on next PCF_GET_S0() */ 60838781Snsouch pcf_stop(pcfdev); 60938781Snsouch 61040784Snsouch else if (len == 2 && last) 61140784Snsouch /* next trigged byte with no ack */ 61240784Snsouch PCF_SET_S1(pcf, ES0); 61338781Snsouch 61440784Snsouch /* receive byte, trig next byte */ 61540784Snsouch *buf++ = PCF_GET_S0(pcf); 61638781Snsouch 61738781Snsouch len --; 61838781Snsouch bytes ++; 61938781Snsouch }; 62038781Snsouch 62138781Snsoucherror: 62238781Snsouch *read = bytes; 62338781Snsouch 62438781Snsouch#ifdef PCFDEBUG 62538781Snsouch printf("pcf%d: << %d bytes read (%d)\n", 62638781Snsouch device_get_unit(pcfdev), bytes, error); 62738781Snsouch#endif 62838781Snsouch 62938781Snsouch return (error); 63038781Snsouch} 63138781Snsouch 63255939SnsouchDRIVER_MODULE(pcf, isa, pcf_driver, pcf_devclass, 0, 0); 633