]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/iicbus/iiconf.c
This commit was generated by cvs2svn to compensate for changes in r156701,
[FreeBSD/FreeBSD.git] / sys / dev / iicbus / iiconf.c
1 /*-
2  * Copyright (c) 1998 Nicolas Souchu
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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/module.h>
33 #include <sys/bus.h>
34
35 #include <dev/iicbus/iiconf.h>
36 #include <dev/iicbus/iicbus.h>
37 #include "iicbus_if.h"
38
39 /*
40  * iicbus_intr()
41  */
42 void
43 iicbus_intr(device_t bus, int event, char *buf)
44 {
45         struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
46
47         /* call owner's intr routine */
48         if (sc->owner)
49                 IICBUS_INTR(sc->owner, event, buf);
50
51         return;
52 }
53
54 static int
55 iicbus_poll(struct iicbus_softc *sc, int how)
56 {
57         int error;
58
59         switch (how) {
60         case (IIC_WAIT | IIC_INTR):
61                 error = tsleep(sc, IICPRI|PCATCH, "iicreq", 0);
62                 break;
63
64         case (IIC_WAIT | IIC_NOINTR):
65                 error = tsleep(sc, IICPRI, "iicreq", 0);
66                 break;
67
68         default:
69                 return (EWOULDBLOCK);
70                 break;
71         }
72
73         return (error);
74 }
75
76 /*
77  * iicbus_request_bus()
78  *
79  * Allocate the device to perform transfers.
80  *
81  * how  : IIC_WAIT or IIC_DONTWAIT
82  */
83 int
84 iicbus_request_bus(device_t bus, device_t dev, int how)
85 {
86         struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
87         int s, error = 0;
88
89         /* first, ask the underlying layers if the request is ok */
90         do {
91                 error = IICBUS_CALLBACK(device_get_parent(bus),
92                                                 IIC_REQUEST_BUS, (caddr_t)&how);
93                 if (error)
94                         error = iicbus_poll(sc, how);
95         } while (error == EWOULDBLOCK);
96
97         while (!error) {
98                 s = splhigh();  
99                 if (sc->owner && sc->owner != dev) {
100                         splx(s);
101
102                         error = iicbus_poll(sc, how);
103                 } else {
104                         sc->owner = dev;
105
106                         splx(s);
107                         return (0);
108                 }
109
110                 /* free any allocated resource */
111                 if (error)
112                         IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS,
113                                         (caddr_t)&how);
114         }
115
116         return (error);
117 }
118
119 /*
120  * iicbus_release_bus()
121  *
122  * Release the device allocated with iicbus_request_dev()
123  */
124 int
125 iicbus_release_bus(device_t bus, device_t dev)
126 {
127         struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
128         int s, error;
129
130         /* first, ask the underlying layers if the release is ok */
131         error = IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS, NULL);
132
133         if (error)
134                 return (error);
135
136         s = splhigh();
137         if (sc->owner != dev) {
138                 splx(s);
139                 return (EACCES);
140         }
141
142         sc->owner = 0;
143         splx(s);
144
145         /* wakeup waiting processes */
146         wakeup(sc);
147
148         return (0);
149 }
150
151 /*
152  * iicbus_started()
153  *
154  * Test if the iicbus is started by the controller
155  */
156 int
157 iicbus_started(device_t bus)
158 {
159         struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
160
161         return (sc->started);
162 }
163
164 /*
165  * iicbus_start()
166  *
167  * Send start condition to the slave addressed by 'slave'
168  */
169 int
170 iicbus_start(device_t bus, u_char slave, int timeout)
171 {
172         struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
173         int error = 0;
174
175         if (sc->started)
176                 return (EINVAL);                /* bus already started */
177
178         if (!(error = IICBUS_START(device_get_parent(bus), slave, timeout)))
179                 sc->started = slave;
180         else
181                 sc->started = 0;
182
183         return (error);
184 }
185
186 /*
187  * iicbus_repeated_start()
188  *
189  * Send start condition to the slave addressed by 'slave'
190  */
191 int
192 iicbus_repeated_start(device_t bus, u_char slave, int timeout)
193 {
194         struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
195         int error = 0;
196
197         if (!sc->started)
198                 return (EINVAL);     /* bus should have been already started */
199
200         if (!(error = IICBUS_REPEATED_START(device_get_parent(bus), slave, timeout)))
201                 sc->started = slave;
202         else
203                 sc->started = 0;
204
205         return (error);
206 }
207
208 /*
209  * iicbus_stop()
210  *
211  * Send stop condition to the bus
212  */
213 int
214 iicbus_stop(device_t bus)
215 {
216         struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
217         int error = 0;
218
219         if (!sc->started)
220                 return (EINVAL);                /* bus not started */
221
222         error = IICBUS_STOP(device_get_parent(bus));
223
224         /* refuse any further access */
225         sc->started = 0;
226
227         return (error);
228 }
229
230 /*
231  * iicbus_write()
232  *
233  * Write a block of data to the slave previously started by
234  * iicbus_start() call
235  */
236 int
237 iicbus_write(device_t bus, char *buf, int len, int *sent, int timeout)
238 {
239         struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
240         
241         /* a slave must have been started with the appropriate address */
242         if (!sc->started || (sc->started & LSB))
243                 return (EINVAL);
244
245         return (IICBUS_WRITE(device_get_parent(bus), buf, len, sent, timeout));
246 }
247
248 /*
249  * iicbus_read()
250  *
251  * Read a block of data from the slave previously started by
252  * iicbus_read() call
253  */
254 int 
255 iicbus_read(device_t bus, char *buf, int len, int *read, int last, int delay)
256 {
257         struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
258         
259         /* a slave must have been started with the appropriate address */
260         if (!sc->started || !(sc->started & LSB))
261                 return (EINVAL);
262
263         return (IICBUS_READ(device_get_parent(bus), buf, len, read, last, delay));
264 }
265
266 /*
267  * iicbus_write_byte()
268  *
269  * Write a byte to the slave previously started by iicbus_start() call
270  */
271 int
272 iicbus_write_byte(device_t bus, char byte, int timeout)
273 {
274         char data = byte;
275         int sent;
276
277         return (iicbus_write(bus, &data, 1, &sent, timeout));
278 }
279
280 /*
281  * iicbus_read_byte()
282  *
283  * Read a byte from the slave previously started by iicbus_start() call
284  */
285 int
286 iicbus_read_byte(device_t bus, char *byte, int timeout)
287 {
288         int read;
289
290         return (iicbus_read(bus, byte, 1, &read, IIC_LAST_READ, timeout));
291 }
292
293 /*
294  * iicbus_block_write()
295  *
296  * Write a block of data to slave ; start/stop protocol managed
297  */
298 int
299 iicbus_block_write(device_t bus, u_char slave, char *buf, int len, int *sent)
300 {
301         u_char addr = slave & ~LSB;
302         int error;
303
304         if ((error = iicbus_start(bus, addr, 0)))
305                 return (error);
306
307         error = iicbus_write(bus, buf, len, sent, 0);
308
309         iicbus_stop(bus);
310
311         return (error);
312 }
313
314 /*
315  * iicbus_block_read()
316  *
317  * Read a block of data from slave ; start/stop protocol managed
318  */
319 int
320 iicbus_block_read(device_t bus, u_char slave, char *buf, int len, int *read)
321 {
322         u_char addr = slave | LSB;
323         int error;
324
325         if ((error = iicbus_start(bus, addr, 0)))
326                 return (error);
327
328         error = iicbus_read(bus, buf, len, read, IIC_LAST_READ, 0);
329
330         iicbus_stop(bus);
331
332         return (error);
333 }