pcf.c revision 46743
1209513Simp/*- 2209513Simp * Copyright (c) 1998 Nicolas Souchu, Marc Bouget 3209552Simp * All rights reserved. 4209513Simp * 5209513Simp * Redistribution and use in source and binary forms, with or without 6209513Simp * modification, are permitted provided that the following conditions 7209513Simp * are met: 8209513Simp * 1. Redistributions of source code must retain the above copyright 9209513Simp * notice, this list of conditions and the following disclaimer. 10209513Simp * 2. Redistributions in binary form must reproduce the above copyright 11209513Simp * notice, this list of conditions and the following disclaimer in the 12209513Simp * documentation and/or other materials provided with the distribution. 13209513Simp * 14209513Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15209513Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16209513Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17209513Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18209513Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19209513Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20209513Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21209513Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22209513Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23209513Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24209513Simp * SUCH DAMAGE. 25209513Simp * 26209513Simp * $Id: pcf.c,v 1.8 1999/05/06 18:54:18 peter Exp $ 27209513Simp * 28209513Simp */ 29209513Simp#include <sys/param.h> 30209513Simp#include <sys/systm.h> 31209513Simp#include <sys/kernel.h> 32209513Simp#include <sys/module.h> 33209513Simp#include <sys/bus.h> 34209513Simp#include <sys/conf.h> 35209513Simp#include <sys/malloc.h> 36209513Simp 37209513Simp#include <machine/clock.h> 38209513Simp 39209513Simp#include <i386/isa/isa_device.h> 40209513Simp 41209513Simp#include <dev/iicbus/iiconf.h> 42209513Simp#include "iicbus_if.h" 43209513Simp 44209513Simp#define TIMEOUT 9999 /* XXX */ 45209513Simp 46209513Simp/* Status bits of S1 register (read only) */ 47209513Simp#define nBB 0x01 /* busy when low set/reset by STOP/START*/ 48209513Simp#define LAB 0x02 /* lost arbitration bit in multi-master mode */ 49209513Simp#define AAS 0x04 /* addressed as slave */ 50209513Simp#define LRB 0x08 /* last received byte when not AAS */ 51209513Simp#define AD0 0x08 /* general call received when AAS */ 52209513Simp#define BER 0x10 /* bus error, misplaced START or STOP */ 53209513Simp#define STS 0x20 /* STOP detected in slave receiver mode */ 54209513Simp#define PIN 0x80 /* pending interrupt not (r/w) */ 55209513Simp 56209513Simp/* Control bits of S1 register (write only) */ 57209513Simp#define ACK 0x01 58209513Simp#define STO 0x02 59209513Simp#define STA 0x04 60209513Simp#define ENI 0x08 61209513Simp#define ES2 0x10 62209513Simp#define ES1 0x20 63209513Simp#define ES0 0x40 64209513Simp 65209513Simp#define BUFSIZE 2048 66209513Simp 67209513Simp#define SLAVE_TRANSMITTER 0x1 68209513Simp#define SLAVE_RECEIVER 0x2 69209513Simp 70209513Simp#define PCF_DEFAULT_ADDR 0xaa 71209513Simp 72209513Simpstruct pcf_softc { 73209513Simp 74209513Simp int pcf_base; /* isa port */ 75209513Simp u_char pcf_addr; /* interface I2C address */ 76209513Simp 77209513Simp int pcf_slave_mode; /* receiver or transmitter */ 78209513Simp int pcf_started; /* 1 if start condition sent */ 79209513Simp 80209513Simp device_t iicbus; /* the corresponding iicbus */ 81209513Simp}; 82209513Simp 83209513Simpstruct pcf_isa_softc { 84209513Simp 85209513Simp int pcf_unit; /* unit of the isa device */ 86209513Simp int pcf_base; /* isa port */ 87209513Simp int pcf_irq; /* isa irq or null if polled */ 88209513Simp 89209513Simp unsigned int pcf_flags; /* boot flags */ 90209513Simp}; 91209513Simp 92209513Simp#define MAXPCF 2 93209513Simp 94220059Sjpaetzelstatic struct pcf_isa_softc *pcfdata[MAXPCF]; 95209513Simpstatic int npcf = 0; 96209513Simp 97209513Simpstatic int pcfprobe_isa(struct isa_device *); 98209513Simpstatic int pcfattach_isa(struct isa_device *); 99209513Simp 100211730Simpstruct isa_driver pcfdriver = { 101225657Sjpaetzel pcfprobe_isa, pcfattach_isa, "pcf" 102209513Simp}; 103211730Simp 104225657Sjpaetzelstatic int pcf_probe(device_t); 105209513Simpstatic int pcf_attach(device_t); 106211730Simpstatic void pcf_print_child(device_t, device_t); 107211730Simp 108209513Simpstatic int pcf_repeated_start(device_t, u_char, int); 109211730Simpstatic int pcf_start(device_t, u_char, int); 110209513Simpstatic int pcf_stop(device_t); 111211730Simpstatic int pcf_write(device_t, char *, int, int *, int); 112209513Simpstatic int pcf_read(device_t, char *, int, int *, int, int); 113209513Simpstatic ointhand2_t pcfintr; 114209513Simpstatic int pcf_rst_card(device_t, u_char, u_char, u_char *); 115209513Simp 116209513Simpstatic device_method_t pcf_methods[] = { 117209513Simp /* device interface */ 118209513Simp DEVMETHOD(device_probe, pcf_probe), 119209513Simp DEVMETHOD(device_attach, pcf_attach), 120209513Simp 121209513Simp /* bus interface */ 122209513Simp DEVMETHOD(bus_print_child, pcf_print_child), 123209513Simp 124209513Simp /* iicbus interface */ 125209513Simp DEVMETHOD(iicbus_callback, iicbus_null_callback), 126209513Simp DEVMETHOD(iicbus_repeated_start, pcf_repeated_start), 127209513Simp DEVMETHOD(iicbus_start, pcf_start), 128209513Simp DEVMETHOD(iicbus_stop, pcf_stop), 129209513Simp DEVMETHOD(iicbus_write, pcf_write), 130209513Simp DEVMETHOD(iicbus_read, pcf_read), 131209513Simp DEVMETHOD(iicbus_reset, pcf_rst_card), 132209513Simp 133209513Simp { 0, 0 } 134209513Simp}; 135209513Simp 136209513Simpstatic driver_t pcf_driver = { 137209513Simp "pcf", 138209513Simp pcf_methods, 139209513Simp sizeof(struct pcf_softc), 140214187Simp}; 141209513Simp 142209513Simpstatic devclass_t pcf_devclass; 143209513Simp 144209513Simp#define DEVTOSOFTC(dev) ((struct pcf_softc *)device_get_softc(dev)) 145209513Simp 146209513Simpstatic int 147209513Simppcfprobe_isa(struct isa_device *dvp) 148209513Simp{ 149209513Simp device_t pcfdev; 150209513Simp struct pcf_isa_softc *pcf; 151209513Simp 152209513Simp if (npcf >= MAXPCF) 153209513Simp return (0); 154209513Simp 155209513Simp if ((pcf = (struct pcf_isa_softc *)malloc(sizeof(struct pcf_isa_softc), 156209513Simp M_DEVBUF, M_NOWAIT)) == NULL) 157209513Simp return (0); 158209513Simp 159209513Simp pcf->pcf_base = dvp->id_iobase; /* XXX should be ivars */ 160209513Simp pcf->pcf_unit = dvp->id_unit; 161209513Simp 162209513Simp if (!(dvp->id_flags & IIC_POLLED)) 163209513Simp pcf->pcf_irq = (dvp->id_irq); 164209513Simp 165209513Simp pcfdata[npcf++] = pcf; 166209513Simp 167209513Simp /* XXX add the pcf device to the root_bus until isa bus exists */ 168209513Simp pcfdev = device_add_child(root_bus, "pcf", pcf->pcf_unit, NULL); 169209513Simp 170209513Simp if (!pcfdev) 171209513Simp goto error; 172209513Simp 173209513Simp return (1); 174209513Simp 175209513Simperror: 176209513Simp free(pcf, M_DEVBUF); 177209513Simp return (0); 178209513Simp} 179209513Simp 180209513Simpstatic int 181209513Simppcfattach_isa(struct isa_device *isdp) 182209513Simp{ 183209513Simp isdp->id_ointr = pcfintr; 184209513Simp return (1); /* ok */ 185209513Simp} 186209513Simp 187209513Simpstatic int 188209513Simppcf_probe(device_t pcfdev) 189209513Simp{ 190209513Simp struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(pcfdev); 191209513Simp int unit = device_get_unit(pcfdev); 192209513Simp 193209513Simp /* retrieve base address from isa initialization 194209513Simp * 195209513Simp * XXX should use ivars with isabus 196209513Simp */ 197211730Simp pcf->pcf_base = pcfdata[unit]->pcf_base; 198211730Simp 199211730Simp /* reset the chip */ 200211730Simp pcf_rst_card(pcfdev, IIC_FASTEST, PCF_DEFAULT_ADDR, NULL); 201209513Simp 202209513Simp /* XXX try do detect chipset */ 203209513Simp 204209513Simp device_set_desc(pcfdev, "PCF8584 I2C bus controller"); 205209513Simp 206209513Simp return (0); 207211730Simp} 208211730Simp 209211730Simpstatic int 210209513Simppcf_attach(device_t pcfdev) 211211730Simp{ 212209513Simp struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(pcfdev); 213211730Simp 214209513Simp pcf->iicbus = iicbus_alloc_bus(pcfdev); 215235453Sjpaetzel 216211730Simp /* probe and attach the iicbus */ 217211730Simp device_probe_and_attach(pcf->iicbus); 218209513Simp 219211730Simp return (0); 220211730Simp} 221211730Simp 222211730Simpstatic void 223211730Simppcf_print_child(device_t bus, device_t dev) 224209513Simp{ 225211730Simp struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(bus); 226211730Simp 227211730Simp printf(" on %s%d addr 0x%x", device_get_name(bus), 228211730Simp device_get_unit(bus), (int)pcf->pcf_addr); 229211730Simp 230209513Simp return; 231209513Simp} 232211730Simp 233209513Simp/* 234209513Simp * PCF8584 datasheet : when operate at 8 MHz or more, a minimun time of 235211730Simp * 6 clocks cycles must be left between two consecutives access 236211730Simp */ 237220059Sjpaetzel#define pcf_nops() DELAY(10) 238211730Simp 239211730Simp#define dummy_read(pcf) PCF_GET_S0(pcf) 240211730Simp#define dummy_write(pcf) PCF_SET_S0(pcf, 0) 241209513Simp 242211730Simp/* 243211730Simp * Specific register access to PCF8584 244209513Simp */ 245211730Simpstatic void PCF_SET_S0(struct pcf_softc *pcf, int data) 246209513Simp{ 247211730Simp outb(pcf->pcf_base, data); 248211730Simp pcf_nops(); 249211730Simp} 250211730Simp 251211730Simpstatic void PCF_SET_S1(struct pcf_softc *pcf, int data) 252209513Simp{ 253211730Simp outb(pcf->pcf_base+1, data); 254209513Simp pcf_nops(); 255209513Simp} 256209513Simp 257209513Simpstatic char PCF_GET_S0(struct pcf_softc *pcf) 258209513Simp{ 259209513Simp char data; 260209513Simp 261209513Simp data = inb(pcf->pcf_base); 262209513Simp pcf_nops(); 263209513Simp 264209513Simp return (data); 265209513Simp} 266209513Simp 267209513Simpstatic char PCF_GET_S1(struct pcf_softc *pcf) 268209513Simp{ 269209513Simp char data; 270209513Simp 271209513Simp data = inb(pcf->pcf_base+1); 272209513Simp pcf_nops(); 273209513Simp 274209513Simp return (data); 275235005Sjpaetzel} 276235005Sjpaetzel 277235453Sjpaetzel/* 278235005Sjpaetzel * Polling mode for master operations wait for a new 279235005Sjpaetzel * byte incomming or outgoing 280247735Sjpaetzel */ 281247735Sjpaetzelstatic int pcf_wait_byte(struct pcf_softc *pcf) 282247735Sjpaetzel{ 283247735Sjpaetzel int counter = TIMEOUT; 284247735Sjpaetzel 285235005Sjpaetzel while (counter--) { 286235005Sjpaetzel 287235005Sjpaetzel if ((PCF_GET_S1(pcf) & PIN) == 0) 288235005Sjpaetzel return (0); 289220909Sjpaetzel } 290209513Simp 291209513Simp return (IIC_ETIMEOUT); 292235005Sjpaetzel} 293209513Simp 294209513Simpstatic int pcf_stop(device_t pcfdev) 295212337Simp{ 296213650Simp struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 297213650Simp 298213650Simp /* 299213650Simp * Send STOP condition iff the START condition was previously sent. 300213650Simp * STOP is sent only once even if a iicbus_stop() is called after 301213650Simp * an iicbus_read()... see pcf_read(): the pcf needs to send the stop 302213650Simp * before the last char is read. 303213650Simp */ 304213650Simp if (pcf->pcf_started) { 305220059Sjpaetzel /* set stop condition and enable IT */ 306213650Simp PCF_SET_S1(pcf, PIN|ES0|ENI|STO|ACK); 307213650Simp 308213650Simp pcf->pcf_started = 0; 309213650Simp } 310213650Simp 311213650Simp return (0); 312213650Simp} 313213650Simp 314213650Simp 315213650Simpstatic int pcf_noack(struct pcf_softc *pcf, int timeout) 316213650Simp{ 317213650Simp int noack; 318213650Simp int k = timeout/10; 319213650Simp 320213650Simp do { 321213650Simp noack = PCF_GET_S1(pcf) & LRB; 322213650Simp if (!noack) 323213650Simp break; 324213650Simp DELAY(10); /* XXX wait 10 us */ 325213650Simp } while (k--); 326213650Simp 327213650Simp return (noack); 328213650Simp} 329213650Simp 330213650Simpstatic int pcf_repeated_start(device_t pcfdev, u_char slave, int timeout) 331213650Simp{ 332213650Simp struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 333213650Simp int error = 0; 334213650Simp 335213650Simp /* repeated start */ 336213650Simp PCF_SET_S1(pcf, ES0|STA|STO|ACK); 337212337Simp 338212337Simp /* set slave address to PCF. Last bit (LSB) must be set correctly 339213650Simp * according to transfer direction */ 340213650Simp PCF_SET_S0(pcf, slave); 341212337Simp 342212337Simp /* wait for address sent, polling */ 343212337Simp if ((error = pcf_wait_byte(pcf))) 344212337Simp goto error; 345212337Simp 346213650Simp /* check for ack */ 347212337Simp if (pcf_noack(pcf, timeout)) { 348212337Simp error = IIC_ENOACK; 349212337Simp goto error; 350212337Simp } 351213650Simp 352212337Simp return (0); 353212337Simp 354212337Simperror: 355212337Simp pcf_stop(pcfdev); 356213650Simp return (error); 357212337Simp} 358212337Simp 359212337Simpstatic int pcf_start(device_t pcfdev, u_char slave, int timeout) 360212337Simp{ 361212337Simp struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 362212337Simp int error = 0; 363212337Simp 364213650Simp if ((PCF_GET_S1(pcf) & nBB) == 0) 365212337Simp return (IIC_EBUSBSY); 366212337Simp 367213650Simp /* set slave address to PCF. Last bit (LSB) must be set correctly 368212337Simp * according to transfer direction */ 369213650Simp PCF_SET_S0(pcf, slave); 370213650Simp 371213650Simp /* START only */ 372213650Simp PCF_SET_S1(pcf, PIN|ES0|STA|ACK); 373213650Simp 374214139Simp pcf->pcf_started = 1; 375214139Simp 376214187Simp /* wait for address sent, polling */ 377214139Simp if ((error = pcf_wait_byte(pcf))) 378214139Simp goto error; 379214139Simp 380214139Simp /* check for ACK */ 381214187Simp if (pcf_noack(pcf, timeout)) { 382214139Simp error = IIC_ENOACK; 383214139Simp goto error; 384214139Simp } 385214139Simp 386214187Simp return (0); 387214139Simp 388214139Simperror: 389214139Simp pcf_stop(pcfdev); 390214139Simp return (error); 391214187Simp} 392214139Simp 393214139Simpstatic void 394214139Simppcfintr(unit) 395214139Simp{ 396214187Simp struct pcf_softc *pcf = 397214139Simp (struct pcf_softc *)devclass_get_softc(pcf_devclass, unit); 398214139Simp 399214139Simp char data, status, addr; 400214139Simp char error = 0; 401214187Simp 402214139Simp status = PCF_GET_S1(pcf); 403214139Simp 404214139Simp if (status & PIN) { 405214139Simp printf("pcf%d: spurious interrupt, status=0x%x\n", unit, 406214187Simp status & 0xff); 407214139Simp 408214139Simp goto error; 409214139Simp } 410214139Simp 411214139Simp if (status & LAB) 412214139Simp printf("pcf%d: bus arbitration lost!\n", unit); 413214139Simp 414214139Simp if (status & BER) { 415214139Simp error = IIC_EBUSERR; 416214187Simp iicbus_intr(pcf->iicbus, INTR_ERROR, &error); 417214139Simp 418212337Simp goto error; 419212337Simp } 420212337Simp 421218776Sjpaetzel do { 422212337Simp status = PCF_GET_S1(pcf); 423212337Simp 424212337Simp switch(pcf->pcf_slave_mode) { 425212337Simp 426212337Simp case SLAVE_TRANSMITTER: 427213650Simp if (status & LRB) { 428213650Simp /* ack interrupt line */ 429213650Simp dummy_write(pcf); 430213650Simp 431213650Simp /* no ack, don't send anymore */ 432212337Simp pcf->pcf_slave_mode = SLAVE_RECEIVER; 433213650Simp 434213650Simp iicbus_intr(pcf->iicbus, INTR_NOACK, NULL); 435213650Simp break; 436212337Simp } 437213650Simp 438213650Simp /* get data from upper code */ 439212337Simp iicbus_intr(pcf->iicbus, INTR_TRANSMIT, &data); 440213650Simp 441213650Simp PCF_SET_S0(pcf, data); 442212337Simp break; 443213650Simp 444213650Simp case SLAVE_RECEIVER: 445212337Simp if (status & AAS) { 446213650Simp addr = PCF_GET_S0(pcf); 447213650Simp 448212337Simp if (status & AD0) 449213650Simp iicbus_intr(pcf->iicbus, INTR_GENERAL, &addr); 450213650Simp else 451212337Simp iicbus_intr(pcf->iicbus, INTR_START, &addr); 452213650Simp 453213650Simp if (addr & LSB) { 454212337Simp pcf->pcf_slave_mode = SLAVE_TRANSMITTER; 455213650Simp 456213650Simp /* get the first char from upper code */ 457212337Simp iicbus_intr(pcf->iicbus, INTR_TRANSMIT, &data); 458213650Simp 459213650Simp /* send first data byte */ 460212337Simp PCF_SET_S0(pcf, data); 461225657Sjpaetzel } 462225657Sjpaetzel 463225657Sjpaetzel break; 464213650Simp } 465213650Simp 466213650Simp /* stop condition received? */ 467212337Simp if (status & STS) { 468212337Simp /* ack interrupt line */ 469213650Simp dummy_read(pcf); 470212337Simp 471218776Sjpaetzel /* emulate intr stop condition */ 472218776Sjpaetzel iicbus_intr(pcf->iicbus, INTR_STOP, NULL); 473218776Sjpaetzel 474218776Sjpaetzel } else { 475218776Sjpaetzel /* get data, ack interrupt line */ 476218776Sjpaetzel data = PCF_GET_S0(pcf); 477218776Sjpaetzel 478218776Sjpaetzel /* deliver the character */ 479218776Sjpaetzel iicbus_intr(pcf->iicbus, INTR_RECEIVE, &data); 480218776Sjpaetzel } 481218776Sjpaetzel break; 482218776Sjpaetzel 483218776Sjpaetzel default: 484218776Sjpaetzel panic("%s: unknown slave mode (%d)!", __FUNCTION__, 485218776Sjpaetzel pcf->pcf_slave_mode); 486218776Sjpaetzel } 487218776Sjpaetzel 488218776Sjpaetzel } while ((PCF_GET_S1(pcf) & PIN) == 0); 489218776Sjpaetzel 490218776Sjpaetzel return; 491218776Sjpaetzel 492218776Sjpaetzelerror: 493218776Sjpaetzel /* unknown event on bus...reset PCF */ 494218776Sjpaetzel PCF_SET_S1(pcf, PIN|ES0|ENI|ACK); 495218776Sjpaetzel 496218776Sjpaetzel pcf->pcf_slave_mode = SLAVE_RECEIVER; 497218776Sjpaetzel 498218776Sjpaetzel return; 499218776Sjpaetzel} 500218776Sjpaetzel 501218776Sjpaetzelstatic int pcf_rst_card(device_t pcfdev, u_char speed, u_char addr, u_char *oldaddr) 502218776Sjpaetzel{ 503218776Sjpaetzel struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 504213650Simp 505213650Simp if (oldaddr) 506213650Simp *oldaddr = pcf->pcf_addr; 507213650Simp 508213650Simp /* retrieve own address from bus level */ 509213650Simp if (!addr) 510213650Simp pcf->pcf_addr = PCF_DEFAULT_ADDR; 511213650Simp else 512212337Simp pcf->pcf_addr = addr; 513212337Simp 514212337Simp PCF_SET_S1(pcf, PIN); /* initialize S1 */ 515212337Simp 516212337Simp /* own address S'O<>0 */ 517212337Simp PCF_SET_S0(pcf, pcf->pcf_addr >> 1); 518212337Simp 519212337Simp /* select clock register */ 520212337Simp PCF_SET_S1(pcf, PIN|ES1); 521212337Simp 522212337Simp /* select bus speed : 18=90kb, 19=45kb, 1A=11kb, 1B=1.5kb */ 523212337Simp switch (speed) { 524218776Sjpaetzel case IIC_SLOW: 525212337Simp PCF_SET_S0(pcf, 0x1b); 526212337Simp break; 527212337Simp 528212337Simp case IIC_FAST: 529212337Simp PCF_SET_S0(pcf, 0x19); 530212337Simp break; 531212337Simp 532212337Simp case IIC_UNKNOWN: 533212337Simp case IIC_FASTEST: 534212337Simp default: 535212337Simp PCF_SET_S0(pcf, 0x18); 536212337Simp break; 537212337Simp } 538212337Simp 539212337Simp /* set bus on, ack=yes, INT=yes */ 540213650Simp PCF_SET_S1(pcf, PIN|ES0|ENI|ACK); 541 542 pcf->pcf_slave_mode = SLAVE_RECEIVER; 543 544 return (0); 545} 546 547static int 548pcf_write(device_t pcfdev, char *buf, int len, int *sent, int timeout /* us */) 549{ 550 struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 551 int bytes, error = 0; 552 553#ifdef PCFDEBUG 554 printf("pcf%d: >> writing %d bytes\n", device_get_unit(pcfdev), len); 555#endif 556 557 bytes = 0; 558 while (len) { 559 560 PCF_SET_S0(pcf, *buf++); 561 562 /* wait for the byte to be send */ 563 if ((error = pcf_wait_byte(pcf))) 564 goto error; 565 566 /* check if ack received */ 567 if (pcf_noack(pcf, timeout)) { 568 error = IIC_ENOACK; 569 goto error; 570 } 571 572 len --; 573 bytes ++; 574 } 575 576error: 577 *sent = bytes; 578 579#ifdef PCFDEBUG 580 printf("pcf%d: >> %d bytes written (%d)\n", 581 device_get_unit(pcfdev), bytes, error); 582#endif 583 584 return (error); 585} 586 587static int 588pcf_read(device_t pcfdev, char *buf, int len, int *read, int last, 589 int delay /* us */) 590{ 591 struct pcf_softc *pcf = DEVTOSOFTC(pcfdev); 592 int bytes, error = 0; 593 594#ifdef PCFDEBUG 595 printf("pcf%d: << reading %d bytes\n", device_get_unit(pcfdev), len); 596#endif 597 598 /* trig the bus to get the first data byte in S0 */ 599 if (len) { 600 if (len == 1 && last) 601 /* just one byte to read */ 602 PCF_SET_S1(pcf, ES0); /* no ack */ 603 604 dummy_read(pcf); 605 } 606 607 bytes = 0; 608 while (len) { 609 610 /* XXX delay needed here */ 611 612 /* wait for trigged byte */ 613 if ((error = pcf_wait_byte(pcf))) { 614 pcf_stop(pcfdev); 615 goto error; 616 } 617 618 if (len == 1 && last) 619 /* ok, last data byte already in S0, no I2C activity 620 * on next PCF_GET_S0() */ 621 pcf_stop(pcfdev); 622 623 else if (len == 2 && last) 624 /* next trigged byte with no ack */ 625 PCF_SET_S1(pcf, ES0); 626 627 /* receive byte, trig next byte */ 628 *buf++ = PCF_GET_S0(pcf); 629 630 len --; 631 bytes ++; 632 }; 633 634error: 635 *read = bytes; 636 637#ifdef PCFDEBUG 638 printf("pcf%d: << %d bytes read (%d)\n", 639 device_get_unit(pcfdev), bytes, error); 640#endif 641 642 return (error); 643} 644 645DRIVER_MODULE(pcf, root, pcf_driver, pcf_devclass, 0, 0); 646