pcf.c revision 181303
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: head/sys/dev/pcf/pcf.c 181303 2008-08-04 20:46:15Z jhb $");
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
4438781Snsouch#include <dev/iicbus/iiconf.h>
45129704Sjoerg#include <dev/pcf/pcfvar.h>
4638781Snsouch#include "iicbus_if.h"
4738781Snsouch
48129704Sjoerg/* Not so official debugging option. */
49129704Sjoerg/* #define PCFDEBUG */
5055939Snsouch
51129704Sjoergstatic int pcf_wait_byte(struct pcf_softc *pcf);
52129704Sjoergstatic int pcf_noack(struct pcf_softc *pcf, int timeout);
53181303Sjhbstatic void pcf_stop_locked(struct pcf_softc *pcf);
5438781Snsouch
5538781Snsouch/*
5638781Snsouch * Polling mode for master operations wait for a new
57181303Sjhb * byte incoming or outgoing
5838781Snsouch */
59181303Sjhbstatic int
60129704Sjoergpcf_wait_byte(struct pcf_softc *sc)
6138781Snsouch{
6238781Snsouch	int counter = TIMEOUT;
6338781Snsouch
64181303Sjhb	PCF_ASSERT_LOCKED(sc);
6538781Snsouch	while (counter--) {
6638781Snsouch
67129704Sjoerg		if ((pcf_get_S1(sc) & PIN) == 0)
6838781Snsouch			return (0);
6938781Snsouch	}
7038781Snsouch
71129893Snsouch#ifdef PCFDEBUG
72129893Snsouch	printf("pcf: timeout!\n");
73129893Snsouch#endif
74129893Snsouch
7538781Snsouch	return (IIC_ETIMEOUT);
7638781Snsouch}
7738781Snsouch
78181303Sjhbstatic void
79181303Sjhbpcf_stop_locked(struct pcf_softc *sc)
8038781Snsouch{
8138781Snsouch
82181303Sjhb	PCF_ASSERT_LOCKED(sc);
83129704Sjoerg#ifdef PCFDEBUG
84129704Sjoerg	device_printf(dev, " >> stop\n");
85129704Sjoerg#endif
8640784Snsouch	/*
8740784Snsouch	 * Send STOP condition iff the START condition was previously sent.
88108533Sschweikh	 * STOP is sent only once even if an iicbus_stop() is called after
89129704Sjoerg	 * an iicbus_read()... see pcf_read(): the PCF needs to send the stop
9040784Snsouch	 * before the last char is read.
9140784Snsouch	 */
92129704Sjoerg	if (sc->pcf_started) {
9340784Snsouch		/* set stop condition and enable IT */
94129704Sjoerg		pcf_set_S1(sc, PIN|ESO|ENI|STO|ACK);
9538781Snsouch
96129704Sjoerg		sc->pcf_started = 0;
9740784Snsouch	}
9838781Snsouch}
9938781Snsouch
100181303Sjhbstatic int
101129704Sjoergpcf_noack(struct pcf_softc *sc, int timeout)
10238781Snsouch{
10340784Snsouch	int noack;
10440784Snsouch	int k = timeout/10;
10540784Snsouch
106181303Sjhb	PCF_ASSERT_LOCKED(sc);
10740784Snsouch	do {
108129704Sjoerg		noack = pcf_get_S1(sc) & LRB;
10940784Snsouch		if (!noack)
11040784Snsouch			break;
11140784Snsouch		DELAY(10);				/* XXX wait 10 us */
11240784Snsouch	} while (k--);
11340784Snsouch
11440784Snsouch	return (noack);
11540784Snsouch}
11640784Snsouch
117129704Sjoergint
118129704Sjoergpcf_repeated_start(device_t dev, u_char slave, int timeout)
11940784Snsouch{
120129704Sjoerg	struct pcf_softc *sc = DEVTOSOFTC(dev);
12138781Snsouch	int error = 0;
12238781Snsouch
123181303Sjhb	PCF_LOCK(sc);
124129704Sjoerg#ifdef PCFDEBUG
125129704Sjoerg	device_printf(dev, " >> repeated start for slave %#x\n",
126129704Sjoerg		      (unsigned)slave);
127129704Sjoerg#endif
12838781Snsouch	/* repeated start */
129129704Sjoerg	pcf_set_S1(sc, ESO|STA|STO|ACK);
13038781Snsouch
13138781Snsouch	/* set slave address to PCF. Last bit (LSB) must be set correctly
13238781Snsouch	 * according to transfer direction */
133129704Sjoerg	pcf_set_S0(sc, slave);
13438781Snsouch
13538781Snsouch	/* wait for address sent, polling */
136129704Sjoerg	if ((error = pcf_wait_byte(sc)))
13738781Snsouch		goto error;
13838781Snsouch
13940784Snsouch	/* check for ack */
140129704Sjoerg	if (pcf_noack(sc, timeout)) {
14138781Snsouch		error = IIC_ENOACK;
142129893Snsouch#ifdef PCFDEBUG
143129893Snsouch		printf("pcf: no ack on repeated_start!\n");
144129893Snsouch#endif
14538781Snsouch		goto error;
14638781Snsouch	}
14738781Snsouch
148181303Sjhb	PCF_UNLOCK(sc);
14938781Snsouch	return (0);
15038781Snsouch
15138781Snsoucherror:
152181303Sjhb	pcf_stop_locked(sc);
153181303Sjhb	PCF_UNLOCK(sc);
15438781Snsouch	return (error);
15538781Snsouch}
15638781Snsouch
157129704Sjoergint
158129704Sjoergpcf_start(device_t dev, u_char slave, int timeout)
15938781Snsouch{
160129704Sjoerg	struct pcf_softc *sc = DEVTOSOFTC(dev);
16138781Snsouch	int error = 0;
16238781Snsouch
163181303Sjhb	PCF_LOCK(sc);
164129704Sjoerg#ifdef PCFDEBUG
165129704Sjoerg	device_printf(dev, " >> start for slave %#x\n", (unsigned)slave);
166129704Sjoerg#endif
167129893Snsouch	if ((pcf_get_S1(sc) & nBB) == 0) {
168129893Snsouch#ifdef PCFDEBUG
169129893Snsouch		printf("pcf: busy!\n");
170129893Snsouch#endif
171181303Sjhb		PCF_UNLOCK(sc);
17238781Snsouch		return (IIC_EBUSBSY);
173129893Snsouch	}
17438781Snsouch
17538781Snsouch	/* set slave address to PCF. Last bit (LSB) must be set correctly
17638781Snsouch	 * according to transfer direction */
177129704Sjoerg	pcf_set_S0(sc, slave);
17838781Snsouch
17938781Snsouch	/* START only */
180129704Sjoerg	pcf_set_S1(sc, PIN|ESO|STA|ACK);
18138781Snsouch
182129704Sjoerg	sc->pcf_started = 1;
18340784Snsouch
18438781Snsouch	/* wait for address sent, polling */
185129704Sjoerg	if ((error = pcf_wait_byte(sc)))
18638781Snsouch		goto error;
18738781Snsouch
18840784Snsouch	/* check for ACK */
189129704Sjoerg	if (pcf_noack(sc, timeout)) {
19038781Snsouch		error = IIC_ENOACK;
191129893Snsouch#ifdef PCFDEBUG
192129893Snsouch		printf("pcf: no ack on start!\n");
193129893Snsouch#endif
19438781Snsouch		goto error;
19538781Snsouch	}
19638781Snsouch
197181303Sjhb	PCF_UNLOCK(sc);
19838781Snsouch	return (0);
19938781Snsouch
20038781Snsoucherror:
201181303Sjhb	pcf_stop_locked(sc);
202181303Sjhb	PCF_UNLOCK(sc);
20338781Snsouch	return (error);
20438781Snsouch}
20538781Snsouch
206181303Sjhbint
207181303Sjhbpcf_stop(device_t dev)
208181303Sjhb{
209181303Sjhb	struct pcf_softc *sc = DEVTOSOFTC(dev);
210181303Sjhb
211181303Sjhb#ifdef PCFDEBUG
212181303Sjhb	device_printf(dev, " >> stop\n");
213181303Sjhb#endif
214181303Sjhb	PCF_LOCK(sc);
215181303Sjhb	pcf_stop_locked(sc);
216181303Sjhb	PCF_UNLOCK(sc);
217181303Sjhb
218181303Sjhb	return (0);
219181303Sjhb}
220181303Sjhb
221129704Sjoergvoid
222129704Sjoergpcf_intr(void *arg)
22338781Snsouch{
224129893Snsouch	struct pcf_softc *sc = arg;
22538781Snsouch	char data, status, addr;
22638781Snsouch	char error = 0;
22738781Snsouch
228181303Sjhb	PCF_LOCK(sc);
229129704Sjoerg	status = pcf_get_S1(sc);
23038781Snsouch
23138781Snsouch	if (status & PIN) {
232129893Snsouch		printf("pcf: spurious interrupt, status=0x%x\n",
233129893Snsouch		       status & 0xff);
23438781Snsouch
23538781Snsouch		goto error;
236129704Sjoerg	}
23738781Snsouch
23838781Snsouch	if (status & LAB)
239129893Snsouch		printf("pcf: bus arbitration lost!\n");
24038781Snsouch
24138781Snsouch	if (status & BER) {
24238781Snsouch		error = IIC_EBUSERR;
243129704Sjoerg		iicbus_intr(sc->iicbus, INTR_ERROR, &error);
24438781Snsouch
24538781Snsouch		goto error;
24638781Snsouch	}
24738781Snsouch
24838781Snsouch	do {
249129704Sjoerg		status = pcf_get_S1(sc);
25038781Snsouch
251129704Sjoerg		switch(sc->pcf_slave_mode) {
25238781Snsouch
25338781Snsouch		case SLAVE_TRANSMITTER:
25438781Snsouch			if (status & LRB) {
25538781Snsouch				/* ack interrupt line */
256129704Sjoerg				dummy_write(sc);
25738781Snsouch
25838781Snsouch				/* no ack, don't send anymore */
259129704Sjoerg				sc->pcf_slave_mode = SLAVE_RECEIVER;
26038781Snsouch
261129704Sjoerg				iicbus_intr(sc->iicbus, INTR_NOACK, NULL);
26238781Snsouch				break;
26338781Snsouch			}
26438781Snsouch
26538781Snsouch			/* get data from upper code */
266129704Sjoerg			iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data);
26738781Snsouch
268129704Sjoerg			pcf_set_S0(sc, data);
269129704Sjoerg			break;
270129704Sjoerg
27138781Snsouch		case SLAVE_RECEIVER:
27238781Snsouch			if (status & AAS) {
273129704Sjoerg				addr = pcf_get_S0(sc);
27438781Snsouch
27538781Snsouch				if (status & AD0)
276129704Sjoerg					iicbus_intr(sc->iicbus, INTR_GENERAL, &addr);
27738781Snsouch				else
278129704Sjoerg					iicbus_intr(sc->iicbus, INTR_START, &addr);
27938781Snsouch
28038781Snsouch				if (addr & LSB) {
281129704Sjoerg					sc->pcf_slave_mode = SLAVE_TRANSMITTER;
28238781Snsouch
28338781Snsouch					/* get the first char from upper code */
284129704Sjoerg					iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data);
28538781Snsouch
28638781Snsouch					/* send first data byte */
287129704Sjoerg					pcf_set_S0(sc, data);
28838781Snsouch				}
28938781Snsouch
29038781Snsouch				break;
29138781Snsouch			}
29238781Snsouch
29338781Snsouch			/* stop condition received? */
29438781Snsouch			if (status & STS) {
29538781Snsouch				/* ack interrupt line */
296129704Sjoerg				dummy_read(sc);
29738781Snsouch
29838781Snsouch				/* emulate intr stop condition */
299129704Sjoerg				iicbus_intr(sc->iicbus, INTR_STOP, NULL);
30038781Snsouch
30138781Snsouch			} else {
30238781Snsouch				/* get data, ack interrupt line */
303129704Sjoerg				data = pcf_get_S0(sc);
30438781Snsouch
30538781Snsouch				/* deliver the character */
306129704Sjoerg				iicbus_intr(sc->iicbus, INTR_RECEIVE, &data);
30738781Snsouch			}
30838781Snsouch			break;
30938781Snsouch
31038781Snsouch		    default:
31187599Sobrien			panic("%s: unknown slave mode (%d)!", __func__,
312129704Sjoerg				sc->pcf_slave_mode);
31338781Snsouch		    }
31438781Snsouch
315129704Sjoerg	} while ((pcf_get_S1(sc) & PIN) == 0);
316181303Sjhb	PCF_UNLOCK(sc);
31738781Snsouch
31838781Snsouch	return;
31938781Snsouch
32038781Snsoucherror:
32138781Snsouch	/* unknown event on bus...reset PCF */
322129704Sjoerg	pcf_set_S1(sc, PIN|ESO|ENI|ACK);
32338781Snsouch
324129704Sjoerg	sc->pcf_slave_mode = SLAVE_RECEIVER;
325181303Sjhb	PCF_UNLOCK(sc);
32638781Snsouch
32738781Snsouch	return;
32838781Snsouch}
32938781Snsouch
330129704Sjoergint
331129704Sjoergpcf_rst_card(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
33238781Snsouch{
333129704Sjoerg	struct pcf_softc *sc = DEVTOSOFTC(dev);
33438781Snsouch
335181303Sjhb	PCF_LOCK(sc);
33640784Snsouch	if (oldaddr)
337129704Sjoerg		*oldaddr = sc->pcf_addr;
33840784Snsouch
33938781Snsouch	/* retrieve own address from bus level */
34040784Snsouch	if (!addr)
341129704Sjoerg		sc->pcf_addr = PCF_DEFAULT_ADDR;
34240784Snsouch	else
343129704Sjoerg		sc->pcf_addr = addr;
34438781Snsouch
345129704Sjoerg	pcf_set_S1(sc, PIN);				/* initialize S1 */
346129704Sjoerg
34738781Snsouch	/* own address S'O<>0 */
348129704Sjoerg	pcf_set_S0(sc, sc->pcf_addr >> 1);
34938781Snsouch
35038781Snsouch	/* select clock register */
351129704Sjoerg	pcf_set_S1(sc, PIN|ES1);
35238781Snsouch
35338781Snsouch	/* select bus speed : 18=90kb, 19=45kb, 1A=11kb, 1B=1.5kb */
35438781Snsouch	switch (speed) {
35538781Snsouch	case IIC_SLOW:
356129704Sjoerg		pcf_set_S0(sc,  0x1b); /* XXX Sun uses 0x1f */
35738781Snsouch		break;
35838781Snsouch
35938781Snsouch	case IIC_FAST:
360129704Sjoerg		pcf_set_S0(sc,  0x19); /* XXX Sun: 0x1d */
36138781Snsouch		break;
36238781Snsouch
36338781Snsouch	case IIC_UNKNOWN:
36438781Snsouch	case IIC_FASTEST:
36538781Snsouch	default:
366129704Sjoerg		pcf_set_S0(sc,  0x18); /* XXX Sun: 0x1c */
36738781Snsouch		break;
36838781Snsouch	}
36938781Snsouch
37038781Snsouch	/* set bus on, ack=yes, INT=yes */
371129704Sjoerg	pcf_set_S1(sc, PIN|ESO|ENI|ACK);
37238781Snsouch
373129704Sjoerg	sc->pcf_slave_mode = SLAVE_RECEIVER;
374181303Sjhb	PCF_UNLOCK(sc);
37538781Snsouch
37638781Snsouch	return (0);
37738781Snsouch}
37838781Snsouch
379129704Sjoergint
380129704Sjoergpcf_write(device_t dev, char *buf, int len, int *sent, int timeout /* us */)
38138781Snsouch{
382129704Sjoerg	struct pcf_softc *sc = DEVTOSOFTC(dev);
38338781Snsouch	int bytes, error = 0;
38438781Snsouch
38538781Snsouch#ifdef PCFDEBUG
386129704Sjoerg	device_printf(dev, " >> writing %d bytes: %#x%s\n", len,
387129704Sjoerg		      (unsigned)buf[0], len > 1? "...": "");
38838781Snsouch#endif
38938781Snsouch
39038781Snsouch	bytes = 0;
391181303Sjhb	PCF_LOCK(sc);
39238781Snsouch	while (len) {
39338781Snsouch
394129704Sjoerg		pcf_set_S0(sc, *buf++);
39538781Snsouch
39640784Snsouch		/* wait for the byte to be send */
397129704Sjoerg		if ((error = pcf_wait_byte(sc)))
39838781Snsouch			goto error;
39938781Snsouch
40040784Snsouch		/* check if ack received */
401129704Sjoerg		if (pcf_noack(sc, timeout)) {
40238781Snsouch			error = IIC_ENOACK;
40338781Snsouch			goto error;
40438781Snsouch		}
40538781Snsouch
40638781Snsouch		len --;
40738781Snsouch		bytes ++;
40838781Snsouch	}
40938781Snsouch
41038781Snsoucherror:
41138781Snsouch	*sent = bytes;
412181303Sjhb	PCF_UNLOCK(sc);
41338781Snsouch
41438781Snsouch#ifdef PCFDEBUG
415129704Sjoerg	device_printf(dev, " >> %d bytes written (%d)\n", bytes, error);
41638781Snsouch#endif
41738781Snsouch
41838781Snsouch	return (error);
41938781Snsouch}
42038781Snsouch
421129704Sjoergint
422129704Sjoergpcf_read(device_t dev, char *buf, int len, int *read, int last,
423129704Sjoerg	 int delay /* us */)
42438781Snsouch{
425129704Sjoerg	struct pcf_softc *sc = DEVTOSOFTC(dev);
42638781Snsouch	int bytes, error = 0;
427129704Sjoerg#ifdef PCFDEBUG
428129704Sjoerg	char *obuf = buf;
42938781Snsouch
430129704Sjoerg	device_printf(dev, " << reading %d bytes\n", len);
43138781Snsouch#endif
43238781Snsouch
433181303Sjhb	PCF_LOCK(sc);
43438781Snsouch	/* trig the bus to get the first data byte in S0 */
43538781Snsouch	if (len) {
43640784Snsouch		if (len == 1 && last)
43738781Snsouch			/* just one byte to read */
438129704Sjoerg			pcf_set_S1(sc, ESO);		/* no ack */
43938781Snsouch
440129704Sjoerg		dummy_read(sc);
44138781Snsouch	}
44238781Snsouch
44338781Snsouch	bytes = 0;
44438781Snsouch	while (len) {
44538781Snsouch
44640784Snsouch		/* XXX delay needed here */
44740784Snsouch
44840784Snsouch		/* wait for trigged byte */
449129704Sjoerg		if ((error = pcf_wait_byte(sc))) {
450181303Sjhb			pcf_stop_locked(sc);
45138781Snsouch			goto error;
45238781Snsouch		}
45338781Snsouch
45440784Snsouch		if (len == 1 && last)
45540784Snsouch			/* ok, last data byte already in S0, no I2C activity
456129704Sjoerg			 * on next pcf_get_S0() */
457181303Sjhb			pcf_stop_locked(sc);
45838781Snsouch
45940784Snsouch		else if (len == 2 && last)
46040784Snsouch			/* next trigged byte with no ack */
461129704Sjoerg			pcf_set_S1(sc, ESO);
46238781Snsouch
46340784Snsouch		/* receive byte, trig next byte */
464129704Sjoerg		*buf++ = pcf_get_S0(sc);
46538781Snsouch
46638781Snsouch		len --;
46738781Snsouch		bytes ++;
46838781Snsouch	};
46938781Snsouch
47038781Snsoucherror:
47138781Snsouch	*read = bytes;
472181303Sjhb	PCF_UNLOCK(sc);
47338781Snsouch
47438781Snsouch#ifdef PCFDEBUG
475129704Sjoerg	device_printf(dev, " << %d bytes read (%d): %#x%s\n", bytes, error,
476129704Sjoerg		      (unsigned)obuf[0], bytes > 1? "...": "");
47738781Snsouch#endif
47838781Snsouch
47938781Snsouch	return (error);
48038781Snsouch}
481