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/lock.h>
33#include <sys/malloc.h>
34#include <sys/module.h>
35#include <sys/mutex.h>
36#include <sys/bus.h>
37
38#include <dev/iicbus/iiconf.h>
39#include <dev/iicbus/iicbus.h>
40#include "iicbus_if.h"
41
42/*
43 * iicbus_intr()
44 */
45void
46iicbus_intr(device_t bus, int event, char *buf)
47{
48	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
49
50	/* call owner's intr routine */
51	if (sc->owner)
52		IICBUS_INTR(sc->owner, event, buf);
53
54	return;
55}
56
57static int
58iicbus_poll(struct iicbus_softc *sc, int how)
59{
60	int error;
61
62	IICBUS_ASSERT_LOCKED(sc);
63	switch (how) {
64	case IIC_WAIT | IIC_INTR:
65		error = mtx_sleep(sc, &sc->lock, IICPRI|PCATCH, "iicreq", 0);
66		break;
67
68	case IIC_WAIT | IIC_NOINTR:
69		error = mtx_sleep(sc, &sc->lock, IICPRI, "iicreq", 0);
70		break;
71
72	default:
73		return (EWOULDBLOCK);
74		break;
75	}
76
77	return (error);
78}
79
80/*
81 * iicbus_request_bus()
82 *
83 * Allocate the device to perform transfers.
84 *
85 * how	: IIC_WAIT or IIC_DONTWAIT
86 */
87int
88iicbus_request_bus(device_t bus, device_t dev, int how)
89{
90	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
91	int error = 0;
92
93	/* first, ask the underlying layers if the request is ok */
94	IICBUS_LOCK(sc);
95	do {
96		error = IICBUS_CALLBACK(device_get_parent(bus),
97						IIC_REQUEST_BUS, (caddr_t)&how);
98		if (error)
99			error = iicbus_poll(sc, how);
100	} while (error == EWOULDBLOCK);
101
102	while (!error) {
103		if (sc->owner && sc->owner != dev) {
104
105			error = iicbus_poll(sc, how);
106		} else {
107			sc->owner = dev;
108
109			IICBUS_UNLOCK(sc);
110			return (0);
111		}
112
113		/* free any allocated resource */
114		if (error)
115			IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS,
116					(caddr_t)&how);
117	}
118	IICBUS_UNLOCK(sc);
119
120	return (error);
121}
122
123/*
124 * iicbus_release_bus()
125 *
126 * Release the device allocated with iicbus_request_dev()
127 */
128int
129iicbus_release_bus(device_t bus, device_t dev)
130{
131	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
132	int error;
133
134	/* first, ask the underlying layers if the release is ok */
135	error = IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS, NULL);
136
137	if (error)
138		return (error);
139
140	IICBUS_LOCK(sc);
141
142	if (sc->owner != dev) {
143		IICBUS_UNLOCK(sc);
144		return (EACCES);
145	}
146
147	sc->owner = NULL;
148
149	/* wakeup waiting processes */
150	wakeup(sc);
151	IICBUS_UNLOCK(sc);
152
153	return (0);
154}
155
156/*
157 * iicbus_started()
158 *
159 * Test if the iicbus is started by the controller
160 */
161int
162iicbus_started(device_t bus)
163{
164	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
165
166	return (sc->started);
167}
168
169/*
170 * iicbus_start()
171 *
172 * Send start condition to the slave addressed by 'slave'
173 */
174int
175iicbus_start(device_t bus, u_char slave, int timeout)
176{
177	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
178	int error = 0;
179
180	if (sc->started)
181		return (EINVAL);		/* bus already started */
182
183	if (!(error = IICBUS_START(device_get_parent(bus), slave, timeout)))
184		sc->started = slave;
185	else
186		sc->started = 0;
187
188	return (error);
189}
190
191/*
192 * iicbus_repeated_start()
193 *
194 * Send start condition to the slave addressed by 'slave'
195 */
196int
197iicbus_repeated_start(device_t bus, u_char slave, int timeout)
198{
199	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
200	int error = 0;
201
202	if (!sc->started)
203		return (EINVAL);     /* bus should have been already started */
204
205	if (!(error = IICBUS_REPEATED_START(device_get_parent(bus), slave, timeout)))
206		sc->started = slave;
207	else
208		sc->started = 0;
209
210	return (error);
211}
212
213/*
214 * iicbus_stop()
215 *
216 * Send stop condition to the bus
217 */
218int
219iicbus_stop(device_t bus)
220{
221	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
222	int error = 0;
223
224	if (!sc->started)
225		return (EINVAL);		/* bus not started */
226
227	error = IICBUS_STOP(device_get_parent(bus));
228
229	/* refuse any further access */
230	sc->started = 0;
231
232	return (error);
233}
234
235/*
236 * iicbus_write()
237 *
238 * Write a block of data to the slave previously started by
239 * iicbus_start() call
240 */
241int
242iicbus_write(device_t bus, const char *buf, int len, int *sent, int timeout)
243{
244	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
245
246	/* a slave must have been started for writing */
247	if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) != 0))
248		return (EINVAL);
249
250	return (IICBUS_WRITE(device_get_parent(bus), buf, len, sent, timeout));
251}
252
253/*
254 * iicbus_read()
255 *
256 * Read a block of data from the slave previously started by
257 * iicbus_read() call
258 */
259int
260iicbus_read(device_t bus, char *buf, int len, int *read, int last, int delay)
261{
262	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
263
264	/* a slave must have been started for reading */
265	if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) == 0))
266		return (EINVAL);
267
268	return (IICBUS_READ(device_get_parent(bus), buf, len, read, last, delay));
269}
270
271/*
272 * iicbus_write_byte()
273 *
274 * Write a byte to the slave previously started by iicbus_start() call
275 */
276int
277iicbus_write_byte(device_t bus, char byte, int timeout)
278{
279	char data = byte;
280	int sent;
281
282	return (iicbus_write(bus, &data, 1, &sent, timeout));
283}
284
285/*
286 * iicbus_read_byte()
287 *
288 * Read a byte from the slave previously started by iicbus_start() call
289 */
290int
291iicbus_read_byte(device_t bus, char *byte, int timeout)
292{
293	int read;
294
295	return (iicbus_read(bus, byte, 1, &read, IIC_LAST_READ, timeout));
296}
297
298/*
299 * iicbus_block_write()
300 *
301 * Write a block of data to slave ; start/stop protocol managed
302 */
303int
304iicbus_block_write(device_t bus, u_char slave, char *buf, int len, int *sent)
305{
306	u_char addr = slave & ~LSB;
307	int error;
308
309	if ((error = iicbus_start(bus, addr, 0)))
310		return (error);
311
312	error = iicbus_write(bus, buf, len, sent, 0);
313
314	iicbus_stop(bus);
315
316	return (error);
317}
318
319/*
320 * iicbus_block_read()
321 *
322 * Read a block of data from slave ; start/stop protocol managed
323 */
324int
325iicbus_block_read(device_t bus, u_char slave, char *buf, int len, int *read)
326{
327	u_char addr = slave | LSB;
328	int error;
329
330	if ((error = iicbus_start(bus, addr, 0)))
331		return (error);
332
333	error = iicbus_read(bus, buf, len, read, IIC_LAST_READ, 0);
334
335	iicbus_stop(bus);
336
337	return (error);
338}
339
340/*
341 * iicbus_transfer()
342 *
343 * Do an aribtrary number of transfers on the iicbus.  We pass these
344 * raw requests to the bridge driver.  If the bridge driver supports
345 * them directly, then it manages all the details.  If not, it can use
346 * the helper function iicbus_transfer_gen() which will do the
347 * transfers at a low level.
348 *
349 * Pointers passed in as part of iic_msg must be kernel pointers.
350 * Callers that have user addresses to manage must do so on their own.
351 */
352int
353iicbus_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs)
354{
355	return (IICBUS_TRANSFER(device_get_parent(bus), msgs, nmsgs));
356}
357
358/*
359 * Generic version of iicbus_transfer that calls the appropriate
360 * routines to accomplish this.  See note above about acceptable
361 * buffer addresses.
362 */
363int
364iicbus_transfer_gen(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
365{
366	int i, error, lenread, lenwrote, nkid, rpstart, addr;
367	device_t *children, bus;
368
369	if ((error = device_get_children(dev, &children, &nkid)) != 0)
370		return (error);
371	if (nkid != 1) {
372		free(children, M_TEMP);
373		return (EIO);
374	}
375	bus = children[0];
376	rpstart = 0;
377	free(children, M_TEMP);
378	for (i = 0, error = 0; i < nmsgs && error == 0; i++) {
379		addr = msgs[i].slave;
380		if (msgs[i].flags & IIC_M_RD)
381			addr |= LSB;
382		else
383			addr &= ~LSB;
384
385		if (!(msgs[i].flags & IIC_M_NOSTART)) {
386			if (rpstart)
387				error = iicbus_repeated_start(bus, addr, 0);
388			else
389				error = iicbus_start(bus, addr, 0);
390		}
391
392		if (error)
393			break;
394
395		if (msgs[i].flags & IIC_M_RD)
396			error = iicbus_read(bus, msgs[i].buf, msgs[i].len,
397			    &lenread, IIC_LAST_READ, 0);
398		else
399			error = iicbus_write(bus, msgs[i].buf, msgs[i].len,
400			    &lenwrote, 0);
401
402		if (!(msgs[i].flags & IIC_M_NOSTOP)) {
403			rpstart = 0;
404			iicbus_stop(bus);
405		} else {
406			rpstart = 1;	/* Next message gets repeated start */
407		}
408	}
409	return (error);
410}
411