xref: /freebsd/sys/dev/pcf/pcf.c (revision 98edb3e17869504d0ada58932efa96b71f899181)
1 /*-
2  * Copyright (c) 1998 Nicolas Souchu, Marc Bouget
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *	$Id: pcf.c,v 1.8 1999/05/06 18:54:18 peter Exp $
27  *
28  */
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/module.h>
33 #include <sys/bus.h>
34 #include <sys/conf.h>
35 #include <sys/malloc.h>
36 
37 #include <machine/clock.h>
38 
39 #include <i386/isa/isa_device.h>
40 
41 #include <dev/iicbus/iiconf.h>
42 #include "iicbus_if.h"
43 
44 #define TIMEOUT	9999					/* XXX */
45 
46 /* Status bits of S1 register (read only) */
47 #define nBB	0x01		/* busy when low set/reset by STOP/START*/
48 #define LAB	0x02		/* lost arbitration bit in multi-master mode */
49 #define AAS	0x04		/* addressed as slave */
50 #define LRB	0x08		/* last received byte when not AAS */
51 #define AD0	0x08		/* general call received when AAS */
52 #define BER	0x10		/* bus error, misplaced START or STOP */
53 #define STS	0x20		/* STOP detected in slave receiver mode */
54 #define PIN	0x80		/* pending interrupt not (r/w) */
55 
56 /* Control bits of S1 register (write only) */
57 #define ACK	0x01
58 #define STO	0x02
59 #define STA	0x04
60 #define ENI	0x08
61 #define ES2	0x10
62 #define ES1	0x20
63 #define ES0	0x40
64 
65 #define BUFSIZE 2048
66 
67 #define SLAVE_TRANSMITTER	0x1
68 #define SLAVE_RECEIVER		0x2
69 
70 #define PCF_DEFAULT_ADDR	0xaa
71 
72 struct pcf_softc {
73 
74 	int pcf_base;			/* isa port */
75 	u_char pcf_addr;		/* interface I2C address */
76 
77 	int pcf_slave_mode;		/* receiver or transmitter */
78 	int pcf_started;		/* 1 if start condition sent */
79 
80 	device_t iicbus;		/* the corresponding iicbus */
81 };
82 
83 struct pcf_isa_softc {
84 
85 	int pcf_unit;			/* unit of the isa device */
86 	int pcf_base;			/* isa port */
87 	int pcf_irq;			/* isa irq or null if polled */
88 
89 	unsigned int pcf_flags;		/* boot flags */
90 };
91 
92 #define MAXPCF 2
93 
94 static struct pcf_isa_softc *pcfdata[MAXPCF];
95 static int npcf = 0;
96 
97 static int	pcfprobe_isa(struct isa_device *);
98 static int	pcfattach_isa(struct isa_device *);
99 
100 struct isa_driver pcfdriver = {
101 	pcfprobe_isa, pcfattach_isa, "pcf"
102 };
103 
104 static int pcf_probe(device_t);
105 static int pcf_attach(device_t);
106 static void pcf_print_child(device_t, device_t);
107 
108 static int pcf_repeated_start(device_t, u_char, int);
109 static int pcf_start(device_t, u_char, int);
110 static int pcf_stop(device_t);
111 static int pcf_write(device_t, char *, int, int *, int);
112 static int pcf_read(device_t, char *, int, int *, int, int);
113 static ointhand2_t pcfintr;
114 static int pcf_rst_card(device_t, u_char, u_char, u_char *);
115 
116 static device_method_t pcf_methods[] = {
117 	/* device interface */
118 	DEVMETHOD(device_probe,		pcf_probe),
119 	DEVMETHOD(device_attach,	pcf_attach),
120 
121 	/* bus interface */
122 	DEVMETHOD(bus_print_child,	pcf_print_child),
123 
124 	/* iicbus interface */
125 	DEVMETHOD(iicbus_callback,	iicbus_null_callback),
126 	DEVMETHOD(iicbus_repeated_start, pcf_repeated_start),
127 	DEVMETHOD(iicbus_start,		pcf_start),
128 	DEVMETHOD(iicbus_stop,		pcf_stop),
129 	DEVMETHOD(iicbus_write,		pcf_write),
130 	DEVMETHOD(iicbus_read,		pcf_read),
131 	DEVMETHOD(iicbus_reset,		pcf_rst_card),
132 
133 	{ 0, 0 }
134 };
135 
136 static driver_t pcf_driver = {
137 	"pcf",
138 	pcf_methods,
139 	sizeof(struct pcf_softc),
140 };
141 
142 static devclass_t pcf_devclass;
143 
144 #define DEVTOSOFTC(dev) ((struct pcf_softc *)device_get_softc(dev))
145 
146 static int
147 pcfprobe_isa(struct isa_device *dvp)
148 {
149 	device_t pcfdev;
150 	struct pcf_isa_softc *pcf;
151 
152 	if (npcf >= MAXPCF)
153 		return (0);
154 
155 	if ((pcf = (struct pcf_isa_softc *)malloc(sizeof(struct pcf_isa_softc),
156 			M_DEVBUF, M_NOWAIT)) == NULL)
157 		return (0);
158 
159 	pcf->pcf_base = dvp->id_iobase;		/* XXX should be ivars */
160 	pcf->pcf_unit = dvp->id_unit;
161 
162 	if (!(dvp->id_flags & IIC_POLLED))
163 		pcf->pcf_irq = (dvp->id_irq);
164 
165 	pcfdata[npcf++] = pcf;
166 
167 	/* XXX add the pcf device to the root_bus until isa bus exists */
168 	pcfdev = device_add_child(root_bus, "pcf", pcf->pcf_unit, NULL);
169 
170 	if (!pcfdev)
171 		goto error;
172 
173 	return (1);
174 
175 error:
176 	free(pcf, M_DEVBUF);
177 	return (0);
178 }
179 
180 static int
181 pcfattach_isa(struct isa_device *isdp)
182 {
183 	isdp->id_ointr = pcfintr;
184 	return (1);				/* ok */
185 }
186 
187 static int
188 pcf_probe(device_t pcfdev)
189 {
190 	struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(pcfdev);
191 	int unit = device_get_unit(pcfdev);
192 
193 	/* retrieve base address from isa initialization
194 	 *
195 	 * XXX should use ivars with isabus
196 	 */
197 	pcf->pcf_base = pcfdata[unit]->pcf_base;
198 
199 	/* reset the chip */
200 	pcf_rst_card(pcfdev, IIC_FASTEST, PCF_DEFAULT_ADDR, NULL);
201 
202 	/* XXX try do detect chipset */
203 
204 	device_set_desc(pcfdev, "PCF8584 I2C bus controller");
205 
206 	return (0);
207 }
208 
209 static int
210 pcf_attach(device_t pcfdev)
211 {
212 	struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(pcfdev);
213 
214 	pcf->iicbus = iicbus_alloc_bus(pcfdev);
215 
216 	/* probe and attach the iicbus */
217 	device_probe_and_attach(pcf->iicbus);
218 
219 	return (0);
220 }
221 
222 static void
223 pcf_print_child(device_t bus, device_t dev)
224 {
225 	struct pcf_softc *pcf = (struct pcf_softc *)device_get_softc(bus);
226 
227 	printf(" on %s%d addr 0x%x", device_get_name(bus),
228 		device_get_unit(bus), (int)pcf->pcf_addr);
229 
230 	return;
231 }
232 
233 /*
234  * PCF8584 datasheet : when operate at 8 MHz or more, a minimun time of
235  * 6 clocks cycles must be left between two consecutives access
236  */
237 #define pcf_nops()	DELAY(10)
238 
239 #define dummy_read(pcf)		PCF_GET_S0(pcf)
240 #define dummy_write(pcf)	PCF_SET_S0(pcf, 0)
241 
242 /*
243  * Specific register access to PCF8584
244  */
245 static void PCF_SET_S0(struct pcf_softc *pcf, int data)
246 {
247 	outb(pcf->pcf_base, data);
248 	pcf_nops();
249 }
250 
251 static void PCF_SET_S1(struct pcf_softc *pcf, int data)
252 {
253 	outb(pcf->pcf_base+1, data);
254 	pcf_nops();
255 }
256 
257 static char PCF_GET_S0(struct pcf_softc *pcf)
258 {
259 	char data;
260 
261 	data = inb(pcf->pcf_base);
262 	pcf_nops();
263 
264 	return (data);
265 }
266 
267 static char PCF_GET_S1(struct pcf_softc *pcf)
268 {
269 	char data;
270 
271 	data = inb(pcf->pcf_base+1);
272 	pcf_nops();
273 
274 	return (data);
275 }
276 
277 /*
278  * Polling mode for master operations wait for a new
279  * byte incomming or outgoing
280  */
281 static int pcf_wait_byte(struct pcf_softc *pcf)
282 {
283 	int counter = TIMEOUT;
284 
285 	while (counter--) {
286 
287 		if ((PCF_GET_S1(pcf) & PIN) == 0)
288 			return (0);
289 	}
290 
291 	return (IIC_ETIMEOUT);
292 }
293 
294 static int pcf_stop(device_t pcfdev)
295 {
296 	struct pcf_softc *pcf = DEVTOSOFTC(pcfdev);
297 
298 	/*
299 	 * Send STOP condition iff the START condition was previously sent.
300 	 * STOP is sent only once even if a iicbus_stop() is called after
301 	 * an iicbus_read()... see pcf_read(): the pcf needs to send the stop
302 	 * before the last char is read.
303 	 */
304 	if (pcf->pcf_started) {
305 		/* set stop condition and enable IT */
306 		PCF_SET_S1(pcf, PIN|ES0|ENI|STO|ACK);
307 
308 		pcf->pcf_started = 0;
309 	}
310 
311 	return (0);
312 }
313 
314 
315 static int pcf_noack(struct pcf_softc *pcf, int timeout)
316 {
317 	int noack;
318 	int k = timeout/10;
319 
320 	do {
321 		noack = PCF_GET_S1(pcf) & LRB;
322 		if (!noack)
323 			break;
324 		DELAY(10);				/* XXX wait 10 us */
325 	} while (k--);
326 
327 	return (noack);
328 }
329 
330 static int pcf_repeated_start(device_t pcfdev, u_char slave, int timeout)
331 {
332 	struct pcf_softc *pcf = DEVTOSOFTC(pcfdev);
333 	int error = 0;
334 
335 	/* repeated start */
336 	PCF_SET_S1(pcf, ES0|STA|STO|ACK);
337 
338 	/* set slave address to PCF. Last bit (LSB) must be set correctly
339 	 * according to transfer direction */
340 	PCF_SET_S0(pcf, slave);
341 
342 	/* wait for address sent, polling */
343 	if ((error = pcf_wait_byte(pcf)))
344 		goto error;
345 
346 	/* check for ack */
347 	if (pcf_noack(pcf, timeout)) {
348 		error = IIC_ENOACK;
349 		goto error;
350 	}
351 
352 	return (0);
353 
354 error:
355 	pcf_stop(pcfdev);
356 	return (error);
357 }
358 
359 static int pcf_start(device_t pcfdev, u_char slave, int timeout)
360 {
361 	struct pcf_softc *pcf = DEVTOSOFTC(pcfdev);
362 	int error = 0;
363 
364 	if ((PCF_GET_S1(pcf) & nBB) == 0)
365 		return (IIC_EBUSBSY);
366 
367 	/* set slave address to PCF. Last bit (LSB) must be set correctly
368 	 * according to transfer direction */
369 	PCF_SET_S0(pcf, slave);
370 
371 	/* START only */
372 	PCF_SET_S1(pcf, PIN|ES0|STA|ACK);
373 
374 	pcf->pcf_started = 1;
375 
376 	/* wait for address sent, polling */
377 	if ((error = pcf_wait_byte(pcf)))
378 		goto error;
379 
380 	/* check for ACK */
381 	if (pcf_noack(pcf, timeout)) {
382 		error = IIC_ENOACK;
383 		goto error;
384 	}
385 
386 	return (0);
387 
388 error:
389 	pcf_stop(pcfdev);
390 	return (error);
391 }
392 
393 static void
394 pcfintr(unit)
395 {
396 	struct pcf_softc *pcf =
397 		(struct pcf_softc *)devclass_get_softc(pcf_devclass, unit);
398 
399 	char data, status, addr;
400 	char error = 0;
401 
402 	status = PCF_GET_S1(pcf);
403 
404 	if (status & PIN) {
405 		printf("pcf%d: spurious interrupt, status=0x%x\n", unit,
406 			status & 0xff);
407 
408 		goto error;
409 	}
410 
411 	if (status & LAB)
412 		printf("pcf%d: bus arbitration lost!\n", unit);
413 
414 	if (status & BER) {
415 		error = IIC_EBUSERR;
416 		iicbus_intr(pcf->iicbus, INTR_ERROR, &error);
417 
418 		goto error;
419 	}
420 
421 	do {
422 		status = PCF_GET_S1(pcf);
423 
424 		switch(pcf->pcf_slave_mode) {
425 
426 		case SLAVE_TRANSMITTER:
427 			if (status & LRB) {
428 				/* ack interrupt line */
429 				dummy_write(pcf);
430 
431 				/* no ack, don't send anymore */
432 				pcf->pcf_slave_mode = SLAVE_RECEIVER;
433 
434 				iicbus_intr(pcf->iicbus, INTR_NOACK, NULL);
435 				break;
436 			}
437 
438 			/* get data from upper code */
439 			iicbus_intr(pcf->iicbus, INTR_TRANSMIT, &data);
440 
441 			PCF_SET_S0(pcf, data);
442 			break;
443 
444 		case SLAVE_RECEIVER:
445 			if (status & AAS) {
446 				addr = PCF_GET_S0(pcf);
447 
448 				if (status & AD0)
449 					iicbus_intr(pcf->iicbus, INTR_GENERAL, &addr);
450 				else
451 					iicbus_intr(pcf->iicbus, INTR_START, &addr);
452 
453 				if (addr & LSB) {
454 					pcf->pcf_slave_mode = SLAVE_TRANSMITTER;
455 
456 					/* get the first char from upper code */
457 					iicbus_intr(pcf->iicbus, INTR_TRANSMIT, &data);
458 
459 					/* send first data byte */
460 					PCF_SET_S0(pcf, data);
461 				}
462 
463 				break;
464 			}
465 
466 			/* stop condition received? */
467 			if (status & STS) {
468 				/* ack interrupt line */
469 				dummy_read(pcf);
470 
471 				/* emulate intr stop condition */
472 				iicbus_intr(pcf->iicbus, INTR_STOP, NULL);
473 
474 			} else {
475 				/* get data, ack interrupt line */
476 				data = PCF_GET_S0(pcf);
477 
478 				/* deliver the character */
479 				iicbus_intr(pcf->iicbus, INTR_RECEIVE, &data);
480 			}
481 			break;
482 
483 		    default:
484 			panic("%s: unknown slave mode (%d)!", __FUNCTION__,
485 				pcf->pcf_slave_mode);
486 		    }
487 
488 	} while ((PCF_GET_S1(pcf) & PIN) == 0);
489 
490 	return;
491 
492 error:
493 	/* unknown event on bus...reset PCF */
494 	PCF_SET_S1(pcf, PIN|ES0|ENI|ACK);
495 
496 	pcf->pcf_slave_mode = SLAVE_RECEIVER;
497 
498 	return;
499 }
500 
501 static int pcf_rst_card(device_t pcfdev, u_char speed, u_char addr, u_char *oldaddr)
502 {
503 	struct pcf_softc *pcf = DEVTOSOFTC(pcfdev);
504 
505 	if (oldaddr)
506 		*oldaddr = pcf->pcf_addr;
507 
508 	/* retrieve own address from bus level */
509 	if (!addr)
510 		pcf->pcf_addr = PCF_DEFAULT_ADDR;
511 	else
512 		pcf->pcf_addr = addr;
513 
514 	PCF_SET_S1(pcf, PIN);				/* initialize S1 */
515 
516 	/* own address S'O<>0 */
517 	PCF_SET_S0(pcf, pcf->pcf_addr >> 1);
518 
519 	/* select clock register */
520 	PCF_SET_S1(pcf, PIN|ES1);
521 
522 	/* select bus speed : 18=90kb, 19=45kb, 1A=11kb, 1B=1.5kb */
523 	switch (speed) {
524 	case IIC_SLOW:
525 		PCF_SET_S0(pcf,  0x1b);
526 		break;
527 
528 	case IIC_FAST:
529 		PCF_SET_S0(pcf,  0x19);
530 		break;
531 
532 	case IIC_UNKNOWN:
533 	case IIC_FASTEST:
534 	default:
535 		PCF_SET_S0(pcf,  0x18);
536 		break;
537 	}
538 
539 	/* set bus on, ack=yes, INT=yes */
540 	PCF_SET_S1(pcf, PIN|ES0|ENI|ACK);
541 
542 	pcf->pcf_slave_mode = SLAVE_RECEIVER;
543 
544 	return (0);
545 }
546 
547 static int
548 pcf_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 
576 error:
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 
587 static int
588 pcf_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 
634 error:
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 
645 DRIVER_MODULE(pcf, root, pcf_driver, pcf_devclass, 0, 0);
646