pcf.c revision 46573
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 * 2646573Speter * $Id: pcf.c,v 1.7 1999/05/02 21:51:17 peter 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); 10638781Snsouchstatic void 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 DRIVER_TYPE_MISC, 14038781Snsouch sizeof(struct pcf_softc), 14138781Snsouch}; 14238781Snsouch 14338781Snsouchstatic devclass_t pcf_devclass; 14438781Snsouch 14538781Snsouch#define DEVTOSOFTC(dev) ((struct pcf_softc *)device_get_softc(dev)) 14638781Snsouch 14738781Snsouchstatic int 14838781Snsouchpcfprobe_isa(struct isa_device *dvp) 14938781Snsouch{ 15038781Snsouch device_t pcfdev; 15138781Snsouch struct pcf_isa_softc *pcf; 15238781Snsouch 15338781Snsouch if (npcf >= MAXPCF) 15438781Snsouch return (0); 15538781Snsouch 15638781Snsouch if ((pcf = (struct pcf_isa_softc *)malloc(sizeof(struct pcf_isa_softc), 15738781Snsouch M_DEVBUF, M_NOWAIT)) == NULL) 15838781Snsouch return (0); 15938781Snsouch 16038781Snsouch pcf->pcf_base = dvp->id_iobase; /* XXX should be ivars */ 16138781Snsouch pcf->pcf_unit = dvp->id_unit; 16238781Snsouch 16338781Snsouch if (!(dvp->id_flags & IIC_POLLED)) 16438781Snsouch pcf->pcf_irq = (dvp->id_irq); 16538781Snsouch 16638781Snsouch pcfdata[npcf++] = pcf; 16738781Snsouch 16838781Snsouch /* XXX add the pcf device to the root_bus until isa bus exists */ 16938781Snsouch pcfdev = device_add_child(root_bus, "pcf", pcf->pcf_unit, NULL); 17038781Snsouch 17138781Snsouch if (!pcfdev) 17238781Snsouch goto error; 17338781Snsouch 17438781Snsouch return (1); 17538781Snsouch 17638781Snsoucherror: 17738781Snsouch free(pcf, M_DEVBUF); 17838781Snsouch return (0); 17938781Snsouch} 18038781Snsouch 18138781Snsouchstatic int 18238781Snsouchpcfattach_isa(struct isa_device *isdp) 18338781Snsouch{ 18440565Sbde isdp->id_ointr = pcfintr; 18538781Snsouch return (1); /* ok */ 18638781Snsouch} 18738781Snsouch 18838781Snsouchstatic int 18938781Snsouchpcf_probe(device_t pcfdev) 19038781Snsouch{ 19138781Snsouch struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(pcfdev); 19240784Snsouch int unit = device_get_unit(pcfdev); 19338781Snsouch 19440784Snsouch /* retrieve base address from isa initialization 19540784Snsouch * 19640784Snsouch * XXX should use ivars with isabus 19740784Snsouch */ 19840784Snsouch pcf->pcf_base = pcfdata[unit]->pcf_base; 19940784Snsouch 20040784Snsouch /* reset the chip */ 20140784Snsouch pcf_rst_card(pcfdev, IIC_FASTEST, PCF_DEFAULT_ADDR, NULL); 20240784Snsouch 20338781Snsouch /* XXX try do detect chipset */ 20438781Snsouch 20538781Snsouch device_set_desc(pcfdev, "PCF8584 I2C bus controller"); 20638781Snsouch 20738781Snsouch return (0); 20838781Snsouch} 20938781Snsouch 21038781Snsouchstatic int 21138781Snsouchpcf_attach(device_t pcfdev) 21238781Snsouch{ 21338781Snsouch struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(pcfdev); 21438781Snsouch 21540784Snsouch pcf->iicbus = iicbus_alloc_bus(pcfdev); 21638781Snsouch 21738781Snsouch /* probe and attach the iicbus */ 21838781Snsouch device_probe_and_attach(pcf->iicbus); 21938781Snsouch 22038781Snsouch return (0); 22138781Snsouch} 22238781Snsouch 22338781Snsouchstatic void 22438781Snsouchpcf_print_child(device_t bus, device_t dev) 22538781Snsouch{ 22640784Snsouch struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(bus); 22740784Snsouch 22838781Snsouch printf(" on %s%d addr 0x%x", device_get_name(bus), 22940784Snsouch device_get_unit(bus), (int)pcf->pcf_addr); 23038781Snsouch 23138781Snsouch return; 23238781Snsouch} 23338781Snsouch 23438781Snsouch/* 23538781Snsouch * PCF8584 datasheet : when operate at 8 MHz or more, a minimun time of 23638781Snsouch * 6 clocks cycles must be left between two consecutives access 23738781Snsouch */ 23838781Snsouch#define pcf_nops() DELAY(10) 23938781Snsouch 24038781Snsouch#define dummy_read(pcf) PCF_GET_S0(pcf) 24138781Snsouch#define dummy_write(pcf) PCF_SET_S0(pcf, 0) 24238781Snsouch 24338781Snsouch/* 24438781Snsouch * Specific register access to PCF8584 24538781Snsouch */ 24638781Snsouchstatic void PCF_SET_S0(struct pcf_softc *pcf, int data) 24738781Snsouch{ 24838781Snsouch outb(pcf->pcf_base, data); 24938781Snsouch pcf_nops(); 25038781Snsouch} 25138781Snsouch 25238781Snsouchstatic void PCF_SET_S1(struct pcf_softc *pcf, int data) 25338781Snsouch{ 25438781Snsouch outb(pcf->pcf_base+1, data); 25538781Snsouch pcf_nops(); 25638781Snsouch} 25738781Snsouch 25838781Snsouchstatic char PCF_GET_S0(struct pcf_softc *pcf) 25938781Snsouch{ 26038781Snsouch char data; 26138781Snsouch 26238781Snsouch data = inb(pcf->pcf_base); 26338781Snsouch pcf_nops(); 26438781Snsouch 26538781Snsouch return (data); 26638781Snsouch} 26738781Snsouch 26838781Snsouchstatic char PCF_GET_S1(struct pcf_softc *pcf) 26938781Snsouch{ 27038781Snsouch char data; 27138781Snsouch 27238781Snsouch data = inb(pcf->pcf_base+1); 27338781Snsouch pcf_nops(); 27438781Snsouch 27538781Snsouch return (data); 27638781Snsouch} 27738781Snsouch 27838781Snsouch/* 27938781Snsouch * Polling mode for master operations wait for a new 28038781Snsouch * byte incomming or outgoing 28138781Snsouch */ 28238781Snsouchstatic int pcf_wait_byte(struct pcf_softc *pcf) 28338781Snsouch{ 28438781Snsouch int counter = TIMEOUT; 28538781Snsouch 28638781Snsouch while (counter--) { 28738781Snsouch 28838781Snsouch if ((PCF_GET_S1(pcf) & PIN) == 0) 28938781Snsouch return (0); 29038781Snsouch } 29138781Snsouch 29238781Snsouch return (IIC_ETIMEOUT); 29338781Snsouch} 29438781Snsouch 29538781Snsouchstatic int pcf_stop(device_t pcfdev) 29638781Snsouch{ 29738781Snsouch struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 29838781Snsouch 29940784Snsouch /* 30040784Snsouch * Send STOP condition iff the START condition was previously sent. 30140784Snsouch * STOP is sent only once even if a iicbus_stop() is called after 30240784Snsouch * an iicbus_read()... see pcf_read(): the pcf needs to send the stop 30340784Snsouch * before the last char is read. 30440784Snsouch */ 30540784Snsouch if (pcf->pcf_started) { 30640784Snsouch /* set stop condition and enable IT */ 30740784Snsouch PCF_SET_S1(pcf, PIN|ES0|ENI|STO|ACK); 30838781Snsouch 30940784Snsouch pcf->pcf_started = 0; 31040784Snsouch } 31140784Snsouch 31238781Snsouch return (0); 31338781Snsouch} 31438781Snsouch 31540784Snsouch 31640784Snsouchstatic int pcf_noack(struct pcf_softc *pcf, int timeout) 31738781Snsouch{ 31840784Snsouch int noack; 31940784Snsouch int k = timeout/10; 32040784Snsouch 32140784Snsouch do { 32240784Snsouch noack = PCF_GET_S1(pcf) & LRB; 32340784Snsouch if (!noack) 32440784Snsouch break; 32540784Snsouch DELAY(10); /* XXX wait 10 us */ 32640784Snsouch } while (k--); 32740784Snsouch 32840784Snsouch return (noack); 32940784Snsouch} 33040784Snsouch 33140784Snsouchstatic int pcf_repeated_start(device_t pcfdev, u_char slave, int timeout) 33240784Snsouch{ 33338781Snsouch struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 33438781Snsouch int error = 0; 33538781Snsouch 33638781Snsouch /* repeated start */ 33738781Snsouch PCF_SET_S1(pcf, ES0|STA|STO|ACK); 33838781Snsouch 33938781Snsouch /* set slave address to PCF. Last bit (LSB) must be set correctly 34038781Snsouch * according to transfer direction */ 34138781Snsouch PCF_SET_S0(pcf, slave); 34238781Snsouch 34338781Snsouch /* wait for address sent, polling */ 34438781Snsouch if ((error = pcf_wait_byte(pcf))) 34538781Snsouch goto error; 34638781Snsouch 34740784Snsouch /* check for ack */ 34840784Snsouch if (pcf_noack(pcf, timeout)) { 34938781Snsouch error = IIC_ENOACK; 35038781Snsouch goto error; 35138781Snsouch } 35238781Snsouch 35338781Snsouch return (0); 35438781Snsouch 35538781Snsoucherror: 35638781Snsouch pcf_stop(pcfdev); 35738781Snsouch return (error); 35838781Snsouch} 35938781Snsouch 36040784Snsouchstatic int pcf_start(device_t pcfdev, u_char slave, int timeout) 36138781Snsouch{ 36238781Snsouch struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 36338781Snsouch int error = 0; 36438781Snsouch 36546343Speter if ((PCF_GET_S1(pcf) & nBB) == 0) 36638781Snsouch return (IIC_EBUSBSY); 36738781Snsouch 36838781Snsouch /* set slave address to PCF. Last bit (LSB) must be set correctly 36938781Snsouch * according to transfer direction */ 37038781Snsouch PCF_SET_S0(pcf, slave); 37138781Snsouch 37238781Snsouch /* START only */ 37338781Snsouch PCF_SET_S1(pcf, PIN|ES0|STA|ACK); 37438781Snsouch 37540784Snsouch pcf->pcf_started = 1; 37640784Snsouch 37738781Snsouch /* wait for address sent, polling */ 37838781Snsouch if ((error = pcf_wait_byte(pcf))) 37938781Snsouch goto error; 38038781Snsouch 38140784Snsouch /* check for ACK */ 38240784Snsouch if (pcf_noack(pcf, timeout)) { 38338781Snsouch error = IIC_ENOACK; 38438781Snsouch goto error; 38538781Snsouch } 38638781Snsouch 38738781Snsouch return (0); 38838781Snsouch 38938781Snsoucherror: 39038781Snsouch pcf_stop(pcfdev); 39138781Snsouch return (error); 39238781Snsouch} 39338781Snsouch 39440565Sbdestatic void 39538781Snsouchpcfintr(unit) 39638781Snsouch{ 39738781Snsouch struct pcf_softc *pcf = 39838781Snsouch (struct pcf_softc *)devclass_get_softc(pcf_devclass, unit); 39938781Snsouch 40038781Snsouch char data, status, addr; 40138781Snsouch char error = 0; 40238781Snsouch 40338781Snsouch status = PCF_GET_S1(pcf); 40438781Snsouch 40538781Snsouch if (status & PIN) { 40638781Snsouch printf("pcf%d: spurious interrupt, status=0x%x\n", unit, 40738781Snsouch status & 0xff); 40838781Snsouch 40938781Snsouch goto error; 41038781Snsouch } 41138781Snsouch 41238781Snsouch if (status & LAB) 41338781Snsouch printf("pcf%d: bus arbitration lost!\n", unit); 41438781Snsouch 41538781Snsouch if (status & BER) { 41638781Snsouch error = IIC_EBUSERR; 41738781Snsouch iicbus_intr(pcf->iicbus, INTR_ERROR, &error); 41838781Snsouch 41938781Snsouch goto error; 42038781Snsouch } 42138781Snsouch 42238781Snsouch do { 42338781Snsouch status = PCF_GET_S1(pcf); 42438781Snsouch 42538781Snsouch switch(pcf->pcf_slave_mode) { 42638781Snsouch 42738781Snsouch case SLAVE_TRANSMITTER: 42838781Snsouch if (status & LRB) { 42938781Snsouch /* ack interrupt line */ 43038781Snsouch dummy_write(pcf); 43138781Snsouch 43238781Snsouch /* no ack, don't send anymore */ 43338781Snsouch pcf->pcf_slave_mode = SLAVE_RECEIVER; 43438781Snsouch 43538781Snsouch iicbus_intr(pcf->iicbus, INTR_NOACK, NULL); 43638781Snsouch break; 43738781Snsouch } 43838781Snsouch 43938781Snsouch /* get data from upper code */ 44038781Snsouch iicbus_intr(pcf->iicbus, INTR_TRANSMIT, &data); 44138781Snsouch 44238781Snsouch PCF_SET_S0(pcf, data); 44338781Snsouch break; 44438781Snsouch 44538781Snsouch case SLAVE_RECEIVER: 44638781Snsouch if (status & AAS) { 44738781Snsouch addr = PCF_GET_S0(pcf); 44838781Snsouch 44938781Snsouch if (status & AD0) 45038781Snsouch iicbus_intr(pcf->iicbus, INTR_GENERAL, &addr); 45138781Snsouch else 45238781Snsouch iicbus_intr(pcf->iicbus, INTR_START, &addr); 45338781Snsouch 45438781Snsouch if (addr & LSB) { 45538781Snsouch pcf->pcf_slave_mode = SLAVE_TRANSMITTER; 45638781Snsouch 45738781Snsouch /* get the first char from upper code */ 45838781Snsouch iicbus_intr(pcf->iicbus, INTR_TRANSMIT, &data); 45938781Snsouch 46038781Snsouch /* send first data byte */ 46138781Snsouch PCF_SET_S0(pcf, data); 46238781Snsouch } 46338781Snsouch 46438781Snsouch break; 46538781Snsouch } 46638781Snsouch 46738781Snsouch /* stop condition received? */ 46838781Snsouch if (status & STS) { 46938781Snsouch /* ack interrupt line */ 47038781Snsouch dummy_read(pcf); 47138781Snsouch 47238781Snsouch /* emulate intr stop condition */ 47338781Snsouch iicbus_intr(pcf->iicbus, INTR_STOP, NULL); 47438781Snsouch 47538781Snsouch } else { 47638781Snsouch /* get data, ack interrupt line */ 47738781Snsouch data = PCF_GET_S0(pcf); 47838781Snsouch 47938781Snsouch /* deliver the character */ 48038781Snsouch iicbus_intr(pcf->iicbus, INTR_RECEIVE, &data); 48138781Snsouch } 48238781Snsouch break; 48338781Snsouch 48438781Snsouch default: 48538781Snsouch panic("%s: unknown slave mode (%d)!", __FUNCTION__, 48638781Snsouch pcf->pcf_slave_mode); 48738781Snsouch } 48838781Snsouch 48938781Snsouch } while ((PCF_GET_S1(pcf) & PIN) == 0); 49038781Snsouch 49138781Snsouch return; 49238781Snsouch 49338781Snsoucherror: 49438781Snsouch /* unknown event on bus...reset PCF */ 49538781Snsouch PCF_SET_S1(pcf, PIN|ES0|ENI|ACK); 49638781Snsouch 49738781Snsouch pcf->pcf_slave_mode = SLAVE_RECEIVER; 49838781Snsouch 49938781Snsouch return; 50038781Snsouch} 50138781Snsouch 50240784Snsouchstatic int pcf_rst_card(device_t pcfdev, u_char speed, u_char addr, u_char *oldaddr) 50338781Snsouch{ 50438781Snsouch struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 50538781Snsouch 50640784Snsouch if (oldaddr) 50740784Snsouch *oldaddr = pcf->pcf_addr; 50840784Snsouch 50938781Snsouch /* retrieve own address from bus level */ 51040784Snsouch if (!addr) 51140784Snsouch pcf->pcf_addr = PCF_DEFAULT_ADDR; 51240784Snsouch else 51340784Snsouch pcf->pcf_addr = addr; 51438781Snsouch 51538781Snsouch PCF_SET_S1(pcf, PIN); /* initialize S1 */ 51638781Snsouch 51738781Snsouch /* own address S'O<>0 */ 51840784Snsouch PCF_SET_S0(pcf, pcf->pcf_addr >> 1); 51938781Snsouch 52038781Snsouch /* select clock register */ 52138781Snsouch PCF_SET_S1(pcf, PIN|ES1); 52238781Snsouch 52338781Snsouch /* select bus speed : 18=90kb, 19=45kb, 1A=11kb, 1B=1.5kb */ 52438781Snsouch switch (speed) { 52538781Snsouch case IIC_SLOW: 52638781Snsouch PCF_SET_S0(pcf, 0x1b); 52738781Snsouch break; 52838781Snsouch 52938781Snsouch case IIC_FAST: 53038781Snsouch PCF_SET_S0(pcf, 0x19); 53138781Snsouch break; 53238781Snsouch 53338781Snsouch case IIC_UNKNOWN: 53438781Snsouch case IIC_FASTEST: 53538781Snsouch default: 53638781Snsouch PCF_SET_S0(pcf, 0x18); 53738781Snsouch break; 53838781Snsouch } 53938781Snsouch 54038781Snsouch /* set bus on, ack=yes, INT=yes */ 54138781Snsouch PCF_SET_S1(pcf, PIN|ES0|ENI|ACK); 54238781Snsouch 54338781Snsouch pcf->pcf_slave_mode = SLAVE_RECEIVER; 54438781Snsouch 54538781Snsouch return (0); 54638781Snsouch} 54738781Snsouch 54838781Snsouchstatic int 54940784Snsouchpcf_write(device_t pcfdev, char *buf, int len, int *sent, int timeout /* us */) 55038781Snsouch{ 55138781Snsouch struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 55238781Snsouch int bytes, error = 0; 55338781Snsouch 55438781Snsouch#ifdef PCFDEBUG 55538781Snsouch printf("pcf%d: >> writing %d bytes\n", device_get_unit(pcfdev), len); 55638781Snsouch#endif 55738781Snsouch 55838781Snsouch bytes = 0; 55938781Snsouch while (len) { 56038781Snsouch 56138781Snsouch PCF_SET_S0(pcf, *buf++); 56238781Snsouch 56340784Snsouch /* wait for the byte to be send */ 56438781Snsouch if ((error = pcf_wait_byte(pcf))) 56538781Snsouch goto error; 56638781Snsouch 56740784Snsouch /* check if ack received */ 56840784Snsouch if (pcf_noack(pcf, timeout)) { 56938781Snsouch error = IIC_ENOACK; 57038781Snsouch goto error; 57138781Snsouch } 57238781Snsouch 57338781Snsouch len --; 57438781Snsouch bytes ++; 57538781Snsouch } 57638781Snsouch 57738781Snsoucherror: 57838781Snsouch *sent = bytes; 57938781Snsouch 58038781Snsouch#ifdef PCFDEBUG 58138781Snsouch printf("pcf%d: >> %d bytes written (%d)\n", 58238781Snsouch device_get_unit(pcfdev), bytes, error); 58338781Snsouch#endif 58438781Snsouch 58538781Snsouch return (error); 58638781Snsouch} 58738781Snsouch 58838781Snsouchstatic int 58940784Snsouchpcf_read(device_t pcfdev, char *buf, int len, int *read, int last, 59040784Snsouch int delay /* us */) 59138781Snsouch{ 59238781Snsouch struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 59338781Snsouch int bytes, error = 0; 59438781Snsouch 59538781Snsouch#ifdef PCFDEBUG 59638781Snsouch printf("pcf%d: << reading %d bytes\n", device_get_unit(pcfdev), len); 59738781Snsouch#endif 59838781Snsouch 59938781Snsouch /* trig the bus to get the first data byte in S0 */ 60038781Snsouch if (len) { 60140784Snsouch if (len == 1 && last) 60238781Snsouch /* just one byte to read */ 60338781Snsouch PCF_SET_S1(pcf, ES0); /* no ack */ 60438781Snsouch 60538781Snsouch dummy_read(pcf); 60638781Snsouch } 60738781Snsouch 60838781Snsouch bytes = 0; 60938781Snsouch while (len) { 61038781Snsouch 61140784Snsouch /* XXX delay needed here */ 61240784Snsouch 61340784Snsouch /* wait for trigged byte */ 61438781Snsouch if ((error = pcf_wait_byte(pcf))) { 61538781Snsouch pcf_stop(pcfdev); 61638781Snsouch goto error; 61738781Snsouch } 61838781Snsouch 61940784Snsouch if (len == 1 && last) 62040784Snsouch /* ok, last data byte already in S0, no I2C activity 62140784Snsouch * on next PCF_GET_S0() */ 62238781Snsouch pcf_stop(pcfdev); 62338781Snsouch 62440784Snsouch else if (len == 2 && last) 62540784Snsouch /* next trigged byte with no ack */ 62640784Snsouch PCF_SET_S1(pcf, ES0); 62738781Snsouch 62840784Snsouch /* receive byte, trig next byte */ 62940784Snsouch *buf++ = PCF_GET_S0(pcf); 63038781Snsouch 63138781Snsouch len --; 63238781Snsouch bytes ++; 63338781Snsouch }; 63438781Snsouch 63538781Snsoucherror: 63638781Snsouch *read = bytes; 63738781Snsouch 63838781Snsouch#ifdef PCFDEBUG 63938781Snsouch printf("pcf%d: << %d bytes read (%d)\n", 64038781Snsouch device_get_unit(pcfdev), bytes, error); 64138781Snsouch#endif 64238781Snsouch 64338781Snsouch return (error); 64438781Snsouch} 64538781Snsouch 64638781SnsouchDRIVER_MODULE(pcf, root, pcf_driver, pcf_devclass, 0, 0); 647