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