xref: /freebsd/sys/dev/pcf/pcf.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 1998 Nicolas Souchu, Marc Bouget
5  * Copyright (c) 2004 Joerg Wunsch
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/param.h>
31 #include <sys/bus.h>
32 #include <sys/lock.h>
33 #include <sys/kernel.h>
34 #include <sys/module.h>
35 #include <sys/mutex.h>
36 #include <sys/systm.h>
37 
38 #include <machine/bus.h>
39 #include <machine/resource.h>
40 
41 #include <sys/rman.h>
42 
43 #include <dev/iicbus/iicbus.h>
44 #include <dev/iicbus/iiconf.h>
45 #include <dev/pcf/pcfvar.h>
46 #include "iicbus_if.h"
47 
48 /* Not so official debugging option. */
49 /* #define PCFDEBUG */
50 
51 static int pcf_wait_byte(struct pcf_softc *pcf);
52 static int pcf_noack(struct pcf_softc *pcf, int timeout);
53 static void pcf_stop_locked(struct pcf_softc *pcf);
54 
55 /*
56  * Polling mode for master operations wait for a new
57  * byte incoming or outgoing
58  */
59 static int
pcf_wait_byte(struct pcf_softc * sc)60 pcf_wait_byte(struct pcf_softc *sc)
61 {
62 	int counter = TIMEOUT;
63 
64 	PCF_ASSERT_LOCKED(sc);
65 	while (counter--) {
66 		if ((pcf_get_S1(sc) & PIN) == 0)
67 			return (0);
68 	}
69 
70 #ifdef PCFDEBUG
71 	printf("pcf: timeout!\n");
72 #endif
73 
74 	return (IIC_ETIMEOUT);
75 }
76 
77 static void
pcf_stop_locked(struct pcf_softc * sc)78 pcf_stop_locked(struct pcf_softc *sc)
79 {
80 
81 	PCF_ASSERT_LOCKED(sc);
82 #ifdef PCFDEBUG
83 	device_printf(dev, " >> stop\n");
84 #endif
85 	/*
86 	 * Send STOP condition iff the START condition was previously sent.
87 	 * STOP is sent only once even if an iicbus_stop() is called after
88 	 * an iicbus_read()... see pcf_read(): the PCF needs to send the stop
89 	 * before the last char is read.
90 	 */
91 	if (sc->pcf_started) {
92 		/* set stop condition and enable IT */
93 		pcf_set_S1(sc, PIN|ESO|ENI|STO|ACK);
94 
95 		sc->pcf_started = 0;
96 	}
97 }
98 
99 static int
pcf_noack(struct pcf_softc * sc,int timeout)100 pcf_noack(struct pcf_softc *sc, int timeout)
101 {
102 	int noack;
103 	int k = timeout/10;
104 
105 	PCF_ASSERT_LOCKED(sc);
106 	do {
107 		noack = pcf_get_S1(sc) & LRB;
108 		if (!noack)
109 			break;
110 		DELAY(10);				/* XXX wait 10 us */
111 	} while (k--);
112 
113 	return (noack);
114 }
115 
116 int
pcf_repeated_start(device_t dev,u_char slave,int timeout)117 pcf_repeated_start(device_t dev, u_char slave, int timeout)
118 {
119 	struct pcf_softc *sc = DEVTOSOFTC(dev);
120 	int error = 0;
121 
122 	PCF_LOCK(sc);
123 #ifdef PCFDEBUG
124 	device_printf(dev, " >> repeated start for slave %#x\n",
125 		      (unsigned)slave);
126 #endif
127 	/* repeated start */
128 	pcf_set_S1(sc, ESO|STA|STO|ACK);
129 
130 	/* set slave address to PCF. Last bit (LSB) must be set correctly
131 	 * according to transfer direction */
132 	pcf_set_S0(sc, slave);
133 
134 	/* wait for address sent, polling */
135 	if ((error = pcf_wait_byte(sc)))
136 		goto error;
137 
138 	/* check for ack */
139 	if (pcf_noack(sc, timeout)) {
140 		error = IIC_ENOACK;
141 #ifdef PCFDEBUG
142 		printf("pcf: no ack on repeated_start!\n");
143 #endif
144 		goto error;
145 	}
146 
147 	PCF_UNLOCK(sc);
148 	return (0);
149 
150 error:
151 	pcf_stop_locked(sc);
152 	PCF_UNLOCK(sc);
153 	return (error);
154 }
155 
156 int
pcf_start(device_t dev,u_char slave,int timeout)157 pcf_start(device_t dev, u_char slave, int timeout)
158 {
159 	struct pcf_softc *sc = DEVTOSOFTC(dev);
160 	int error = 0;
161 
162 	PCF_LOCK(sc);
163 #ifdef PCFDEBUG
164 	device_printf(dev, " >> start for slave %#x\n", (unsigned)slave);
165 #endif
166 	if ((pcf_get_S1(sc) & nBB) == 0) {
167 #ifdef PCFDEBUG
168 		printf("pcf: busy!\n");
169 #endif
170 		PCF_UNLOCK(sc);
171 		return (IIC_EBUSERR);
172 	}
173 
174 	/* set slave address to PCF. Last bit (LSB) must be set correctly
175 	 * according to transfer direction */
176 	pcf_set_S0(sc, slave);
177 
178 	/* START only */
179 	pcf_set_S1(sc, PIN|ESO|STA|ACK);
180 
181 	sc->pcf_started = 1;
182 
183 	/* wait for address sent, polling */
184 	if ((error = pcf_wait_byte(sc)))
185 		goto error;
186 
187 	/* check for ACK */
188 	if (pcf_noack(sc, timeout)) {
189 		error = IIC_ENOACK;
190 #ifdef PCFDEBUG
191 		printf("pcf: no ack on start!\n");
192 #endif
193 		goto error;
194 	}
195 
196 	PCF_UNLOCK(sc);
197 	return (0);
198 
199 error:
200 	pcf_stop_locked(sc);
201 	PCF_UNLOCK(sc);
202 	return (error);
203 }
204 
205 int
pcf_stop(device_t dev)206 pcf_stop(device_t dev)
207 {
208 	struct pcf_softc *sc = DEVTOSOFTC(dev);
209 
210 #ifdef PCFDEBUG
211 	device_printf(dev, " >> stop\n");
212 #endif
213 	PCF_LOCK(sc);
214 	pcf_stop_locked(sc);
215 	PCF_UNLOCK(sc);
216 
217 	return (0);
218 }
219 
220 void
pcf_intr(void * arg)221 pcf_intr(void *arg)
222 {
223 	struct pcf_softc *sc = arg;
224 	char data, status, addr;
225 	char error = 0;
226 
227 	PCF_LOCK(sc);
228 	status = pcf_get_S1(sc);
229 
230 	if (status & PIN) {
231 		printf("pcf: spurious interrupt, status=0x%x\n",
232 		       status & 0xff);
233 
234 		goto error;
235 	}
236 
237 	if (status & LAB)
238 		printf("pcf: bus arbitration lost!\n");
239 
240 	if (status & BER) {
241 		error = IIC_EBUSERR;
242 		iicbus_intr(sc->iicbus, INTR_ERROR, &error);
243 
244 		goto error;
245 	}
246 
247 	do {
248 		status = pcf_get_S1(sc);
249 
250 		switch(sc->pcf_slave_mode) {
251 		case SLAVE_TRANSMITTER:
252 			if (status & LRB) {
253 				/* ack interrupt line */
254 				dummy_write(sc);
255 
256 				/* no ack, don't send anymore */
257 				sc->pcf_slave_mode = SLAVE_RECEIVER;
258 
259 				iicbus_intr(sc->iicbus, INTR_NOACK, NULL);
260 				break;
261 			}
262 
263 			/* get data from upper code */
264 			iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data);
265 
266 			pcf_set_S0(sc, data);
267 			break;
268 
269 		case SLAVE_RECEIVER:
270 			if (status & AAS) {
271 				addr = pcf_get_S0(sc);
272 
273 				if (status & AD0)
274 					iicbus_intr(sc->iicbus, INTR_GENERAL, &addr);
275 				else
276 					iicbus_intr(sc->iicbus, INTR_START, &addr);
277 
278 				if (addr & LSB) {
279 					sc->pcf_slave_mode = SLAVE_TRANSMITTER;
280 
281 					/* get the first char from upper code */
282 					iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data);
283 
284 					/* send first data byte */
285 					pcf_set_S0(sc, data);
286 				}
287 
288 				break;
289 			}
290 
291 			/* stop condition received? */
292 			if (status & STS) {
293 				/* ack interrupt line */
294 				dummy_read(sc);
295 
296 				/* emulate intr stop condition */
297 				iicbus_intr(sc->iicbus, INTR_STOP, NULL);
298 
299 			} else {
300 				/* get data, ack interrupt line */
301 				data = pcf_get_S0(sc);
302 
303 				/* deliver the character */
304 				iicbus_intr(sc->iicbus, INTR_RECEIVE, &data);
305 			}
306 			break;
307 
308 		    default:
309 			panic("%s: unknown slave mode (%d)!", __func__,
310 				sc->pcf_slave_mode);
311 		    }
312 
313 	} while ((pcf_get_S1(sc) & PIN) == 0);
314 	PCF_UNLOCK(sc);
315 
316 	return;
317 
318 error:
319 	/* unknown event on bus...reset PCF */
320 	pcf_set_S1(sc, PIN|ESO|ENI|ACK);
321 
322 	sc->pcf_slave_mode = SLAVE_RECEIVER;
323 	PCF_UNLOCK(sc);
324 
325 	return;
326 }
327 
328 int
pcf_rst_card(device_t dev,u_char speed,u_char addr,u_char * oldaddr)329 pcf_rst_card(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
330 {
331 	struct pcf_softc *sc = DEVTOSOFTC(dev);
332 
333 	PCF_LOCK(sc);
334 	if (oldaddr)
335 		*oldaddr = sc->pcf_addr;
336 
337 	/* retrieve own address from bus level */
338 	if (!addr)
339 		sc->pcf_addr = PCF_DEFAULT_ADDR;
340 	else
341 		sc->pcf_addr = addr;
342 
343 	pcf_set_S1(sc, PIN);				/* initialize S1 */
344 
345 	/* own address S'O<>0 */
346 	pcf_set_S0(sc, sc->pcf_addr >> 1);
347 
348 	/* select clock register */
349 	pcf_set_S1(sc, PIN|ES1);
350 
351 	/* select bus speed : 18=90kb, 19=45kb, 1A=11kb, 1B=1.5kb */
352 	switch (speed) {
353 	case IIC_SLOW:
354 		pcf_set_S0(sc,  0x1b); /* XXX Sun uses 0x1f */
355 		break;
356 
357 	case IIC_FAST:
358 		pcf_set_S0(sc,  0x19); /* XXX Sun: 0x1d */
359 		break;
360 
361 	case IIC_UNKNOWN:
362 	case IIC_FASTEST:
363 	default:
364 		pcf_set_S0(sc,  0x18); /* XXX Sun: 0x1c */
365 		break;
366 	}
367 
368 	/* set bus on, ack=yes, INT=yes */
369 	pcf_set_S1(sc, PIN|ESO|ENI|ACK);
370 
371 	sc->pcf_slave_mode = SLAVE_RECEIVER;
372 	PCF_UNLOCK(sc);
373 
374 	return (0);
375 }
376 
377 int
pcf_write(device_t dev,const char * buf,int len,int * sent,int timeout)378 pcf_write(device_t dev, const char *buf, int len, int *sent, int timeout /* us */)
379 {
380 	struct pcf_softc *sc = DEVTOSOFTC(dev);
381 	int bytes, error = 0;
382 
383 #ifdef PCFDEBUG
384 	device_printf(dev, " >> writing %d bytes: %#x%s\n", len,
385 		      (unsigned)buf[0], len > 1? "...": "");
386 #endif
387 
388 	bytes = 0;
389 	PCF_LOCK(sc);
390 	while (len) {
391 		pcf_set_S0(sc, *buf++);
392 
393 		/* wait for the byte to be send */
394 		if ((error = pcf_wait_byte(sc)))
395 			goto error;
396 
397 		/* check if ack received */
398 		if (pcf_noack(sc, timeout)) {
399 			error = IIC_ENOACK;
400 			goto error;
401 		}
402 
403 		len --;
404 		bytes ++;
405 	}
406 
407 error:
408 	*sent = bytes;
409 	PCF_UNLOCK(sc);
410 
411 #ifdef PCFDEBUG
412 	device_printf(dev, " >> %d bytes written (%d)\n", bytes, error);
413 #endif
414 
415 	return (error);
416 }
417 
418 int
pcf_read(device_t dev,char * buf,int len,int * read,int last,int delay)419 pcf_read(device_t dev, char *buf, int len, int *read, int last,
420 	 int delay /* us */)
421 {
422 	struct pcf_softc *sc = DEVTOSOFTC(dev);
423 	int bytes, error = 0;
424 #ifdef PCFDEBUG
425 	char *obuf = buf;
426 
427 	device_printf(dev, " << reading %d bytes\n", len);
428 #endif
429 
430 	PCF_LOCK(sc);
431 	/* trig the bus to get the first data byte in S0 */
432 	if (len) {
433 		if (len == 1 && last)
434 			/* just one byte to read */
435 			pcf_set_S1(sc, ESO);		/* no ack */
436 
437 		dummy_read(sc);
438 	}
439 
440 	bytes = 0;
441 	while (len) {
442 		/* XXX delay needed here */
443 
444 		/* wait for trigged byte */
445 		if ((error = pcf_wait_byte(sc))) {
446 			pcf_stop_locked(sc);
447 			goto error;
448 		}
449 
450 		if (len == 1 && last)
451 			/* ok, last data byte already in S0, no I2C activity
452 			 * on next pcf_get_S0() */
453 			pcf_stop_locked(sc);
454 
455 		else if (len == 2 && last)
456 			/* next trigged byte with no ack */
457 			pcf_set_S1(sc, ESO);
458 
459 		/* receive byte, trig next byte */
460 		*buf++ = pcf_get_S0(sc);
461 
462 		len --;
463 		bytes ++;
464 	}
465 
466 error:
467 	*read = bytes;
468 	PCF_UNLOCK(sc);
469 
470 #ifdef PCFDEBUG
471 	device_printf(dev, " << %d bytes read (%d): %#x%s\n", bytes, error,
472 		      (unsigned)obuf[0], bytes > 1? "...": "");
473 #endif
474 
475 	return (error);
476 }
477 
478 DRIVER_MODULE(iicbus, pcf, iicbus_driver, 0, 0);
479 MODULE_DEPEND(pcf, iicbus, PCF_MINVER, PCF_PREFVER, PCF_MAXVER);
480 MODULE_VERSION(pcf, PCF_MODVER);
481