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