xref: /freebsd/sys/dev/iicbus/iiconf.c (revision 0efd6615cd5f39b67cec82a7034e655f3b5801e3)
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, const 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 }
334 
335 /*
336  * iicbus_trasnfer()
337  *
338  * Do an aribtrary number of transfers on the iicbus.  We pass these
339  * raw requests to the bridge driver.  If the bridge driver supports
340  * them directly, then it manages all the details.  If not, it can use
341  * the helper function iicbus_transfer_gen() which will do the
342  * transfers at a low level.
343  *
344  * Pointers passed in as part of iic_msg must be kernel pointers.
345  * Callers that have user addresses to manage must do so on their own.
346  */
347 int
348 iicbus_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs)
349 {
350 	return (IICBUS_TRANSFER(device_get_parent(bus), msgs, nmsgs));
351 }
352 
353 /*
354  * Generic version of iicbus_transfer that calls the appropriate
355  * routines to accomplish this.  See note above about acceptable
356  * buffer addresses.
357  */
358 int
359 iicbus_transfer_gen(device_t bus, struct iic_msg *msgs, uint32_t nmsgs)
360 {
361 	int i, error, max, lenread, lenwrote;
362 
363 	for (i = 0, max = 0; i < nmsgs; i++)
364 		if (max < msgs[i].len)
365 			max = msgs[i].len;
366 	for (i = 0, error = 0; i < nmsgs && error == 0; i++) {
367 		if (msgs[i].flags & IIC_M_RD)
368 			error = iicbus_block_read(bus, msgs[i].slave,
369 			    msgs[i].buf, msgs[i].len, &lenread);
370 		else
371 			error = iicbus_block_write(bus, msgs[i].slave,
372 			    msgs[i].buf, msgs[i].len, &lenwrote);
373 	}
374 	return (error);
375 }
376