pcf.c revision 49195
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 * 2649195Smdodd * $Id: pcf.c,v 1.9 1999/05/08 21:59:27 dfr Exp $ 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#include <sys/conf.h> 3538781Snsouch#include <sys/malloc.h> 3638781Snsouch 3738781Snsouch#include <machine/clock.h> 3838781Snsouch 3938781Snsouch#include <i386/isa/isa_device.h> 4038781Snsouch 4138781Snsouch#include <dev/iicbus/iiconf.h> 4238781Snsouch#include "iicbus_if.h" 4338781Snsouch 4440784Snsouch#define TIMEOUT 9999 /* XXX */ 4538781Snsouch 4638781Snsouch/* Status bits of S1 register (read only) */ 4738781Snsouch#define nBB 0x01 /* busy when low set/reset by STOP/START*/ 4838781Snsouch#define LAB 0x02 /* lost arbitration bit in multi-master mode */ 4938781Snsouch#define AAS 0x04 /* addressed as slave */ 5038781Snsouch#define LRB 0x08 /* last received byte when not AAS */ 5138781Snsouch#define AD0 0x08 /* general call received when AAS */ 5238781Snsouch#define BER 0x10 /* bus error, misplaced START or STOP */ 5338781Snsouch#define STS 0x20 /* STOP detected in slave receiver mode */ 5438781Snsouch#define PIN 0x80 /* pending interrupt not (r/w) */ 5538781Snsouch 5638781Snsouch/* Control bits of S1 register (write only) */ 5738781Snsouch#define ACK 0x01 5838781Snsouch#define STO 0x02 5938781Snsouch#define STA 0x04 6038781Snsouch#define ENI 0x08 6138781Snsouch#define ES2 0x10 6238781Snsouch#define ES1 0x20 6338781Snsouch#define ES0 0x40 6438781Snsouch 6538781Snsouch#define BUFSIZE 2048 6638781Snsouch 6738781Snsouch#define SLAVE_TRANSMITTER 0x1 6838781Snsouch#define SLAVE_RECEIVER 0x2 6938781Snsouch 7040784Snsouch#define PCF_DEFAULT_ADDR 0xaa 7140784Snsouch 7238781Snsouchstruct pcf_softc { 7338781Snsouch 7438781Snsouch int pcf_base; /* isa port */ 7540784Snsouch u_char pcf_addr; /* interface I2C address */ 7638781Snsouch 7738781Snsouch int pcf_slave_mode; /* receiver or transmitter */ 7840784Snsouch int pcf_started; /* 1 if start condition sent */ 7938781Snsouch 8038781Snsouch device_t iicbus; /* the corresponding iicbus */ 8138781Snsouch}; 8238781Snsouch 8338781Snsouchstruct pcf_isa_softc { 8438781Snsouch 8538781Snsouch int pcf_unit; /* unit of the isa device */ 8638781Snsouch int pcf_base; /* isa port */ 8738781Snsouch int pcf_irq; /* isa irq or null if polled */ 8838781Snsouch 8938781Snsouch unsigned int pcf_flags; /* boot flags */ 9038781Snsouch}; 9138781Snsouch 9238781Snsouch#define MAXPCF 2 9338781Snsouch 9438781Snsouchstatic struct pcf_isa_softc *pcfdata[MAXPCF]; 9546573Speterstatic int npcf = 0; 9638781Snsouch 9738781Snsouchstatic int pcfprobe_isa(struct isa_device *); 9838781Snsouchstatic int pcfattach_isa(struct isa_device *); 9938781Snsouch 10038781Snsouchstruct isa_driver pcfdriver = { 10138781Snsouch pcfprobe_isa, pcfattach_isa, "pcf" 10238781Snsouch}; 10338781Snsouch 10438781Snsouchstatic int pcf_probe(device_t); 10538781Snsouchstatic int pcf_attach(device_t); 10649195Smdoddstatic int pcf_print_child(device_t, device_t); 10738781Snsouch 10840784Snsouchstatic int pcf_repeated_start(device_t, u_char, int); 10940784Snsouchstatic int pcf_start(device_t, u_char, int); 11038781Snsouchstatic int pcf_stop(device_t); 11140788Speterstatic int pcf_write(device_t, char *, int, int *, int); 11240788Speterstatic int pcf_read(device_t, char *, int, int *, int, int); 11340565Sbdestatic ointhand2_t pcfintr; 11440788Speterstatic int pcf_rst_card(device_t, u_char, u_char, u_char *); 11538781Snsouch 11638781Snsouchstatic device_method_t pcf_methods[] = { 11738781Snsouch /* device interface */ 11838781Snsouch DEVMETHOD(device_probe, pcf_probe), 11938781Snsouch DEVMETHOD(device_attach, pcf_attach), 12038781Snsouch 12138781Snsouch /* bus interface */ 12238781Snsouch DEVMETHOD(bus_print_child, pcf_print_child), 12338781Snsouch 12438781Snsouch /* iicbus interface */ 12540784Snsouch DEVMETHOD(iicbus_callback, iicbus_null_callback), 12638781Snsouch DEVMETHOD(iicbus_repeated_start, pcf_repeated_start), 12738781Snsouch DEVMETHOD(iicbus_start, pcf_start), 12838781Snsouch DEVMETHOD(iicbus_stop, pcf_stop), 12938781Snsouch DEVMETHOD(iicbus_write, pcf_write), 13038781Snsouch DEVMETHOD(iicbus_read, pcf_read), 13138781Snsouch DEVMETHOD(iicbus_reset, pcf_rst_card), 13238781Snsouch 13338781Snsouch { 0, 0 } 13438781Snsouch}; 13538781Snsouch 13638781Snsouchstatic driver_t pcf_driver = { 13738781Snsouch "pcf", 13838781Snsouch pcf_methods, 13938781Snsouch sizeof(struct pcf_softc), 14038781Snsouch}; 14138781Snsouch 14238781Snsouchstatic devclass_t pcf_devclass; 14338781Snsouch 14438781Snsouch#define DEVTOSOFTC(dev) ((struct pcf_softc *)device_get_softc(dev)) 14538781Snsouch 14638781Snsouchstatic int 14738781Snsouchpcfprobe_isa(struct isa_device *dvp) 14838781Snsouch{ 14938781Snsouch device_t pcfdev; 15038781Snsouch struct pcf_isa_softc *pcf; 15138781Snsouch 15238781Snsouch if (npcf >= MAXPCF) 15338781Snsouch return (0); 15438781Snsouch 15538781Snsouch if ((pcf = (struct pcf_isa_softc *)malloc(sizeof(struct pcf_isa_softc), 15638781Snsouch M_DEVBUF, M_NOWAIT)) == NULL) 15738781Snsouch return (0); 15838781Snsouch 15938781Snsouch pcf->pcf_base = dvp->id_iobase; /* XXX should be ivars */ 16038781Snsouch pcf->pcf_unit = dvp->id_unit; 16138781Snsouch 16238781Snsouch if (!(dvp->id_flags & IIC_POLLED)) 16338781Snsouch pcf->pcf_irq = (dvp->id_irq); 16438781Snsouch 16538781Snsouch pcfdata[npcf++] = pcf; 16638781Snsouch 16738781Snsouch /* XXX add the pcf device to the root_bus until isa bus exists */ 16838781Snsouch pcfdev = device_add_child(root_bus, "pcf", pcf->pcf_unit, NULL); 16938781Snsouch 17038781Snsouch if (!pcfdev) 17138781Snsouch goto error; 17238781Snsouch 17338781Snsouch return (1); 17438781Snsouch 17538781Snsoucherror: 17638781Snsouch free(pcf, M_DEVBUF); 17738781Snsouch return (0); 17838781Snsouch} 17938781Snsouch 18038781Snsouchstatic int 18138781Snsouchpcfattach_isa(struct isa_device *isdp) 18238781Snsouch{ 18340565Sbde isdp->id_ointr = pcfintr; 18438781Snsouch return (1); /* ok */ 18538781Snsouch} 18638781Snsouch 18738781Snsouchstatic int 18838781Snsouchpcf_probe(device_t pcfdev) 18938781Snsouch{ 19038781Snsouch struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(pcfdev); 19140784Snsouch int unit = device_get_unit(pcfdev); 19238781Snsouch 19340784Snsouch /* retrieve base address from isa initialization 19440784Snsouch * 19540784Snsouch * XXX should use ivars with isabus 19640784Snsouch */ 19740784Snsouch pcf->pcf_base = pcfdata[unit]->pcf_base; 19840784Snsouch 19940784Snsouch /* reset the chip */ 20040784Snsouch pcf_rst_card(pcfdev, IIC_FASTEST, PCF_DEFAULT_ADDR, NULL); 20140784Snsouch 20238781Snsouch /* XXX try do detect chipset */ 20338781Snsouch 20438781Snsouch device_set_desc(pcfdev, "PCF8584 I2C bus controller"); 20538781Snsouch 20638781Snsouch return (0); 20738781Snsouch} 20838781Snsouch 20938781Snsouchstatic int 21038781Snsouchpcf_attach(device_t pcfdev) 21138781Snsouch{ 21238781Snsouch struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(pcfdev); 21338781Snsouch 21440784Snsouch pcf->iicbus = iicbus_alloc_bus(pcfdev); 21538781Snsouch 21638781Snsouch /* probe and attach the iicbus */ 21738781Snsouch device_probe_and_attach(pcf->iicbus); 21838781Snsouch 21938781Snsouch return (0); 22038781Snsouch} 22138781Snsouch 22249195Smdoddstatic int 22338781Snsouchpcf_print_child(device_t bus, device_t dev) 22438781Snsouch{ 22540784Snsouch struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(bus); 22649195Smdodd int retval = 0; 22740784Snsouch 22849195Smdodd retval += bus_print_child_header(bus, dev); 22949195Smdodd retval += printf(" on %s addr 0x%x\n", device_get_nameunit(bus), 23049195Smdodd (int)pcf->pcf_addr); 23138781Snsouch 23249195Smdodd return (retval); 23338781Snsouch} 23438781Snsouch 23538781Snsouch/* 23638781Snsouch * PCF8584 datasheet : when operate at 8 MHz or more, a minimun time of 23738781Snsouch * 6 clocks cycles must be left between two consecutives access 23838781Snsouch */ 23938781Snsouch#define pcf_nops() DELAY(10) 24038781Snsouch 24138781Snsouch#define dummy_read(pcf) PCF_GET_S0(pcf) 24238781Snsouch#define dummy_write(pcf) PCF_SET_S0(pcf, 0) 24338781Snsouch 24438781Snsouch/* 24538781Snsouch * Specific register access to PCF8584 24638781Snsouch */ 24738781Snsouchstatic void PCF_SET_S0(struct pcf_softc *pcf, int data) 24838781Snsouch{ 24938781Snsouch outb(pcf->pcf_base, data); 25038781Snsouch pcf_nops(); 25138781Snsouch} 25238781Snsouch 25338781Snsouchstatic void PCF_SET_S1(struct pcf_softc *pcf, int data) 25438781Snsouch{ 25538781Snsouch outb(pcf->pcf_base+1, data); 25638781Snsouch pcf_nops(); 25738781Snsouch} 25838781Snsouch 25938781Snsouchstatic char PCF_GET_S0(struct pcf_softc *pcf) 26038781Snsouch{ 26138781Snsouch char data; 26238781Snsouch 26338781Snsouch data = inb(pcf->pcf_base); 26438781Snsouch pcf_nops(); 26538781Snsouch 26638781Snsouch return (data); 26738781Snsouch} 26838781Snsouch 26938781Snsouchstatic char PCF_GET_S1(struct pcf_softc *pcf) 27038781Snsouch{ 27138781Snsouch char data; 27238781Snsouch 27338781Snsouch data = inb(pcf->pcf_base+1); 27438781Snsouch pcf_nops(); 27538781Snsouch 27638781Snsouch return (data); 27738781Snsouch} 27838781Snsouch 27938781Snsouch/* 28038781Snsouch * Polling mode for master operations wait for a new 28138781Snsouch * byte incomming or outgoing 28238781Snsouch */ 28338781Snsouchstatic int pcf_wait_byte(struct pcf_softc *pcf) 28438781Snsouch{ 28538781Snsouch int counter = TIMEOUT; 28638781Snsouch 28738781Snsouch while (counter--) { 28838781Snsouch 28938781Snsouch if ((PCF_GET_S1(pcf) & PIN) == 0) 29038781Snsouch return (0); 29138781Snsouch } 29238781Snsouch 29338781Snsouch return (IIC_ETIMEOUT); 29438781Snsouch} 29538781Snsouch 29638781Snsouchstatic int pcf_stop(device_t pcfdev) 29738781Snsouch{ 29838781Snsouch struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 29938781Snsouch 30040784Snsouch /* 30140784Snsouch * Send STOP condition iff the START condition was previously sent. 30240784Snsouch * STOP is sent only once even if a iicbus_stop() is called after 30340784Snsouch * an iicbus_read()... see pcf_read(): the pcf needs to send the stop 30440784Snsouch * before the last char is read. 30540784Snsouch */ 30640784Snsouch if (pcf->pcf_started) { 30740784Snsouch /* set stop condition and enable IT */ 30840784Snsouch PCF_SET_S1(pcf, PIN|ES0|ENI|STO|ACK); 30938781Snsouch 31040784Snsouch pcf->pcf_started = 0; 31140784Snsouch } 31240784Snsouch 31338781Snsouch return (0); 31438781Snsouch} 31538781Snsouch 31640784Snsouch 31740784Snsouchstatic int pcf_noack(struct pcf_softc *pcf, int timeout) 31838781Snsouch{ 31940784Snsouch int noack; 32040784Snsouch int k = timeout/10; 32140784Snsouch 32240784Snsouch do { 32340784Snsouch noack = PCF_GET_S1(pcf) & LRB; 32440784Snsouch if (!noack) 32540784Snsouch break; 32640784Snsouch DELAY(10); /* XXX wait 10 us */ 32740784Snsouch } while (k--); 32840784Snsouch 32940784Snsouch return (noack); 33040784Snsouch} 33140784Snsouch 33240784Snsouchstatic int pcf_repeated_start(device_t pcfdev, u_char slave, int timeout) 33340784Snsouch{ 33438781Snsouch struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 33538781Snsouch int error = 0; 33638781Snsouch 33738781Snsouch /* repeated start */ 33838781Snsouch PCF_SET_S1(pcf, ES0|STA|STO|ACK); 33938781Snsouch 34038781Snsouch /* set slave address to PCF. Last bit (LSB) must be set correctly 34138781Snsouch * according to transfer direction */ 34238781Snsouch PCF_SET_S0(pcf, slave); 34338781Snsouch 34438781Snsouch /* wait for address sent, polling */ 34538781Snsouch if ((error = pcf_wait_byte(pcf))) 34638781Snsouch goto error; 34738781Snsouch 34840784Snsouch /* check for ack */ 34940784Snsouch if (pcf_noack(pcf, timeout)) { 35038781Snsouch error = IIC_ENOACK; 35138781Snsouch goto error; 35238781Snsouch } 35338781Snsouch 35438781Snsouch return (0); 35538781Snsouch 35638781Snsoucherror: 35738781Snsouch pcf_stop(pcfdev); 35838781Snsouch return (error); 35938781Snsouch} 36038781Snsouch 36140784Snsouchstatic int pcf_start(device_t pcfdev, u_char slave, int timeout) 36238781Snsouch{ 36338781Snsouch struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 36438781Snsouch int error = 0; 36538781Snsouch 36646343Speter if ((PCF_GET_S1(pcf) & nBB) == 0) 36738781Snsouch return (IIC_EBUSBSY); 36838781Snsouch 36938781Snsouch /* set slave address to PCF. Last bit (LSB) must be set correctly 37038781Snsouch * according to transfer direction */ 37138781Snsouch PCF_SET_S0(pcf, slave); 37238781Snsouch 37338781Snsouch /* START only */ 37438781Snsouch PCF_SET_S1(pcf, PIN|ES0|STA|ACK); 37538781Snsouch 37640784Snsouch pcf->pcf_started = 1; 37740784Snsouch 37838781Snsouch /* wait for address sent, polling */ 37938781Snsouch if ((error = pcf_wait_byte(pcf))) 38038781Snsouch goto error; 38138781Snsouch 38240784Snsouch /* check for ACK */ 38340784Snsouch if (pcf_noack(pcf, timeout)) { 38438781Snsouch error = IIC_ENOACK; 38538781Snsouch goto error; 38638781Snsouch } 38738781Snsouch 38838781Snsouch return (0); 38938781Snsouch 39038781Snsoucherror: 39138781Snsouch pcf_stop(pcfdev); 39238781Snsouch return (error); 39338781Snsouch} 39438781Snsouch 39540565Sbdestatic void 39638781Snsouchpcfintr(unit) 39738781Snsouch{ 39838781Snsouch struct pcf_softc *pcf = 39938781Snsouch (struct pcf_softc *)devclass_get_softc(pcf_devclass, unit); 40038781Snsouch 40138781Snsouch char data, status, addr; 40238781Snsouch char error = 0; 40338781Snsouch 40438781Snsouch status = PCF_GET_S1(pcf); 40538781Snsouch 40638781Snsouch if (status & PIN) { 40738781Snsouch printf("pcf%d: spurious interrupt, status=0x%x\n", unit, 40838781Snsouch status & 0xff); 40938781Snsouch 41038781Snsouch goto error; 41138781Snsouch } 41238781Snsouch 41338781Snsouch if (status & LAB) 41438781Snsouch printf("pcf%d: bus arbitration lost!\n", unit); 41538781Snsouch 41638781Snsouch if (status & BER) { 41738781Snsouch error = IIC_EBUSERR; 41838781Snsouch iicbus_intr(pcf->iicbus, INTR_ERROR, &error); 41938781Snsouch 42038781Snsouch goto error; 42138781Snsouch } 42238781Snsouch 42338781Snsouch do { 42438781Snsouch status = PCF_GET_S1(pcf); 42538781Snsouch 42638781Snsouch switch(pcf->pcf_slave_mode) { 42738781Snsouch 42838781Snsouch case SLAVE_TRANSMITTER: 42938781Snsouch if (status & LRB) { 43038781Snsouch /* ack interrupt line */ 43138781Snsouch dummy_write(pcf); 43238781Snsouch 43338781Snsouch /* no ack, don't send anymore */ 43438781Snsouch pcf->pcf_slave_mode = SLAVE_RECEIVER; 43538781Snsouch 43638781Snsouch iicbus_intr(pcf->iicbus, INTR_NOACK, NULL); 43738781Snsouch break; 43838781Snsouch } 43938781Snsouch 44038781Snsouch /* get data from upper code */ 44138781Snsouch iicbus_intr(pcf->iicbus, INTR_TRANSMIT, &data); 44238781Snsouch 44338781Snsouch PCF_SET_S0(pcf, data); 44438781Snsouch break; 44538781Snsouch 44638781Snsouch case SLAVE_RECEIVER: 44738781Snsouch if (status & AAS) { 44838781Snsouch addr = PCF_GET_S0(pcf); 44938781Snsouch 45038781Snsouch if (status & AD0) 45138781Snsouch iicbus_intr(pcf->iicbus, INTR_GENERAL, &addr); 45238781Snsouch else 45338781Snsouch iicbus_intr(pcf->iicbus, INTR_START, &addr); 45438781Snsouch 45538781Snsouch if (addr & LSB) { 45638781Snsouch pcf->pcf_slave_mode = SLAVE_TRANSMITTER; 45738781Snsouch 45838781Snsouch /* get the first char from upper code */ 45938781Snsouch iicbus_intr(pcf->iicbus, INTR_TRANSMIT, &data); 46038781Snsouch 46138781Snsouch /* send first data byte */ 46238781Snsouch PCF_SET_S0(pcf, data); 46338781Snsouch } 46438781Snsouch 46538781Snsouch break; 46638781Snsouch } 46738781Snsouch 46838781Snsouch /* stop condition received? */ 46938781Snsouch if (status & STS) { 47038781Snsouch /* ack interrupt line */ 47138781Snsouch dummy_read(pcf); 47238781Snsouch 47338781Snsouch /* emulate intr stop condition */ 47438781Snsouch iicbus_intr(pcf->iicbus, INTR_STOP, NULL); 47538781Snsouch 47638781Snsouch } else { 47738781Snsouch /* get data, ack interrupt line */ 47838781Snsouch data = PCF_GET_S0(pcf); 47938781Snsouch 48038781Snsouch /* deliver the character */ 48138781Snsouch iicbus_intr(pcf->iicbus, INTR_RECEIVE, &data); 48238781Snsouch } 48338781Snsouch break; 48438781Snsouch 48538781Snsouch default: 48638781Snsouch panic("%s: unknown slave mode (%d)!", __FUNCTION__, 48738781Snsouch pcf->pcf_slave_mode); 48838781Snsouch } 48938781Snsouch 49038781Snsouch } while ((PCF_GET_S1(pcf) & PIN) == 0); 49138781Snsouch 49238781Snsouch return; 49338781Snsouch 49438781Snsoucherror: 49538781Snsouch /* unknown event on bus...reset PCF */ 49638781Snsouch PCF_SET_S1(pcf, PIN|ES0|ENI|ACK); 49738781Snsouch 49838781Snsouch pcf->pcf_slave_mode = SLAVE_RECEIVER; 49938781Snsouch 50038781Snsouch return; 50138781Snsouch} 50238781Snsouch 50340784Snsouchstatic int pcf_rst_card(device_t pcfdev, u_char speed, u_char addr, u_char *oldaddr) 50438781Snsouch{ 50538781Snsouch struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 50638781Snsouch 50740784Snsouch if (oldaddr) 50840784Snsouch *oldaddr = pcf->pcf_addr; 50940784Snsouch 51038781Snsouch /* retrieve own address from bus level */ 51140784Snsouch if (!addr) 51240784Snsouch pcf->pcf_addr = PCF_DEFAULT_ADDR; 51340784Snsouch else 51440784Snsouch pcf->pcf_addr = addr; 51538781Snsouch 51638781Snsouch PCF_SET_S1(pcf, PIN); /* initialize S1 */ 51738781Snsouch 51838781Snsouch /* own address S'O<>0 */ 51940784Snsouch PCF_SET_S0(pcf, pcf->pcf_addr >> 1); 52038781Snsouch 52138781Snsouch /* select clock register */ 52238781Snsouch PCF_SET_S1(pcf, PIN|ES1); 52338781Snsouch 52438781Snsouch /* select bus speed : 18=90kb, 19=45kb, 1A=11kb, 1B=1.5kb */ 52538781Snsouch switch (speed) { 52638781Snsouch case IIC_SLOW: 52738781Snsouch PCF_SET_S0(pcf, 0x1b); 52838781Snsouch break; 52938781Snsouch 53038781Snsouch case IIC_FAST: 53138781Snsouch PCF_SET_S0(pcf, 0x19); 53238781Snsouch break; 53338781Snsouch 53438781Snsouch case IIC_UNKNOWN: 53538781Snsouch case IIC_FASTEST: 53638781Snsouch default: 53738781Snsouch PCF_SET_S0(pcf, 0x18); 53838781Snsouch break; 53938781Snsouch } 54038781Snsouch 54138781Snsouch /* set bus on, ack=yes, INT=yes */ 54238781Snsouch PCF_SET_S1(pcf, PIN|ES0|ENI|ACK); 54338781Snsouch 54438781Snsouch pcf->pcf_slave_mode = SLAVE_RECEIVER; 54538781Snsouch 54638781Snsouch return (0); 54738781Snsouch} 54838781Snsouch 54938781Snsouchstatic int 55040784Snsouchpcf_write(device_t pcfdev, char *buf, int len, int *sent, int timeout /* us */) 55138781Snsouch{ 55238781Snsouch struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 55338781Snsouch int bytes, error = 0; 55438781Snsouch 55538781Snsouch#ifdef PCFDEBUG 55638781Snsouch printf("pcf%d: >> writing %d bytes\n", device_get_unit(pcfdev), len); 55738781Snsouch#endif 55838781Snsouch 55938781Snsouch bytes = 0; 56038781Snsouch while (len) { 56138781Snsouch 56238781Snsouch PCF_SET_S0(pcf, *buf++); 56338781Snsouch 56440784Snsouch /* wait for the byte to be send */ 56538781Snsouch if ((error = pcf_wait_byte(pcf))) 56638781Snsouch goto error; 56738781Snsouch 56840784Snsouch /* check if ack received */ 56940784Snsouch if (pcf_noack(pcf, timeout)) { 57038781Snsouch error = IIC_ENOACK; 57138781Snsouch goto error; 57238781Snsouch } 57338781Snsouch 57438781Snsouch len --; 57538781Snsouch bytes ++; 57638781Snsouch } 57738781Snsouch 57838781Snsoucherror: 57938781Snsouch *sent = bytes; 58038781Snsouch 58138781Snsouch#ifdef PCFDEBUG 58238781Snsouch printf("pcf%d: >> %d bytes written (%d)\n", 58338781Snsouch device_get_unit(pcfdev), bytes, error); 58438781Snsouch#endif 58538781Snsouch 58638781Snsouch return (error); 58738781Snsouch} 58838781Snsouch 58938781Snsouchstatic int 59040784Snsouchpcf_read(device_t pcfdev, char *buf, int len, int *read, int last, 59140784Snsouch int delay /* us */) 59238781Snsouch{ 59338781Snsouch struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 59438781Snsouch int bytes, error = 0; 59538781Snsouch 59638781Snsouch#ifdef PCFDEBUG 59738781Snsouch printf("pcf%d: << reading %d bytes\n", device_get_unit(pcfdev), len); 59838781Snsouch#endif 59938781Snsouch 60038781Snsouch /* trig the bus to get the first data byte in S0 */ 60138781Snsouch if (len) { 60240784Snsouch if (len == 1 && last) 60338781Snsouch /* just one byte to read */ 60438781Snsouch PCF_SET_S1(pcf, ES0); /* no ack */ 60538781Snsouch 60638781Snsouch dummy_read(pcf); 60738781Snsouch } 60838781Snsouch 60938781Snsouch bytes = 0; 61038781Snsouch while (len) { 61138781Snsouch 61240784Snsouch /* XXX delay needed here */ 61340784Snsouch 61440784Snsouch /* wait for trigged byte */ 61538781Snsouch if ((error = pcf_wait_byte(pcf))) { 61638781Snsouch pcf_stop(pcfdev); 61738781Snsouch goto error; 61838781Snsouch } 61938781Snsouch 62040784Snsouch if (len == 1 && last) 62140784Snsouch /* ok, last data byte already in S0, no I2C activity 62240784Snsouch * on next PCF_GET_S0() */ 62338781Snsouch pcf_stop(pcfdev); 62438781Snsouch 62540784Snsouch else if (len == 2 && last) 62640784Snsouch /* next trigged byte with no ack */ 62740784Snsouch PCF_SET_S1(pcf, ES0); 62838781Snsouch 62940784Snsouch /* receive byte, trig next byte */ 63040784Snsouch *buf++ = PCF_GET_S0(pcf); 63138781Snsouch 63238781Snsouch len --; 63338781Snsouch bytes ++; 63438781Snsouch }; 63538781Snsouch 63638781Snsoucherror: 63738781Snsouch *read = bytes; 63838781Snsouch 63938781Snsouch#ifdef PCFDEBUG 64038781Snsouch printf("pcf%d: << %d bytes read (%d)\n", 64138781Snsouch device_get_unit(pcfdev), bytes, error); 64238781Snsouch#endif 64338781Snsouch 64438781Snsouch return (error); 64538781Snsouch} 64638781Snsouch 64738781SnsouchDRIVER_MODULE(pcf, root, pcf_driver, pcf_devclass, 0, 0); 648