138781Snsouch/*-
238781Snsouch * Copyright (c) 1998 Nicolas Souchu, Marc Bouget
3129704Sjoerg * Copyright (c) 2004 Joerg Wunsch
438781Snsouch * All rights reserved.
538781Snsouch *
638781Snsouch * Redistribution and use in source and binary forms, with or without
738781Snsouch * modification, are permitted provided that the following conditions
838781Snsouch * are met:
938781Snsouch * 1. Redistributions of source code must retain the above copyright
1038781Snsouch *    notice, this list of conditions and the following disclaimer.
1138781Snsouch * 2. Redistributions in binary form must reproduce the above copyright
1238781Snsouch *    notice, this list of conditions and the following disclaimer in the
1338781Snsouch *    documentation and/or other materials provided with the distribution.
1438781Snsouch *
1538781Snsouch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1638781Snsouch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1738781Snsouch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1838781Snsouch * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1938781Snsouch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2038781Snsouch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2138781Snsouch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2238781Snsouch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2338781Snsouch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2438781Snsouch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2538781Snsouch * SUCH DAMAGE.
2638781Snsouch */
27115703Sobrien
28115703Sobrien#include <sys/cdefs.h>
29115703Sobrien__FBSDID("$FreeBSD$");
30115703Sobrien
3138781Snsouch#include <sys/param.h>
32181303Sjhb#include <sys/bus.h>
33181303Sjhb#include <sys/lock.h>
3438781Snsouch#include <sys/kernel.h>
3538781Snsouch#include <sys/module.h>
36181303Sjhb#include <sys/mutex.h>
37181303Sjhb#include <sys/systm.h>
3838781Snsouch
3955939Snsouch#include <machine/bus.h>
4055939Snsouch#include <machine/resource.h>
41129704Sjoerg
4255939Snsouch#include <sys/rman.h>
4338781Snsouch
44181332Sjhb#include <dev/iicbus/iicbus.h>
4538781Snsouch#include <dev/iicbus/iiconf.h>
46129704Sjoerg#include <dev/pcf/pcfvar.h>
4738781Snsouch#include "iicbus_if.h"
4838781Snsouch
49129704Sjoerg/* Not so official debugging option. */
50129704Sjoerg/* #define PCFDEBUG */
5155939Snsouch
52129704Sjoergstatic int pcf_wait_byte(struct pcf_softc *pcf);
53129704Sjoergstatic int pcf_noack(struct pcf_softc *pcf, int timeout);
54181303Sjhbstatic void pcf_stop_locked(struct pcf_softc *pcf);
5538781Snsouch
5638781Snsouch/*
5738781Snsouch * Polling mode for master operations wait for a new
58181303Sjhb * byte incoming or outgoing
5938781Snsouch */
60181303Sjhbstatic int
61129704Sjoergpcf_wait_byte(struct pcf_softc *sc)
6238781Snsouch{
6338781Snsouch	int counter = TIMEOUT;
6438781Snsouch
65181303Sjhb	PCF_ASSERT_LOCKED(sc);
6638781Snsouch	while (counter--) {
6738781Snsouch
68129704Sjoerg		if ((pcf_get_S1(sc) & PIN) == 0)
6938781Snsouch			return (0);
7038781Snsouch	}
7138781Snsouch
72129893Snsouch#ifdef PCFDEBUG
73129893Snsouch	printf("pcf: timeout!\n");
74129893Snsouch#endif
75129893Snsouch
7638781Snsouch	return (IIC_ETIMEOUT);
7738781Snsouch}
7838781Snsouch
79181303Sjhbstatic void
80181303Sjhbpcf_stop_locked(struct pcf_softc *sc)
8138781Snsouch{
8238781Snsouch
83181303Sjhb	PCF_ASSERT_LOCKED(sc);
84129704Sjoerg#ifdef PCFDEBUG
85129704Sjoerg	device_printf(dev, " >> stop\n");
86129704Sjoerg#endif
8740784Snsouch	/*
8840784Snsouch	 * Send STOP condition iff the START condition was previously sent.
89108533Sschweikh	 * STOP is sent only once even if an iicbus_stop() is called after
90129704Sjoerg	 * an iicbus_read()... see pcf_read(): the PCF needs to send the stop
9140784Snsouch	 * before the last char is read.
9240784Snsouch	 */
93129704Sjoerg	if (sc->pcf_started) {
9440784Snsouch		/* set stop condition and enable IT */
95129704Sjoerg		pcf_set_S1(sc, PIN|ESO|ENI|STO|ACK);
9638781Snsouch
97129704Sjoerg		sc->pcf_started = 0;
9840784Snsouch	}
9938781Snsouch}
10038781Snsouch
101181303Sjhbstatic int
102129704Sjoergpcf_noack(struct pcf_softc *sc, int timeout)
10338781Snsouch{
10440784Snsouch	int noack;
10540784Snsouch	int k = timeout/10;
10640784Snsouch
107181303Sjhb	PCF_ASSERT_LOCKED(sc);
10840784Snsouch	do {
109129704Sjoerg		noack = pcf_get_S1(sc) & LRB;
11040784Snsouch		if (!noack)
11140784Snsouch			break;
11240784Snsouch		DELAY(10);				/* XXX wait 10 us */
11340784Snsouch	} while (k--);
11440784Snsouch
11540784Snsouch	return (noack);
11640784Snsouch}
11740784Snsouch
118129704Sjoergint
119129704Sjoergpcf_repeated_start(device_t dev, u_char slave, int timeout)
12040784Snsouch{
121129704Sjoerg	struct pcf_softc *sc = DEVTOSOFTC(dev);
12238781Snsouch	int error = 0;
12338781Snsouch
124181303Sjhb	PCF_LOCK(sc);
125129704Sjoerg#ifdef PCFDEBUG
126129704Sjoerg	device_printf(dev, " >> repeated start for slave %#x\n",
127129704Sjoerg		      (unsigned)slave);
128129704Sjoerg#endif
12938781Snsouch	/* repeated start */
130129704Sjoerg	pcf_set_S1(sc, ESO|STA|STO|ACK);
13138781Snsouch
13238781Snsouch	/* set slave address to PCF. Last bit (LSB) must be set correctly
13338781Snsouch	 * according to transfer direction */
134129704Sjoerg	pcf_set_S0(sc, slave);
13538781Snsouch
13638781Snsouch	/* wait for address sent, polling */
137129704Sjoerg	if ((error = pcf_wait_byte(sc)))
13838781Snsouch		goto error;
13938781Snsouch
14040784Snsouch	/* check for ack */
141129704Sjoerg	if (pcf_noack(sc, timeout)) {
14238781Snsouch		error = IIC_ENOACK;
143129893Snsouch#ifdef PCFDEBUG
144129893Snsouch		printf("pcf: no ack on repeated_start!\n");
145129893Snsouch#endif
14638781Snsouch		goto error;
14738781Snsouch	}
14838781Snsouch
149181303Sjhb	PCF_UNLOCK(sc);
15038781Snsouch	return (0);
15138781Snsouch
15238781Snsoucherror:
153181303Sjhb	pcf_stop_locked(sc);
154181303Sjhb	PCF_UNLOCK(sc);
15538781Snsouch	return (error);
15638781Snsouch}
15738781Snsouch
158129704Sjoergint
159129704Sjoergpcf_start(device_t dev, u_char slave, int timeout)
16038781Snsouch{
161129704Sjoerg	struct pcf_softc *sc = DEVTOSOFTC(dev);
16238781Snsouch	int error = 0;
16338781Snsouch
164181303Sjhb	PCF_LOCK(sc);
165129704Sjoerg#ifdef PCFDEBUG
166129704Sjoerg	device_printf(dev, " >> start for slave %#x\n", (unsigned)slave);
167129704Sjoerg#endif
168129893Snsouch	if ((pcf_get_S1(sc) & nBB) == 0) {
169129893Snsouch#ifdef PCFDEBUG
170129893Snsouch		printf("pcf: busy!\n");
171129893Snsouch#endif
172181303Sjhb		PCF_UNLOCK(sc);
17338781Snsouch		return (IIC_EBUSBSY);
174129893Snsouch	}
17538781Snsouch
17638781Snsouch	/* set slave address to PCF. Last bit (LSB) must be set correctly
17738781Snsouch	 * according to transfer direction */
178129704Sjoerg	pcf_set_S0(sc, slave);
17938781Snsouch
18038781Snsouch	/* START only */
181129704Sjoerg	pcf_set_S1(sc, PIN|ESO|STA|ACK);
18238781Snsouch
183129704Sjoerg	sc->pcf_started = 1;
18440784Snsouch
18538781Snsouch	/* wait for address sent, polling */
186129704Sjoerg	if ((error = pcf_wait_byte(sc)))
18738781Snsouch		goto error;
18838781Snsouch
18940784Snsouch	/* check for ACK */
190129704Sjoerg	if (pcf_noack(sc, timeout)) {
19138781Snsouch		error = IIC_ENOACK;
192129893Snsouch#ifdef PCFDEBUG
193129893Snsouch		printf("pcf: no ack on start!\n");
194129893Snsouch#endif
19538781Snsouch		goto error;
19638781Snsouch	}
19738781Snsouch
198181303Sjhb	PCF_UNLOCK(sc);
19938781Snsouch	return (0);
20038781Snsouch
20138781Snsoucherror:
202181303Sjhb	pcf_stop_locked(sc);
203181303Sjhb	PCF_UNLOCK(sc);
20438781Snsouch	return (error);
20538781Snsouch}
20638781Snsouch
207181303Sjhbint
208181303Sjhbpcf_stop(device_t dev)
209181303Sjhb{
210181303Sjhb	struct pcf_softc *sc = DEVTOSOFTC(dev);
211181303Sjhb
212181303Sjhb#ifdef PCFDEBUG
213181303Sjhb	device_printf(dev, " >> stop\n");
214181303Sjhb#endif
215181303Sjhb	PCF_LOCK(sc);
216181303Sjhb	pcf_stop_locked(sc);
217181303Sjhb	PCF_UNLOCK(sc);
218181303Sjhb
219181303Sjhb	return (0);
220181303Sjhb}
221181303Sjhb
222129704Sjoergvoid
223129704Sjoergpcf_intr(void *arg)
22438781Snsouch{
225129893Snsouch	struct pcf_softc *sc = arg;
22638781Snsouch	char data, status, addr;
22738781Snsouch	char error = 0;
22838781Snsouch
229181303Sjhb	PCF_LOCK(sc);
230129704Sjoerg	status = pcf_get_S1(sc);
23138781Snsouch
23238781Snsouch	if (status & PIN) {
233129893Snsouch		printf("pcf: spurious interrupt, status=0x%x\n",
234129893Snsouch		       status & 0xff);
23538781Snsouch
23638781Snsouch		goto error;
237129704Sjoerg	}
23838781Snsouch
23938781Snsouch	if (status & LAB)
240129893Snsouch		printf("pcf: bus arbitration lost!\n");
24138781Snsouch
24238781Snsouch	if (status & BER) {
24338781Snsouch		error = IIC_EBUSERR;
244129704Sjoerg		iicbus_intr(sc->iicbus, INTR_ERROR, &error);
24538781Snsouch
24638781Snsouch		goto error;
24738781Snsouch	}
24838781Snsouch
24938781Snsouch	do {
250129704Sjoerg		status = pcf_get_S1(sc);
25138781Snsouch
252129704Sjoerg		switch(sc->pcf_slave_mode) {
25338781Snsouch
25438781Snsouch		case SLAVE_TRANSMITTER:
25538781Snsouch			if (status & LRB) {
25638781Snsouch				/* ack interrupt line */
257129704Sjoerg				dummy_write(sc);
25838781Snsouch
25938781Snsouch				/* no ack, don't send anymore */
260129704Sjoerg				sc->pcf_slave_mode = SLAVE_RECEIVER;
26138781Snsouch
262129704Sjoerg				iicbus_intr(sc->iicbus, INTR_NOACK, NULL);
26338781Snsouch				break;
26438781Snsouch			}
26538781Snsouch
26638781Snsouch			/* get data from upper code */
267129704Sjoerg			iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data);
26838781Snsouch
269129704Sjoerg			pcf_set_S0(sc, data);
270129704Sjoerg			break;
271129704Sjoerg
27238781Snsouch		case SLAVE_RECEIVER:
27338781Snsouch			if (status & AAS) {
274129704Sjoerg				addr = pcf_get_S0(sc);
27538781Snsouch
27638781Snsouch				if (status & AD0)
277129704Sjoerg					iicbus_intr(sc->iicbus, INTR_GENERAL, &addr);
27838781Snsouch				else
279129704Sjoerg					iicbus_intr(sc->iicbus, INTR_START, &addr);
28038781Snsouch
28138781Snsouch				if (addr & LSB) {
282129704Sjoerg					sc->pcf_slave_mode = SLAVE_TRANSMITTER;
28338781Snsouch
28438781Snsouch					/* get the first char from upper code */
285129704Sjoerg					iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data);
28638781Snsouch
28738781Snsouch					/* send first data byte */
288129704Sjoerg					pcf_set_S0(sc, data);
28938781Snsouch				}
29038781Snsouch
29138781Snsouch				break;
29238781Snsouch			}
29338781Snsouch
29438781Snsouch			/* stop condition received? */
29538781Snsouch			if (status & STS) {
29638781Snsouch				/* ack interrupt line */
297129704Sjoerg				dummy_read(sc);
29838781Snsouch
29938781Snsouch				/* emulate intr stop condition */
300129704Sjoerg				iicbus_intr(sc->iicbus, INTR_STOP, NULL);
30138781Snsouch
30238781Snsouch			} else {
30338781Snsouch				/* get data, ack interrupt line */
304129704Sjoerg				data = pcf_get_S0(sc);
30538781Snsouch
30638781Snsouch				/* deliver the character */
307129704Sjoerg				iicbus_intr(sc->iicbus, INTR_RECEIVE, &data);
30838781Snsouch			}
30938781Snsouch			break;
31038781Snsouch
31138781Snsouch		    default:
31287599Sobrien			panic("%s: unknown slave mode (%d)!", __func__,
313129704Sjoerg				sc->pcf_slave_mode);
31438781Snsouch		    }
31538781Snsouch
316129704Sjoerg	} while ((pcf_get_S1(sc) & PIN) == 0);
317181303Sjhb	PCF_UNLOCK(sc);
31838781Snsouch
31938781Snsouch	return;
32038781Snsouch
32138781Snsoucherror:
32238781Snsouch	/* unknown event on bus...reset PCF */
323129704Sjoerg	pcf_set_S1(sc, PIN|ESO|ENI|ACK);
32438781Snsouch
325129704Sjoerg	sc->pcf_slave_mode = SLAVE_RECEIVER;
326181303Sjhb	PCF_UNLOCK(sc);
32738781Snsouch
32838781Snsouch	return;
32938781Snsouch}
33038781Snsouch
331129704Sjoergint
332129704Sjoergpcf_rst_card(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
33338781Snsouch{
334129704Sjoerg	struct pcf_softc *sc = DEVTOSOFTC(dev);
33538781Snsouch
336181303Sjhb	PCF_LOCK(sc);
33740784Snsouch	if (oldaddr)
338129704Sjoerg		*oldaddr = sc->pcf_addr;
33940784Snsouch
34038781Snsouch	/* retrieve own address from bus level */
34140784Snsouch	if (!addr)
342129704Sjoerg		sc->pcf_addr = PCF_DEFAULT_ADDR;
34340784Snsouch	else
344129704Sjoerg		sc->pcf_addr = addr;
34538781Snsouch
346129704Sjoerg	pcf_set_S1(sc, PIN);				/* initialize S1 */
347129704Sjoerg
34838781Snsouch	/* own address S'O<>0 */
349129704Sjoerg	pcf_set_S0(sc, sc->pcf_addr >> 1);
35038781Snsouch
35138781Snsouch	/* select clock register */
352129704Sjoerg	pcf_set_S1(sc, PIN|ES1);
35338781Snsouch
35438781Snsouch	/* select bus speed : 18=90kb, 19=45kb, 1A=11kb, 1B=1.5kb */
35538781Snsouch	switch (speed) {
35638781Snsouch	case IIC_SLOW:
357129704Sjoerg		pcf_set_S0(sc,  0x1b); /* XXX Sun uses 0x1f */
35838781Snsouch		break;
35938781Snsouch
36038781Snsouch	case IIC_FAST:
361129704Sjoerg		pcf_set_S0(sc,  0x19); /* XXX Sun: 0x1d */
36238781Snsouch		break;
36338781Snsouch
36438781Snsouch	case IIC_UNKNOWN:
36538781Snsouch	case IIC_FASTEST:
36638781Snsouch	default:
367129704Sjoerg		pcf_set_S0(sc,  0x18); /* XXX Sun: 0x1c */
36838781Snsouch		break;
36938781Snsouch	}
37038781Snsouch
37138781Snsouch	/* set bus on, ack=yes, INT=yes */
372129704Sjoerg	pcf_set_S1(sc, PIN|ESO|ENI|ACK);
37338781Snsouch
374129704Sjoerg	sc->pcf_slave_mode = SLAVE_RECEIVER;
375181303Sjhb	PCF_UNLOCK(sc);
37638781Snsouch
37738781Snsouch	return (0);
37838781Snsouch}
37938781Snsouch
380129704Sjoergint
381194026Savgpcf_write(device_t dev, const char *buf, int len, int *sent, int timeout /* us */)
38238781Snsouch{
383129704Sjoerg	struct pcf_softc *sc = DEVTOSOFTC(dev);
38438781Snsouch	int bytes, error = 0;
38538781Snsouch
38638781Snsouch#ifdef PCFDEBUG
387129704Sjoerg	device_printf(dev, " >> writing %d bytes: %#x%s\n", len,
388129704Sjoerg		      (unsigned)buf[0], len > 1? "...": "");
38938781Snsouch#endif
39038781Snsouch
39138781Snsouch	bytes = 0;
392181303Sjhb	PCF_LOCK(sc);
39338781Snsouch	while (len) {
39438781Snsouch
395129704Sjoerg		pcf_set_S0(sc, *buf++);
39638781Snsouch
39740784Snsouch		/* wait for the byte to be send */
398129704Sjoerg		if ((error = pcf_wait_byte(sc)))
39938781Snsouch			goto error;
40038781Snsouch
40140784Snsouch		/* check if ack received */
402129704Sjoerg		if (pcf_noack(sc, timeout)) {
40338781Snsouch			error = IIC_ENOACK;
40438781Snsouch			goto error;
40538781Snsouch		}
40638781Snsouch
40738781Snsouch		len --;
40838781Snsouch		bytes ++;
40938781Snsouch	}
41038781Snsouch
41138781Snsoucherror:
41238781Snsouch	*sent = bytes;
413181303Sjhb	PCF_UNLOCK(sc);
41438781Snsouch
41538781Snsouch#ifdef PCFDEBUG
416129704Sjoerg	device_printf(dev, " >> %d bytes written (%d)\n", bytes, error);
41738781Snsouch#endif
41838781Snsouch
41938781Snsouch	return (error);
42038781Snsouch}
42138781Snsouch
422129704Sjoergint
423129704Sjoergpcf_read(device_t dev, char *buf, int len, int *read, int last,
424129704Sjoerg	 int delay /* us */)
42538781Snsouch{
426129704Sjoerg	struct pcf_softc *sc = DEVTOSOFTC(dev);
42738781Snsouch	int bytes, error = 0;
428129704Sjoerg#ifdef PCFDEBUG
429129704Sjoerg	char *obuf = buf;
43038781Snsouch
431129704Sjoerg	device_printf(dev, " << reading %d bytes\n", len);
43238781Snsouch#endif
43338781Snsouch
434181303Sjhb	PCF_LOCK(sc);
43538781Snsouch	/* trig the bus to get the first data byte in S0 */
43638781Snsouch	if (len) {
43740784Snsouch		if (len == 1 && last)
43838781Snsouch			/* just one byte to read */
439129704Sjoerg			pcf_set_S1(sc, ESO);		/* no ack */
44038781Snsouch
441129704Sjoerg		dummy_read(sc);
44238781Snsouch	}
44338781Snsouch
44438781Snsouch	bytes = 0;
44538781Snsouch	while (len) {
44638781Snsouch
44740784Snsouch		/* XXX delay needed here */
44840784Snsouch
44940784Snsouch		/* wait for trigged byte */
450129704Sjoerg		if ((error = pcf_wait_byte(sc))) {
451181303Sjhb			pcf_stop_locked(sc);
45238781Snsouch			goto error;
45338781Snsouch		}
45438781Snsouch
45540784Snsouch		if (len == 1 && last)
45640784Snsouch			/* ok, last data byte already in S0, no I2C activity
457129704Sjoerg			 * on next pcf_get_S0() */
458181303Sjhb			pcf_stop_locked(sc);
45938781Snsouch
46040784Snsouch		else if (len == 2 && last)
46140784Snsouch			/* next trigged byte with no ack */
462129704Sjoerg			pcf_set_S1(sc, ESO);
46338781Snsouch
46440784Snsouch		/* receive byte, trig next byte */
465129704Sjoerg		*buf++ = pcf_get_S0(sc);
46638781Snsouch
46738781Snsouch		len --;
46838781Snsouch		bytes ++;
46938781Snsouch	};
47038781Snsouch
47138781Snsoucherror:
47238781Snsouch	*read = bytes;
473181303Sjhb	PCF_UNLOCK(sc);
47438781Snsouch
47538781Snsouch#ifdef PCFDEBUG
476129704Sjoerg	device_printf(dev, " << %d bytes read (%d): %#x%s\n", bytes, error,
477129704Sjoerg		      (unsigned)obuf[0], bytes > 1? "...": "");
47838781Snsouch#endif
47938781Snsouch
48038781Snsouch	return (error);
48138781Snsouch}
482181332Sjhb
483181332SjhbDRIVER_MODULE(iicbus, pcf, iicbus_driver, iicbus_devclass, 0, 0);
484181332SjhbMODULE_DEPEND(pcf, iicbus, PCF_MINVER, PCF_PREFVER, PCF_MAXVER);
485181332SjhbMODULE_VERSION(pcf, PCF_MODVER);
486