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